1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
// 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 \
enum yytokentype yylex (YYSTYPE* yylval, int *nerrs)
YY_DECL;
void yyerror (int *nerrs, const char *msg);
}
// Emitted on top of the implementation file.
%code top
{
#include <stdio.h> // printf.
#include <stdlib.h> // getenv.
}
%define api.pure full
%define api.token.prefix {TOK_}
%define api.value.type union
%define parse.error verbose
%define parse.trace
// Error count, exchanged between main, yyparse and yylex.
%param {int *nerrs}
%token
PLUS "+"
MINUS "-"
STAR "*"
SLASH "/"
LPAREN "("
RPAREN ")"
EOL "end-of-line"
EOF 0 "end-of-file"
;
%token <int> NUM "number"
%type <int> exp
%printer { fprintf (yyo, "%d", $$); } <int>
// Precedence (from lowest to highest) and associativity.
%left "+" "-"
%left "*" "/"
%%
// Rules.
input:
%empty
| input line
;
line:
exp EOL { printf ("%d\n", $exp); }
| error EOL { yyerrok; }
;
exp:
exp "+" exp { $$ = $1 + $3; }
| exp "-" exp { $$ = $1 - $3; }
| exp "*" exp { $$ = $1 * $3; }
| exp "/" exp
{
if ($3 == 0)
{
yyerror (nerrs, "invalid division by zero");
YYERROR;
}
else
$$ = $1 / $3;
}
| "(" exp ")" { $$ = $2; }
| NUM { $$ = $1; }
;
%%
// Epilogue (C code).
void yyerror (int *nerrs, const char *msg)
{
fprintf (stderr, "%s\n", msg);
++*nerrs;
}
int main (void)
{
int nerrs = 0;
// Possibly enable parser runtime debugging.
yydebug = !!getenv ("YYDEBUG");
yyparse (&nerrs);
// Exit on failure if there were errors.
return !!nerrs;
}
|