- •1. Введение
- •2. Регулярные выражения в Lex-правилах
- •2.1. Обозначения символов в выражениях
- •2.2. Операторы регулярных выражений
- •2.3. Оператор выделения классов символов
- •2.4. Повторители
- •2.5. Операторы выбора
- •2.6. Оператор {}
- •3. Структура Lex-программы
- •3.1. Раздел определений Lex-программы
- •3.2. Раздел правил
- •3.2.1. Действия в правилах Lex-программы
- •3.2.2. Порядок действия активных правил
- •3.3. Раздел программ пользователя
- •3.4. Комментарии Lex-программы
- •3.5. Примеры Lex-программ
- •4. Структура файла lex.Yy.C
- •5. Функция yywrap()
- •6. Функция reject
- •7. Функции yyless и yymore
- •8. Совместное использование lex и yacc
- •9. Использование Ратфора
- •10. Флаги Lex
2.5. Операторы выбора
Операторы:
/ | ? $ ^
управляют процессом выбора символов.
Оператор /:
ab/cd
"ab" учитывается только тогда, когда за ним следует
"cd".
Опeратор |:
ab|cd
или "ab", или "cd".
Опeратор ?:
x? означает необязательный символ "x".
_?[A-Za-z]*
означает, что перед цепочкой любого количества латинс-
ких букв может быть необязательный знак подчеркивания.
10
-?[0-9]+
выделит любое целое число с необязательным минусом впе-
реди.
Оператор $:
x$ означает выбрать символ "x", если он является последним
в строке. Стоит перед символом "\n"!
abc$ означает выбрать цепочку "abc", если она завершает
строку.
Оператор ^:
^x означает выбрать символ "x", если он является первым
символом строки;
^abc означает выбрать цепочку символов "abc", если она начи-
нает строку.
[^A-Z]*
означает все символы, кроме прописных латинских букв.
Когда символ ^ стоит перед выражением или внутри [], он
выполняет операцию дополнение. Внутри квадратных скобок
символ ^ должен обязательно стоять первым у открывающей
скобки!
2.6. Оператор {}
Оператор {} имеет два различных применения:
x{n,m} здесь n и m натуральные, m > n. Означает от n до m
вхождений x, например, x{2,7} - от 2 до 7 вхождений
x.
{имя} вместо {имя} в данное место выражения будет подстав-
лено определение имени из области определений Lex-
программы.
Пример:
БУКВА [A-ZА-Яa-zа-я_]
ЦИФРА [0-9]
ИДЕНТИФИКАТОР {БУКВА}({БУКВА}|{ЦИФРА})*
%%
{ИДЕНТИФИКАТОР} printf("\n%s",yytext);
lex построит лексический анализатор, который будет опреде-
лять и выводить все "слова" из входного файла. Под словом в
данном случае подразумевается идентификатор Си-программы. В
этом примере {ИДЕНТИФИКАТОР} будет заменен на
{БУКВА}({БУКВА}|{ЦИФРА})*, затем на [A-ZА-Яa-zа-я_]([A-ZА-
Яa-zа-я_]|[0-9])*.
11
yytext - это внешний массив символов программы
lex.yy.c, которую строит lex. yytext формируется в процессе
чтения входного файла и содержит текст, для которого уста-
новлено соответствие какому-либо выражению. Этот массив дос-
тупен пользовательским разделам Lex-программы.
Оператор printf выводит каждый идентификатор на новой
строке.
Правило ".|\n ;" используется для того, чтобы
пропустить (не выводить) все цепочки символов, которые не
соответствуют регулярному выражению {ИДЕНТИФИКАТОР}.
2.7. Оператор <<>>. Служебные слова START и BEGIN
Раздел правил Lex-программы может содержать активные и
неактивные правила. Активные правила выполняются всегда.
Неактивные выполняются только в тех случаях, когда выполня-
ется некоторое начальное условие.
Начальные условия Lex-программы помещаются в раздел
определений, а неактивные правила помечаются соответствую-
щими условиями. Оператор START позволяет указать список
начальных условий Lex-программы, а оператор BEGIN позволяет
активировать правила, помеченные начальными условиями.
Активные правила имеют следующий синтаксис:
РЕГУЛЯРНОЕ_ВЫРАЖЕНИЕ ДЕЙСТВИЕ
Неактивные правила имеют следующий синтаксис:
<<МЕТКА_УСЛОВИЯ>>РЕГ_ВЫРАЖЕНИЕ ДЕЙСТВИЕ
ВАЖНО: любое правило должно начинаться с первой позиции
строки, пробелы и табуляции недопустимы - они используются
как разделители между регулярным выражением и действием в
правиле!
Рассмотрим пример:
12
%START COMMENT
КОММ_НАЧАЛО "/*"
КОММ_КОНЕЦ "*/"
%%
{КОММ_НАЧАЛО} { ECHO;
BEGIN COMMENT;};
[\t\n]* ;
<COMMENT>[^*]* ECHO;
<COMMENT>[^/] ECHO;
<COMMENT>{КОММ_КОНЕЦ} {
ECHO;
printf("0);
BEGIN 0;};
lex построит лексический анализатор, который выделяет ком-
ментарии в Си-программе и записывает их в стандартный файл
вывода. Программа начинается с ключевого слова START, кото-
рое указано после символа %. Ключевое слово START можно
указать и так: Start, или S, или s . За ключевым словом
START указана метка начального условия COMMENT.
Оператор "<COMMENT>x" означает - x, если анализатор
находится в начальном условии COMMENT.
Oператор "BEGIN COMMENT;" переводит анализатор в
начальное условие COMMENT (смотрите первое правило раздела
правил этой Lex-программы). После этого анализатор уже нахо-
дится в новом состоянии и теперь разбор входного потока сим-
волов будет осуществляется и теми правилами, которые начина-
ются оператором "<COMMENT>". Например, правило
<COMMENT>[^*]* ECHO;
выполняется только тогда, когда во входном потоке символов
будет обнаружено начало комментариев ("/*"). В этом случае
анализатор записывает в стандартный файл вывода любое число
(в том числе и ноль) символов, отличных от символа "*". Опе-
ратор "BEGIN 0;" переводит анализатор в исходное состояние.
Lex-программа может содержать несколько помеченных
начальных условий. Например, если Lex-программа начинается
строкой
%START AA BB CC DD
то это означает, что она управляет четырьмя начальными сос-
тояниями анализатора. В каждое из этих начальных состояний
анализатор можно перевести, используя оператор BEGIN.
13
Каждое правило, перед которым указан оператор типа
"<<МЕТКА>>", мы будем называть помеченным правилом. Метка фор-
мируется так же, как и метка в Си.
Количество помеченных правил не ограничивается. Кроме
того, разрешается одно правило помечать несколькими метками,
например:
<<МЕТКА1,МЕТКА2,МЕТКА3>>x ДЕЙСТВИЕ
Запятая - обязательный разделитель списка меток!
Рассмотрим пример с несколькими начальными условиями:
%START AA BB CC
БУКВА [A-ZА-Яa-zа-я_]
ЦИФРА [0-9]
ИДЕНТИФИКАТОР {БУКВА}({БУКВА}|{ЦИФРА})*
%%
^# BEGIN AA;
^[ \t]*main BEGIN BB;
^[ \t]*{ИДЕНТИФИКАТОР} BEGIN CC;
\t ;
\n BEGIN 0;
<AA>define printf("Определение.\n");
<AA>include printf("Включение.\n");
<AA>ifdef {
printf("Условная компиляция.\n"); }
<BB>[^\,]*","[^\,]*")" {
printf("main с аргументамии.\n"); }
<BB>[^\,]*")" {
printf("main без аргументов.\n"); }
<CC>":"/[ \t] printf("Метка.\n");
Программа содержит активные и неактивные правила. Все неак-
тивные правила помечены, перед ними указана метка начального
условия. Lex-программа управляет тремя начальными условиями,
в соответствии с которыми активируются помеченные правила.
В результате работы lex мы получим лексический анализа-
тор, который будет распознавать в Си-программе строки преп-
роцессора Си-компилятора, выделять функцию main, распозна-
вая, с аргументами она или без них, распознавать метки.
Лексический анализатор не выводит ничего, кроме сообщений о
выделенных лексемах.
14