%code top { #include #include /* isdigit. */ #include /* printf. */ #include /* abort. */ #include /* strcmp. */ int yylex (void); void yyerror (char const *); } %define api.header.include {"calc.h"} /* Generate YYSTYPE from the types used in %token and %type. */ %define api.value.type union %token NUM "number" %type expr term fact /* Generate the parser description file (calc.output). */ %verbose /* Nice error messages with details. */ %define parse.error detailed /* Enable run-time traces (yydebug). */ %define parse.trace /* Formatting semantic values in debug traces. */ %printer { fprintf (yyo, "%g", $$); } ; %% /* The grammar follows. */ input: %empty | input line ; line: '\n' | expr '\n' { printf ("%.10g\n", $1); } | error '\n' { yyerrok; } ; expr: expr '+' term { $$ = $1 + $3; } | expr '-' term { $$ = $1 - $3; } | term ; term: term '*' fact { $$ = $1 * $3; } | term '/' fact { $$ = $1 / $3; } | fact ; fact: "number" | '(' expr ')' { $$ = $2; } ; %% int yylex (void) { int c; /* Ignore white space, get first nonwhite character. */ while ((c = getchar ()) == ' ' || c == '\t') continue; if (c == EOF) return 0; /* Char starts a number => parse the number. */ if (c == '.' || isdigit (c)) { ungetc (c, stdin); if (scanf ("%lf", &yylval.NUM) != 1) abort (); return NUM; } /* Any other character is a token by itself. */ return c; } /* Called by yyparse on error. */ void yyerror (char const *s) { fprintf (stderr, "%s\n", s); } int main (int argc, char const* argv[]) { /* Enable parse traces on option -p. */ for (int i = 1; i < argc; ++i) if (!strcmp (argv[i], "-p")) yydebug = 1; return yyparse (); }