| /* Parser and scanner for pushcalc. -*- C -*- |
| |
| Copyright (C) 2020-2022, 2025 Free Software Foundation, Inc. |
| |
| This file is part of Bison, the GNU Compiler Compiler. |
| |
| This program is free software: you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
| |
| %code top { |
| #include <ctype.h> /* isdigit. */ |
| #include <stdio.h> /* printf. */ |
| #include <stdlib.h> /* abort. */ |
| #include <string.h> /* strcmp. */ |
| } |
| |
| %code { |
| int yylex (YYSTYPE *yylval); |
| 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 <double> NUM "number" |
| %type <double> expr term fact |
| |
| /* Don't share global variables between the scanner and the parser. */ |
| %define api.pure full |
| /* Generate a push parser. */ |
| %define api.push-pull push |
| |
| /* Nice error messages with details. */ |
| %define parse.error detailed |
| |
| /* Generate the parser description file (calc.output). */ |
| %verbose |
| |
| /* Enable run-time traces (yydebug). */ |
| %define parse.trace |
| |
| /* Formatting semantic values in debug traces. */ |
| %printer { fprintf (yyo, "%g", $$); } <double>; |
| |
| %% /* 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 ')' { $$ = $expr; } |
| ; |
| |
| %% |
| |
| int |
| yylex (YYSTYPE *yylval) |
| { |
| 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; |
| int status; |
| yypstate *ps = yypstate_new (); |
| do { |
| YYSTYPE lval; |
| status = yypush_parse (ps, yylex (&lval), &lval); |
| } while (status == YYPUSH_MORE); |
| yypstate_delete (ps); |
| return status; |
| } |