interpreter, Linux, Mac, Raspberry Pi

Zbudujmy interpreter (2) – kolejny krok

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 – zinterpretować ten zapis.

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");
%%
Standard

Dodaj komentarz