lex генерирует синтаксические анализаторы, работающие на порядок медленнее написанных вручную. Однако данный факт не является причиной для ручного кодирования, это аргумент в пользу создания с помощью lex прототипа и доработки кода вручную, только если прототип показывает реальное "бутылочное горлышко".
Утилита уасс — генератор синтаксических анализаторов. Она также была написана для автоматизации части работы по написанию компиляторов, уасс принимает на входе грамматическую спецификацию в декларативном мини-языке, подобном BNF (Backus-Naur Form — запись Бэкуса-Наура), с С-кодом, связанным с каждым элементом грамматики. Данная программа генерирует код для функции синтаксического анализа, которая при вызове принимает текст, соответствующий грамматике из входного потока. По мере распознавания каждого грамматического элемента, функция анализатора запускает связанный С-код.
Комбинация утилит lex и уасс весьма эффективна для написания языковых интерпретаторов всех видов. Хотя большинству Unix-программистов никогда не придется выполнять данный вид универсального построения компилятора, для которого задумывались эти инструменты, они чрезвычайно полезны для написания анализаторов синтаксиса конфигурационных файлов и узкоспециальных мини-языков.
Сгенерированные с помощью lex анализаторы лексем работают очень быстро при распознавании низкоуровневых образцов во входных потоках, однако известный утилите lex язык регулярных выражений плохо подходит для вычисления или распознавания рекурсивно вложенных структур. Для их анализа потребуется уасс. С другой стороны, несмотря на то, что теоретически возможно написать yacc-грамматику с собственным сбором лексем, такая грамматика была бы перегружена кодом, а анализатор был бы крайне медленным. Для анализа входных лексем следует использовать lex. Таким образом, данные инструменты являются симбиотическими.
Как и в случае с макропроцессорами, одной из проблем, связанных с генераторами кода и препроцессорами, является то, что ошибки компиляции в сгенерированном коде могут содержать номера строк сгенерированного кода (который редактировать нежелательно), а не номера строк во входных данных генератора (т.е. там, где необходимо внести изменения). В утилитах уасс и lex данная проблема решается такими же конструкциями #line, что и в препроцессоре С. Они устанавливают текущий номер строки для отчета об ошибках. Любая программа, генерирующая код на С или С++, должна работать аналогичным образом.
В более широком смысле хорошо спроектированные генераторы процедурного кода никогда не должны требовать от пользователя исправлять вручную или даже просматривать сгенерированный код. Создание корректного кода является непосредственной задачей генератора.
15.3.1.1. Учебный пример: грамматика fetchmailrc
Вместо этого грамматика анализатора конфигурационных файлов fetchmail предоставляет хороший учебный пример среднего размера по использованию lex и уасс. Здесь имеется несколько интересных моментов.
/ег-спецификация в файле rcfile_l.l— весьма типичная реализация shell-подобного синтаксиса. Обратите внимание на то, как два дополняющих правила поддерживают строки либо с одинарными, либо с двойными кавычками; данная идея хороша в принципе. Правила для принятия (возможно, со знаком) целых литералов и отклонения комментариев также являются достаточно распространенными.
уасс-спецификация в файле rcfile_y.y достаточно длинная, но понятная. Она не осуществляет каких-либо fetchmail-действий, а только устанавливает биты в списке внутренних управляющих блоков. После запуска fetchmail в обычном режиме программа только периодически проходит по данному списку, используя каждую запись для управления сеансом получения почты с удаленного узла.
15.3.2. Учебный пример:Glade
Программа Glade рассматривалась в главе 8 в качестве хорошего примера декларативного мини-языка. Также отмечалось, что в результате работы серверной части Glade генерируется код на одном из нескольких языков.