这里要实现一个计算器,输入一个算术表达式,输出计算结果,支持加减乘除四则运算,操作数可以是负数,可以使用括号。
首先我们需要搞清楚什么样的表达式是一个合法的算术表达式,下面给出算术表达式的文法,
E -> E + T | E - T | T
T -> T * F | T / F | F
F -> -num | num | (E)
由文法能生成的表达式是合法的算术表达式,不能由文法生成的表达式不是合法的算术表达式。
由文法可知,数值是合法的算术表达式,算术表达式通过+ - * /连接得到的还是算术表达式,算术表达式被()括起来还是算术表达式。
由文法可知运算数和运算符是交替出现的,(E)作为一个整体去看,它是一个运算数,如果我们把它代换为numE,括号被消除之后,整个表达式要么是一个单一的运算数,要么是运算数和运算符交替出现的一个串(串的首尾都是运算数),因此,当我们从左至右去解释执行算术表达式的时候,就有一个预期,一开始我们预期得到一个运算数(可以是括号括起来的表达式),接下来预期得到一个运算符,再接下来预期得到一个运算数,依次交替。当我们得到了两个运算数和一个运算符的时候,是不是立即展开计算?不一定,举例来说,1+2*3,我们不能计算1+2,而是要先计算2*3,如果是1*2+3,就能立即计算1*2了,因为运算具有优先级的缘故,当前运算符能不能被立即执行计算要看下一个运算符的运算优先级,如果当前运算符优先级更高,则执行计算,否则,先计算下一个运算符后再执行当前运算符,这是我们解释执行算术表达式的逻辑基础,下面看源码实现。
class Calc(object):
def __call__(self, exp):
self.exp = exp
self.explen = len(exp)
self.pos = 0
return self._calc()
def consumeblanks(self):
exp = self.exp
explen = len(exp)
pos = self.pos
while pos < explen:
if exp[pos] in [' ', '\t', '\v', '\n']:
pos += 1
else:
break
if pos != self.pos:
self.pos = pos
def get_number(self):
exp = self.exp
self.consumeblanks()
if exp[self.pos] == '(':
self.pos += 1
return self._calc(True)
else:
width = 0
if exp[self.pos] in ('+', '-'):
width = 1
for i in range(self.pos + width, len(self.exp)):
if exp[i] in ('+', '-', '*', '/', ')'):
break
width += 1
num = float(exp[self.pos: self.pos + width])
self.pos += width
return num
def get_operator(self):
self.consumeblanks()
if self.pos == len(self.exp):
return None
op = self.exp[self.pos]
if op not in ('+', '-', '*', '/', ')'):
raise ValueError("operator '%s' not supported" % op)
self.pos += 1
return op
def _calc(self, issubexp = False):
left = self.get_number()
op = self.get_operator()
if issubexp:
if op == ')':
return left
else:
if op == None:
return left
if op == ')':
raise ValueError("calc expression %s is invalid!" % self.exp)
if op == '+':
result = self.add(left)
elif op == '-':
result = self.dec(left)
elif op == '*':
result = self.mul(left)
elif op == '/':
result = self.div(left)
if issubexp:
if self.exp[self.pos - 1] != ')':
raise ValueError("calc expression %s is invalid!" % self.exp)
else:
if self.exp[self.pos - 1] == ')':
raise ValueError("calc expression %s is invalid!" % self.exp)
return result
def add(self, left):
right = self.get_number()
op2 = self.get_operator()
if op2 == ')' or op2 == None:
print("%f + %f = %f" % (left, right, left + right))
return left + right
if op2 == '+':
print("%f + %f = %f" % (left, right, left + right))
return self.add(left + right)
elif op2 == '-':
print("%f + %f = %f" % (left, right, left + right))
return self.dec(left + right)
elif op2 == '*':
right = self.mul(right)
print("%f + %f = %f" % (left, right, left + right))
return left + right
elif op2 == '/':
right = self.div(right)
print("%f + %f = %f" % (left, right, left + right))
return left + right
def dec(self, left):
right = self.get_number()
op2 = self.get_operator()
if op2 == ')' or op2 == None:
print("%f - %f = %f" % (left, right, left - right))
return left - right
if op2 == '+':
print("%f - %f = %f" % (left, right, left - right))
return self.add(left - right)
elif op2 == '-':
print("%f - %f = %f" % (left, right, left - right))
return self.dec(left - right)
elif op2 == '*':
right = self.mul(right)
print("%f - %f = %f" % (left, right, left - right))
return left - right
elif op2 == '/':
right = self.div(right)
print("%f - %f = %f" % (left, right, left - right))
return left - right
def mul(self, left):
right = self.get_number()
op2 = self.get_operator()
if op2 == ')' or op2 == None:
print("%f * %f = %f" % (left, right, left * right))
return left * right
if op2 == '+':
print("%f * %f = %f" % (left, right, left * right))
return self.add(left * right)
elif op2 == '-':
print("%f * %f = %f" % (left, right, left * right))
return self.dec(left * right)
elif op2 == '*':
print("%f * %f = %f" % (left, right, left * right))
return self.mul(left * right)
elif op2 == '/':
print("%f * %f = %f" % (left, right, left * right))
return self.div(left * right)
def div(self, left):
right = self.get_number()
op2 = self.get_operator()
if op2 == ')' or op2 == None:
print("%f / %f = %f" % (left, right, left / right))
return left / right
if op2 == '+':
print("%f / %f = %f" % (left, right, left / right))
return self.add(left / right)
elif op2 == '-':
print("%f / %f = %f" % (left, right, left / right))
return self.dec(left / right)
elif op2 == '*':
print("%f / %f = %f" % (left, right, left / right))
return self.mul(left / right)
elif op2 == '/':
print("%f / %f = %f" % (left, right, left / right))
return self.div(left /right)
_c = Calc()
print(_c("1"))
print(_c("(1)"))
print(_c("(+1+2)*-1+3/3"))