Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Yacc.docx
Скачиваний:
13
Добавлен:
20.03.2016
Размер:
121.86 Кб
Скачать

Val. Если функция yylex находится в отдельном файле, то эта

переменная должна быть объявлена:

extern int yylval;

- 16 -

Уточним, что в дальнейшем значением лексемы мы будем

называть значение, присвоенное при ее распознавании перемен-

ной yylval; значение, возвращаемое функцией yylex, является

номером типа лексемы. Примером значения лексемы могут слуить

числовое значение цифры, вычисленное значение константы,

адрес идентификатора в таблице имен (построение таблицы имен

удобно осуществлять лексическим анализатором). Заметим,

что, хотя значение yylval устанавливается с целью использо-

вания его в действиях, непосредственное обращение к переМен-

ной yylval в действии не имеет смысла (поскольку в yylval

всегда находится значение последней выделенной лексемы).

Доступ в действиях к значениям лексем осуществляется с

помощью специального механизма, описанного в разделе 4.5.

7.2. Действия с использованием псевдопеременных

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

действиями и лексическим анализатором создаваемые yacc грам-

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

котором сохраняются значения лексем и нетерминальных симво-

лов. Значение лексемы автоматически попадает в стек после

ее распознавания лексическим анализатором (напомним, что им

считается текущее значение переменной yylval). После каждой

свертки вычисляется значение нетерминала, заместившего свер-

нутую строку, и помещается в вершину стека; значения элемен-

тов правой части примененного правила перед этим выталкива-

ются из стека. Заметим, что таким образом к моменту свертки

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

зываются вычисленными в результате сверток. Способ вычисле-

ния значения нетерминала будет рассмотрен ниже.

Описанный механизм не требует вмешательства пользова-

теля и предоставляет ему следующие возможности:

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

по правилу, значение любого элемента его правой части.

Доступ к этим значениям обеспечивается набором так

называемых псевдопеременных с именами $1,$2,..., где $i

соответствует значению i-го элемента; элементы правой

части правила нумеруются слева направо без различия

лексем и нетерминальных символов, например, в правиле

P_Head: P_name '(' P_list ')';

псевдопеременные $1,$2,$3,$4 относились бы соответст-

венно к P_name, '(', P_list, ')'.

- Формировать в действиях значение, образованного в

результате свертки нетерминала путем присвоения этого

значения псевдопеременной с именем $$. Так, в правиле

- 17 -

expr: expr '+' expr { $$=$1+$3; }

значением нового нетерминала expr станет сумма ранее

вычисленных значений двух других нетерминалов expr.

Eсли в действии не определяется значение переменной $$

(а также если действие отсутствует), значением нетерми-

нала после свертки по умолчанию становится значение

первого элемента правой части, т.е. неявно выполняется

присваивание

$$=$1;

Пример (вычисление значения целого числа)

%token DIGIT

%%

...

CONST: DIGIT

| CONST DIGIT {$$=$1*10+$2;}

...

%%

yylex()

{

char c;

if((c=getchar())>='0'&& c<='9') {

yylval = c-'0';

return (DIGIT);

}

...

}

Здесь при свертке по первому правилу нетерминал CONST

получает значение первой цифры, присвоенное в функции

yylex переменной yylval; при каждой свертке по второму

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

CONST.

Несколько иная ситуация в отношении использования псев-

допеременных имеет место для правил, содержащих действия

внутри правой части. На самом деле yacc интерпретирует пра-

вило вида

A: B C {действие 1} D {действие 2}

K {действие 3}

как

A: B C EMPTY1 D EMPTY2 K;

EMPTY1: {действие 1}

EMPTY2: {действие 2}

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

- 18 -

осуществляется свертка по пустому правилу, сопровождающаяся

выполнением указанного действия. При этом независимо от

характера действия очередной элемент в стеке значений отво-

дится для хранения значения неявно присутствующего "пустого"

нетерминала. В действии, находящемся в конце правила, согла-

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

иметь в виду наличие дополнительных символов. В приведенном

выше правиле в действии 3 для доступа к значениям элементов

B, C, D, K следовало бы использовать соответственно псевдо-

переменные $1, $2, $4, $6; псевдоперемнные $3, $5 хранят

результаты действий 1 и 2. В действиях, находящихся внутри

правила, с помощью псевдоперемнных $i доступны значения рас-

положенных левее элементов, а также результаты предшествую-

щих вставленных в тело действий. Результатом внутреннего

действия (т.е. значением неявного нетерминала) является зна-

чение, присвоенное в этом действии псевдопеременной $$, при

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

лен. Заметим, что присваивание значения псевдопеременной $$

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

новки значения нетерминала, стоящего в левой части правила:

это значение в любом случае устанавливется только действием

в конце правила или считается равным значению $1.

В нашем примере в действии 1 доступными являются только

значения элементов B и C (им соответствуют псевдопеременные

$1 и $2), а в действии 2 - значения элементов B, C, D и

результат действия 1 с помощью псевдопеременных $1, $2, $4,

$3.

Следующий пример иллюстрирует варианты использования

псевдопеременных:

%token ИМЯ КЛЮЧ1 КЛЮЧ2 КОНЕЦ

. . .

%%

входной_поток: данные КОНЕЦ

{printf("Данные занесены в файл %s\n",$1);};

данные:

ИМЯ {abc = creat($1,0666);}

КЛЮЧ1 КЛЮЧ2 {option($3,$4);}

упр_строка '\n' {converse(0,$5,$6);

write($1,$6,80);}

текст {converse(1,$5,$8);

write($1,$6,$8);

close($1);};

упр_строка: ...

текст : ...

. . .

- 19 -

Управляющая строка и текст преобразуются в соответствии с

заданными ключами и записываются в файл с указанным именем.

Значением нетерминала данные в результате неявного действия

становится значение лексемы ИМЯ (адрес строки с именем файла

присваивается в лексическом анализаторе переменной yylval).

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]