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