Skip to content

Instantly share code, notes, and snippets.

@m00nlight
Last active August 29, 2015 14:15
Show Gist options
  • Save m00nlight/0c378d9a7246a02b4650 to your computer and use it in GitHub Desktop.
Save m00nlight/0c378d9a7246a02b4650 to your computer and use it in GitHub Desktop.
Python S-exp arithmetic evaluation
import operator
Symbol = str
def tokenize(exp):
return exp.replace('(', ' ( ').replace(')', ' ) ').split()
def parser(exp):
return read_from_tokens(tokenize(exp))
def read_from_tokens(tokens):
if len(tokens) == 0:
raise SyntaxError(' Unexpected EOF of exp ')
token = tokens.pop(0)
if token == '(':
L = []
while tokens[0] != ')':
L.append(read_from_tokens(tokens))
tokens.pop(0)
return L
elif token == ')':
raise SyntaxError(' Unbalanced bracket ')
else:
return atom(token)
def atom(token):
try: return int(token)
except ValueError:
try: return float(token)
except ValueError:
if token in {'+', '*', '/', '-'}:
return Symbol(token)
else:
raise SyntaxError(' Unsupport operator ')
def evaluate(parser_tree):
if isinstance(parser_tree, int) or isinstance(parser_tree, float):
return parser_tree
else:
tmp = map(evaluate, parser_tree[1:])
if parser_tree[0] == '+':
return reduce(operator.add, tmp, 0)
elif parser_tree[0] == '-':
return reduce(operator.sub, tmp, 0)
elif parser_tree[0] == '*':
return reduce(operator.mul, tmp, 1)
elif parser_tree[0] == '/':
ret = tmp[0]
return reduce(operator.div, tmp[1:], ret)
def run(exp):
parser_tree = parser(exp)
return evaluate(parser_tree)
def test():
assert run('(+ 3 4)') == 7
assert run('(+ 3 4 5)') == 12
assert run('(+ (* 3 4) 5)') == 17
assert run('(* 3 (+ 4 5))') == 27
assert run('(* 3 (/ 15 7) 4)') == 24
return 'test pass!'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment