『Rubyを256倍使うための本 無道編』の 12.if_while/intp.y を移植
class Node: def exec_list(self, nodes): for x in nodes: x.evaluate() class RootNode(Node): def __init__(self, tree): self.tree = tree def evaluate(self): self.exec_list(self.tree) class FuncallNode(Node): def __init__(self, func, args): self.func = func self.args = args def evaluate(self): args = map(lambda x: x.evaluate(), self.args) if self.func in ["+", "-", "*", "/"]: cmd = "%s%s%s" % (args[0], self.func, args[1]) return eval(cmd) else: import string cmd_args = string.join([repr(x) for x in args], ",") cmd = self.func + "(" + cmd_args + ")" cmd_no_paren = self.func + " " + cmd_args try: return eval(cmd) except SyntaxError: exec(cmd_no_paren) class IfNode(Node): def __init__(self, condition, tstmt, fstmt): self.condition = condition self.tstmt = tstmt self.fstmt = fstmt def evaluate(self): if self.condition.evaluate(): self.exec_list(self.tstmt) else: self.exec_list(self.fstmt) class WhileNode(Node): def __init__(self, condition, body): self.condition = condition self.body = body def evaluate(self): while self.condition.evaluate(): self.exec_list(self.body) class AssignNode(Node): def __init__(self, vtable, vname, val): self.vtable = vtable self.vname = vname self.val = val def evaluate(self): self.vtable[self.vname] = self.val.evaluate() class VarRefNode(Node): def __init__(self, vtable, vname): self.vtable = vtable self.vname = vname def evaluate(self): if self.vtable.has_key(self.vname): return self.vtable[self.vname] else: try: return eval(self.vtable[vname]) except SyntaxError: print "unknown method or local variable %s" % self.vname class StringNode(Node): def __init__(self, val): self.val = val def evaluate(self): return self.val class LiteralNode(Node): def __init__(self, val): self.val = val def evaluate(self): return self.val
と
#!/usr/bin/env python import sys from math import * from m20090512 import * import ply.lex as lex tokens = ( 'NUMBER', 'STRING', 'IDENT', 'EOL', 'IF', 'THEN', 'ELSE', 'WHILE', 'DO', 'END', ) literals = "(),=+-*/" reserved = { 'if' : 'IF', 'then' : 'THEN', 'else' : 'ELSE', 'while' : 'WHILE', 'do' : 'DO', 'end' : 'END', } def t_NUMBER(t): r'\d+' try: t.value = int(t.value) except ValueError: print "Integer value too large", t.value t.value = 0 return t def t_STRING(t): r""""(?:[^"\\]+|\\.)*"|'(?:[^'\\]+|\\.)*'""" t.value = eval(t.value) return t def t_EOL(t): r'\n' return t def t_IDENT(t): r'[a-zA-Z_]\w*' t.type = reserved.get(t.value, 'IDENT') return t t_ignore = " \t" def t_error(t): print "Illegal character '%s'" % t.value[0] t.lexer.skip(1) lex.lex() import ply.yacc as yacc precedence = ( ('left', '+', '-'), ('left', '*', '/'), ('right', 'UMINUS'), ) def p_program_stmt(p): "program : stmt_list" p[0] = RootNode(p[1]) def p_stmt_list_empty(p): "stmt_list : " p[0] = [] def p_stmt_list_stmt(p): "stmt_list : stmt_list stmt EOL" global lineno lineno += 1 p[1].append(p[2]) p[0] = p[1] def p_stmt_list(p): "stmt_list : stmt_list EOL" global lineno lineno += 1 p[0] = p[1] def p_stmt(p): """stmt : expr | assign | if_stmt | while_stmt""" p[0] = p[1] def p_stmt_IDENT(p): "stmt : IDENT realprim" p[0] = FuncallNode(p[1], [p[2]]) def p_if_stmt(p): "if_stmt : IF stmt THEN EOL stmt_list else_stmt END" p[0] = IfNode(p[2], p[5], p[6]) def p_else_stmt(p): "else_stmt : ELSE EOL stmt_list" p[0] = p[3] def p_else_stmt_empty(p): "else_stmt : " p[0] = [] def p_while_stmt(p): "while_stmt : WHILE stmt DO EOL stmt_list END" p[0] = WhileNode(p[2], p[5]) def p_assign(p): "assign : IDENT '=' expr" global vtable p[0] = AssignNode(vtable, p[1], p[3]) def p_expr_plus(p): "expr : expr '+' expr" p[0] = FuncallNode('+', [p[1], p[3]]) def p_expr_minus(p): "expr : expr '-' expr" p[0] = FuncallNode('-', [p[1], p[3]]) def p_expr_mul(p): "expr : expr '*' expr" p[0] = FuncallNode('*', [p[1], p[3]]) def p_expr_div(p): "expr : expr '/' expr" p[0] = FuncallNode('/', [p[1], p[3]]) def p_expr_primary(p): "expr : primary" p[0] = p[1] def p_primary(p): "primary : realprim" p[0] = p[1] def p_primary_paren(p): "primary : '(' expr ')'" p[0] = p[2] def p_primary_uminus(p): "primary : '-' primary %prec UMINUS" p[0] = FuncallNode('-', [LiteralNode(0), p[2]]) def p_realprim_ident(p): "realprim : IDENT" global vtable p[0] = VarRefNode(vtable, p[1]) def p_realprim_number(p): "realprim : NUMBER" p[0] = LiteralNode(p[1]) def p_realprim_string(p): "realprim : STRING" p[0] = StringNode(p[1]) def p_realprim_funcall(p): "realprim : funcall" p[0] = p[1] def p_funcall_args(p): "funcall : IDENT '(' args ')'" p[0] = FuncallNode(p[1], p[3]) def p_funcall_no_args(p): "funcall : IDENT '(' ')'" p[0] = FuncallNode(p[1], []) def p_args1(p): "args : expr" p[0] = [p[1]] def p_args2(p): "args : args ',' expr" p[1].append(p[3]) p[0] = p[1] def p_error(p): global lineno try: print "%s:%d Syntax error at '%s'" % ("-", lineno, p.value) except AttributeError: print "%s:%d Syntax error" % ("-", lineno) yacc.yacc() vtable = {} lineno = 1 tree = yacc.parse(sys.stdin.read()) #print tree.tree tree.evaluate()
で、
message = "funcall ok" print(message) print "\n" print message print "\n" print( "operator", " ok", "\n" ) print( 1+1, " ", 1+2*3, " ", 10/3, "\n" ) if 1 then print "if ok\n" else print "if not ok\n" end i = 1 while i do print "while ok\n" i = 0 end
を入力すると、
funcall ok funcall ok operator ok 2 7 3 if ok while ok