| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- # Copyright (c) 2016, 2020 by Rocky Bernstein
- """Simple expression evaluator in SPARK
- """
- from expr_parser import parse_expr
- from spark_parser import GenericASTTraversal # , DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
- import operator
- BINARY_OPERATORS = {
- "**": pow,
- "*": operator.mul,
- "/": operator.truediv,
- "//": operator.floordiv,
- "%": operator.mod,
- "+": operator.add,
- "-": operator.sub,
- "<<": operator.lshift,
- ">>": operator.rshift,
- "&": operator.and_,
- "^": operator.xor,
- "|": operator.or_,
- }
- BINOP_SET = frozenset(BINARY_OPERATORS.keys())
- class ExprFormatterError(Exception):
- def __init__(self, errmsg):
- self.errmsg = errmsg
- def __str__(self):
- return self.errmsg
- class ExprEvaluator(GenericASTTraversal, object):
- def __init__(self):
- GenericASTTraversal.__init__(self, ast=None)
- self.ERROR = None
- return
- def traverse(self, node):
- self.preorder(node)
- return node.value
- def n_NUMBER(self, node):
- if node.attr.find("j") >= 0:
- node.value = complex(node.attr)
- elif node.attr.find(".") > 0:
- node.value = float(node.attr)
- else:
- node.value = int(node.attr)
- self.prune()
- def n_BOOL(self, node):
- node.value = node.attr
- self.prune()
- def n_atom(self, node):
- """atom ::= NUMBER | '(' expr ')' """
- length = len(node)
- if length == 1:
- self.preorder(node[0])
- node.value = node[0].value
- self.prune()
- elif length == 3:
- self.preorder(node[1])
- node.value = node[1].value
- self.prune()
- else:
- assert False, "Expecting atom to have length 1 or 3"
- def n_expr(self, node):
- """
- expr ::= expr ADD_OP term | term
- term ::= term MULT_OP term | atom
- """
- if len(node) == 1:
- self.preorder(node[0])
- node.value = node[0].value
- self.prune()
- else:
- self.preorder(node[0])
- self.preorder(node[2])
- op = node[1].attr
- assert op in BINOP_SET, "Expecting operator to be in %s" % op
- node.value = BINARY_OPERATORS[node[1].attr](node[0].value, node[2].value)
- self.prune()
- assert False, "Expecting atom to have length 1 or 3"
- n_factor = n_term = n_expr
- def eval_expr(
- expr_str,
- show_tokens=False,
- show_parse_tree=False,
- showgrammar=False,
- compile_mode="exec",
- ):
- """
- evaluate simple expression
- """
- parser_debug = {
- "rules": False,
- "transition": False,
- "reduce": showgrammar,
- "errorstack": True,
- "context": True,
- }
- parsed = parse_expr(expr_str, show_tokens=show_tokens, parser_debug=parser_debug)
- if show_parse_tree:
- print(parsed)
- assert parsed == "expr", "Should have parsed grammar start"
- evaluator = ExprEvaluator()
- # What we've been waiting for: Generate source from AST!
- return evaluator.traverse(parsed)
- if __name__ == "__main__":
- def eval_test(eval_str):
- result = eval_expr(
- eval_str, show_tokens=False, show_parse_tree=True, showgrammar=False,
- )
- print("%s = %s" % (eval_str, result))
- return
- eval_test("1")
- eval_test("1.0")
- eval_test("1 + 2")
- eval_test("1 * 2 + 3")
- eval_test("1 + 2 * 3")
- eval_test("(1 + 2) * 3")
- eval_test("(10.5 + 2 * 5) // (2 << 1) / 5")
|