『Rubyを256倍使うための本 無道編』の 11.op_ok/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

precedence = (
    ('left',  '+', '-'),
    ('left',  '*', '/'),
    ('right', 'UMINUS'),
    )

def p_program_stmt(p):
    """program :
               | program stmt EOL
               | program EOL"""

def p_stmt(p):
    """stmt : expr
            | assign"""

def p_stmt_IDENT(p):
    "stmt : IDENT realprim"
    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 : expr"
    p[0] = [p[1]]

def p_args2(p):
    "args : args ',' expr"
    p[1].append(p[3])
    p[0] = p[1]

def p_assign(p):
    "assign : IDENT '=' expr"
    p[0] = do_assign(p[1], p[3])

def p_expr_plus(p):
    "expr : expr '+' expr"
    p[0] = p[1] + p[3]

def p_expr_minus(p):
    "expr : expr '-' expr"
    p[0] = p[1] - p[3]

def p_expr_mul(p):
    "expr : expr '*' expr"
    p[0] = p[1] * p[3]

def p_expr_div(p):
    "expr : expr '/' expr"
    p[0] = p[1] / p[3]

def p_expr_primary(p):
    "expr : primary"
    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] = -p[2]

def p_primary(p):
    "primary : realprim"
    p[0] = p[1]

def p_realprim_ident(p):
    "realprim : IDENT"
    p[0] = do_varref(p[1])

def p_realprim_others(p):
    """realprim : 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(1+2)
x = 1+2*3
print(x, " ", x/2)
print((1+-2)*3)

を入力すると、

3
7   3
-3

Commons Lang、Validate.isTrue()

import org.apache.commons.lang.Validate;

public class C2009051100 {
    public static void main(String[] args) {
        Validate.isTrue(true,  "foo", "Hoge");

        Validate.isTrue(false, "foo", "Hoge");
    }
}

で、

Exception in thread "main" java.lang.IllegalArgumentException: fooHoge
	at org.apache.commons.lang.Validate.isTrue(Validate.java:75)
	at C2009051100.main(C2009051100.java:8)