『Rubyを256倍使うための本 無道編』の 01.first/intp.y を移植

#!/usr/bin/env python

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_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"""
    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", "bar", "baz")
foo bar baz
print(1, 2, 3)
1 2 3
123
Syntax error at '123'
x = 1
print(x)
1