W kolejnym kroku budowy interpretera dodam obsługę zmiennych (dla ułatwienia przyjąłem, że zmienne będą oznaczone jedną literą – w sumie możemy wykorzystać 26 zmiennych – od a do z). Chciałbym aby można było przypisywać wartość liczbową do zmiennej oraz wykorzystywać zmienne do obliczeń. Parser i lekser muszę uzupełnić o obsługę wyrażenia:
<zmienna> = <wyrażenie>
Plik parser.y uzupełniłem w następujący sposób:
%{ #include <stdio.h> int yylex(void); void yyerror(char *s ); int vars[26]; %} %start expression_list %token NUM VARIABLE %left '-' '+' %left '*' '/' %nonassoc UMINUS %% expression_list: expression_list statement '\n'{ printf(" = %d\n",$2); } | expression_list '\n' | ; statement: expression | VARIABLE '=' expression { vars[$1] = $3; } ; expression: NUM | VARIABLE { $$ = vars[$3]; } | '-' expression %prec UMINUS { $$ = -$2; } | '(' expression ')' { $$ = $2; } | expression '+' expression { $$ = $1 + $3; } | expression '-' expression { $$ = $1 - $3; } | expression '*' expression { $$ = $1 * $3; } | expression '/' expression { $$ = $1 / $3; } ; %% void yyerror(char *s ) { fprintf (stderr, "%s\n", s); } int main (int argc, char **argv) { return yyparse(); }
W tablicy int vars[] będę przechowywał wartości zmiennych. W definicji parsera dodałem opis wyrażenia statement w celu rozróżnienia czy dokonujemy przypisanie wartości do zmiennej czy dokonujemy obliczenia wyrażenia.
Pozostaje nam zmienić jeszcze plik scan.l aby dodać identyfikację tokena VARIABLE oraz znaku = .
%{ #include #include "parse.h" void yyerror(char *s); %} %% [a-z] { yylval = *yytext - 'a'; return VARIABLE; } [0-9]+ { yylval = atoi (yytext); return NUM; } [-+()=/*\n] return *yytext; [ \t] ; /* skip whitespace */ . yyerror("invalid character"); %%