実験コード

Python2.6で実験


# -*- coding: utf8 -*-


class Stack(object):
class StackEmpty(Exception):pass
def __init__(self):
self.sp=0
self._stack=[]
def push(self,x):
self._stack.append(x)
self.sp+=1
#spは最後にpushされたアイテムのインデクス+1を指す
#同時に、それは格納されたアイテム数でもある
def pop(self):
self.sp-=1 #spは最後にpopされたアイテムのインデクスを指す
if self.sp<0:
raise self.StackEmpty
return self._stack.pop()
def __len__(self):
return len(self._stack)
def __getitem__(self,idx):
return self._stack[idx]
def __setitem__(self,idx,val):
self._stack[idx]=val
def setitem(self,idx,val):
self._stack[idx]=val
def __repr__(self):
return repr(self._stack)
def __str__(self):
return str(self._stack)
def pushzeros(self,n):
[self.push(0) for i in xrange(n+1)]

class RegisterFrame(object):
#スタック上の領域にレジスタ名でアクセスするための
#アクセッサクラス
#レジスタを最初からスタック上に持つ というアイディア
#良さそうだと思ったのだけれど、考えおちだったかも
#考えてみたら、Cなら構造体にポインタ渡してやるだけで十分だったのでは
reglist=["PC","SP","A","LOCALS","PARENT"]
reglist2=reglist[:]
reglist2.remove("PARENT")
def __init__(self,stack):
self._stack=stack
stack.pushzeros(len(self.reglist))
self.IDX0=stack.sp-1 #spは最後にpushされたアイテムのインデクス+1=個数を指す
self.LOCALS=dict()
def __setval__(self,idx,val):
self._stack[idx]=val
def __str__(self):

return " ".join(["%s:%s"%(r,str(self.__getattribute__(r))) for r in self.reglist2])

#
for ridx,reg in enumerate(RegisterFrame.reglist):
setattr(RegisterFrame,reg,
property(fget=lambda self,ridx=ridx:self._stack[self.IDX0-ridx],
fset=lambda self, val,ridx=ridx:self._stack.setitem(self.IDX0-ridx,val),
))

class Opcode(object):
pass

class op_Nop(Opcode):
@staticmethod
def opexec(vm):
pass
class op_RegAlloc(Opcode):
@staticmethod
def execute(vm):
parent=vm.reg
reg=RegisterFrame(vm.stack)
vm.reg=reg
reg.PARENT=parent

class op_RegFree(Opcode):
@staticmethod
def execute(vm):
if vm.reg.PARENT is None:
raise Exception("You cannot Free Root Register ")
stk=vm.stack
vm.reg=vm.reg.PARENT
vm.stack=stk[0:vm.reg.IDX0+1]

del stk



class StackMachine(object):
#スタックマシンにOpコードをどうやってふやす?
#Opコード ごとに クラスを別にしたほうがよさげ
opcodes=[op_Nop]
def __init__(self):
self.stack=Stack()
self.reg=RegisterFrame(self.stack)
self.reg.PARENT=None

if __name__=="__main__":
stack=Stack()
stack.push(1)
stack.push(2)
stack.push(3)
assert stack._stack==[1,2,3] and stack.sp==3
assert stack.pop()==3 and stack.sp==2 and stack._stack==[1,2]
reg=RegisterFrame(stack)
[stack.pop() for i in xrange(len(stack))]
assert len(stack)==0
try:
stack.pop()
assert "stack empty not raise"
except Stack.StackEmpty:
pass

vm=StackMachine()
print vm.stack
print vm.reg,"parent:",repr(vm.reg.PARENT),


print repr(vm.reg)
op_RegAlloc.execute(vm)
vm.reg.PC=100

print vm.stack

print vm.reg,"parent:",repr(vm.reg.PARENT),
print repr(vm.reg)
op_RegFree.execute(vm)
print vm.stack
print vm.reg,"parent:",repr(vm.reg.PARENT),
print repr(vm.reg)