lex (813547), страница 12
Текст из файла (страница 12)
В современных версияхзаготовка для функции yylook включена непосредственно в выполняемый модуль генератораLEX.Функция yylex содержит инструкции всех действий секции правил, обеспечивая обработкулексем, распознаваемых во входном потоке, и управление процедурой лексического анализа.Вызов этой функции реализует обращение к лексическому анализатору, а ее целочисленныйкод возврата может быть использован для идентификации лексем, например, в интересахпоследующейпроцедурылексического анализа.синтаксическогоанализаилиинтерпретациирезультатовСледует отметить, что кроме функций yylook и yylex в исходный текст лексическогоанализатора без изменений включается содержимое секции подпрограмм и блока описаний, атакже инструкции секции описаний, которые начинаются не с первой позиции своих строк.Дополнительно к перечисленному генератор LEX включает в исходный текст лексическогоанализатора определения своих встроенных переменных, функций и операторов, которыеиспользуются в действиях секции правил.СЕКЦИЯ ПОДПРОГРАММСекция подпрограмм – необязательная заключительная секция файла спецификации лексем.Она должна быть отделена от предшествующей секции правил разделительной парой символовпроцента %% и продолжается до конца файла спецификации лексем.
Содержимое секцииправил без изменений включается в исходный текст лексического анализатора и должно бытьоформлено в нотации языка программирования C.Секция подпрограмм в основном предназначена для спецификации исходного кода прикладныхфункций, которые используются в действиях секции правил. Кроме того, в секции подпрограммможноперегрузитьисходныекодынекоторыхстандартныхфункцийввода-выводалексического анализатора, которые предоставляет генератор LEX, а также специфицироватьосновную функцию main, когда это необходимо.
При этом следует сохранять неизменнымиимена, типы аргументов и кодов возврата перегружаемых функций.На практике наиболее часто встречается перегрузка стандартной функции yywrap, котораяавтоматически вызывается лексическим анализатором при достижении конца входного потокастандартного ввода. Эта функция не имеет аргументов и должна возвращать целочисленноезначение 0 или 1, оценка которого предусмотрена в программе лексического анализатора.
Приэтом возврат значения 1 вызывает корректное завершение процедуры лексического анализа.Возврат нулевого значения предоставляет возможность продолжить выполнение процедурылексического анализа для обработки данных, поступающих из другого источника. Встандартном варианте функция yywrap возвращает значение 1.
Перегрузка стандартнойфункции yywrap обычно применяется, когда необходимо изменить ее стандартный кодвозврата с 1 на 0 или выполнить определенные завершающие действия в конце лексическогоанализа входного потока при коде возврата 1.Использование прикладных и перегруженных функций секции подпрограмм иллюстрируетследующийпримерспецификацийлексическогоанализатора,которыйотображаетмаксимальную длину слова входного текста через поток стандартного вывода:%%[A-Za-z]+wordlen(yyleng);.|\n;%%/* Прикладная функция оценки длины слова */int wordlen(int len) {static int maxlen = 0;if(len > maxlen)maxlen = len;} /* wordlen *//* Перегрузка стандартной функции yywrap */int yywrap() {printf("%d\n", wordlen(0));} /* wordlen */В этом примере, в соответствии с регулярным выражением первого правила, словом считаетсялюбая последовательность строчных и/или заглавных латинских букв.
Для оценки длиныкаждого полученного слова в действии этого правила вызывается прикладная функция wordlen,которая определена в секции подпрограмм. При вызове в действии правила ей передаетсязначение внутренней переменной yyleng, фиксирующей длину текущего слова, чтобысопоставить его со значением статической переменной maxlen, которая сохраняет размернаиболее длинного из полученных слов входного текста. Текущее значение переменной maxlenизменяется, если его величина меньше длины очередного слова и всегда может быть полученочерез код возврата прикладной функции wordlen. Однако в данном примере код возвратаприкладной функции wordlen используется только для контроля итогового значениястатической переменной maxlen, которое получается после обработки всех слов входногопотока и, следовательно, соответствует максимальной длине слова входного текста.Конец входного потока инициирует автоматический вызов стандартной функции yywrap,исходный код которой перегружен в секции подпрограмм.
Перегрузка стандартной функцииyywrap осуществляется с целью обеспечить контрольный вызов прикладной функции wordlen вконце лексического анализа, когда ее код возврата определяет максимальную длину словавходного текста. При этом прикладная функция wordlen вызывается с нулевым аргументом,чтобы исключить изменение величины статической переменной maxlen, а ее код возвратапередается библиотечной функции printf системы программирования C для отображенияполученного результата через поток стандартного вывода. Выполнение функции yywrapоканчивается возвратом значения 1, чтобы корректно обозначить завершение процедурылексического анализа входного потока.Кроме стандартной функции yywrap в секции подпрограмм могут быть перегружены еще двестандартные функции input и unput, генератор LEX использует для обработки входногопотока.ПерегружаемыефункцииinputиunputявляютсяLEX-ориентированнымиреализациями библиотечных функций getc и ungetc системы программирования C, которыеконкретизированы для обработки потока стандартного ввода в лексическом анализаторе.В частности, стандартная функция input в лексическом анализаторе обеспечивает чтениевходного потока, возвращая код каждого полученного символа или 0, когда достигнут конецвходного потока.
Стандартная функция unput обеспечивает возврат обратно во входной потокдля повторного чтения символ, код которого задается ее целочисленным аргументом.В некоторых реализациях генератора LEX дополнительно к стандартным функциям input иunput предусмотрена также стандартная функция output, которая используется для обработкивыходногопотокапрограммирования C.иОнаэквивалентнаобеспечиваетбиблиотечнойстандартныйфункциивыводputcизсистемысимвола,кодкоторогоидентифицирован ее аргументом. Однако в большинстве современных версий генератора LEXэта стандартная функция либо отсутствует, либо недоступна для явного обращения.Следует отметить, что перегрузка стандартных функций ввода-вывода относительно редкоприменяется на практике.
Обычно они неявно вызываются лексическим анализатором длястандартной обработки входного потока. Однако в некоторых случаях целесообразнореализовать явный вызов этих функций в действиях правил или в прикладных функциях секцииподпрограмм.Эту ситуацию иллюстрирует следующий пример спецификации лексем для лексическогоанализатора скобочных выражений, где явный вызов стандартных функций input и unputисключает остаток входной строки после обнаружения ошибки расстановки скобок:%{extern int bracketcount;int bracketcount;%}%%bracketcount = 0;\(ECHO; bracketcount++;\){ ECHO;if(--bracketcount < 0) resync();}\nreturn(bracketcount);.;%%void resync() {while(input() != '\n');unput('\n');return;} /* resync */Правила этого примера обеспечивают проверку соответствия открывающих и закрывающихкруглых скобок в каждой входной строке, содержащей произвольное алгебраическое илиарифметическое выражение, игнорируя при этом любые символы потока стандартного вводакроме круглых скобок и перевода строки.
Они реализуют упрощенный вариант алгоритмаРутисхаузера, где лексический анализ скобочных выражений осуществляется по значениюсчетчика скобок. В этом алгоритме каждая очередная открывающая скобка увеличивает, акаждая закрывающая скобка уменьшает значение счетчика на 1. Любые другие символывыражения не изменяют значения счетчика скобок. Анализ скобок завершается, если значениесчетчика скобок отрицательно или когда достигнут конец выражения. При правильнойрасстановке скобок значение счетчика в конце выражения должно быть равно нулю, а внутривыражения всегда неотрицательно.В правилах, реализующих этот алгоритм, для хранения значения счетчика скобок используетсявнешняя целочисленная переменная bracketcount, которая объявляется в блоке описаний иинициализируется нулем перед обработкой каждой входной строки в действии начальногоправилабезрегулярноговыражения.Инкрементзначенияпеременнойbracketcountобеспечивает действие первого полного правила, когда во входном потоке обнаруженаоткрывающая круглая скобка.
Второе правило гарантирует декремент значения переменнойbracketcount при обнаружении во входном потоке закрывающей круглой скобки, а такжепринудительное исключение всех символов до конца строки, если ее величина становитсяотрицательной.Исключение остатка строки реализует прикладная функция resync, которая специфицирована всекции подпрограмм для явного вызова стандартных функций input и unput.