It is not too hard to use pyparsing to cobble together a simple expression evaluator.
Suppose you want to eval expression, including parens, of the type of expressions of the following:
2+3
4.0^2+5*(2+3+4)
1.23+4.56-7.890
(1+2+3+4)/5
1e6^2/1e7
This simplification of the SimpleCalc example:
import pyparsing as pp
import re
ex='''\
2+3
4.0^2+5*(2+3+4)
1.23+4.56-7.890
(1+2+3+4)/5
1e6^2/1e7'''
e = pp.CaselessLiteral('E')
dec, plus, minus, mult, div, expop=map(pp.Literal,'.+-*/^')
addop = plus | minus
multop = mult | div
lpar, rpar=map(pp.Suppress,'()')
p_m = plus | minus
num = pp.Word(pp.nums)
integer = pp.Combine( pp.Optional(p_m) + num )
floatnumber = pp.Combine( integer +
pp.Optional( dec + pp.Optional(num) ) +
pp.Optional( e + integer ) )
stack=[]
def pushFirst(s, l, t):
stack.append( t[0] )
expr=pp.Forward()
atom = ((floatnumber | integer).setParseAction(pushFirst) |
( lpar + expr.suppress() + rpar )
)
factor = pp.Forward()
factor << atom + pp.ZeroOrMore( ( expop + factor ).setParseAction( pushFirst ) )
term = factor + pp.ZeroOrMore( ( multop + factor ).setParseAction( pushFirst ) )
expr << term + pp.ZeroOrMore( ( addop + term ).setParseAction( pushFirst ) )
pattern=expr+pp.StringEnd()
opn = { "+" : ( lambda a,b: a + b ),
"-" : ( lambda a,b: a - b ),
"*" : ( lambda a,b: a * b ),
"/" : ( lambda a,b: a / b ),
"^" : ( lambda a,b: a ** b ) }
def evaluateStack(stk):
op = stk.pop()
if op in "+-*/^":
op2 = evaluateStack(stk)
op1 = evaluateStack(stk)
return opn[op](op1, op2)
elif re.search('^[-+]?[0-9]+$',op):
return int(op)
else:
return float(op)
for line in ex.splitlines():
parse=pattern.parseString(line)
s=stack[:]
print('"{}"->{} = {}'.format(line,s,evaluateStack(stack)))
Prints:
"2+3"->['2', '3', '+'] = 5
"4.0^2+5*(2+3+4)"->['4.0', '2', '^', '5', '2', '3', '+', '4', '+', '*', '+'] = 61.0
"1.23+4.56-7.890"->['1.23', '4.56', '+', '7.890', '-'] = -2.1000000000000005
"(1+2+3+4)/5"->['1', '2', '+', '3', '+', '4', '+', '5', '/'] = 2.0
"1e6^2/1e7"->['1E6', '2', '^', '1E7', '/'] = 100000.0