-
Notifications
You must be signed in to change notification settings - Fork 3
/
calc-gram.ll
140 lines (133 loc) · 4.13 KB
/
calc-gram.ll
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#
# Copyright © 2019 Keith Packard <[email protected]>
#
# 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, write to the Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
#
#
# The parser operation is table driven -- the parse table
# is a set of mappings from (terminal,non-terminal) to (token ...),
# with (token ...) including terminals, non-terminals and actions.
#
# There is a parse stack of tokens. Depending on the type of the token on the
# top of the parse stack, three different actions are taken.
#
# 1) When the top of the parse stack is a non-terminal, it is replaced
# by the contents of the parse table entry cooresponding to the
# current input terminal and top of stack non-terminal
#
# 2) When the top of the parse stack is a terminal, it must match
# the current input terminal. The top of stack is discarded and
# another input token read.
#
# 3) When the top of the parse stack is an action, it is executed
#
# Because of this operation, actions wanting to use the value of the
# current input terminal are placed *before* the token itself. This is
# guaranteed to work as the only way to get to the production is if
# the input terminal is of the correct type.
#
# Actions wanting to be executed after the actions within one of the productions
# of a non-terminal are placed *after* the non-terminal. Otherwise, they would
# be executed before the actions within the non-terminal production due to the
# order of tokens pulled from the stack.
#
# The syntax is pretty simple, and is designed to mirror the usual
# yacc syntax.
#
# Actions are any sequence of characters enclosed in
# @. Use two @ signs to include an actual @ in the action.
#
# What I'd like to figure out is how to automate the management
# of the value stack so that actions can associate values
# with the non-terminal associated with the production in which
# they occur. This would make them work more like yacc actions as
# values could then be synthesized upwards in the grammar
#
# Perhaps a special token could be placed on the stack at the end of
# each sequence of tokens that replace a non-terminal, and this token
# could signal suitable value stack handling? That would need to know
# the number of elements that had been in the production when it was
# placed on the parse stack to know how many values to remove from the
# value stack, it would then drop that number of elements from the
# value stack and push the value computed by the last action within
# the production
#
# A calculator session is a sequence of lines
start : line start
|
;
# A line is an expression followed by a newline, or just a newline
# alone.
#
# The C code implementing the calculator provides a numeric stack with
# push/pop functions. Note that this set of actions is responsible for
# maintaining that stack correctly; errors will terminate the parser, and so
# the stack could be re-initialized when the parser is restarted.
#
line : expr NL
@{
printf("%g\n", pop());
}@
| NL
;
# Three levels of precedence, (+ -), (* /) and then unary
# minus/parenthesized exprs
expr : term expr-p
;
expr-p : PLUS term
@{
double b = pop();
double a = pop();
push(a + b);
}@
expr-p
| MINUS term
@{
double b = pop();
double a = pop();
push(a - b);
}@
expr-p
|
;
term : fact term-p
;
term-p : TIMES fact
@{
double b = pop();
double a = pop();
push(a * b);
}@
term-p
| DIVIDE fact
@{
double b = pop();
double a = pop();
push(a / b);
}@
term-p
|
;
fact : OP expr CP
| MINUS fact
@{
double a = pop();
push(-a);
}@
| NUMBER
@{
push(lex_value);
}@
;