pythonによる小さな玩具VM

現実逃避したかったので、tinyvm.cなるプログラム(http://pastebin.com/f22e2c91)をpythonに移植した。


class Ins(object):
def __init__(self, op, *arg):
self.op, self.arg = op, arg
def __repr__(self):
return "%s(%s)" % (self.op.__name__,
','.join(map(str,
filter(lambda x: x is not None,
self.arg))))

class VM(object):
def __init__(self, code):
self.pc=0
self.condpc=0
self.register=[None]*4
self.code=code

DONE=0
NOINC=1

def OP_HALT(mv, *args):
return DONE
def OP_ADD(mv, reg, n):
vm.register[reg]+=n
def OP_LOAD(mv, reg, value):
vm.register[reg]=value
def OP_LOADW(mv, reg):
vm.pc+=1
assert isinstance(vm.code[vm.pc], int)
vm.register[reg]=vm.code[vm.pc]
def OP_CNDPC(mv, pcv):
vm.condpc=pcv
def OP_JMP(mv, pcv):
vm.pc=pcv
return NOINC
def OP_JMPEQ(mv, reg, value):
if vm.register[reg]==value:
vm.pc=vm.condpc
return NOINC
def OP_JMPEQW(mv, reg):
vm.pc+=1
assert isinstance(vm.code[vm.pc], int)
if vm.register[reg]==vm.code[vm.pc]:
vm.pc=vm.condpc
return NOINC
def OP_PRINT(mv, reg):
print vm.register[reg]

if __name__=='__main__':

REG_0=0

code=[
Ins(OP_CNDPC, 8), # 0 condpc=8. set JMPEQW's dest.
Ins(OP_LOADW, REG_0), # 1 reg[0]=0
0, # 2 this---^ value
Ins(OP_ADD, REG_0, 1), # 3 reg[0]+=1
Ins(OP_JMPEQW, REG_0), # 4 if reg[0]==ins[pc+1]: pc=condpc
10, # 5 this value ^^^^^^^^^
Ins(OP_PRINT, REG_0), # 6 print reg[0]
Ins(OP_JMP, 3), # 7 goto #3
Ins(OP_PRINT, REG_0), # 8 print reg[0]
Ins(OP_HALT), # 9 exit()
]

vm=VM(code)

while True:
ins=code[vm.pc]
#print ins
#print 'reg0=', vm.register[0]
hoge=ins.op(vm, *ins.arg)
if hoge==DONE:
break
elif hoge==NOINC:
pass
else:
vm.pc+=1