『Rubyを256倍使うための本 無道編』の 09.errmsg/intp.y を移植
#!/usr/bin/env python from math import * import fileinput 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_stmt(p): """program : | program stmt EOL""" def p_program(p): "program : program EOL" 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): global lineno try: print "%s:%d Syntax error at '%s'" % (fileinput.filename(), fileinput.lineno(), p.value) except AttributeError: print "%s:%d Syntax error" % (fileinput.filename(), fileinput.lineno()) yacc.yacc() vtable = {} lineno = 1 def do_funcall(func, args): import string 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: return eval(vname) for line in fileinput.input(): yacc.parse(line)
で、
print((
を入力すると、
foo:1 Syntax error at '('