Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/third_party/ply/example/closurecalc/calc.py
7087 views
1
# -----------------------------------------------------------------------------
2
# calc.py
3
#
4
# A calculator parser that makes use of closures. The function make_calculator()
5
# returns a function that accepts an input string and returns a result. All
6
# lexing rules, parsing rules, and internal state are held inside the function.
7
# -----------------------------------------------------------------------------
8
9
import sys
10
sys.path.insert(0,"../..")
11
12
if sys.version_info[0] >= 3:
13
raw_input = input
14
15
# Make a calculator function
16
17
def make_calculator():
18
import ply.lex as lex
19
import ply.yacc as yacc
20
21
# ------- Internal calculator state
22
23
variables = { } # Dictionary of stored variables
24
25
# ------- Calculator tokenizing rules
26
27
tokens = (
28
'NAME','NUMBER',
29
)
30
31
literals = ['=','+','-','*','/', '(',')']
32
33
t_ignore = " \t"
34
35
t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*'
36
37
def t_NUMBER(t):
38
r'\d+'
39
t.value = int(t.value)
40
return t
41
42
def t_newline(t):
43
r'\n+'
44
t.lexer.lineno += t.value.count("\n")
45
46
def t_error(t):
47
print("Illegal character '%s'" % t.value[0])
48
t.lexer.skip(1)
49
50
# Build the lexer
51
lexer = lex.lex()
52
53
# ------- Calculator parsing rules
54
55
precedence = (
56
('left','+','-'),
57
('left','*','/'),
58
('right','UMINUS'),
59
)
60
61
def p_statement_assign(p):
62
'statement : NAME "=" expression'
63
variables[p[1]] = p[3]
64
p[0] = None
65
66
def p_statement_expr(p):
67
'statement : expression'
68
p[0] = p[1]
69
70
def p_expression_binop(p):
71
'''expression : expression '+' expression
72
| expression '-' expression
73
| expression '*' expression
74
| expression '/' expression'''
75
if p[2] == '+' : p[0] = p[1] + p[3]
76
elif p[2] == '-': p[0] = p[1] - p[3]
77
elif p[2] == '*': p[0] = p[1] * p[3]
78
elif p[2] == '/': p[0] = p[1] / p[3]
79
80
def p_expression_uminus(p):
81
"expression : '-' expression %prec UMINUS"
82
p[0] = -p[2]
83
84
def p_expression_group(p):
85
"expression : '(' expression ')'"
86
p[0] = p[2]
87
88
def p_expression_number(p):
89
"expression : NUMBER"
90
p[0] = p[1]
91
92
def p_expression_name(p):
93
"expression : NAME"
94
try:
95
p[0] = variables[p[1]]
96
except LookupError:
97
print("Undefined name '%s'" % p[1])
98
p[0] = 0
99
100
def p_error(p):
101
if p:
102
print("Syntax error at '%s'" % p.value)
103
else:
104
print("Syntax error at EOF")
105
106
107
# Build the parser
108
parser = yacc.yacc()
109
110
# ------- Input function
111
112
def input(text):
113
result = parser.parse(text,lexer=lexer)
114
return result
115
116
return input
117
118
# Make a calculator object and use it
119
calc = make_calculator()
120
121
while True:
122
try:
123
s = raw_input("calc > ")
124
except EOFError:
125
break
126
r = calc(s)
127
if r:
128
print(r)
129
130
131
132