# AST classes class Expr: def eval(self): raise NotImplementedError class Number(Expr): def __init__(self,n): self.n = n def eval(self): return self.n class BinaryExpr(Expr): def __init__(self,l,r): self.l = l self.r = r # operators: the docstrings contain the # symbol associated with each operator class Op_Add(BinaryExpr): '+' class Op_Sub(BinaryExpr): '-' # entry-point def main(argv): e = parse(argv[1:]) print e.eval() return 0 # parse a list of string into an AST def parse(lst): stack = [] for token in lst: try: node = Number(int(token)) except ValueError: # find opcode class op = OPCODES.get(token, None) y, x = stack.pop(), stack.pop() # instantiate the class node = op(x, y) stack.append(node) return stack[0] # INIT-TIME only: build the table of # opcodes by inspecting all the declared # classes and their docstrings and add # eval methods to Op_* classes # generate the appropriate eval method def gen_eval(ch): code = """ def eval(self): return self.l.eval() %s self.r.eval() """ d = {} exec code.strip() % (ch) in d return d['eval'] OPCODES = {} def build_opcodes(): for name, value in globals().items(): if name.startswith('Op_'): value.eval = \ gen_eval(value.__doc__) OPCODES[value.__doc__] = value build_opcodes()