пакетом GNU plotutils, в которой использована внутренняя модульность кода GNU pic (1). Код был разделен на клиентскую часть, выполняющую синтаксический анализ, и серверную часть, генерирующую troff-разметку. Обе части взаимодействовали посредством уровня чертежных примитивов. Поскольку данная конструкция подчинялась правилу модульности, программисты pic2plot(1) имели возможность отделить этап синтаксического анализа GNU pic и реконструировать чертежные примитивы с помощью современной библиотеки для построения графиков. Однако их решение имеет один недостаток. Текст на выходе генерируется со встроенными в pic2plot шрифтами, которые не соответствуют шрифтам troff.
8.2.7. Учебный пример: синтаксис конфигурационного файла fetchmail
Рассмотрим пример 8.5.
Конфигурационный файл может рассматриваться как императивный мини-язык. Существует предполагаемый поток выполнения: повторяющаяся, циклическая обработка списка команд опроса ('засыпающая' на время в конце каждого цикла) и последовательный сбор почты с каждого из указанных узлов для каждого пользователя, связанного с определенными узлами. Данный язык далек от универсальных языков. Все, что он способен делать, — создавать последовательность команд опроса серверов.
Как и в случае с программой pic(1), данный мини-язык можно рассматривать как объявления либо как слабый императивный язык и бесконечно спорить об отличиях. С одной стороны, в нем нет ни условных операторов, ни рекурсии, ни циклов. Фактически он вообще не имеет явных управляющих структур. С другой стороны, он описывает скорее действия, чем зависимости, что отличает его от исключительно декларативного синтаксиса, подобного GUI-описаниям Glade.
Пример 8.5. Синтетический код fetchmailrc
#Опрашивать данный узел первым в цикле.
poll pop.provider.net proto pop3
user 'jsmith' with pass 'secret1' is 'smith' here
user jones with pass 'secret2' is 'jjones' here with options keep
# Опрашивать данный узел вторым
poll billywig.hogwarts.com with proto imap:
user harry_potter with pass 'floo' is harry_potter here
# Опрашивать данный узел третьим в цикле.
# Пароль будет взят из файла ~/.netrc
poll mailhost.net with proto imap:
user esr is esr here
Конфигурационные мини-языки для сложных программ часто переходят эту границу. Данный факт подчеркивается здесь потому, что отсутствие явных управляющих структур в императивном мини-языке может быть колоссальным упрощением, если это позволяет предметная область.
Примечательной особенностью синтаксиса .fetchmailrc
является использование необязательных ключевых слов, которые поддерживаются просто для того, чтобы язык спецификаций более походил на английский язык. Ключевые слова 'with' и однократное употребление слова 'options' в примере фактически не являются обязательными, но позволяют упростить описания для чтения.
Традиционно подобный синтаксис называется синтаксическим сахаром (syntactic sugar). Данному термину сопутствует известное высказывание о том, что 'синтаксический сахар вызывает рак двоеточий'[85]. Действительно, чтобы синтаксический сахар не создавал трудностей больше, чем может решить проблем, его необходимо использовать умеренно.
В главе 9 показано, как создание программ, управляемых данными, способствует изящному решению проблемы редактирования конфигурационных файлов fetchmail с помощью графического интерфейса.
8.2.8. Учебный пример: awk
Мини-язык awk является инструментальным средством Unix старой школы, прежде широко используемым в shell-сценариях. Как и m4, утилита awk предназначена для написания небольших, но выразительных программ для преобразования текстового ввода в текстовый вывод. Версии утилиты поставляются со всеми Unix- системами. Некоторые из них реализованы с открытым исходным кодом. Команда info gawk
в командной строке Unix весьма вероятно позволит получить справочную документацию по программе.
Программы, написанные на awk, состоят из пар шаблон/действие. Каждый шаблон представляет собой регулярное выражение; эта концепция подробно описывается в главе 9. После запуска awk-программа последовательно анализирует все строки во входном файле. Каждая строка по порядку сравнивается с парой шаблон/действие. Если шаблон соответствует строке, то осуществляется связанное с шаблоном действие.
Каждое действие кодируется на языке, подобном подмножеству языка С, с переменными, условными операторами, циклами и онтологией типов, включая целые числа, строки и (в отличие от С) словари[86].
Язык действий awk является языком Тьюринга и позволяет считывать и записывать файлы. В некоторых версиях он также позволяет открывать и использовать сетевые сокеты. Однако awk главным образом используется как генератор отчетов, особенно для интерпретации и предварительной обработки табличных данных. Он редко используется автономно, но часто встраивается в сценарии. В главе 9, в учебном примере по созданию HTML-документа имеется пример awk-программы.
Учебный пример awk приведен в этой книге, чтобы подчеркнуть, что данный язык не является моделью для подражания. Фактически с 1990 года awk почти совершенно вышел из употребления. На смену ему пришли языки сценариев новой школы, особенно Perl, который явно предназначался для того, чтобы полностью вытеснить awk. Причины достойны внимания, поскольку они поучительны для разработчиков мини-языков.
Язык awk первоначально разрабатывался как небольшой, выразительный язык специального назначения для создания отчетов. К сожалению, его соотношение сложность-мощность оказалось неудачным. Язык действий некомпактен, а шаблонно-управляемая структура, внутри которой он содержится, не позволяет применять его широко. Данный язык унаследовал худшие черты обоих миров. Кроме того, языки сценариев новой школы могут решать все задачи, решаемые awk. Эквивалентные программы, написанные на этих языках, обычно также, если не лучше, читабельны.
Язык awk вышел из употребления также вследствие того, что более современные оболочки обладают средствами вычислений с плавающей точкой, ассоциативными массивами, поддержкой регулярных выражений и средствами обработки подстрок, поэтому эквивалентные небольшим awk-сценариям программы могут быть реализованы без издержек создания процесса.
Дэвид Корн.