/* Parser for lexcalc. -*- C -*-
Copyright (C) 2018-2021 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 . */
// Prologue (directives).
%expect 0
// Emitted in the header file, after the definition of YYSTYPE.
%code provides
{
// Tell Flex the expected prototype of yylex.
#define YY_DECL \
yytoken_kind_t yylex (YYSTYPE* yylval, YYLTYPE *yylloc)
YY_DECL;
void yyerror (YYLTYPE *loc, const char *msg);
}
// Emitted on top of the implementation file.
%code top
{
#include // printf.
#include // getenv.
#include // strcmp.
}
// Include the header in the implementation rather than duplicating it.
%define api.header.include {"parse.h"}
// Don't share global variables between the scanner and the parser.
%define api.pure full
// To avoid name clashes (e.g., with C's EOF) prefix token definitions
// with TOK_ (e.g., TOK_EOF).
%define api.token.prefix {TOK_}
// %token and %type use genuine types (e.g., "%token "). Let
// %bison define YYSTYPE as a union of all these types.
%define api.value.type union
// Generate detailed error messages.
%define parse.error detailed
// with locations.
%locations
// Enable debug traces (see yydebug in main).
%define parse.trace
%token
PLUS "+"
MINUS "-"
STAR "*"
SLASH "/"
LPAREN "("
RPAREN ")"
EOL "end of line"
;
%token NUM "number"
%type exp expression line
%printer { fprintf (yyo, "%d", $$); }
%start input expression NUM
// Precedence (from lowest to highest) and associativity.
%left "+" "-"
%left "*" "/"
%%
// Rules.
input:
%empty
| input line
;
line:
exp EOL { $$ = $exp; printf ("%d\n", $$); }
| error EOL { $$ = 0; yyerrok; }
;
expression:
exp EOL { $$ = $exp; }
;
exp:
exp "+" exp { $$ = $1 + $3; }
| exp "-" exp { $$ = $1 - $3; }
| exp "*" exp { $$ = $1 * $3; }
| exp "/" exp
{
if ($3 == 0)
{
yyerror (&@$, "error: division by zero");
YYERROR;
}
else
$$ = $1 / $3;
}
| "(" exp ")" { $$ = $2; }
| NUM { $$ = $1; }
;
%%
// Epilogue (C code).
void yyerror (YYLTYPE *loc, const char *msg)
{
YY_LOCATION_PRINT (stderr, *loc);
fprintf (stderr, ": %s\n", msg);
}
int main (int argc, const char *argv[])
{
// Possibly enable parser runtime debugging.
yydebug = !!getenv ("YYDEBUG");
int parse_expression_p = 0;
int nerrs = 0;
// Enable parse traces on option -p.
for (int i = 1; i < argc; ++i)
if (strcmp (argv[i], "-e") == 0)
parse_expression_p = 1;
else if (strcmp (argv[i], "-p") == 0)
yydebug = 1;
if (parse_expression_p)
{
yyparse_expression_t res = yyparse_expression ();
nerrs = res.yynerrs;
if (res.yystatus == 0)
printf ("expression: %d\n", res.yyvalue);
else
printf ("expression: failure\n");
}
else
nerrs = yyparse_input ().yynerrs;
if (nerrs)
fprintf (stderr, "errors: %d\n", nerrs);
// Exit on failure if there were errors.
return !!nerrs;
}