8 Мини-языки: поиск выразительной нотации

We use cookies. Read the Privacy and Cookie Policy

8

Мини-языки: поиск выразительной нотации

Хорошая нотация обладает тонкостью и выразительностью, которая со временем делает ее почти похожей на живого учителя.

The World of Mathematics (1956)

—Бертранд Рассел (Bertrand Russell)

Одним из самых последовательных результатов крупномасштабных исследований ошибок в программировании является то, что уровень ошибок программиста, выраженный в количестве дефектов на 100 строк кода, почти не зависит от языка, на котором написана программа[76]. Высокоуровневые языки, которые позволяют добиться больших результатов, используя меньшее количество строк, также означают меньшее количество ошибок.

В Unix имеется давняя традиция поддержки небольших языков, предназначенных для определенной прикладной области, языков, которые могут способствовать в радикальном сокращении количества строк кода в программах. Примеры узкоспециальных (domain-specific) языков включают в себя многочисленные языки разметки текстов (troff, eqn, tbl, pic, grap), утилиты оболочки (awk, sed, dc, bc) и средства разработки программного обеспечения (make, уасс, lex). Невозможно провести четкие границы между узкоспециальными языками и более гибким видом файлов конфигурации программ (sendmail, BIND, X), или форматами файлов данных, или языками сценариев (которые рассматриваются в главе 14).

В сообществе Unix для таких языков узкоспециального назначения исторически определилось название "малые языки" или "мини-языки" , поскольку ранние их примеры были небольшими и имели небольшую сложность по сравнению с универсальными языками (в настоящее время широко используются все 3 термина для данной категории). Однако если предметная область сложна (тем, что имеет множество различных примитивных операций или включает в себя манипуляцию сложными структурами данных), то для нее может понадобиться прикладной язык, гораздо более сложный, чем некоторые универсальные языки. В данной книге используется традиционный термин "мини-язык" (minilanguage), для того чтобы подчеркнуть, что мудрое решение обычно заключается в сохранении данных конструкций небольшими и простыми насколько это возможно.

Узкоспециальный небольшой язык — чрезвычайно мощная конструкторская идея. Он позволяет определить собственный высокоуровневый язык для указания соответствующих методов, правил и алгоритмов, направленных на разрешение ближайшей задачи, сокращая глобальную сложность по сравнению с конструкцией, в которой для тех же целей используется жестко встроенный низкоуровневый код. Прийти к использованию мини-языка можно как минимум тремя путями, два из которых хороши, а один опасен.

Один из верных путей заключается в том, чтобы заранее осознать возможность использования конструкции на основе мини-языка, для того чтобы поднять данную спецификацию проблемы программирования на уровень выше к форме записи, которая является более компактной и выразительной, чем нотация, поддерживаемая в универсальном языке. Как и в случае с генерацией кода и создания программ, управляемых данными, мини-язык позволяет извлечь практическое преимущество из того факта, что количество ошибок в программном обеспечении будет почти не зависеть от уровня используемого языка; использование более выразительных языков означает более короткие программы и меньшее количество ошибок.

Второй правильный путь — заметить, что один из файловых форматов разрабатываемой спецификации очень похож на мини-язык, т.е. в нем развиваются сложные структуры и подразумеваются действия в контролируемом приложении. Можно ли с помощью данного языка попытаться описать управляющую логику так же, как форматы данных? Если это так, то, возможно, настало время перевести управляющую логику из неявного вида в явный в языке спецификации.

Ошибочный путь к конструкции мини-языка — это растягивать путь к нему, постепенно добавляя заплатки и сложные функции. На этом пути файл спецификации содержит задатки более скрытой управляющей логики и более замысловатых специализированных структур до тех пор, пока незаметно не станет сложным уникальным языком. Несколько "легендарных кошмаров встают" на этом пути. Каждый Unix-гуру вздрогнет при упоминании конфигурационного файла sendmail.cf, связанного с почтовым транспортом sendmail.

К сожалению, большинство разработчиков создают свой первый мини-язык ошибочным способом и только позднее осознают, насколько он запутан. Как очистить мини-язык? Иногда ответ предполагает переосмысление конструкции всего приложения. Другим печально известным примером был редактор TECO, в котором возник первый макрос, а затем появились циклы и условные операторы по мере того, как программисты хотели использовать его для упаковки редактирующих подпрограмм с возрастающей сложностью. Созданная в результате уродливая конструкция была в конечном итоге исправлена путем переработки всего редактора, основанного на заранее продуманном языке. Так развивался Emacs Lisp (который рассматривается ниже).

Все достаточно сложные файлы спецификаций поднимаются до уровня мини- языков. Поэтому часто единственный способ обезопасить себя от создания плохого мини-языка заключается в том, чтобы знать, как создать хороший мини-язык. Это не должно быть сопряжено с неимоверными трудностями и наличием особых знаний относительно формальной теории языков. Вполне достаточно практического проектирования с помощью современных инструментов, изучения немногих относительно простых технических приемов и ознакомления с хорошими примерами.

В данной главе рассматриваются все виды мини-языков, обычно поддерживаемых в Unix. Кроме того, ниже определяются ситуации, в которых каждый из них представляет эффективное конструктивное решение. При этом данная глава не является исчерпывающим каталогом Unix-языков, а скорее направлена на выявления принципов конструирования, задействованных в структурировании приложений вокруг мини-языка. Универсальные языки программирования более подробно рассматриваются в главе 14.

Начать следует с небольшой классификации, которая поможет лучше понять дальнейший материал.

Данный текст является ознакомительным фрагментом.