Advertisement
morgoth1145

Expression Parser

Jun 23rd, 2012
81
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 25.17 KB | None | 0 0
  1. # NOTE FOR TESTERS: Just run this and call the test_parser() function.
  2. # That should make testing for bugs in the expression parser a lot more
  3. # user friendly
  4.  
  5. # Fun fact:
  6. # 2**16 == phi(phi(phi(phi(phi(phi(phi(phi(phi(phi(phi(phi(phi(phi(21887929759))))))))))))))
  7.  
  8. # This is based heavily on the parsing structure explained here:
  9. # http://effbot.org/zone/simple-top-down-parsing.htm
  10. class ExpressionParser:
  11.     allowKeywordOverwrite = True
  12.  
  13.     class symbol_base:
  14.         id = None
  15.         value = None
  16.         first = second = third = None
  17.         pre = post = False
  18.  
  19.         def nud(self):
  20.             raise SyntaxError("Syntax error (%r)." % self.id)
  21.  
  22.         def led(self, left):
  23.             raise SyntaxError("Unknown operator (%r)." % self.id)
  24.  
  25.         def preeval(self):
  26.             if self.first is not None:
  27.                 self.first.preeval()
  28.             if self.second is not None:
  29.                 self.second.preeval()
  30.             if self.third is not None:
  31.                 self.third.preeval()
  32.  
  33.         def eval(self):
  34.             raise SyntaxError("Evaluation procedure unknown for (%r)." % self.id)
  35.  
  36.         def posteval(self):
  37.             if self.first is not None:
  38.                 self.first.posteval()
  39.             if self.second is not None:
  40.                 self.second.posteval()
  41.             if self.third is not None:
  42.                 self.third.posteval()
  43.  
  44.         def call(self, arglist):
  45.             raise SyntaxError("%r not callable" % self.id)
  46.  
  47.         def __repr__(self):
  48.             if self.id == "(name)" or self.id == "(literal)":
  49.                 return "(%s %s)" % (self.id[1:-1], self.value)
  50.             out = [self.id, self.first, self.second, self.third]
  51.             out = map(str, filter(None, out))
  52.             return "(" + " ".join(out) + ")"
  53.  
  54.     symbol_table = {}
  55.     variables = {}
  56.     functions = {}
  57.     keywords = set()
  58.  
  59.     def __init__(self):
  60.         import math
  61.         me = self
  62.  
  63.         def symbol(id, bp=0):
  64.             try:
  65.                 s = me.symbol_table[id]
  66.             except KeyError:
  67.                 me.keywords.add(id) # Add this symbol as a keyword
  68.                 class s(ExpressionParser.symbol_base):
  69.                     pass
  70.                 s.__name__ = "symbol-" + id # for debugging
  71.                 s.id = id
  72.                 s.value = None
  73.                 s.lbp = bp
  74.                 me.symbol_table[id] = s
  75.             else:
  76.                 s.lbp = max(bp, s.lbp)
  77.             return s
  78.  
  79.         # helpers
  80.  
  81.         def infix(id, bp):
  82.             def led(self, left):
  83.                 self.first = left
  84.                 self.second = me.to_parse_tree(bp)
  85.                 return self
  86.             s = symbol(id, bp)
  87.             s.led = led
  88.             return s
  89.  
  90.         def infix_r(id, bp):
  91.             def led(self, left):
  92.                 self.first = left
  93.                 self.second = me.to_parse_tree(bp-1)
  94.                 return self
  95.             s = symbol(id, bp)
  96.             s.led = led
  97.             return s
  98.  
  99.         def prefix(id, bp):
  100.             def nud(self):
  101.                 self.first = me.to_parse_tree(bp)
  102.                 self.pre = True
  103.                 return self
  104.             s = symbol(id)
  105.             s.nud = nud
  106.             return s
  107.  
  108.         def postfix(id, bp):
  109.             def led(self, left):
  110.                 self.first = left
  111.                 self.post = True
  112.                 return self
  113.             s = symbol(id, bp)
  114.             s.led = led
  115.             return s
  116.  
  117.         def constant(id, value):
  118.             if id not in self.variables:
  119.                 self.keywords.add(id) # This constant is now a keyword
  120.                 self.variables[id] = value
  121.  
  122.         def advance(id=None):
  123.             if id:
  124.                 if not me.token or me.token.id != id:
  125.                     raise SyntaxError("Expected %r" % id)
  126.             me.token = me.next()
  127.  
  128.         def method(s):
  129.             # decorator
  130.             assert issubclass(s, ExpressionParser.symbol_base)
  131.             def bind(fn):
  132.                 setattr(s, fn.__name__, fn)
  133.             return bind
  134.  
  135.         def function(id):
  136.             # Decorator
  137.             me.keywords.add(id) # Add this function name as a keyword
  138.             def bind(fn):
  139.                 me.functions[id] = fn
  140.             return bind
  141.  
  142.         # For compound operations of the form:
  143.         # a (compoundop) b => a (op1) a (op2) b
  144.         def compound_infix(id, ops, bp):
  145.             op1 = me.symbol_table[ops[0]]
  146.             op2 = me.symbol_table[ops[1]]
  147.             @method(symbol(id, bp))
  148.             def led(self, left):
  149.                 o1 = op1()
  150.                 o2 = op2()
  151.                 o2.led(left)
  152.                 o1.first = left; o1.second = o2
  153.                 return o1
  154.  
  155.         # Constants
  156.         constant("pi", math.pi)
  157.         constant("e", math.e)
  158.  
  159.         # Syntax
  160.  
  161.         # Assignment
  162.         infix("=", 10)
  163.         @method(symbol("="))
  164.         def eval(self):
  165.             # Evaluate assignment
  166.             if "(name)" == self.first.id:
  167.                 if me.test_var_mutable(self.first.value):
  168.                     val = self.second.eval()
  169.                     me.variables[self.first.value] = val
  170.                     return val
  171.                 else:
  172.                     raise SyntaxError("Cannot assign a value to keyword %r" % self.first.value)
  173.             else:
  174.                 raise SyntaxError("Cannot assign a value to %r" % self.first.id)
  175.  
  176.         # Deletion
  177.         @method(prefix("del", 140))
  178.         def eval(self):
  179.             if "(name)" == self.first.id:
  180.                 if me.test_var_mutable(self.first.value):
  181.                     val = self.first.eval()
  182.                     del me.variables[self.first.value]
  183.                     return val
  184.                 else:
  185.                     raise SyntaxError("Cannot delete %r" % self.first.value)
  186.             else:
  187.                 raise SyntaxError("Cannot delete %r" % self.first.id)
  188.         self.symbol_table["delete"] = self.symbol_table["del"]
  189.  
  190.         # Increment
  191.         prefix("++", 140); postfix("++", 130)
  192.         @method(symbol("++"))
  193.         def preeval(self):
  194.             if self.pre:
  195.                 # preincrement
  196.                 if "(name)" == self.first.id:
  197.                     if me.test_var_mutable(self.first.value):
  198.                         if self.first.value in me.variables:
  199.                             me.variables[self.first.value] += 1
  200.                         else:
  201.                             raise NameError("%r not defined" % self.first.value)
  202.                     else:
  203.                         raise SyntaxError("Cannot increment keyword %r" % self.first.value)
  204.                 else:
  205.                     raise SyntaxError("Cannot increment %r" % self.first.id)
  206.         @method(symbol("++"))
  207.         def eval(self):
  208.             # Just return the evaluation
  209.             return self.first.eval()
  210.         @method(symbol("++"))
  211.         def posteval(self):
  212.             if self.post:
  213.                 # postincrement
  214.                 if "(name)" == self.first.id:
  215.                     if me.test_var_mutable(self.first.value):
  216.                         if self.first.value in me.variables:
  217.                             me.variables[self.first.value] += 1
  218.                         else:
  219.                             raise NameError("%r not defined" % self.first.value)
  220.                     else:
  221.                         raise SyntaxError("Cannot increment keyword %r" % self.first.value)
  222.                 else:
  223.                     raise SyntaxError("Cannot increment %r" % self.first.id)
  224.  
  225.         # Decrement
  226.         prefix("--", 140); postfix("--", 130)
  227.         @method(symbol("--"))
  228.         def preeval(self):
  229.             if self.pre:
  230.                 # predecrement
  231.                 if "(name)" == self.first.id:
  232.                     if me.test_var_mutable(self.first.value):
  233.                         if self.first.value in me.variables:
  234.                             me.variables[self.first.value] -= 1
  235.                         else:
  236.                             raise NameError("%r not defined" % self.first.value)
  237.                     else:
  238.                         raise SyntaxError("Cannot decrement keyword %r" % self.first.value)
  239.                 else:
  240.                     raise SyntaxError("Cannot decrement %r" % self.first.id)
  241.         @method(symbol("--"))
  242.         def eval(self):
  243.             # Just return the evaluation
  244.             return self.first.eval()
  245.         @method(symbol("--"))
  246.         def posteval(self):
  247.             if self.post:
  248.                 # postdecrement
  249.                 if "(name)" == self.first.id:
  250.                     if me.test_var_mutable(self.first.value):
  251.                         if self.first.value in me.variables:
  252.                             me.variables[self.first.value] -= 1
  253.                         else:
  254.                             raise NameError("%r not defined" % self.first.value)
  255.                     else:
  256.                         raise SyntaxError("Cannot decrement keyword %r" % self.first.value)
  257.                 else:
  258.                     raise SyntaxError("Cannot decrement %r" % self.first.id)
  259.  
  260.         # Addition
  261.         infix("+", 110); prefix("+", 130)
  262.         @method(symbol("+"))
  263.         def eval(self):
  264.             # evaluate addition
  265.             if self.second is None: # Prefix
  266.                 return self.first.eval()
  267.             else: # Infix
  268.                 return self.first.eval() + self.second.eval()
  269.  
  270.         # Subtraction and negation
  271.         infix("-", 110); prefix("-", 130)
  272.         @method(symbol("-"))
  273.         def eval(self):
  274.             # evaluate subtraction
  275.             if self.second is None: # Prefix
  276.                 return -self.first.eval()
  277.             else: # Infix
  278.                 return self.first.eval() - self.second.eval()
  279.  
  280.         # Multiplication
  281.         @method(infix("*", 120))
  282.         def eval(self):
  283.             # evaluate multiplication
  284.             return self.first.eval() * self.second.eval()
  285.  
  286.         # Division
  287.         @method(infix("/", 120))
  288.         def eval(self):
  289.             # evaluate division
  290.             a = self.first.eval()
  291.             b = self.second.eval()
  292.             if isinstance(a, (int, long)) and isinstance(b, (int, long)) and 0 != a % b:
  293.                 return float(a) / float(b)
  294.             else:
  295.                 return a / b
  296.  
  297.         # Floor division
  298.         @method(infix("//", 120))
  299.         def eval(self):
  300.             # evaluate floor division
  301.             return int(self.first.eval() // self.second.eval())
  302.  
  303.         # In-place addition
  304.         compound_infix("+=", ("=", "+"), 10)
  305.  
  306.         # In-place subtraction
  307.         compound_infix("-=", ("=", "-"), 10)
  308.  
  309.         # In-place multiplication
  310.         compound_infix("*=", ("=", "*"), 10)
  311.  
  312.         # In-place division
  313.         compound_infix("/=", ("=", "/"), 10)
  314.  
  315.         # In-place floor division
  316.         compound_infix("//=", ("=", "//"), 10)
  317.  
  318.         # Exponentiation
  319.         @method(infix_r("**", 140))
  320.         def eval(self):
  321.             # evaluate exponentiation
  322.             return self.first.eval() ** self.second.eval()
  323.  
  324.         # Factorial
  325.         @method(postfix("!", 140))
  326.         def eval(self):
  327.             # evaluate factorial
  328.             val = self.first.eval()
  329.             if isinstance(val, (int, long)) and val >= 0:
  330.                 return math.factorial(val)
  331.             else:
  332.                 raise SyntaxError("Factorial is only defined for nonnegative integer values")
  333.  
  334.         # Parentheses
  335.         @method(symbol("("))
  336.         def nud(self):
  337.             expr = me.to_parse_tree()
  338.             advance(")")
  339.             return expr
  340.         @method(symbol("(", 150)) # lbp so that the parenthesis grabs the expression
  341.         def led(self, left):
  342.             self.first = left
  343.             self.second = []
  344.             if me.token.id != ")":
  345.                 while 1:
  346.                     self.second.append(me.to_parse_tree())
  347.                     if me.token.id != ",":
  348.                         break
  349.                     advance(",")
  350.             advance(")")
  351.             return self
  352.         @method(symbol("("))
  353.         def eval(self):
  354.             return self.first.call(self.second)
  355.  
  356.         symbol(")"); symbol(",")
  357.  
  358.         # Absolute value function
  359.         @function("abs")
  360.         def call(arglist):
  361.             if 1 == len(arglist):
  362.                 return abs(arglist[0].eval())
  363.             else:
  364.                 raise SyntaxError("The absolute value function requires 1 argument")
  365.  
  366.         # Square root function
  367.         @function("sqrt")
  368.         def call(arglist):
  369.             if 1 == len(arglist):
  370.                 return math.sqrt(arglist[0].eval())
  371.             else:
  372.                 raise SyntaxError("The square root function requires 1 argument")
  373.  
  374.         # Logarithm (base 10) function
  375.         @function("log")
  376.         def call(arglist):
  377.             if 1 == len(arglist):
  378.                 return math.log10(arglist[0].eval())
  379.             else:
  380.                 raise SyntaxError("The logarithm function requires 1 argument")
  381.  
  382.         # Natural Logarithm function
  383.         @function("ln")
  384.         def call(arglist):
  385.             if 1 == len(arglist):
  386.                 return math.log(arglist[0].eval())
  387.             else:
  388.                 raise SyntaxError("The natural logarithm function requires 1 argument")
  389.  
  390.         # Logarithm (base 2) function
  391.         @function("log2")
  392.         def call(arglist):
  393.             if 1 == len(arglist):
  394.                 return math.log(arglist[0].eval(), 2)
  395.             else:
  396.                 raise SyntaxError("The logarithm (base 2) function requires 1 argument")
  397.  
  398.         # Sine function
  399.         @function("sin")
  400.         def call(arglist):
  401.             if 1 == len(arglist):
  402.                 return math.sin(arglist[0].eval())
  403.             else:
  404.                 raise SyntaxError("The sine function requires 1 argument")
  405.  
  406.         # Cosine function
  407.         @function("cos")
  408.         def call(arglist):
  409.             if 1 == len(arglist):
  410.                 return math.cos(arglist[0].eval())
  411.             else:
  412.                 raise SyntaxError("The cosine function requires 1 argument")
  413.  
  414.         # Tangent function
  415.         @function("tan")
  416.         def call(arglist):
  417.             if 1 == len(arglist):
  418.                 return math.tan(arglist[0].eval())
  419.             else:
  420.                 raise SyntaxError("The tangent function requires 1 argument")
  421.  
  422.         # Arc sine function
  423.         @function("asin")
  424.         def call(arglist):
  425.             if 1 == len(arglist):
  426.                 return math.asin(arglist[0].eval())
  427.             else:
  428.                 raise SyntaxError("The arc sine function requires 1 argument")
  429.         self.functions["arcsin"] = self.functions["asin"]
  430.  
  431.         # Arc cosine function
  432.         @function("acos")
  433.         def call(arglist):
  434.             if 1 == len(arglist):
  435.                 return math.acos(arglist[0].eval())
  436.             else:
  437.                 raise SyntaxError("The arc cosine function requires 1 argument")
  438.         self.functions["arccos"] = self.functions["acos"]
  439.  
  440.         # Arc tangent function
  441.         @function("atan")
  442.         def call(arglist):
  443.             if 1 == len(arglist):
  444.                 return math.atan(arglist[0].eval())
  445.             elif 2 == len(arglist):
  446.                 return math.atan2(arglist[0].eval(), arglist[1].eval())
  447.             else:
  448.                 raise SyntaxError("The arc tangent function requires 1-2 arguments")
  449.         self.functions["arctan"] = self.functions["atan"]
  450.  
  451.         # Int function
  452.         @function("int")
  453.         def call(arglist):
  454.             if 1 == len(arglist):
  455.                 return int(arglist[0].eval())
  456.             else:
  457.                 raise SyntaxError("The int function requires 1 argument")
  458.  
  459.         # Floor function
  460.         self.functions["floor"] = self.functions["int"] # Int automatically floors
  461.  
  462.         # Ceil function
  463.         @function("ceil")
  464.         def call(arglist):
  465.             if 1 == len(arglist):
  466.                 return int(math.ceil(arglist[0].eval()))
  467.             else:
  468.                 raise SyntaxError("The ceil function requires 1 argument")
  469.  
  470.         # Round function
  471.         @function("round")
  472.         def call(arglist):
  473.             if 1 == len(arglist):
  474.                 return int(round(arglist[0].eval()))
  475.             else:
  476.                 raise SyntaxError("The round function requires 1 argument")
  477.  
  478.         # Permutation function
  479.         @function("nPr")
  480.         def call(arglist):
  481.             if 2 == len(arglist):
  482.                 n = arglist[0].eval()
  483.                 r = arglist[1].eval()
  484.                 if isinstance(n, (int, long)) and isinstance(r, (int, long)):
  485.                     if 0 <= r and r <= n:
  486.                         p = 1
  487.                         for t in xrange(n-r+1, n+1):
  488.                             p = p * t
  489.                         return p
  490.                     raise SyntaxError("0 <= r <= n required for the permutation function")
  491.                 else:
  492.                     raise SyntaxError("The permutation function requires integer arguments")
  493.             else:
  494.                 raise SyntaxError("The permutation function requires 2 arguments")
  495.  
  496.         # Combination function
  497.         @function("nCr")
  498.         def call(arglist):
  499.             if 2 == len(arglist):
  500.                 n = arglist[0].eval()
  501.                 r = arglist[1].eval()
  502.                 if isinstance(n, (int, long)) and isinstance(r, (int, long)):
  503.                     if 0 <= r and r <= n:
  504.                         c = 1
  505.                         for t in xrange(min(r, n-r)):
  506.                             c = c * (n - t) // (t + 1)
  507.                         return c
  508.                     raise SyntaxError("0 <= r <= n required for the combination function")
  509.                 else:
  510.                     raise SyntaxError("The combination function requires integer arguments")
  511.             else:
  512.                 raise SyntaxError("The combination function requires 2 arguments")
  513.  
  514.         # Coprime counting function (Euler's totient)
  515.         @function("phi")
  516.         def call(arglist):
  517.             if 1 == len(arglist):
  518.                 num = arglist[0].eval()
  519.                 if isinstance(num, (int, long)):
  520.                     # Factor the number and compute phi
  521.                     phi = num
  522.                     if 0 == num % 2:
  523.                         phi = phi / 2
  524.                         num /= 2
  525.                         while 0 == num % 2:
  526.                             num /= 2
  527.                     if 0 == num % 3:
  528.                         phi = phi / 3 * 2
  529.                         num /= 3
  530.                         while 0 == num % 3:
  531.                             num /= 3
  532.                     i = 0
  533.                     while i <= num ** 0.5:
  534.                         i += 6
  535.                         if 0 == num % (i - 1):
  536.                             phi = phi / (i - 1) * (i - 2)
  537.                             num /= (i - 1)
  538.                             while 0 == num % (i - 1):
  539.                                 num /= (i - 1)
  540.                         if 0 == num % (i + 1):
  541.                             phi = phi / (i + 1) * i
  542.                             num /= (i + 1)
  543.                             while 0 == num % (i + 1):
  544.                                 num /= (i + 1)
  545.                     if 1 != num:
  546.                         phi = phi / num * (num - 1)
  547.                     return phi
  548.                 else:
  549.                     raise SyntaxError("The coprime counting function requires an integer argument")
  550.             else:
  551.                 raise SyntaxError("The coprime counting function requires 1 argument")
  552.  
  553.         # Literals
  554.         symbol("(literal)").nud = lambda self: self
  555.         symbol("(literal)").eval = lambda self: self.value
  556.  
  557.         # Variables/named objects
  558.         symbol("(name)").nud = lambda self: self
  559.         @method(symbol("(name)"))
  560.         def eval(self):
  561.             val = me.variables.get(self.value, None)
  562.             if val is None:
  563.                 raise NameError("%r is not defined" % self.value)
  564.             else:
  565.                 return val
  566.         @method(symbol("(name)"))
  567.         def call(self, arglist):
  568.             funct = me.functions.get(self.value, None)
  569.             if funct is None:
  570.                 raise SyntaxError("%r not callable" % self.value)
  571.             else:
  572.                 return funct(arglist)
  573.  
  574.         # End symbol for evaluation termination
  575.         symbol("(end)")
  576.  
  577.     import re
  578.     def test_var_name(self, name):
  579.         return test_var_name.test.match(name)
  580.     test_var_name.test = re.compile("[a-zA-Z_]\w*$")
  581.  
  582.     def test_var_mutable(self, name):
  583.         if name in self.keywords:
  584.             if self.allowKeywordOverwrite:
  585.                 del self.keywords[name]
  586.             else:
  587.                 return False
  588.         return True
  589.  
  590.     def set_variable(self, id, value):
  591.         if self.test_var_name(id):
  592.             if self.test_var_mutable(id):
  593.                 self.variables[id] = value
  594.             else:
  595.                raise NameError("Cannot overwrite keyword %r" % id)
  596.         else:
  597.             raise NameError("Variable name must begin with [a-zA-Z_] and contain only [a-zA-Z0-9_]")
  598.  
  599.     def del_variable(self, id):
  600.         if id in self.variables:
  601.             if self.test_var_mutable(id):
  602.                 del self.variables[id]
  603.             else:
  604.                raise NameError("Cannot delete keyword %r" % id)
  605.         else:
  606.             raise NameError("%r not defined" % id)
  607.  
  608.     def tokenize(self, expression):
  609.         import re
  610.         splitter = re.compile("\s*(?:([0-9\.]+)|(\w+)|([^\s\w]+))")
  611.         for number, symbol, other in splitter.findall(expression):
  612.             if number:
  613.                 s = self.symbol_table["(literal)"]()
  614.                 try:
  615.                     s.value = int(number)
  616.                 except ValueError:
  617.                     try:
  618.                         s.value = float(number)
  619.                     except ValueError:
  620.                         raise SyntaxError("Invalid number %r" % number)
  621.             elif symbol:
  622.                 s = self.symbol_table.get(symbol, None)
  623.                 if s is None:
  624.                     s = self.symbol_table["(name)"]()
  625.                     s.value = symbol
  626.                 else:
  627.                     s = s()
  628.             elif other:
  629.                 while 0 != len(other):
  630.                     bestmatch = ""
  631.                     match = ""
  632.                     for c in other:
  633.                         match += c
  634.                         if match in self.symbol_table:
  635.                             bestmatch = match
  636.                     if 0 == len(bestmatch):
  637.                         raise SyntaxError("Unknown operator %r" % other)
  638.                     else:
  639.                         other = other[len(bestmatch):]
  640.                         s = self.symbol_table[bestmatch]()
  641.                         if 0 != len(other):
  642.                             yield s
  643.             yield s
  644.         yield self.symbol_table["(end)"]()
  645.  
  646.     def to_parse_tree(self, rbp=0):
  647.         t = self.token
  648.         try:
  649.             self.token = self.next()
  650.         except StopIteration:
  651.             raise SyntaxError("Expression ends unexpectedly")
  652.         left = t.nud()
  653.         while rbp < self.token.lbp:
  654.             t = self.token
  655.             try:
  656.                 self.token = self.next()
  657.             except StopIteration:
  658.                 raise SyntaxError("Expression ends unexpectedly")
  659.             left = t.led(left)
  660.         return left
  661.  
  662.     def parse(self, expression):
  663.         self.next = self.tokenize(expression).next
  664.         self.token = self.next()
  665.         tree = self.to_parse_tree()
  666.         try:
  667.             self.next()
  668.         except StopIteration:
  669.             # This is a good thing
  670.             tree.preeval() # Do preevaluation
  671.             val = tree.eval()
  672.             tree.posteval() # Do postevaluation
  673.             return val
  674.         else:
  675.             raise SyntaxError("Expression did not end when expected")
  676.  
  677. def test_parser():
  678.     exp = ExpressionParser()
  679.     exp.allowKeywordOverwrite = False
  680.     print "Known operations:"
  681.     print "Constants: pi, e"
  682.     print "Operations: +, -, *, /, //, **, !, parenthesis, =, del, delete"
  683.     print "\t-- (pre and post), ++ (pre and post), +=, -=, *=, /=, //=,"
  684.     print "Functions: abs, sqrt, log (this is base 10), ln, log2, sin, cos,"
  685.     print "\ttan, asin, arcsin, acos, arccos, atan (can take 1 or 2 arguments),"
  686.     print "\tarctan (can take 1 or 2 arguments), int, floor, ceil, round,"
  687.     print "\tnPr (permutation function), nCr (combination function),"
  688.     print "\tphi (Euler's totient, coprime counting function)"
  689.     print "You can set a variable using 'var_name = (expression)'"
  690.     print "You can delete variables using 'del/delete var_name'"
  691.     print "Keywords are not allowed to be changed."
  692.     while True:
  693.         expression = raw_input("Enter an expression to parse or exit to quit: ")
  694.         if "exit" == expression:
  695.             break
  696.         else:
  697.             var = None
  698.             lst = expression.split()
  699.             if 0 == len(lst):
  700.                 continue
  701.             try:
  702.                 val = exp.parse(expression)
  703.             except Exception, err:
  704.                 print "There was an issue with evaluation:", err
  705.             else:
  706.                 print val
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement