ВЫПОЛНЕНИЕ LEX'А В СИСТЕМЕ UNIX
Прежде чем продвигаться дальше, вернемся на некоторое время к рисунку в начале главы. Для порождения C-текста лексического анализатора следует выполнить команду
lex файл
где файл содержащит lex-спецификацию. Обычно в качестве имени файла берется lex.l, однако в принципе имя файла может быть любым. Порожденный lex'ом выходной файл будет автоматически назван lex.yy.c. Он содержит созданную C-программу лексического анализа, которую следует откомпилировать и выполнить редактирование связей с обязательным подключением библиотеки lex'a libl.a, что достигается указанием опции -ll:
cc lex.yy.c -ll
Библиотека предоставляет недостающую программу main(), которая по имени yylex вызывает лексический анализатор, так что создавать свою собственную программу main() нет необходимости.
Если lex-спецификация состоит из нескольких файлов, можно для каждого из них запустить lex, обязательно переименовывая результирующий файл lex.yy.c [при помощи команды mv(1)] перед следующим запуском lex'а. В противном случае каждый следующий результат будет затирать предыдущий. После того как все .c-файлы сгенерированы, можно скомпилировать их все разом посредством одной командной строки.
Если выполняемый файл a.out порожден, с его помощью можно проанализировать любой входной текст. Предположим, текст помещен в файл с именем textin (имя выбирается произвольно). Лексический анализатор по умолчанию осуществляет ввод с терминала. Чтобы использовать файл textin, достаточно переназначить ввод:
a.out < textin
По умолчанию и вывод осуществляется на терминал, но его также можно переназначить:
a.out < textin > textout
При использовании lex'а совместно с yacc'ом любой из инструментов может быть запущен первым. Команды
yacc -d grammar.y lex lex.l
формируют процедуру разбора в файле y.tab.c. (Если указана опция -d, создается файл y.tab.h, который содержит операторы #define, связывающие назначенные yacc'ом целочисленные значения типов лексем с определенными пользователем именами лексем). Чтобы откомпилировать порожденные файлы и отредактировать связи, введите командную строку
cc lex.yy.c y.tab.c -ly -ll
Заметим, что библиотека yacc'а загружается (опция -ly) перед библиотекой lex'а (опция -ll), что гарантирует использование той программы main(), которая вызывает процедуру разбора.
У команды lex есть несколько допустимых опций, которые следует указывать между именем команды lex и именем файла-аргумента. Для того, чтобы lex выводил сгенерированную C-программу lex.yy.c на терминал (устройство вывода, заданное по умолчанию), используется опция -t:
lex -t lex.l
По опции -v распечатывается небольшая статистическая сводка, характеризующая так называемый конечный автомат, который реализует порожденная lex'ом C-программа lex.yy.c.
Для представления конечного автомата lex использует таблицу (двумерный массив в C). Максимально возможное число состояний конечного автомата по умолчанию устанавливается равным 500. Если lex-спецификация содержит много правил или очень сложные правила, может потребоваться большее число состояний. Увеличение максимального числа состояний достигается добавлением к секции определений строки вида
%n 700
Подобная строка заставляет lex сделать таблицу достаточно большой, чтобы вместить до 700 состояний. (Опция -v позволит узнать, какое число состояний было фактически использовано). Для того, чтобы увеличить максимально допустимое число переходов между состояниями с подразумеваемого значения 2000, предусмотрен параметр a:
%a 2800
В заключение рекомендуем изучить статью lex(1) из Справочника пользователя, в которой содержится список всех опций, предусмотренных у данной команды. Описание нотации регулярных выражений можно найти, например, в статье ed(1) Справочника пользователя.
Вы прочитали введение в разработку lex-программ. Чтобы овладеть lex'ом, как и любым другим программистским инструментом, нужно им пользоваться - чем больше, тем лучше.