Python interpreter

import re


#####################################################
# date:2012-11-13
# desc:Stack Class -- Utils
#####################################################
class AyStack:
    def __init__(self, rsize = 100):
        self.data = []
        self.rsize = rsize
        self.esp = -1

    def size(self):
        return len(self.data)

    def push(self, i):
        if self.isFull():
            raise 'AyStackOverFlow'
        else:
            self.data.append(i)
            self.esp = self.esp + 1

    def pop(self):
        if self.isEmpty():
            raise 'AyStackUnderFlow'
        else:
            r = self.data[-1]
            self.esp = self.esp - 1
            del self.data[-1]
            return r

    def top(self):
        return self.data[-1]

    def isEmpty(self):
        if self.esp == -1:
            return True
        else:
            return False

    def isFull(self):
        if self.esp == self.rsize - 1:
            return True
        else:
            return False

        
#####################################################
# date:2012-11-13
# desc:Method Stuff
#####################################################
AyMethodTable = {}

class AyMethod:
    def __init__(self):
        self.code = []
        self.arg_num = 0
        self.arg_name = []
        self.arg_type = []
        self.rtn_name = ''
        self.rtn_type = None
        self.methodname = ''
        self.max_locals = 0

    def setMaxLocals(self, max_locals):
        self.max_locals = max_locals

    def setArgNum(self, arg_num):
        self.arg_num = arg_num

    def getArgNum(self):
        return self.arg_num

    def setArgName(self, arg_name):
        self.arg_name = arg_name

    def setArgType(self, arg_type):
        self.arg_type = arg_type

    def setRtnType(self, rtn_type):
        self.rtn_type = rtn_type

    def setRtnName(self, rtn_name):
        self.rtn_name = rtn_name

    def setMethodName(self, name):
        self.methodname = name

    def addCode(self, instruction):
        self.code.append(instruction)

    def loadFromFile(self, filename):
        for line in open(filename):
            for e in line.rstrip().split(' '):
                self.addCode(e)


# corresponding with method's invocation
class AyStackFrame:
    def __init__(self, method):
        self.locals = []
        self.stack = AyStack()
        self.method = method
        self.eip = 0
        if isinstance(self.method, AyMethod):
            for i in range(self.method.max_locals):
                self.locals.append(0)

    def setPrevStackFrame(self, StackFrame):
        self.prevStackFrame = StackFrame

    def readcode(self):
        if self.eip >= len(self.method.code):
            raise 'AyCodeOverFlow'
        else:
            rtn = self.method.code[self.eip]
            self.eip += 1
            return rtn

# dummy StackFrame for entry point
dummyMethod = AyMethod()
dummyStackFrame = AyStackFrame(dummyMethod)
LastStackFrame = dummyStackFrame


#####################################################
# date:2012-11-14
# desc:Exception
#####################################################
class AyException(Exception):
    def __init__(self, msg):
        self.msg = msg

    def __str__(self):
        return repr(self.msg)


#####################################################
# date:2012-11-13
# desc:VM instruction set
#####################################################

# ----------------------------------------- iload idx
def Opcode_iload(StackFrame):
    validx = int(StackFrame.readcode())
    val = int(StackFrame.locals[validx])
    StackFrame.stack.push(val)

# ----------------------------------------- istore idx
def Opcode_istore(StackFrame):
    validx = int(StackFrame.readcode())
    val = int(StackFrame.stack.pop())
    StackFrame.locals[validx] = val

# ----------------------------------------- ipush val
def Opcode_ipush(StackFrame):
    const = int(StackFrame.readcode())
    StackFrame.stack.push(const)

# ----------------------------------------- iadd
def Opcode_iadd(StackFrame):
    val1 = int(StackFrame.stack.pop())
    val2 = int(StackFrame.stack.pop())
    StackFrame.stack.push(val1 + val2)

# ----------------------------------------- isub
def Opcode_isub(StackFrame):
    val1 = int(StackFrame.stack.pop())
    val2 = int(StackFrame.stack.pop())
    StackFrame.stack.push(val1 - val2)

# ----------------------------------------- imul
def Opcode_imul(StackFrame):
    val1 = int(StackFrame.stack.pop())
    val2 = int(StackFrame.stack.pop())
    StackFrame.stack.push(val1 * val2)

# ----------------------------------------- idiv
def Opcode_idiv(StackFrame):
    val1 = int(StackFrame.stack.pop())
    val2 = int(StackFrame.stack.pop())
    StackFrame.stack.push(val1 / val2)

# ----------------------------------------- if_cmpeq
def Opcode_if_icmpeq(StackFrame):
    val1 = int(StackFrame.stack.pop())
    val2 = int(StackFrame.stack.pop())
    offset = int(StackFrame.readcode())
    if val1 == val2:
        StackFrame.eip = offset

# ----------------------------------------- if_cmpne
def Opcode_if_icmpne(StackFrame):
    val1 = int(StackFrame.stack.pop())
    val2 = int(StackFrame.stack.pop())
    offset = int(StackFrame.readcode())
    if val1 != val2:
        StackFrame.eip = offset

# ----------------------------------------- if_cmplt
def Opcode_if_icmplt(StackFrame):
    val2 = int(StackFrame.stack.pop())
    val1 = int(StackFrame.stack.pop())
    offset = int(StackFrame.readcode())
    if val1 < val2:
        StackFrame.eip = offset

# ----------------------------------------- iconst
def Opcode_iconst(StackFrame):
    const = int(StackFrame.readcode())
    StackFrame.stack.push(const)

# ----------------------------------------- iinc
def Opcode_iinc(StackFrame):
    idx = int(StackFrame.readcode())
    const = int(StackFrame.readcode())
    StackFrame.locals[idx] += const

# ----------------------------------------- goto
def Opcode_goto(StackFrame):
    offset = int(StackFrame.readcode())
    StackFrame.eip = offset

# ----------------------------------------- invoke
def Opcode_invoke(StackFrame):
    global AyMethodTable
    methodName = str(StackFrame.readcode())
    method = AyMethodTable.get(methodName)

    if method == None:
        print('!!! fail to invoke %s !!!' % methodName)
        prevStackFrame = StackFrame
        while prevStackFrame != dummyStackFrame:
            print('-----------------------------')
            print_local(prevStackFrame)
            print_stack(prevStackFrame)
            print('-----------------------------')
            prevStackFrame = prevStackFrame.prevStackFrame
        raise AyException('Function definition not found !')

    if isinstance(method, AyMethod):
        calleeStackFrame = AyStackFrame(method)
        calleeStackFrame.setPrevStackFrame(StackFrame)
        #print('>>> invoke %s' % method.methodname)
        arg_num = method.arg_num
        for i in range(arg_num - 1, -1, -1):
            calleeStackFrame.locals[i] = StackFrame.stack.data[arg_num - 1 - i]

        Interpreter(calleeStackFrame)

        if method.rtn_type:
            StackFrame.stack.push(calleeStackFrame.stack.pop())


# ----------------------------------------- ireturn
# return from main loop in Interpreter

# ----------------------------------------- print
def Opcode_print(StackFrame):
    idx = int(StackFrame.readcode())
    print(StackFrame.locals[idx])

OpcodeTable = {
    "iload"     : Opcode_iload,
    "istore"    : Opcode_istore,
    "ipush"     : Opcode_ipush,
    "iadd"      : Opcode_iadd,
    "isub"      : Opcode_isub,
    "imul"      : Opcode_imul,
    "idiv"      : Opcode_idiv,
    "if_icmpeq" : Opcode_if_icmpeq,
    "if_icmpne" : Opcode_if_icmpne,
    "if_icmplt" : Opcode_if_icmplt,
    "iconst"    : Opcode_iconst,
    "iinc"      : Opcode_iinc,
    "goto"      : Opcode_goto,
    "invoke"    : Opcode_invoke,
    "print"     : Opcode_print
    }


#####################################################
# date:2012-11-13
# desc:Interpreter
#####################################################
def Interpreter(StackFrame):
    if isinstance(StackFrame.method, AyMethod):
        code = StackFrame.method.code
        while StackFrame.eip < len(code):
            inst = code[StackFrame.eip]
            #print(inst)
            if (inst == 'ireturn'):
                return
            StackFrame.eip += 1
            Opcode_func = OpcodeTable[inst]
            Opcode_func(StackFrame)


#####################################################
# date:2012-11-13
# desc:Debug stuff
#####################################################
def print_local(StackFrame):
    print('locals>>>>>>>>>>>>>>')
    for l in StackFrame.locals:
        print(str(l))
    print('locals<<<<<<<<<<<<<<')

def print_stack(StackFrame):
    print('stack>>>>>>>>>>>>>>')
    for s in StackFrame.stack.data:
        print(str(s))
    print('stack<<<<<<<<<<<<<<')    


#####################################################
# date:2012-11-13
# desc:test
#####################################################
if __name__ == '__main__':
    
    testMethod = AyMethod()
    testMethod.loadFromFile('bytecode.txt')
    testMethod.setMethodName('test_method')
    testMethod.setMaxLocals(1)

    calleeMethod = AyMethod()
    calleeMethod.loadFromFile('callee.txt')
    calleeMethod.setMethodName('callee_method')
    calleeMethod.setMaxLocals(1)

    AyMethodTable[calleeMethod.methodname] = calleeMethod

    testStackFrame = AyStackFrame(testMethod)
    testStackFrame.setPrevStackFrame(LastStackFrame)

    Interpreter(testStackFrame)
posted @ 2012-11-14 17:32  buaaspy  阅读(309)  评论(0编辑  收藏  举报