Россия |
Грамматики и YACC
Секция правил грамматики
Секция правил грамматики
A: production_body { program_fragment; } ;
Секция грамматических правил состоит из правил, которые записываются следующим образом:
A: production_body;
где A - имя нетерминала, production_body -последовательность нуля или большего количества имен и литералов.
Имена могут быть произвольной длины и содержать буквы, цифры (как обычно, цифра не может быть первой литерой имени), подчеркивания и точки. Литерал состоит из литер, заключенных в апострофы. Как и в языке C, литера обратная косая черта (backslash) используется для задания управляющей последовательности (escape sequence).
Если имеется несколько грамматических правил с одинаковой левой частью, то может использовать литера вертикальная черта для объединения всех правил в одно:
A: production_body_1 | production_body_2 ;
Заметим, что каждое имя, не объявленное как терминал, считается нетерминалом. Каждый нетерминал должен появиться в левой части, хотя бы одного правила. Нетерминал, являющийся левой частью первого правила, по умолчанию считается аксиомой. Вообще говоря, аксиому можно определить в секции объявлений как:
%start axiom.
Семантики
Семантики
Nonterminal: production_body_1 { semantic_action_1 } | . . . production_body_n { semantic_action_n } ;
Грамматические правила могут содержать так называемые семантики (semantic actions), представляющие собой фрагменты программ на языке С, заключенные в фигурные скобки. Например,
lines: lines expr '\n' { printf ("%s\n", %2); }
Нетерминал может иметь значение некоторого типа, который указан в объединении, определенном в секции объявлений. Для этого
-
нетерминал должен быть объявлен следующим образом:
%type <имя-вида> имя-нетерминала
Причем, в объединении должен быть элемент вид имя-вида. Например,
%union { ... unsigned short int myCounter; ... } %type <myCounter> counter %%
- Семантика правил, левой частью которых является этот нетерминал, должна содержать оператор: $$ = значение;
Заметим, что значение может иметь не только нетерминалы, но и терминальные символы. В этом случае терминал должен быть объявлен следующим образом: %type <имя-вида> имя-нетерминала
Естественно, в объединении должен быть элемент вид имя-вида. Например,
%union {... signed int myValue;...} %token <myValue> NUMBER_LC
Семантики (продолжение)
Поскольку нетерминал, может иметь значение, то если такой нетерминал находится в правой части правила, мы можем воспользоваться его значением. Все имена и литералы, содержащиеся в правой части правила нумеруются слева направо, начиная с единицы. Для того, чтобы воспользоваться значением нетерминала следует написать $номер-нетерминала, например:
T: F { &&=&1; } | T*F { && = &1*&2; } ;
Заметим, что по умолчанию значение правила и тем самым значение нетерминала, находящегося в его левой части, - это значение первого элемента в нем. Таким образом, предыдущий пример может быть переписан:
T: F | T*F { && = &1*&2; } ;
На самом деле, семантики могут быть использованы не только в конце правила, но и в середине. Например,
A: B { && = 1; } C { x = &2; y = &3; } ;
Правда, при этом надо иметь в виду, что семантики, которые не завершают правило, обрабатываются путем введения нового нетерминала и нового правила, сопоставляющего этот нетерминал пустой строке. Т.е. на самом деле приведенное выше правило эквивалентно следующему:
&&1: /* пустая правая часть */ { && = 1; } ; A: B &&1 C { x = &2; y = &3; } ;