Чтение онлайн

на главную

Жанры

Искусство программирования для Unix

Реймонд Эрик Стивен

Шрифт:

В данном вопросе, как и в других, хороший вкус и инженерное мышление невозможно заменить ничем. Разрабатывая мини-язык, не следует делать это наполовину. Декларативные мини-языки должны иметь очевидный, последовательный языковой синтаксис, облегчающий их чтение. В императивных языках необходимо добавить полный диапазон управляющих структур, который адаптирован из языковых моделей, с которыми, пользователи разрабатываемого мини-языка, вероятно, знакомы. О языке необходимо думать как о языке, спрашивая себя: "будет ли удобно программировать на нем?" и даже "приятно ли будет смотреть на данную конструкцию?". Здесь, как и в других областях разработки программного обеспечения, применим принцип Дэвида Гелентера: красота — основная

защита против сложности.

8.3.2. Расширение и встраивание языков

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

Иногда можно написать императивный язык путем простого кодирования служебных функций в интерпретируемый язык, который далее в целях освещения данной темы называется "базовым" (host) языком. Программы, написанные на таком мини-языке, являются просто сценариями, которые загружают служебную библиотеку и используют управляющие структуры и другие средства базового языка как каркас. Каждое средство, имеющееся в базовом языке, избавляет от необходимости писать собственное аналогичное средство.

Данный способ является простейшим для написания мини-языка. Lisp-программисты старой школы (включая самого автора) предпочитают данный прием и интенсивно его используют. Он лежит в основе конструкции редактора Emacs и открывается заново в языках сценариев новой школы, таких как Tcl, Python и Perl. Однако такой подход имеет свои недостатки.

Базовый язык может оказаться неспособным предоставить интерфейс к необходимой библиотеке кода. Или его онтология типов данных может оказаться неадекватной для необходимого вида вычислений. Или измерения покажут слишком низкий уровень производительности прототипа. В таких ситуациях обычным решением является программирование на С (или С++) и интеграция результатов в создаваемый мини-язык.

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

Обе методики также зависят от способности перемещать данные между онтологией типов С и онтологией типов используемого языка сценариев. Некоторые языки сценариев, в целях поддержки такой возможности разработаны снизу вверх. Одним из них является Tcl, который рассматривается в главе 14, другим — Guile, диалект с открытым исходным кодом Lisp-варианта Scheme. Guile поставляется в виде библиотеки и специально предназначен для внедрения в C-программы.

Вполне возможно (хотя до сих пор довольно трудно) расширять или встраивать язык Perl. Очень просто расширять Python и немного сложнее внедрять его; C-расширения в мире Python используются особенно интенсивно. Язык Java имеет интерфейс для вызова "собственных методов" в С, хотя практические результаты этого бесперспективны, поскольку нарушается переносимость. Большинство версий командного интерпретатора Unix (shell) не предназначены для внедрения или расширения, однако оболочка Korn (ksh93 и боле поздние версии) является заметным исключением.

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

8.3.3.

Написание специальной грамматики

Для декларативных мини-языков основной вопрос состоит в том, следует ли использовать XML в качестве основного синтаксиса и определять грамматику как тип XML-документа. Вполне возможно, что такой подход верен для сложно структурированных декларативных мини-языков, однако здесь также актуальны предостережения, изложенные в главе 5, о конструкции форматов файлов данных — XML может быть излишним. Если XML не используется, следует соблюдать правило наименьшей неожиданности, поддерживая описанные Unix-соглашения для файлов данных (простой синтаксис на основе лексем, поддержка C-соглашений об использовании обратной косой черты и т.д.).

Если специальная грамматика действительно требуется, то утилиты yacc и lex (или их локальный эквивалент в используемом языке), вероятно, будут наилучшими помощниками, кроме тех случаев, когда грамматика используемого языка настолько проста, что ручное кодирование рекурсивного нисходящего синтаксического анализатора представляет собой тривиальную задачу. Даже тогда утилита yacc может предоставить более надежное устранение ошибок, а модифицировать yacc-спецификацию по мере развития синтаксиса языка будет проще. В главе 9 рассматриваются производные от yacc и lex инструменты, доступные в языках различной реализации.

Даже в случае принятия решения о реализации собственного синтаксиса рекомендуется рассмотреть возможную выгоду от повторного использования имеющихся инструментальных средств. Если требуются макросредства, следует учесть, что предобработка средствами m4(1) может быть правильным решением. Однако, прежде всего, необходимо учесть предостережения, приведенные в следующем разделе.

8.3.4. Проблемы макросов

Средства макрорасширения были излюбленной тактикой разработчиков языков в ранней Unix. Язык С, несомненно, имеет такое средство. Кроме того, они обнаруживаются в некоторых более сложных мини-языках специального назначения, таких как pic(1). Препроцессор m4 предоставляет общее средство для реализации макрорасширяющих препроцессоров.

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

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

Для языка С классическим примером такой проблемы является макрос, подобный следующему.

#define max(x, у) х > у ? x : у

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

>
или
?:
. Рассмотрим выражение
max(а = b, ++с)
. Если программист забыл, что max является макросом, то он будет ожидать, что присваивание
a = b
и преинкрементная операция с
с
будут выполнены до того, как результирующие значения будут переданы
max
в качестве аргументов.

Поделиться:
Популярные книги

Я не князь. Книга XIII

Дрейк Сириус
13. Дорогой барон!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Я не князь. Книга XIII

Последний попаданец 11. Финал. Часть 1

Зубов Константин
11. Последний попаданец
Фантастика:
фэнтези
юмористическое фэнтези
рпг
5.00
рейтинг книги
Последний попаданец 11. Финал. Часть 1

Покоритель Звездных врат

Карелин Сергей Витальевич
1. Повелитель звездных врат
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Покоритель Звездных врат

Совок-8

Агарев Вадим
8. Совок
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Совок-8

Столичный доктор. Том III

Вязовский Алексей
3. Столичный доктор
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Столичный доктор. Том III

Король Масок. Том 1

Романовский Борис Владимирович
1. Апофеоз Короля
Фантастика:
городское фэнтези
попаданцы
аниме
5.00
рейтинг книги
Король Масок. Том 1

Ищу жену для своего мужа

Кат Зозо
Любовные романы:
любовно-фантастические романы
6.17
рейтинг книги
Ищу жену для своего мужа

Мастер Разума III

Кронос Александр
3. Мастер Разума
Фантастика:
героическая фантастика
попаданцы
аниме
5.25
рейтинг книги
Мастер Разума III

Темный Охотник 2

Розальев Андрей
2. Темный охотник
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Темный Охотник 2

Идеальный мир для Лекаря 20

Сапфир Олег
20. Лекарь
Фантастика:
фэнтези
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 20

Обыкновенные ведьмы средней полосы

Шах Ольга
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Обыкновенные ведьмы средней полосы

Возвышение Меркурия. Книга 16

Кронос Александр
16. Меркурий
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия. Книга 16

Адепт. Том 1. Обучение

Бубела Олег Николаевич
6. Совсем не герой
Фантастика:
фэнтези
9.27
рейтинг книги
Адепт. Том 1. Обучение

Идущий в тени 4

Амврелий Марк
4. Идущий в тени
Фантастика:
боевая фантастика
6.58
рейтинг книги
Идущий в тени 4