Главная

Популярная публикация

Научная публикация

Случайная публикация

Обратная связь

ТОР 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 используется для выделения буквенных пар, начи-

нающихся на каждой букве, а не на каждой следующей.

 






Не нашли, что искали? Воспользуйтесь поиском:

vikidalka.ru - 2015-2024 год. Все права принадлежат их авторам! Нарушение авторских прав | Нарушение персональных данных