Poprzednio pokazałem jak można zbudować „kadłubek” parsera i leksera z wykorzystaniem narzędzi yacc i flex. W tym wpisie uzupełnię parser (plik parse.y) i lekser (plik scan.l) o interpretacje następujących wyrażeń:
<liczba> * <liczba> <liczba>/<liczba> -<liczba> (<wyrażenie>)
W pliku parser.y wprowadziłem następujące zmiany (zaznaczone kolorem czerwonym):
%{ #include <stdio.h> int yylex(void); void yyerror(char *s ); %} %start expression_list %token NUM %left '-' '+' %left '*' '/' %nonassoc UMINUS %% expression_list: expression_list expression '\n'{ printf(" = %d\n",$2); } | expression_list '\n' | ; expression: NUM | '-' 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(); }
Wytłumaczenia wymagają linie:
%nonassoc UMINUS | '-' expression %prec UMINUS { $$ = -$2; }
Komenda %nonassoc oznacza, że operator ‚-‚ nie wiąże się ani lewostronnie, ani prawostronnie.
Token UMINUS jest wykorzystywany jedynie do nadania odpowiedniego priorytetu znakowi minus. Jeżeli nie skorzystałbym ze znacznika %prec w powyższej regule, parser nie wiedziałbym jak w przypadku –
Pozostaje mi zmienić jeszcze plik scan.l, aby lekser identyfikował znaki * / ( ).
%{
#include <stdio.h>
#include "parse.h"
void yyerror(char *s );
%}
%%
[0-9]+ return NUM;
[-+*/()\n] return *yytext;
[ \t] ;
. yyerror("Niepoprawny znak");
%%