-
Notifications
You must be signed in to change notification settings - Fork 2
/
caculator.py
146 lines (131 loc) · 3.93 KB
/
caculator.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
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
141
142
143
144
145
146
##1.输入处理
# 输入字符处理
class Buffer(object):
def __init__(self,data):
self.data = data
self.offset = 0
# 提取offset位置处的一个字符
def peek(self):
#如果没有后续字符则返回None
if self.offset >= len(self.data):
return None
return self.data[self.offset]
# 取字符的位置向后移动一位
def advance(self):
self.offset += 1
##2.生成Token列表
class Token(object):
def consume(self,buffer):
pass
# 整数类型的Token
class IntToken(Token):
# 从字符串中读取字符直到字符不是整数
def consume(self,buffer):
accum = ""
while True:
ch = buffer.peek()
if ch is None or ch not in "0123456789":
break
else:
accum += ch
buffer.advance()
# 如果读取的内容不为空则返回整数,否则返回None
if accum != "":
return ("int",int(accum))
else:
return None
# 操作(+,-)类型的Token
class OperatorToken(Token):
# 读取一个字符,然后返回这个字符,如果字符不是+-,则返回None
def consume(self,buffer):
ch = buffer.peek()
if ch is not None and ch in "+-":
buffer.advance()
return ("ope",ch)
return None
# 从字符串中获取整数及操作的Token
def tokenize(string):
buffer = Buffer(string)
tk_int = IntToken()
tk_op = OperatorToken()
tokens = []
while buffer.peek():
token = None
# 用两种类型的Token进行测试
for tk in (tk_int,tk_op):
token = tk.consume(buffer)
if token:
tokens.append(token)
break
# 如果不存在可以识别的Token表示输入错误
if not token:
raise ValueError("Error in syntax")
return tokens
##3. 生成表达式树
# 表达式二叉树的节点
class Node(object):
pass
# 整数节点
class IntNode(Node):
def __init__(self,value):
self.value = value
# 操作符节点 (+ 或 -)
class BinaryOpNode(Node):
def __init__(self,kind):
self.kind = kind
self.left = None # 左节点
self.right = None # 右节点
# 从Token列表生成表达式二叉树
def parse(tokens):
if tokens[0][0] != 'int':
raise ValueError("Must start with an int")
#取出tokens[0],该Token类型为整数
node = IntNode(tokens[0][1])
nbo = None
last = tokens[0][0]
#从第二个Token开始循环取出
for token in tokens[1:]:
#相邻两个Token的类型一样则为错误
if token[0] == last:
raise ValueError("Error in syntax")
last = token[0]
#如果Token为操作符,则保存为操作符节点,把前一个整数Token作为左子节点
if token[0] == 'ope':
nbo = BinaryOpNode(token[1])
nbo.left = node
#如果Token为整数,则将该Token保存为右节点
if token[0] == 'int':
nbo.right = IntNode(token[1])
node = nbo
return node
# 采用递归的方法计算表达式二叉树的值
def caculate(nbo):
# 如果左节点是二叉树,则先计算左节点二叉树的值
if isinstance(nbo.left,BinaryOpNode):
leftval = caculate(nbo.left)
else:
leftval = nbo.left.value
# 根据操作符节点是加还是减计算
if nbo.kind == '-':
return leftval - nbo.right.value
elif nbo.kind == '+':
return leftval + nbo.right.value
else:
raise ValueError("Wrong operator")
# 判断是否只输入了一个整数
def evaluate(node):
# 如果表达式中只有一个整数,则直接返回值
if isinstance(node,IntNode):
return node.value
else:
return caculate(node)
# 主程序,输入输出处理
if __name__ == '__main__':
# 获取输入字符串
input = input('Input:')
# 从输入字符串获得Token列表
tokens = tokenize(input)
# 从Token列表生成表达式树
node = parse(tokens)
# 遍历计算表达式树并输出结果
print("Result:"+str(evaluate(node)))