Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/third_party/ply/example/classcalc/calc.py
7087 views
1
#!/usr/bin/env python
2
3
# -----------------------------------------------------------------------------
4
# calc.py
5
#
6
# A simple calculator with variables. This is from O'Reilly's
7
# "Lex and Yacc", p. 63.
8
#
9
# Class-based example contributed to PLY by David McNab
10
# -----------------------------------------------------------------------------
11
12
import sys
13
sys.path.insert(0,"../..")
14
15
if sys.version_info[0] >= 3:
16
raw_input = input
17
18
import ply.lex as lex
19
import ply.yacc as yacc
20
import os
21
22
class Parser:
23
"""
24
Base class for a lexer/parser that has the rules defined as methods
25
"""
26
tokens = ()
27
precedence = ()
28
29
def __init__(self, **kw):
30
self.debug = kw.get('debug', 0)
31
self.names = { }
32
try:
33
modname = os.path.split(os.path.splitext(__file__)[0])[1] + "_" + self.__class__.__name__
34
except:
35
modname = "parser"+"_"+self.__class__.__name__
36
self.debugfile = modname + ".dbg"
37
self.tabmodule = modname + "_" + "parsetab"
38
#print self.debugfile, self.tabmodule
39
40
# Build the lexer and parser
41
lex.lex(module=self, debug=self.debug)
42
yacc.yacc(module=self,
43
debug=self.debug,
44
debugfile=self.debugfile,
45
tabmodule=self.tabmodule)
46
47
def run(self):
48
while 1:
49
try:
50
s = raw_input('calc > ')
51
except EOFError:
52
break
53
if not s: continue
54
yacc.parse(s)
55
56
57
class Calc(Parser):
58
59
tokens = (
60
'NAME','NUMBER',
61
'PLUS','MINUS','EXP', 'TIMES','DIVIDE','EQUALS',
62
'LPAREN','RPAREN',
63
)
64
65
# Tokens
66
67
t_PLUS = r'\+'
68
t_MINUS = r'-'
69
t_EXP = r'\*\*'
70
t_TIMES = r'\*'
71
t_DIVIDE = r'/'
72
t_EQUALS = r'='
73
t_LPAREN = r'\('
74
t_RPAREN = r'\)'
75
t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*'
76
77
def t_NUMBER(self, t):
78
r'\d+'
79
try:
80
t.value = int(t.value)
81
except ValueError:
82
print("Integer value too large %s" % t.value)
83
t.value = 0
84
#print "parsed number %s" % repr(t.value)
85
return t
86
87
t_ignore = " \t"
88
89
def t_newline(self, t):
90
r'\n+'
91
t.lexer.lineno += t.value.count("\n")
92
93
def t_error(self, t):
94
print("Illegal character '%s'" % t.value[0])
95
t.lexer.skip(1)
96
97
# Parsing rules
98
99
precedence = (
100
('left','PLUS','MINUS'),
101
('left','TIMES','DIVIDE'),
102
('left', 'EXP'),
103
('right','UMINUS'),
104
)
105
106
def p_statement_assign(self, p):
107
'statement : NAME EQUALS expression'
108
self.names[p[1]] = p[3]
109
110
def p_statement_expr(self, p):
111
'statement : expression'
112
print(p[1])
113
114
def p_expression_binop(self, p):
115
"""
116
expression : expression PLUS expression
117
| expression MINUS expression
118
| expression TIMES expression
119
| expression DIVIDE expression
120
| expression EXP expression
121
"""
122
#print [repr(p[i]) for i in range(0,4)]
123
if p[2] == '+' : p[0] = p[1] + p[3]
124
elif p[2] == '-': p[0] = p[1] - p[3]
125
elif p[2] == '*': p[0] = p[1] * p[3]
126
elif p[2] == '/': p[0] = p[1] / p[3]
127
elif p[2] == '**': p[0] = p[1] ** p[3]
128
129
def p_expression_uminus(self, p):
130
'expression : MINUS expression %prec UMINUS'
131
p[0] = -p[2]
132
133
def p_expression_group(self, p):
134
'expression : LPAREN expression RPAREN'
135
p[0] = p[2]
136
137
def p_expression_number(self, p):
138
'expression : NUMBER'
139
p[0] = p[1]
140
141
def p_expression_name(self, p):
142
'expression : NAME'
143
try:
144
p[0] = self.names[p[1]]
145
except LookupError:
146
print("Undefined name '%s'" % p[1])
147
p[0] = 0
148
149
def p_error(self, p):
150
if p:
151
print("Syntax error at '%s'" % p.value)
152
else:
153
print("Syntax error at EOF")
154
155
if __name__ == '__main__':
156
calc = Calc()
157
calc.run()
158
159