ASMで四則演算

なんというか、とつぜんですが、asm使って四則演算してみました。
そのうち解説を書きますが、とりあえず、ソースだけ。


javac -cp .;asm-3.1.jar A.java
java -cp .;asm-3.1.jar A 1+2*3

なかんじで試せます。

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
//import org.objectweb.asm.Type;
//import org.objectweb.asm.Label;

class A extends ClassLoader implements Opcodes {
	public A(ClassLoader parent) {
		super(parent);
	}
	public A() {
		super();
	}

	int index;
	String str;
	char c;
	void getc() {
		if (index >= str.length()) c = 0;
		else c = str.charAt(index++);
	}

	final int INT = 256;
	int token;
	int val;
	void advance() {
		while (c == ' ' || c == '\r' || c == '\t' || c == '\n') {
			getc(); 
		}
		if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')') {
			token = c;
			getc();
			return;
		}
		if (c >= '0' && c <= '9') {
			int v = 0;
			while(c >= '0' && c <= '9') {
				v = v * 10 + (c - '0');
				getc();
			}
			token = INT;
			val = v;
			return;
		}
	}

	int max(int m, int m2) {
		return m > m2 ? m : m2;
	}
	int stackm;
	int stackmax;

	void push(int n) {
		stackm += n;
		stackmax = max(stackmax, stackm);
	}
	void pop(int n) {
		stackm -= n;
	}

	void exp() throws Exception {
		term();
		while(token=='+'||token=='-') {
			int t = token;
			advance();
			term();
			pop(1);
			switch(t) {
			case '+': mw.visitInsn(IADD); break;
			case '-': mw.visitInsn(ISUB); break;
			}
		}
	}
	
	void term() throws Exception  {
		fact();
		while(token=='*'||token=='/') {
			int t = token;
			advance();
			fact();
			pop(1);
			switch(t) {
			case '*': mw.visitInsn(IMUL); break;
			case '/': mw.visitInsn(IDIV); break;
			}
		}
	}

	void fact() throws Exception {
		if (token == INT) {
			mw.visitLdcInsn(new Integer(val));
			push(1);
			advance();
		}
		if (token == '(') {
			advance();
			exp();
			if (token != ')') throw new Exception("error");
			advance();
		}
	}

	ClassWriter cw;
	MethodVisitor mw;
	byte[] compile(String str)  throws Exception {
		this.str = str;
		index = 0;
		stackm = stackmax = 0;
		getc();
		advance();

		cw = new ClassWriter(0);
		cw.visit(V1_1, ACC_PUBLIC, "a", null, "java/lang/Object", null);
		mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
		mw.visitVarInsn(ALOAD, 0);
		mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
		mw.visitInsn(RETURN);
		mw.visitMaxs(1, 1);
		mw.visitEnd();

		mw = cw.visitMethod(ACC_PUBLIC, "n", "()I", null, null);

		exp();
		mw.visitInsn(IRETURN);
		mw.visitMaxs(stackmax, 1);
		mw.visitEnd();
		return cw.toByteArray();
	}

	public static void main(String[] argv) throws Exception {
		A a = new A();
		byte[] code = a.compile(argv[0]);
		Class ac = a.defineClass("a", code, 0, code.length);
		Object object = ac.newInstance();
		System.out.println(ac.getMethod("n").invoke(object, (Object[])null));
	}
}