ТОР 5 статей: Методические подходы к анализу финансового состояния предприятия Проблема периодизации русской литературы ХХ века. Краткая характеристика второй половины ХХ века Характеристика шлифовальных кругов и ее маркировка Служебные части речи. Предлог. Союз. Частицы КАТЕГОРИИ:
|
Структура файла lex.yy.c
lex строит программу - лексический анализатор на языке Си, которая размещается в файле со стандартным именем lex. yy. c. Эта программа содержит две основных функции и нес- колько вспомогательных. Основные - это:
функция yylex () Она содержит разделы действий всех правил, которые определены пользователем;
функция yylook () Она реализует детерминированный конечный автомат, кото- рый осуществляет разбор входного потока символов в соответствии с регулярными выражениями правил Lex- программы.
Вспомогательные функции, которые являются подпрограм- мами ввода-вывода. К ним относятся:
input () читает и возвращает символ из входного потока символов;
unput (c) возвращает символ обратно во входной поток для повтор- ного чтения;
output (c) выводит в выходной поток символ c.
Эти функции определены как макроподстановки следующим образом:
input -
fprintf (fout, " %s%d%s 0, " #define input () (((yytchar = yysptr > yysbuf ctable ['0], "?(yylineno ++, yytchar): yytchar)== EOF?0: yyt
unput -
#define unput (c){ yytchar = (c); if (yytchar == '\n') yylineno --; *yysptr ++ = yytchar; }
output -
#define output (c) putc (c, yyout)
Эти функции можно изменить, указав им те же имена и разместив в разделе программ пользователя.
При сборке программы лексического анализа редактор связи ld по флагу -ll подключает головную функцию main, если она не определена. Ниже приведен текст этой функции из биб- лиотеки / usr / lib / libl. a
# include " stdio. h " main (){ yylex (); exit (0); }
Функция yywrap()
Функция yywrap используется для определения конца файла, из которого лексический анализатор читает поток сим- волов. Если yywrap возвращает 1, лексический анализатор прекращает работу. Однако, иногда имеется необходимость начать ввод данных из другого источника и продолжить работу. В этом случае пользователь должен написать свою подпрограмму yywrap, которая организует новый входной поток и возвращает 0, что служит сигналом к продолжению работы анализатора. По умолчанию yywrap всегда возвращает 1 при завершении входного потока символов.
В Lex-программе невозможно записать правило, которое будет обнаруживать конец файла. Единственный способ это сде- лать - использовать фунцию yywrap. Эта функция также удобна, когда необходимо выполнить какие-либо действия по завершению входного потока символов, определив в разделе программ поль- зователя новый вариант функции yywrap. Пример:
%START AA BB CC
/* * Строится лексический анализатор, * который распознает наличие * включений файлов в Си-программе, * условных компиляций, * макроопределений, * меток и головной функции main. * Анализатор ничего не выводит, пока * осуществляется чтение входного * потока, а по его завершении * выводит статистику. */
БУКВА = [A-ZА-Яa-zа-я_] ЦИФРА [0-9] ИДЕНТИФИКАТОР {БУКВА}({БУКВА}|{ЦИФРА})*
int a1,a2,a3,b1,b2,c; %% {a1 = a2 = a3 = b1 = b2 = c = 0;}
^# BEGIN AA; ^[ \t]*main BEGIN BB; ^[ \t]*{ИДЕНТИФИКАТОР} BEGIN CC; \t; \n BEGIN 0;
<AA>define { a1 ++; } <AA>include { a2 ++; } <AA>ifdef { a3 ++; }
<BB>[^\,]*","[^\,]*")" { b1 ++; } <BB>[^\,]*")" { b2 ++; }
<CC>":"/[ \t] { c ++; }
%%
yywrap (){
if (b 1 == 0 && b2 == 0) printf ("В программе\ отсутствует функция main.\n");
if (b1 >= 1 && b2 >= 1){ printf ("Многократное\ определение функции main.\n");
} else { if (b1 == 1) printf ("Функция main\
с аргументами.\n");
if (b2 == 1) printf ("Функция main\ без аргументов.\n"); }
printf ("Включений файлов: %d.\n", a2); printf ("Условных компиляций: %d.\n", a3); printf ("Определений: %d.\n", a1); printf ("Меток: %d.\n", c);
return (1);
}
Оператор return (1) в функции yywrap указывает, что лек- сический анализатор должен завершить работу. Если необходимо продолжить работу анализатора для чтения данных из нового файла, нужно указать return (0), предварительно осуществив операции закрытия и открытия файлов и, в этом случае, анали- затор продолжит чтение и обработку входного потока. Однако, если yywrap не возвращает 1, то это приводит к бесконечному циклу.
Функция REJECT
Обычно lex разделяет входной поток, не осуществляя поиск всех возможных соответствий каждому выражению. Это означает, что каждый символ рассматривается один и только один раз. Предположим, что мы хотим подсчитать все вхождения цепочек she и he во входном тексте. Для этого мы могли бы записать следующие правила:
she s ++; he h ++; . | \n;
Так как she включает в себя he, анализатор не распознает те вхождения he, которые включены в she, так как, прочитав один раз she, эти символы он не вернет во входной поток.
Иногда желательно переопределить этот выбор. Действие функции REJECT означает "выбрать следующую альтернативу". Это приводит к тому, что каким бы ни было правило, после него необходимо выполнить второй выбор. Соответственно изме- нится и положение указателя во входном потоке:
she { s ++; REJECT; } he { h ++; REJECT; } . | \n;
Здесь после выполнения одного правила символы возвращаются назад во входной поток, и выполняется другое правило.
Функция REJECT полезна в том случае, когда она применя- ется для определения всех вхождений какого-либо объекта, причем вхождения могут перекрываться или включать друг друга. Предположим, необходимо получить из одного потока таблицу всех двухбуквенных сочетаний, которые обычно перек- рываются, например, слово the содержит как th, так и he. Допустим, имеется двумерный массив digram, тогда:
%% [a-z][a-z] {
digram [ yytext [0]][ yytext [1]]++; REJECT; } \n;
Здесь REJECT используется для выделения буквенных пар, начи- нающихся на каждой букве, а не на каждой следующей.
Не нашли, что искали? Воспользуйтесь поиском:
|