Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@bradbeattie
Last active October 25, 2016 14:33
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save bradbeattie/2ab33e377f907a20fb6f to your computer and use it in GitHub Desktop.
Save bradbeattie/2ab33e377f907a20fb6f to your computer and use it in GitHub Desktop.
import re
# Supported tokens and their operations
ORDER_OF_OPERATIONS = ["MULTIPLY", "DIVIDE", "ADD", "SUBTRACT"]
scanner = re.Scanner([
(r"([0-9]+)", lambda x, y: int(y)),
(r"\+", lambda x, y: "ADD"),
(r"-", lambda x, y: "SUBTRACT"),
(r"\*", lambda x, y: "MULTIPLY"),
(r"/", lambda x, y: "DIVIDE"),
(r"\s+", lambda x, y: None),
], flags=re.DOTALL)
def operation_multiply(a, b):
return a * b
def operation_divide(a, b):
return a / b
def operation_add(a, b):
return a + b
def operation_subtract(a, b):
return a - b
def interpret(results):
assert isinstance(results[0], int) and isinstance(results[-1], int), "Trailing operators were encoutered!"
if len(results) == 1:
return results[0]
for operation in reversed(ORDER_OF_OPERATIONS):
try:
boundary = results.index(operation)
return globals()["operation_%s" % operation.lower()](
interpret(results[:boundary]),
interpret(results[boundary+1:]),
)
except ValueError:
pass
assert False, "Missing an operator"
def evaluate(expression):
results, remainder = scanner.scan(expression)
assert not remainder, "Some of the input couldn't be interpreted"
return interpret(results)
assert evaluate("14 + 2 * 3 - 6 / 2") == 17
assert evaluate("(1 + 2) * 3") == 9
assert evaluate("__import__('os').remove('foobar.file')")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment