Beispiel #1
0
 def __init__(self):
     self.classesDirectory = {}
     self.methodsDirectory = {}
     self.code = [] #list of quadruples
     self.ip = -1    #qudruple pointer
     self.callStack = CallStack() #stack of frames
     self.mainClass = None
     self.mainMethod = None
Beispiel #2
0
class RVM (object):

    mainMethodName = "Main@main"
    mainClassName = "Main"
    firstRegisterInFrames = 10000

    def __init__(self):
        self.classesDirectory = {}
        self.methodsDirectory = {}
        self.code = [] #list of quadruples
        self.ip = -1    #qudruple pointer
        self.callStack = CallStack() #stack of frames
        self.mainClass = None
        self.mainMethod = None

    def cpu(self):
        
        """
        the first main frame should return to the HALT instruction, which is the last
        quadruple
        """
        HALTinstIdx = len(self.code) - 1
        mainMethodFrame = Frame(self.mainMethod, HALTinstIdx)
        mainObject = ObjectSpace(self.mainClass)
        mainMethodFrame.registers[0] = mainObject
        self.callStack.push(mainMethodFrame)

        quadruple = self.code[self.ip]
        toBeInvokedFrame = None
        while (quadruple.opCode != "HALT" and self.ip < len(self.code)):
            registers = self.callStack.peek().registers  #shortcut to current stack registers
            self.ip = self.ip + 1 #almost all the instructions should increment the ip
                                #if not, the instruction should take care of it
                
            if(quadruple.opCode == "+"):
                op1 = int(quadruple.op1)
                op2 = int(quadruple.op2)
                op3 = int(quadruple.op3)
                registers[offset(op3)] = registers[offset(op1)] + registers[offset(op2)]
            elif(quadruple.opCode == "-"):
                op1 = int(quadruple.op1)
                op2 = int(quadruple.op2)
                op3 = int(quadruple.op3)
                registers[offset(op3)] = registers[offset(op1)] - registers[offset(op2)]
            elif(quadruple.opCode == "*"):
                op1 = int(quadruple.op1)
                op2 = int(quadruple.op2)
                op3 = int(quadruple.op3)
                registers[offset(op3)] = registers[offset(op1)] * registers[offset(op2)]
            elif(quadruple.opCode == "/"):
                op1 = int(quadruple.op1)
                op2 = int(quadruple.op2)
                op3 = int(quadruple.op3)
                registers[offset(op3)] = registers[offset(op1)] / registers[offset(op2)]
            elif(quadruple.opCode == "or"):
                op1 = int(quadruple.op1)
                op2 = int(quadruple.op2)
                op3 = int(quadruple.op3)
                registers[offset(op3)] = registers[offset(op1)] or registers[offset(op2)]
            elif(quadruple.opCode == "and"):
                op1 = int(quadruple.op1)
                op2 = int(quadruple.op2)
                op3 = int(quadruple.op3)
                registers[offset(op3)] = registers[offset(op1)] and registers[offset(op2)]
            elif(quadruple.opCode == "=="):
                op1 = int(quadruple.op1)
                op2 = int(quadruple.op2)
                op3 = int(quadruple.op3)
                registers[offset(op3)] = registers[offset(op1)] == registers[offset(op2)]
            elif(quadruple.opCode == "!="):
                op1 = int(quadruple.op1)
                op2 = int(quadruple.op2)
                op3 = int(quadruple.op3)
                registers[offset(op3)] = registers[offset(op1)] != registers[offset(op2)]
            elif(quadruple.opCode == ">="):
                op1 = int(quadruple.op1)
                op2 = int(quadruple.op2)
                op3 = int(quadruple.op3)
                registers[offset(op3)] = registers[offset(op1)] >= registers[offset(op2)]
            elif(quadruple.opCode == ">"):
                op1 = int(quadruple.op1)
                op2 = int(quadruple.op2)
                op3 = int(quadruple.op3)
                registers[offset(op3)] = registers[offset(op1)] > registers[offset(op2)]
            elif(quadruple.opCode == "<="):
                op1 = int(quadruple.op1)
                op2 = int(quadruple.op2)
                op3 = int(quadruple.op3)
                registers[offset(op3)] = registers[offset(op1)] <= registers[offset(op2)]
            elif(quadruple.opCode == "<"):
                op1 = int(quadruple.op1)
                op2 = int(quadruple.op2)
                op3 = int(quadruple.op3)
                registers[offset(op3)] = registers[offset(op1)] < registers[offset(op2)]
            elif(quadruple.opCode == "PRINT"):
                op1 = int(quadruple.op1)
                print(str(registers[offset(op1)]), end = "")
            elif(quadruple.opCode == "PRINTLINE"):
                print()
            elif(quadruple.opCode == "READINT"):
                op1 = int(quadruple.op1)
                read = input()
                try:
                    tmp = int(read)
                except ValueError:
                    exit("ERROR Inesperado: Se leyo una literal no valida en readint(): " + read)
                registers[offset(op1)] = tmp
            elif(quadruple.opCode == "READDOUBLE"):
                op1 = int(quadruple.op1)
                read = input()
                try:
                    tmp = float(read)
                except ValueError:
                    exit("ERROR Inesperado: Se leyo una literal no valida en readdouble(): " + read)
                registers[offset(op1)] = tmp
            elif(quadruple.opCode == "READCHAR"):
                op1 = int(quadruple.op1)
                read = input()
                if(len(read) > 1):
                    exit("ERROR Inesperado: Se leyo mas de un caracter en readchar(): " + read)
                registers[offset(op1)] = read
            elif(quadruple.opCode == "GOTOFALSE"):
                op1 = int(quadruple.op1)
                op2 = int(quadruple.op2)
                if(not registers[offset(op1)]):
                    self.ip = op2
            elif(quadruple.opCode == "GOTO"):
                op1 = int(quadruple.op1)
                self.ip = op1
            elif(quadruple.opCode == "CCONST"):
                op1 = quadruple.op1
                op2 = int(quadruple.op2)
                registers[offset(op2)] = chr(ord(op1))
            elif(quadruple.opCode == "DCONST"):
                op1 = float(quadruple.op1)
                op2 = int(quadruple.op2)
                registers[offset(op2)] = op1
            elif(quadruple.opCode == "ICONST"):
                op1 = int(quadruple.op1)
                op2 = int(quadruple.op2)
                registers[offset(op2)] = op1
            elif(quadruple.opCode == "="):
                op1 = int(quadruple.op1)
                op2 = int(quadruple.op2)
                registers[offset(op2)] = registers[offset(op1)]
            elif(quadruple.opCode == "ERA"):
                op1 = quadruple.op1
                methodToBeInvoked = self.methodsDirectory[op1]
                toBeInvokedFrame = Frame(methodToBeInvoked, -1) #the return address of the invokedFrame should be set in the GOSUB/GOSUBVOID.
                                                                #here we leave it pending with a -1
            elif(quadruple.opCode == "PARAM"):
                op1 = int(quadruple.op1)
                op2 = int(quadruple.op2)
                toBeInvokedFrame.registers[op2] = registers[offset(op1)]
            elif(quadruple.opCode == "GOSUB"):
                op1 = quadruple.op1
                op2 = int(quadruple.op2)
                invokedMethodSymbol = self.methodsDirectory[op1]
                callerFrame = self.callStack.peek()
                callerFrame.tempReturned = op2  #register that will be used to store the value that invokedFrame will return. No offseted yet
                toBeInvokedFrame.returnAddress = self.ip
                self.callStack.push(toBeInvokedFrame)
                self.ip = invokedMethodSymbol.firstQuadrupleIdx
            elif(quadruple.opCode == "GOSUBVOID"):
                op1 = quadruple.op1
                invokedMethodSymbol = self.methodsDirectory[op1]
                callerFrame = self.callStack.peek()
                toBeInvokedFrame.returnAddress = self.ip
                self.callStack.push(toBeInvokedFrame)
                self.ip = invokedMethodSymbol.firstQuadrupleIdx
            elif(quadruple.opCode == "RETURN"):
                op1 = int(quadruple.op1)
                returnValue = registers[offset(op1)]
                popedFrame = self.callStack.pop()
                callerFrame = self.callStack.peek()
                callerFrame.registers[offset(callerFrame.tempReturned)] = returnValue
                self.ip = popedFrame.returnAddress
            elif(quadruple.opCode == "RETURNVOID"):
                popedFrame = self.callStack.pop()
                self.ip = popedFrame.returnAddress
            elif(quadruple.opCode == "SHOULD_RETURN_SOMETHING_ERROR"):
                op1 = quadruple.op1
                exit("ERROR Inesperado: Metodo " + op1 + " no regreso nada...")
            elif(quadruple.opCode == "OBJECT"):
                op1 = int(quadruple.op1)
                op2 = quadruple.op2.strip()
                clase = self.classesDirectory[op2]
                obj = ObjectSpace(clase)
                registers[offset(op1)] = obj
            elif(quadruple.opCode == "PUTFIELD"):
                op1 = int(quadruple.op1)
                op2 = int(quadruple.op2)
                op3 = int(quadruple.op3)
                registers[offset(op2)].fields[op3] = registers[offset(op1)]
            elif(quadruple.opCode == "GETFIELD"):
                op1 = int(quadruple.op1)
                op2 = int(quadruple.op2)
                op3 = int(quadruple.op3)
                registers[offset(op1)] = registers[offset(op2)].fields[op3]
            elif(quadruple.opCode == "VERIFYARRAYACCESS"):
                op1 = int(quadruple.op1)
                op2 = int(quadruple.op2)
                if(registers[offset(op1)] < 0 or registers[offset(op1)] >= op2):
                    exit("ERROR Inesperado: Indice " + str(registers[offset(op1)]) + " fuera de rango en acceso a elemento de arreglo.")
            elif(quadruple.opCode == "GETARRAYELEM"):
                op1 = int(quadruple.op1)
                op2 = int(quadruple.op2)
                registers[offset(op2)] = registers[offset(registers[offset(op1)])]
            elif(quadruple.opCode == "PUTARRAYELEM"):
                op1 = int(quadruple.op1)
                op2 = int(quadruple.op2)
                registers[offset(registers[offset(op1)])] = registers[offset(op2)]
            else:
                print("Cuadruplo no reconocido: " + quadruple.opCode)
            quadruple = self.code[self.ip]

    def loadQuadruplesFromFile(self, inFile):
        nQuadruples = int(inFile.readline())
        for iQuad in range(nQuadruples):
            line = inFile.readline()
            if(line.startswith("CCONST")):
                start = line.find("'") + 1
                end = line.rfind("'")
                quadruple = Quadruple("CCONST", line[start:end], line.split()[-1])

            else:
                quadElems = line.split()
                quadruple = Quadruple(quadElems[0])
                if(len(quadElems) >= 2):
                    quadruple.op1 = quadElems[1]
                if(len(quadElems) >= 3):
                    quadruple.op2 = quadElems[2]
                if(len(quadElems) >= 4):
                    quadruple.op3 = quadElems[3]
            self.code.append(quadruple)

        

    def loadDirectoriesFromFile(self, inFile):
       
        self.ip = int(inFile.readline())
        nClasses = int(inFile.readline())

        for iClass in range(nClasses):
            className = inFile.readline().rstrip()
            classSymbol = ClassSymbol(className)
            nInstanceVars = int(inFile.readline().rstrip())
            if(nInstanceVars > 0):
                typesList = inFile.readline().split()
                for type in typesList:
                    classSymbol.addInstanceVarType(type)
            self.classesDirectory[classSymbol.name] = classSymbol

            nMethods = int(inFile.readline().rstrip())
            for iMethod in range(nMethods):
                methodName = inFile.readline().rstrip()
                firstQuadrupleIdx = int(inFile.readline().rstrip())
                totalOfVars = int(inFile.readline().rstrip())
                numberOfLocalVars = int(inFile.readline().rstrip())
                methodSymbol = MethodSymbol(methodName, firstQuadrupleIdx, totalOfVars, numberOfLocalVars)
                if(numberOfLocalVars > 0):
                    registerOfTheFirstLocal = int(inFile.readline().rstrip())
                    methodSymbol.registerOfTheFirstLocal = registerOfTheFirstLocal

                for x in range(numberOfLocalVars):
                    type = inFile.readline().rstrip()
                    methodSymbol.addLocalVarType(type)

                self.methodsDirectory[methodSymbol.name] = methodSymbol
        self.mainClass = self.classesDirectory[RVM.mainClassName]
        self.mainMethod = self.methodsDirectory[RVM.mainMethodName]

    def printCode(self):
        for quadruple in self.code:
            print(quadruple)

    def printClassesDirectory(self):
        for key in self.classesDirectory:
            print(self.classesDirectory[key])

    def printMethodsDirectory(self):
        for key in self.methodsDirectory:
            print(self.methodsDirectory[key])

    def loadCodeFile(self):
        toOpen = "../../../../bin/Debug/" + sys.argv[1] #TODO quitar la primera parte de la ruta
        inFile = open (toOpen, "r")
        self.loadDirectoriesFromFile(inFile)
        self.loadQuadruplesFromFile(inFile)
        inFile.close()