Смекни!
smekni.com

Проектирование трансляторов (стр. 12 из 31)

вательских программ. Рассмотрим подробнее способы оформления этих

разделов.

Все строки, в которых занята первая позиция, относятся к

Lex-программе. Любая строка, не являющаяся частью правила или

действия, которая начинается с пробела или табуляции, копируется

в сгенерированную программу lex.yy.c - результат работы Lex.

Раздел определений Lex-программы

Определения, предназначенные для Lex, помещаются перед пер-

вым %%. Любая строка этого раздела, не содержащаяся между %{ и %}

и начинающаяся в первой колонке, является определением строки

подстановки Lex. Раздел определений Lexпрограммы может включать:

- начальные условия;

- определения;

- фрагменты программы пользователя;

- таблицы наборов символов;

- указатели host-языка;

- изменения размеров внутренних массивов;

- комментарии в формате host-языка.

НАЧАЛЬНЫЕ УСЛОВИЯ задаются в форме:

%START имя1 имя2 ...

Если начальные условия определены, то эта строка должна быть

первой в Lex-программе.

ОПРЕДЕЛЕНИЯ задаются в форме:

имя трансляция

В качестве разделителя используется один или более пробелов

или табуляций. Имя - как обычно, любая последовательность букв и

цифр, начинающаяся с буквы. Трансляция - это регулярное выраже-

ние (или его часть), которое будет подставлено всюду там, где

указано имя (смотрите третью строку этого примера).

ФРАГМЕНТЫ ПРОГРАММЫ ПОЛЬЗОВАТЕЛЯ указываются двумя способами:

- в виде "пробел фрагмент";

- в виде %{ строки фрагмента программы пользователя %}

Такая форма включения пользовательского фрагмента необходи-

ма для ввода, например, макроопределений Си, которые должны начи-

наться в первой колонке строки. Все строки фрагмента пользова-

тельской программы, размещенные в разделе определений, будут яв-

ляться внешними для любой функции программы lex.yy.c

ТАБЛИЦА НАБОРОВ СИМВОЛОВ задается в виде:

%T

целое_число строка_символов

.........

целое_число строка_символов

%T

Сгенерированная программа lex.yy.c осуществляет ввод-вывод

символов посредством библиотечных функций Lex с именами input,

output, unput. Таким образом, Lex помещает в yytext символы в

представлении, используемом в этих библиотечных функциях. Для

внутреннего использования символ представляется целым числом,

значение которого образовано набором битов, представляющих сим-

вол в конкретной ЭВМ. Пользователю предоставляется возможность

менять представление символов (целых констант) с помощью таблицы

наборов символов. Если таблица символов присутствует в разделе

определений, то любой символ, появляющийся либо во входном пото-

ке, либо в правилах, должен быть определен в таблице символов.

Символам нельзя назначать число 0 и число, большее числа, выде-

ленного для внутреннего представления символов конкретной ЭВМ.

УКАЗАТЕЛЬ host-языка имеет вид:

%C для Си;

%R для Ратфора.

Если указатель host-языка отсутствует, то по умолчанию при-

нимается Си.

ИЗМЕНЕНИЯ РАЗМЕРА ВНУТРЕННИХ МАССИВОВ задаются в форме:

%x число

"число" - новый размер массива;

"x" - одна из букв p - позиции;

n - состояния;

e - узлы дерева;

a - упакованные переходы;

k - упакованные классы символов;

o - массив выходных элементов.

Lex имеет внутренние таблицы, размеры которых ограничены.

При построении программы лексического анализа может произойти пе-

реполнение любой из этих таблиц, о чем Lex сообщает при построе-

нии лексического анализатора. Пользователю предоставляется воз-

можность изменить размеры таблиц (сокращая размеры одних и увели-

чивая размеры других) таким образом, чтобы они не переполнялись.

Естественно, эти изменения возможны лишь в пределах той памяти,

которая выделяется под процесс.

Ниже перечислены размеры таблиц, которые устанавливаются по

умолчанию:

p - позиций 1500;

n - состояний 300;

e - узлов 600;

a - упакованных переходов 1500;

k - упакованных классов символов 1000;

o - выходных элементов 1500.

КОММЕНТАРИИ в разделе определений задаются в форме host-язы-

ка и должны начинаться не с первой колонки строки.

Раздел правил

Все, что указано после первой пары %% и до конца Lexпрограм-

мы или до второй пары %%, если она указана, относится к разделу

правил. Раздел правил может содержать правила и фрагменты прог-

рамм. Фрагменты программ, содержащиеся в разделе правил, стано-

вятся частью функции yylex файла lex.yy.c, в которой осущес-

твляется выполнение действий активных правил. Фрагмент прогрммы

указывается следующим образом:

%{ строки фрагмента программы %}

Раздел правил может включать список активных и неактивных

(помеченных) правил. Активные и неактивные правила могут быть

указаны в любом порядке, в том числе быть "перемешанными" в спис-

ке. Активные правила выполняются всегда, неактивные только по

ссылке на них оператором BEGIN.

Активное правило имеет вид:

ВЫРАЖЕНИЕ ДЕЙСТВИЕ

Неактивное правило имеет вид:

<МЕТКА>ВЫРАЖЕНИЕ ДЕЙСТВИЕ

или

<СПИСОК МЕТОК>ВЫРАЖЕНИЕ ДЕЙСТВИЕ

где СПИСОК_МЕТОК имеет вид:

метка1,метка2,...

В качестве первого правила раздела правил может быть прави-

ло вида:

BEGIN МЕТКА;

В этом правиле отсутствует ВЫРАЖЕНИЕ, и первым действием в

разделе правил будет активизация помеченных правил. Для возвраще-

ния автомата в исходное состояние можно использовать действие:

BEGIN 0;

Важно отметить следующее. Если Lex-программа содержит актив-

ные и неактивные правила, то активные правила работают всегда.

Оператор "BEGIN МЕТКА;" просто расширяет список активных правил,

активируя помеченные меткой МЕТКА. А оператор "BEGIN 0;" удаляет

из списка активных правил все помеченные правила, которые до это-

го были активированы. Кроме того, если из помеченного и активно-

го в данный момент времени правила осуществляется действие BEGIN

МЕТКА, то из помеченных правил активными останутся только те, ко-

торые помечены меткой МЕТКА.

Действия в правилах Lex-программы

Действие можно представлять либо как оператор Lex, например,

"BEGIN МЕТКА;", либо как оператор Си. Если имеется необходимость

выполнить достаточно большой набор преобразований, то действие

оформляют как блок Си-программы (он начинается открывающей фигур-

ной скобкой и завершается закрывающей фигурной скобкой), содержа-

щий необходимые фрагменты.

Действие в правиле указывается через не менее, чем один про-

бел или табуляцию после выражения (обязательно в той же строке,

где и выражение), а его продолжение может быть указано в следую-

щих строках только в том случае, если действие оформлено как блок

Си-программы.

Область действия переменных, об'явленных внутри блока, рас-

пространяется только на этот блок. Внешними переменными для всех

действий будут являться только те переменные, которые об'явлены в

разделе определений Lex-программы.

Действия в правилах Lex-программы выполняются, если правило

активно, и если автомат распознает цепочку символов из входного

потока как соответствующую регулярному выражению данного правила.

Однако, одно действие выполняется всегда - оно заключается в ко-

пировании входного потока символов в выходной. Это копирование

осуществляется для всех входных строк, которые не соответствуют

правилам, преобразующим эти строки. Комбинация символов, не уч-

тенная в правилах и появившаяся на входе, будет напечатана на вы-

ходе. Можно сказать, что действие - это то, что делается вместо

копирования входного потока символов на выход.

Когда необходимо вывести или преобразовать текст, соответ-

ствующий некоторому регулярному выражению, используется внешний

массив символов, который формирует Lex. Называется он yytext и

доступен в действиях правил. Например:

[A-Z]+ printf("%s",yytext);

По этому правилу распознается слово, содержащее прописные

латинские буквы и выводится с помощью printf, если оно выделено.

Операция вывода распознанного выражения используется очень часто,

поэтому имеется сокращенная форма записи этого действия: [A-Z]+

ECHO;

Результат действия этого правила будет аналогичен результа-

ту предыдущего примера. В выходном файле lex.yy.c ECHO определе-

но как макроподстановка:

#define ECHO fprintf(yyout, "%s",yytext);

Когда необходимо знать длину обнаруженной последовательнос-

ти символов, используется счетчик найденных символов yyleng, ко-

торый также доступен в действиях. Например:

[A-Z]+ printf("%c",yytext[yyleng-1]);

В этом примере будет выводится последний символ слова, соот-

ветствующего регулярному выражению [A-Z]+.

Рассмотрим еще один пример:

[A-Z]+ {число_слов++;число_букв += yyleng;}

Здесь ведется подсчет числа распознанных слов и количества

символов во всех словах.

Порядок действий активных правил

Список правил Lex-программы может содержать активные иеак-

тивные правила, размещенные в любом порядке в разделе правил. В

процессе работы лексического анализатора список активных правил

может видоизменяться за счет действий оператора BEGIN. В процес-

се распознавания символов входного потока может оказаться так,

что одна цепочка символов будет удовлетворять нескольким прави-

лам и, следовательно, возникает проблема: действие какого прави-

ла должно выполняться?

Для разрешения этого противоречия можно использовать кванто-

вание (разбиение) регулярных выражений этих правил Lex-программы

на такие новые регулярные выражения, которые дадут, по возможнос-

ти, однозначное распознавание лексемы. Однако, когда это не сде-

лано, Lex использует определенный детерминированный механизм раз-

решения такого противоречия:

- выбирается действие того правила, которое распознает наи-