- •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
3.2.2. Порядок действия активных правил
Список правил Lex-программы может содержать активные и
неактивные правила, размещенные в любом порядке в разделе
правил. В процессе работы лексического анализатора список
активных правил может видоизменяться за счет действий опера-
тора BEGIN. В процессе распознавания символов входного
потока может оказаться так, что одна цепочка символов будет
удовлетворять нескольким правилам и, следовательно, возни-
кает проблема: действие какого правила должно выполняться?
Для разрешения этого противоречия можно использовать
квантование (разбиение) регулярных выражений этих правил
Lex-программы на такие новые регулярные выражения, которые
дадут, по возможности, однозначное распознавание лексемы.
Однако, когда это не сделано, lex использует определенный
детерминированный механизм разрешения такого противоречия:
- выбирается действие того правила, которое распознает
наиболее длинную последовательность символов из вход-
ного потока;
21
- если несколько правил распознают последовательности
символов одной длины, то выполняется действие того
правила, которое записано первым в списке раздела
правил Lex-программы.
Рассмотрим пример:
.
.
.
[Мм][Аа][Йй] ECHO;
[А-Яа-я]+ ECHO;
.
.
.
Слово "Май" распознают оба правила, однако, выполнится пер-
вое из них, так как и первое, и второе правило распознали
лексему одинакового размера (3 символа). Если во входном
потоке будет, допустим, слово "майский", то первые 3 символа
удовлетворяют первому правилу, а все 7 символов удовлетво-
ряют второму правилу, следовательно, выполнится второе пра-
вило, так как ему удовлетворяет более длинная последователь-
ность символов.
3.3. Раздел программ пользователя
Все, что размещено за вторым набором %%, относится к
разделу программ пользователя. Содержимое этого раздела
копируется в выходной файл lex.yy.c без каких-либо измене-
ний. В файле lex.yy.c строки этого раздела рассматриваются
как функции в смысле Си. Эти функции могут вызываться в
действиях правил и, как обычно, передавать и возвращать зна-
чения аргументов.
3.4. Комментарии Lex-программы
Комментарии можно указывать во всех разделах Lex-
программы. Формат комментариев должен соответствовать фор-
мату комментариев host-языка. Однако, в каждом разделе Lex-
программы комментарии указываются по разному. В разделе
определений комментарии должны начинаться не с первой пози-
ции строки. В разделе правил комментарии можно указывать
только внутри блоков, принадлежащих действиям. В разделе
программ пользователя комментарии указываются как и в host-
языке.
3.5. Примеры Lex-программ
Пример1.
22
%Start KOMMENT
/*
* Программа записывает в
* стандартный файл вывода
* комментарии Си-программы.
* Обратите внимание на то, что
* здесь строки комментариев указаны
* не с первой позиции строки!
*/
КОММ_НАЧАЛО "/*"
КОММ_КОНЕЦ "*/"
%%
{КОММ_НАЧАЛО} { ECHO;
BEGIN KOMMENT;}
[0* ;
<KOMMENT>[^*]* ECHO;
<KOMMENT>[^/] ECHO;
<KOMMENT>{КОММ_КОНЕЦ} {
ECHO;
printf("0);
/*
* Здесь приведен пример
* использования комментариев в
* разделе правил Lex-программы.
* Обратите внимание на то, что
* комментрий указан внутри блока,
* определяющего действие правила.
*/
BEGIN 0;}
%%
/*
* Здесь приведен пример комментариев
* в разделе программ пользователя.
*/
Пример 2.
23
%Start IC1 IC2 Normal
/*
* Отладочный фрагмент
* Lex-программы, которая строит
* лексический анализатор для
* компилятора языка Паскаль.
* Действие return(...)
* возвращает тип лексемы в
* в вызывающую анализатор
* программу.
* Обратите внимание на то, что в
* этой Lex-программе отсутствуют
* активные правила. Это сделано
* в связи с тем, что нет
* необходимости иметь правила,
* которые всегда активны.
* Все цепочки символов входного
* потока, не распознанные в
* правилах, копируются в выходной
* поток символов.
*/
LETTER [A-ZА-Яa-zа-я_]
DIGIT [0-9]
IDENT {LETTER}({LETTER}|{DIGIT})*
INT {DIGIT}+
FIXED {INT}?.{INT}
WHISP [ 0*
%%
BEGIN Normal;
<Normal>"{" BEGIN IC1;
<IC1>[^}] ;
<IC1>"}" BEGIN Normal;
<Normal>"(*" BEGIN IC2;
<IC2>[^*]|[^)] ;
<IC2>>"*)" BEGIN Normal;
<Normal>'([^']|'')*' return( строка );
<Normal>"<>" return( не_равно );
<Normal>"=" return( равно );
<Normal>"<" return( меньше );
<Normal>">" return( больше );
<Normal>">=" return(больше_или_равно);
<Normal>"<=" return(меньше_или_равно);
<Normal>".." return( точка_точка );
<Normal>"+" return( плюс );
<Normal>"-" return( минус );
<Normal>":=" return( присвоить );
<Normal>"*" return( умножить );
<Normal>"/" return( разделить );
<Normal>mod return( t_mod );
24
<Normal>div return( t_div );
<Normal>and return( t_and );
<Normal>or return( t_or );
<Normal>not return( t_not );
<Normal>"(" return( lpar );
<Normal>")" return( rpar );
<Normal>"[" return( lbracket );
<Normal>"]" return( rbracket );
<Normal>"," return( comma );
<Normal>":" return( colon );
<Normal>"^" return( circumflex );
<Normal>";" return( semicolon );
<Normal>write return( Write );
<Normal>writeln return( Writeln );
<Normal>label return( t_label );
<Normal>program return( );
<Normal>const x( "константы" ) ;
<Normal>type x( "типы" ) ;
<Normal>var x( "перем" ) ;
<Normal>procedure x( "процедура" ) ;
<Normal>function x( "функция" ) ;
<Normal>begin x( "начало" ) ;
<Normal>end{WHISP}. x( "конец прогр" ) ;
<Normal>end x( "конец" ) ;
<Normal>array x( "массив" ) ;
<Normal>of x( "из" ) ;
<Normal>record x( "запись" ) ;
<Normal>case x( "выбор" ) ;
<Normal>in x( "в" ) ;
<Normal>file x( "файл" ) ;
<Normal>for x( "для" ) ;
<Normal>to x( "к" ) ;
<Normal>downto x( "вниз к" ) ;
<Normal>do x( "выполн" ) ;
<Normal>while x( "пока" ) ;
<Normal>repeat x( "повт" ) ;
<Normal>until x( "до" ) ;
<Normal>set x( "множество" ) ;
<Normal>with x( "с" );
<Normal>nil x( "nil" ) ;
<Normal>if x( "если" ) ;
<Normal>then x( "то" ) ;
<Normal>else x( "иначе" ) ;
<Normal>{FIXED} x( "float" ) ;
<Normal>{INT} x( "ц.б.з" ) ;
<Normal>{IDENT} x( "идент" ) ;
<Normal>[ 0] ;
%%
x( s )
char *s ;
{
25
printf("%-15.15s 177> %s <1770,
s, yytext ) ;
}