-
Notifications
You must be signed in to change notification settings - Fork 0
/
calculator.py
111 lines (85 loc) · 3.24 KB
/
calculator.py
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
import sys
from antlr4.error.ErrorListener import ErrorListener
from antlr4.error.ErrorStrategy import DefaultErrorStrategy
from antlr4.error.Errors import InputMismatchException
from gen.calculatorLexer import calculatorLexer, CommonTokenStream
from gen.calculatorVisitor import calculatorVisitor
from gen.calculatorParser import calculatorParser, InputStream
class MyVisitor(calculatorVisitor):
def __init__(self):
self.memory = {}
def visitClear(self, ctx):
print('flush memory!')
self.memory = {}
return 0
def visitAssign(self, ctx):
name = ctx.ID().getText()
value = self.visit(ctx.expr())
self.memory[name] = value
print(f'keep variable {name}={value}')
return value
def visitPrintExpr(self, ctx):
value = self.visit(ctx.expr())
print(f'{ctx.expr().getText()}={value}')
return value
def visitInt(self, ctx):
return ctx.INT().getText()
def visitId(self, ctx):
name = ctx.ID().getText()
if name in self.memory:
return self.memory[name]
print(f'no variable {name} found, use default value 0')
return 0
def visitMulDiv(self, ctx):
left = int(self.visit(ctx.expr(0)))
right = int(self.visit(ctx.expr(1)))
if ctx.op.type == calculatorParser.MUL:
return left * right
return left / right
def visitDMul(self, ctx):
left = int(self.visit(ctx.expr(0)))
right = int(self.visit(ctx.expr(1)))
if ctx.op.type != calculatorParser.DMUL:
raise Exception('error operator')
return left**right
def visitAddSub(self, ctx):
left = int(self.visit(ctx.expr(0)))
right = int(self.visit(ctx.expr(1)))
if ctx.op.type == calculatorParser.ADD:
return left + right
return left - right
def visitParens(self, ctx):
return self.visit(ctx.expr())
# 收集所有的语法错误信息
# 可以综合判断
class VerboseListener(ErrorListener) :
def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e):
stack = recognizer.getRuleInvocationStack()
stack.reverse()
print("rule stack: ", str(stack))
print(f'line {line} : {column} at {offendingSymbol} : {msg}')
# 直接报语法异常
class ErrorHandler(DefaultErrorStrategy):
def sync(self, recognizer):
pass
def recoverInline(self, recognizer):
raise InputMismatchException(recognizer)
def recover(self, recognizer, e):
raise e
def reportNoViableAlternative(self, recognizer, e):
recognizer.notifyErrorListeners("缺少备选条件", e.offendingToken, e)
if __name__ == '__main__':
input_stream = InputStream(sys.stdin.readline())
lexer = calculatorLexer(input_stream)
token_stream = CommonTokenStream(lexer)
parser = calculatorParser(token_stream)
parser.print_times = 2
parser.removeErrorListeners()
parser.addErrorListener(VerboseListener())
parser._errHandler = ErrorHandler()
tree = parser.prog()
print('tree result:',tree.result)
for stat in tree.children:
print(f'stat<{stat.getText()}> result:', stat.result)
visitor = MyVisitor()
print('vistor value:', visitor.visit(tree))