Искусство программирования для Unix
Шрифт:
Один из этих уроков отрицательный. Иногда пользователи, пишущие описание в миниязыке, допускают некорректные действия с низкоуровневой troff-разметкой, вставленной вручную. Это может повлечь за собой последствия и ошибки, которые трудно диагностировать, поскольку данные, сгенерированные troff и выходящие из конвейера, не видны, а если бы были видны, то были бы нечитаемыми. Такие ошибки аналогичны ошибкам, которые возникают в коде, когда С-код смешан с фрагментами ассемблера. Было бы лучше, если бы уровни языков были разделены более основательно, если бы это было возможно. Разработчикам мини-языков следует учесть эти проблемы.
Все языки препроцессоров (кроме самой troff-разметки) имеют сравнительно четкий, shell-подобный
Хотя troff сам по себе представляет собой специализированный императивный мини-язык, одной из идей, которая "проходит" как минимум через 3 мини-языка в DWB, является декларативная семантика: компоновка документа на основе ограничивающих условий. Данная идея также характерна для современных GUI-инстру-ментариев. Вместо того чтобы указывать координаты пикселей для графических объектов, единственное, что действительно требуется сделать — это объявить пространственные взаимозависимости между ними ("элемент управления А расположен выше элемента В, который находится слева от элемента С"), а затем заставить программное обеспечение вычислить наилучшее расположение элементов А, В и С, соответствующее заданным ограничивающим условиям.
В программе pic( 1) данный подход используется для компоновки элементов диаграмм. Диаграмма классификации языков на рис. 8.1 была создана на основе приведенного в примере 8.463 исходного pic-кода, обработанного с помощью команды pic2graph, которая рассматривалась в одном из учебных примеров главы 7.
Это весьма типичная для Unix конструкция мини-языка, и как таковая она имеет несколько интересных моментов даже на уровне синтаксиса. Следует отметить ее сходство с shell-программой: комментарии начинаются с символа #, а синтаксис, очевидно, организован на основе лексем и имеет простейшее возможное соглашение для строк. Разработчик pic(1) знал, что Unix-программисты ожидают подобный этому синтаксис мини-языков, если не существует значительной и специфической причины не делать этого. В данном случае в полной мере выполняется правило наименьшей неожиданности.
Пример 8.4. pic-код для схемы классификации языков
# Minilanguage taxonomy (классификация мини-языков)
#
# Base ellipses (основные элипсы)
define smallellipse {ellipse width 3.0 height 1.5} M: ellipse width 3.0 height 1.8 fill 0.2 line from M.n to M.s dashed D: smallellipse with .e at M.w + (0.8, 0) line from D.n to D.s dashed
I: smallellipse with .w at M.e - (0.8, 0)
#
# Captions (подписи) "" "Data formats" at D.s "" "Minilanguages" at M.s
«« "interpreters" at I.в #
# Heads (заголовки)
arrow from D.w + (0.4, 0.8) to D.e + (-0.4, 0.8) "flat to structured" "" at last arrow.с
arrow from M.w + (0.4, 1.0) to M.e + (-0.4, 1.0)
"declarative to imperative" "" at last arrow.с
arrow from I.w + (0.4, 0.8) to I.e + (-0.4, 0.8)
"less to more general" "" at last arrow.с
#
# The arrow of loopiness (стрелка развития циклов) arrow from D.w + (0, 1.2) to I.e + (0, 1.2)
"increasing loopiness" "" at last arrow.с
#
# Flat data files (плоские файлы данных) "/etc/passwd" ".newsrc" at 0.5 between D.c and D.w
# Structured data files (структурированные файлы данных) "SNG" at 0.5 between D.c and M.w
# Datafile/minilanguage borderline cases (пограничные случаи файлы данных/мини-язык)
"regexps" "Glade" at 0.5 between M.w and D.e
# Declarative minilanguages (декларативные мини-языки) "m4" "Yacc" "Lex" "make" "XSLT" "pic" "tbl" "eqn" \
at 0.5 between M.с and D.e
# Imperative minilanguages (императивные мини-языки) "fetchmail" "awk" "troff" "Postscript" at 0.5 between M.c and I.w
# Minilanguage/interpreter borderline cases (пограничные случаи мини-язык/интерпретатор)
"dc" "be" at 0.5 between I.w and M.e
# Interpreters (интерпретаторы)
"Emacs Lisp" "JavaScript" at 0.25 between M.e and I.e
"sh" "tel" at 0.55 between M.e and I.e
"Perl" "Python" "Java" at 0.8 between M.e and I.e
Комбинация макросов с компоновкой на основе ограничивающих условий позволяет программе pic(1) выражать структуру диаграмм таким способом, который недоступен для более современных векторных разметок, таких как SVG. Следовательно, благоприятно, то, что одним из следствий конструкции Documenter's Workbench является то, что она относительно упрощает использование программы pic(1) за пределами среды DWB. Сценарий pic2graph, использованный в качестве учебного примера в главе 7, был специально создан для достижения этой цели с помощью модернизированных PostScript-возможностей groff (1) как промежуточный этап на пути к современному растровому формату.
Более четким решением является утилита pic2plot(1), распространяемая с пакетом GNU plotutils, в которой использована внутренняя модульность кода GNU pic( 1). Код был разделен на клиентскую часть, выполняющую синтаксический анализ, и серверную часть, генерирующую troff-разметку. Обе части взаимодействовали посредством уровня чертежных примитивов. Поскольку данная конструкция подчинялась правилу модульности, программисты pic2plot(1) имели возможность отделить этап синтаксического анализа GNU pic и реконструировать чертежные примитивы с помощью современной библиотеки для построения графиков. Однако их решение имеет один недостаток. Текст на выходе генерируется со встроенными в pic2plot шрифтами, которые не соответствуют шрифтам troff.
8.2.7. Учебный пример: синтаксис конфигурационного файла fetchmail
Рассмотрим пример 8.5.
Конфигурационный файл может рассматриваться как императивный мини-язык. Существует предполагаемый поток выполнения: повторяющаяся, циклическая обработка списка команд опроса ("засыпающая" на время в конце каждого цикла) и последовательный сбор почты с каждого из указанных узлов для каждого пользователя, связанного с определенными узлами. Данный язык далек от универсальных языков. Все, что он способен делать, — создавать последовательность команд опроса серверов.