[ Содержание ] [ Предыдущая ] [ Следующая ]
Каждому грамматическому правилу пользователь может приписать действия, исполняемые каждый раз, когда распознается правило во входных данных. Эти действия могут возвращать значения, и получать значения, возвращенные предыдущими действиями. Более того, лексический анализатор может возвращать значения токенов, если это необходимо.
Действие - это произвольный оператор C, и поэтому может производить ввод и вывод, вызывать подпрограммы и изменять внешние переменные. Дейстиве обозначается одним или более операторами, заключенными в фигурные скобки "{" и "}". Hапример,
A : '(' B ')'
{ hello( 1, "abc" ); }
и
XXX : YYY ZZZ
{ printf("a message\n"); flag = 25; }
являются грамматическими правилами с действиями.
Операторы действий слегка изменяются, чтобы способствовать простой связим между действиями и парсером. Символ доллара "$" используется как сигнал Yacc-y в этом контексте.
Чтобы вернуть значение, дейстиве обычно устанавливает псевдопеременную "$$" в некоторое значение. Hапример, действие, которое ничего не делает, а только возвращает значение 1 , это
{ $$ = 1 }
Чтобы получить значения, возвращенные предыдущими действиями и лексическим анализатором, действие может использовать псевдо-переменные $1, $2, . . ., которые относятся к значениям, возвращенным компонентами в правой части правила, при его чтении слева направо. Таким образом, если правило, например,
A : B C D ;
то $2 имеет значение, возвращенное C, а $3 - значение, возвращенное D.
Как более конкретный пример, представим правило
expr : '(' expr ')' ;
Значение, возвращенное этим правилом - это обычно значение expr в скобках. Это может быть выражено так:
expr : '(' expr ')'
{ $$ = $2 ; }
По умолчанию значение правила - это значение первого элемента в нем ($1). Таким образом, грамматическое правило вида
A : B ;
часто не требует явного действия.
В вышеприведенных примерах все действия указывались в конце своих правил. Иногда желательно получить контроль перед тем, как правило полностью разобрано. Yacc позволяет писать действия как в конце, так и в середине правила. Считается, что это правило возвращает значение, доступное через обычный механизм действиям справа. В совю очередь, он может иметь доступ к значениям, возвращаемым символами слева от него. Таким образом, правило
A : B
{ $$ = 1; }
C
{ x = $2; y = $3; }
;
устанавливает x в 1, а y - в значение, возвращенное C.
Действия, которые не завершают правило, в действительности обрабатываются Yaccом с помощью нового нетерминального символа и нового правила, сопоставляющего это имя с пустой строкой. Внутреннее действие - это действие, вызываемое при распознавании этого добавленного правила. Yacc в действительности обращается с вышеприведенным примером, как будто он написан как
$ACT : /* пустое */
{ $$ = 1; }
;
A : B $ACT C
{ x = $2; y = $3; }
;
В многих приложениях вывод не производится напрямую действиями; скорее, в памяти генерируется структура, такая как дерево разбора и она преобразуется перед тем, как генерируется вывод. Деревья разбора чрезвычайно просто строить, при заданных функциях построения и обработки желаемой структуры дерева. Hапример, предположим, что существует функция на C node(), написанная так, что вызов
node( L, n1, n2 )
создает узел с меткой L и потомками n1 и n2 и возвращает индекс этого нового узла. Тогда дерево разбора может быть построена с применением таких действий в, спецификации, как
expr : expr '+' expr
{ $$ = node( '+', $1, $3 ); }
Пользователь может определить другие переменные для использования в дейстивях. Объявления и описания могут появляться в секции объявлений, заключенные в символы "%{" и "}%". Эти объявления и определения имеют глобальную область действия, так что они известны операторам действий и лексическому анализатору. Hапример,
%{
int variable = 0;
%}
может быть помещено в секцию объявлений, делая переменные доступными всем действиям. Парсер Yacc-а использует только имена, начинающиеся с "yy"; пользователь должен избегать использования таких имен.
В этих примерах все значения - целые: обсуждение значений других типов будет в главе 10.
[ Содержание ] [ Предыдущая ] [ Следующая ]
c 1998-2000 SoloTony (Antonio Solo) | solotony@mail.ru |