Я изучаю yacc и lex с помощью некоторого учебного кода, который создает парсер, позволяющий вам делать следующее:
1. Назначьте целые числа для однобуквенных переменных
2. Делайте сложение и вычитание, используя числа и переменные
3. Выведите значение переменной
В учебнике говорится, что для разрешения присвоения чисел переменным нам необходим файл lex, чтобы возвращать два разных типа значений, которые затем объявляются в объединении в файле yacc.
Я понятия не имею, почему это даже необходимо. Я на самом деле пошел дальше и изменил учебный код, чтобы он работал без использования types / union и работал просто отлично (я просто использовал значение NAME, чтобы установить индекс в symtbl для целого числа, которому он назначен). Так что меня смущает то, зачем вообще использовать типы и объединение? Ниже приведен код из учебника.
%{
...
int symtbl[26];
bool issym[26];
%}
%union {
int rvalue; /* value of evaluated expression */
int lvalue; /* index into symtbl for variable name */
}
%token <rvalue> NUMBER
%token <lvalue> NAME
%type <rvalue> expression
%type <rvalue> const
%%
statement_list : statement '\n'
| statement_list statement '\n'
;
statement: NAME '=' expression { symtbl[$1] = $3; issym[$1] = true; }
| expression { printf("%d\n", $1); }
;
expression: expression '+' const { $$ = $1 + $3; }
| expression '-' const { $$ = $1 - $3; }
| const { $$ = $1; }
;
const: NUMBER { $$ = $1; }
| NAME
{
if (issym[$1]) { $$ = symtbl[$1]; }
else { fprintf(stderr, "Error: variable %c not previously defined\n", $1+'a'); exit(1); }
}
;
%%
Итак, мой вопрос: зачем нам нужны типы rvalue и lvalue? Зачем ставить это в союз? Также зачем объявлять правило как определенный тип?