lex_doc (1119420), страница 2
Текст из файла (страница 2)
можно указывать в двойных кавычках. В этом случае это всегда
просто символ - его специальное значение отменяется. Напри-
мер:
"abc"
abc
эти последовательности символов идентичны.
. точка означает любой символ, кроме символа новой строки
"\n";
\восьмеричный_код_символа
указание символа его восьмеричным кодом (как в Си);
\n символ новой строки;
\t символ табуляции;
\b возврат курсора на один шаг назад;
8
пробел
любой символ пробела в выражении, если он не находится
внутри квадратных скобок, необходимо заключать в двой-
ные кавычки. Это необходимо, так как пробел и табуляция
используются lex в качестве разделителя между определе-
нием и действием в правиле.
2.2. Операторы регулярных выражений
Операторы обозначаются символами-операторами, к ним
относятся:
\ ^ ? * + | $ / %
[] {} () <<>>
Каждый из этих символов или пар скобок в регулярном выраже-
нии играет роль оператора. Если необходимо отменить специ-
альное значение символа, обозначающего оператор, перед ним
нужно поставить символ \ или указать его в двойных кавычках.
Например:
abc+ - символ "+" - оператор;
abc\+ - символ "+";
abc"+" - символ "+".
2.3. Оператор выделения классов символов
Квадратные скобки задают классы символов, которые в них
заключены.
[abc]
означает либо символ "a", либо "b", либо символ "c";
Знак - используется для указания любого символа из лек-
сикографически упорядоченной последовательности:
[A-z]
означает любой латинский символ;
[А-Я]
любая прописная русская буква;
[+-0-9]
все цифры и знаки "+" и "-".
2.4. Повторители
Когда необходимо указать повторяемость вхождения сим-
вола в регулярном выражении, используют операторы-
повторители * и +.
9
Оператор * означает любое (в том числе и 0) число вхож-
дений символа или класса символов. Например:
x* любое число вхождений символа "x";
abc* любое число вхождений цепочки "abc";
[A-z]*
любое число вхождений любой латинской буквы;
[A-ZА-Яa-zа-я_0-9]*
любое вхождение русских и латинских букв, знака подчер-
кивания и цифр.
Оператор + означает одно и более вхождений. Например:
x+ одно или более вхождений "x";
[0-9]+
одно или более вхождений цифр;
abc+ одно или более вхождений цепочки abc;
[A-z]+
одно или более вхождений любой латинской буквы.
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
3. Структура Lex-программы
Lex-программа включает разделы опредeлений, правил и
пользовательских программ. Рассмотрим подробнее способы
оформления этих разделов.
Все строки, в которых занята первая позиция, относятся
к Lex-программе. Любая строка, не являющаяся частью правила
или действия, которая начинается с пробела или табуляции,
копируется в сгенерированную программу lex.yy.c - результат
работы lex.
3.1. Раздел определений Lex-программы
Определения, предназначенные для lex, помещаются перед
первым %%. Любая строка этого раздела, не содержащаяся между
%{ и %} и начинающаяся в первой колонке, является определе-
нием строки подстановки lex. Раздел определений Lex-
программы может включать:
начальные условия,
определения,
фрагменты программы пользователя,
таблицы наборов символов,
указатели host-языка,
изменения размеров внутренних массивов,
комментарии в формате host-языка.
НАЧАЛЬНЫЕ УСЛОВИЯ задаются в форме:
%START имя1 имя2 ...
Если начальные условия определены, то эта строка должна быть
первой в Lex-программе.
ОПРЕДЕЛЕНИЯ задаются в форме:
имя трансляция
В качестве разделителя используется один или более пробелов
или табуляций. Пример:
БУКВА [A-ZА-Яa-zа-я_]
DIGIT [0-9]
ИДЕНТИФИКАТОР {БУКВА}({БУКВА}|{DIGIT})*















