import math class ParseError(Exception): pass vars = { 'e' : math.exp(1), 'pi' : math.pi } funcs = { 'sin': math.sin, 'cos': math.cos, 'exp': math.exp, 'log': math.log, 'sqrt': math.sqrt, 'floor': math.floor, 'abs': abs, 'sgn': lambda x: (x<0 and -1) or (x>0 and 1) or 0 } binops = { '^': ( 1, 'r', lambda a,b: a**b), '*': ( 2, 'l', lambda a,b: a*b), '/': ( 2, 'l', lambda a,b: a/b), '+': ( 3, 'l', lambda a,b: a+b), '-': ( 3, 'l', lambda a,b: a-b) } expr_level = 3 def calc_term(s): while s[0].isspace(): s.pop(0) if s[0].isdigit(): acc = 0.0 while s[0].isdigit(): acc = acc*10 + int(s.pop(0)) if s[0] == '.': den = 10.0 s.pop(0) while s[0].isdigit(): acc = acc + int(s.pop(0))/den den *= 10.0 if s[0].upper() == 'E': s.pop(0) if s[0] == '-': sign = -1 elif s[0] == '+': sign = +1 else: raise ParseError("Exponent sign is required") s.pop(0) if not s[0].isdigit(): raise ParseError("Exponent value required") exp = 0 while s[0].isdigit(): exp = exp*10 + int(s.pop(0)) acc *= 10 ** (sign*exp) return acc if s[0] == '-': s.pop(0) return - calc_term(s) if s[0] == '(': s.pop(0) v = calc_expr(s) while s[0].isspace(): s.pop(0) if s[0] != ')': raise ParseError("')' expected") s.pop(0) return v if s[0].isalpha(): t = "" while s[0].isalnum() or s[0]=='_': t += s.pop(0) while s[0].isspace(): s.pop(0) if t in funcs: if s[0] != '(': raise ParseError("'(' expected") x = calc_term(s) return funcs[t](x) elif s[0] == '=': s.pop(0) x = calc_expr(s) vars[t] = x return x if t in vars: return vars[t] raise ParseError("Undefined symbol %s" % repr(t)) raise ParseError("Syntax error: %s" % repr(s[0])) def calc_expr(s,level = expr_level): if level == 0: return calc_term(s) a = calc_expr(s,level-1) while True: while s[0].isspace(): s.pop(0) if s[0] in binops: (lv, gr, op) = binops[s[0]] if level != lv: break s.pop(0) if gr == 'r': a = op(a,calc_expr(s,level)) else: a = op(a,calc_expr(s,level-1)) else: break return a if __name__ == "__main__": def test(s): print repr(s),"==>", try: charlist = list(s) + ["#END#"] result = calc_expr(charlist) if charlist[0] != "#END#": raise ParseError("Extra charaters at end of expression: %s" % repr(charlist[0])) print result except ParseError,e: print "Error: %s"%e print " "*(len(s)-len(charlist)+2)+"^" test("2+2") test(" 2 + 2") test("(2+2)*3") test("2+2*3") test("pi") test("pi_2 = 2*pi") test("cos(pi/3)") test("cos+2") test("x=pi*11+2") test("cos(x)") test("cos(x - floor(x/pi_2)*pi_2)") test("eps = 1E-5") test("der = (cos(x+eps)-cos(x))/eps") test("sin(x)") test("x=1+1/(1+1/x)") test("x=1+1/(1+1/x)") test("x=1+1/(1+1/x)") test("x=1+1/(1+1/x)") test("x=1+1/(1+1/x)") test("x=1+1/(1+1/x)") test("x=1+1/(1+1/x)") test("x=1+1/(1+1/x)") test("x=1+1/(1+1/x)") test("x - (1+sqrt(y))/2") test("y = 2^(1+1)+1") test("x - (1+sqrt(y))/2") test("2^3^4") test("(2^3)^4")