『Rubyを256倍使うための本 無道編』の 07.parenomit/intp.y を移植
#!/usr/bin/env python from math import * import string import ply.lex as lex tokens = ( 'NUMBER', 'STRING', 'IDENT', # 'EOL', ) literals = "(),=" 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 t_IDENT = r'[a-zA-Z_]\w*' 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 def p_program(p): """program : | program stmt""" def p_stmt(p): """stmt : funcall | assign""" def p_stmt_IDENT(p): "stmt : IDENT args" p[0] = do_funcall(p[1], p[2]) def p_funcall_args(p): "funcall : IDENT '(' args ')'" p[0] = do_funcall(p[1], p[3]) def p_funcall_no_args(p): "funcall : IDENT '(' ')'" p[0] = do_funcall(p[1], []) def p_args1(p): "args : primary" p[0] = [p[1]] def p_args2(p): "args : args ',' primary" p[1].append(p[3]) p[0] = p[1] def p_assign(p): "assign : IDENT '=' primary" p[0] = do_assign(p[1], p[3]) def p_primary_ident(p): "primary : IDENT" p[0] = do_varref(p[1]) def p_primary_others(p): """primary : NUMBER | STRING | funcall""" p[0] = p[1] def p_error(p): try: print "Syntax error at '%s'" % p.value except AttributeError: print "Syntax error" yacc.yacc() vtable = {} def do_funcall(func, args): cmd_args = string.join([repr(x) for x in args], ",") cmd = func + "(" + cmd_args + ")" cmd_no_paren = func + " " + cmd_args try: return eval(cmd) except SyntaxError: exec(cmd_no_paren) def do_assign(vname, val): global vtable vtable[vname] = val def do_varref(vname): global vtable if vtable.has_key(vname): return vtable[vname] else: print "un-initialized variable", vname while 1: try: s = raw_input() except EOFError: break if not s: continue yacc.parse(s)
で、
print("foo") foo print "foo" foo