Mój interpreter do tej pory wykonywał jedynie działania na liczbach całkowitych. Dzisiaj przyszedł czas na dodanie obsługi liczb rzeczywistych. Zacznijmy od modyfikacji leksera.
%{ #define YYSTYPE double #include <stdio.h> #include "parse.h" void yyerror(char *s); %} %% [a-z] { yylval = (double) (*yytext - 'a'); return VARIABLE; } [0-9]+ { yylval = atof (yytext); return NUM; } (([0-9]+(\.[0-9]*)?)|([0-9]*\.[0-9]+)) { yylval = atof (yytext); return NUM; } [-+()=/*\n] return *yytext; [ \t] ; /* skip whitespace */ . yyerror("invalid character"); %%
Warto zwrócić uwagę na dodaną definicję typu YYSTYPE – domyślnie wskazuje on na typ int. Na potrzeby obsługi liczb rzeczywistych zmieniłem typ na double. Drugą ważną sprawą jest wyrażenie regularne wykrywające liczbę zmiennoprzecinkową (([0-9]+(\.[0-9]*)?)|([0-9]*\.[0-9]+)).
Ze względu na zmieniony typ YYSTYPE musimy dokonać również modyfikacji pliku parse.y.
%{ #define YYSTYPE double #include <stdio.h> int yylex(void); void yyerror(char *s ); double vars[26]; %} %start expression_list %token NUM VARIABLE %left '-' '+' %left '*' '/' %nonassoc UMINUS %% expression_list: expression_list statement '\n'{ printf(" = %f\n",$2); } | expression_list '\n' | ; statement: expression | VARIABLE '=' expression { vars[(int)$1] = $3; } ; expression: NUM | VARIABLE { $$ = vars[(int) $1]; } | '-' 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(); }