![]() |
YACC |
||||||||||||||
|
[ Содержание ] [ Предыдущая ] [ Следующая ] Глава 2. Действия Каждому грамматическому правилу пользователь может приписать действия, исполняемые каждый раз, когда распознается правило во входных данных. Эти действия могут возвращать значения, и получать значения, возвращенные предыдущими действиями. Более того, лексический анализатор может возвращать значения токенов, если это необходимо. A : '(' B ')'
{ hello( 1, "abc" ); }
и XXX : YYY ZZZ
{ printf("a message\n"); flag = 25; }
являются грамматическими правилами с действиями. { $$ = 1 }
Чтобы получить значения, возвращенные предыдущими действиями и лексическим анализатором, действие может использовать псевдо-переменные $1, $2, . . ., которые относятся к значениям, возвращенным компонентами в правой части правила, при его чтении слева направо. Таким образом, если правило, например, A : B C D ; то $2 имеет значение, возвращенное C, а $3 - значение, возвращенное D. expr : '(' expr ')' ;
Значение, возвращенное этим правилом - это обычно значение expr в скобках. Это может быть выражено так: expr : '(' expr ')'
{ $$ = $2 ; }
По умолчанию значение правила - это значение первого элемента в нем ($1). Таким образом, грамматическое правило вида A : B ; часто не требует явного действия. A : B
{ $$ = 1; }
C
{ x = $2; y = $3; }
;
устанавливает x в 1, а y - в значение, возвращенное C. $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"; пользователь должен избегать использования таких имен. [ Содержание ] [ Предыдущая ] [ Следующая ] | ||||||||||||||
|