def gosubQuad(self, returnType, numQuad, funcName, returnAddress): """ Generate the GOSUB quad when calling a function Args: returnType (string): Data type the called functon returns numQuad (integer): The number of the quadrupĺe where the called function starts funcName (string): Name of the current function to know if the memory address needs to be global or local. returnAddress (integer): Memory address of the return value from the called function """ if (returnType == 'void'): returnDir = None else: returnDir = memoryObj.getMemoryAddress(returnType, 1, funcName, True) self.stkType.append(returnType) self.stkOperand.append(returnDir) # Store on memory the constant value gosubAddr = memoryObj.getMemoryAddressToConstant('int', numQuad) # Generate GOSUB Quad to execute a function and update the return data self.stkQuadruples.append(Quadruple('GOSUB', None, None, gosubAddr)) # Generate assignation quad to store the returned value in a termporal value if (returnAddress != None): self.stkQuadruples.append( Quadruple('=', returnAddress, None, returnDir))
def generateAssignmentSingleQuad(self): """ Generate the quadruple when using the operators ++ and -- Raises: Exception: If the variables are not Integers or Floats """ # Pop the last operands lftOperand = self.stkOperand.pop() lftOpndType = self.stkType.pop() # Pop the operator operator = self.stkOperator.pop() # Raise exception if it is a invalid operation if (lftOpndType not in ['int', 'float']): if (operator == '++'): actionName = 'increment' else: actionName = 'decrement' raise Exception("Cannot {} a {}".format(actionName, lftOpndType)) # Get memory address for the constant cteAddr = memoryObj.getMemoryAddressToConstant('int', 1) if (operator == '++'): # Push the quadruple self.stkQuadruples.append( Quadruple('+', lftOperand, cteAddr, lftOperand)) elif (operator == '--'): # Push the quadruple self.stkQuadruples.append( Quadruple('-', lftOperand, cteAddr, lftOperand))
def fillForQuad(self): """ Generate the last quads of the FOR and the GOTO if the condition still does not meet. Also fill the previous GOTOF quad. """ # Pop the memory address VControl = self.stkOperand.pop() IDMemory = self.stkOperand.pop() self.stkType.pop() self.stkType.pop() # Get memory address for the constant cteAddr = memoryObj.getMemoryAddressToConstant('int', 1) # Generate the update quad self.stkQuadruples.append(Quadruple('+', VControl, cteAddr, VControl)) self.stkQuadruples.append(Quadruple('=', VControl, None, IDMemory)) # Get jumps endFOR = self.stkJumps.pop() returnFOR = self.stkJumps.pop() # Generate the GOTO quad self.stkQuadruples.append(Quadruple('GOTO', None, None, returnFOR)) # Store the jump quad jumpAddr = memoryObj.getMemoryAddressToConstant( 'int', len(self.stkQuadruples)) # Fill the jump quad self.stkQuadruples[endFOR].result = jumpAddr
def argumentQuad(self, varType, argNum): """ Generate the quad per argument sent to a function. Also checks that the user do not send more thant the expécted amount. Args: varType (string): Data type of the expected argument argNum (integer): Number of the expected argument Raises: Exception: If there are more arguments than the called function needs """ # Pop the arg value argValue = self.stkOperand.pop() argType = self.stkType.pop() # Validate the data type if (varType != argType): raise Exception("The argument is {} but needs to be {}".format( argType, varType)) # Store the constant value argNumAddr = memoryObj.getMemoryAddressToConstant('int', argNum) # Push the quadruple self.stkQuadruples.append( Quadruple('PARAM', argValue, None, argNumAddr))
def performRETURN(self, quad): # Parche guadalupano asgn_quad = Quadruple( Operator.ASGN, self.func_table["global"].var_table[ self.ctx_stack[-1].ctx].address, quad.res) self.performASGN(asgn_quad) self.performENDPROC()
def performREAD(self, quad): # Reads std input and writes the value addr = quad.op1 val = input() # Check if address is a pointer that needs solving, before writing to mem if addr >= 4000: quad = Quadruple(Operator.ASGN, self.pointer_mem.getAddress(addr), val) self.performASGN(quad, True) return # Gets datatype and casts accordingly data_type = (addr % 1000) // 100 if data_type == 0: val = int(val) elif data_type == 1: val = float(val) # Writes memory if addr >= 2000: self.ctx_stack[-1].temp_mem.writeAddress(addr, val) elif addr >= 1000: self.ctx_stack[-1].local_mem.writeAddress(addr, val) else: self.global_mem.writeAddress(addr, val)
def performASGN(self, quad, flag=False): # If pointer, use op1 as value, otherwise it's an address if flag: value = quad.op1 else: value = self.resolveMem(quad.op1) # Solves data type and casts accordingly target_addr = quad.res data_type_val = (target_addr % 1000) // 100 if data_type_val == 0: value = int(value) elif data_type_val == 1: value = float(value) # Writes to memory if target_addr >= 4000: quad = Quadruple(Operator.ASGN, self.pointer_mem.getAddress(target_addr), quad.op1) self.performASGN(quad) elif target_addr >= 2000: self.ctx_stack[-1].temp_mem.writeAddress(target_addr, value) elif target_addr >= 1000: self.ctx_stack[-1].local_mem.writeAddress(target_addr, value) else: self.global_mem.writeAddress(target_addr, value)
def endFunctionQuad(self): """ Generate the ENDFUNC quad """ self.stkQuadruples.append(Quadruple('ENDFUNC', None, None, None)) # Reset local memory address memoryObj.resetLocalCounters()
def writeQuad(self): """ Generate the quadruple of the WRITE function """ # Get the value to print toWriteVal = self.stkOperand.pop() self.stkType.pop() # Push the quad self.stkQuadruples.append(Quadruple('WRITE', None, None, toWriteVal))
def updateMatrixAddress(self, arrayData): """ Function to make the VERIFY quads and the sum to get the pointer to the real indexed address from a matri Args: arrayData (Dictionary): A dict with the variable data """ # Get expresion as index indexCol = self.stkOperand.pop() self.stkType.pop() indexRow = self.stkOperand.pop() self.stkType.pop() # Add the dimension to constant context dim1Addr = memoryObj.getMemoryAddressToConstant( 'int', arrayData['dimensions'][0]) dim2Addr = memoryObj.getMemoryAddressToConstant( 'int', arrayData['dimensions'][1]) baseAddr = memoryObj.getMemoryAddressToConstant( 'int', arrayData['memoryAddress']) # Make the verify quad self.stkQuadruples.append(Quadruple('VERIFY', indexRow, dim1Addr, None)) self.stkQuadruples.append(Quadruple('VERIFY', indexCol, dim2Addr, None)) # Create memory address to store the sum of base address and index sumAddr = memoryObj.getMemoryAddress('int', 1, self.currentFunction, True) multAddr = memoryObj.getMemoryAddress('int', 1, self.currentFunction, True) # Make the sum to get the actual memory address self.stkQuadruples.append(Quadruple('*', indexRow, dim2Addr, multAddr)) self.stkQuadruples.append(Quadruple('+', multAddr, dim1Addr, sumAddr)) self.stkQuadruples.append(Quadruple('+', baseAddr, sumAddr, sumAddr)) # Append the pointer to the stack self.stkOperand.append('->' + str(sumAddr)) self.stkType.append(arrayData['dataType'])
def readQuad(self): """ Generate the quadruple of the READ function """ # Get were to store the data toReadDir = self.stkOperand.pop() self.stkType.pop() # Push the quad self.stkQuadruples.append(Quadruple('READ', None, None, toReadDir))
def eraQuad(self, callingFunc): """ Generate the ERA quad when calling a function Args: callingFunc (string): Name of the called function """ # Store the function name nameAddr = memoryObj.getMemoryAddressToConstant("str", callingFunc) self.stkQuadruples.append(Quadruple('ERA', None, None, nameAddr))
def generateVCVFComparisonQuad(self, funcName): """ Generate the quads where the VControl and VFinal are compared Args: funcName (string): Name of the current function to know if the memory address needs to be global or local. Raises: Exception: If the goal expression is not an integer """ # Checks that the goal expresion is a integer expType = self.stkType.pop() if (expType != 'int'): raise Exception("The final expression on a FOR must be an integer") # Pop the fianl expresion expOperand = self.stkOperand.pop() # Generate the memory address of the VFinal VFinal = memoryObj.getMemoryAddress('int', 1, self.currentFunction, True) # Generate memory for the temporal boolean tempBoolean = memoryObj.getMemoryAddress('int', 1, self.currentFunction, True) # Generate quads self.stkQuadruples.append(Quadruple('=', expOperand, None, VFinal)) self.stkQuadruples.append( Quadruple('<', self.stkOperand[-1], VFinal, tempBoolean)) # Push the jump quad self.stkJumps.append(len(self.stkQuadruples) - 1) # Generate the GOTOF quad self.stkQuadruples.append(Quadruple('GOTOF', tempBoolean, None, None)) # Push the jump quad self.stkJumps.append(len(self.stkQuadruples) - 1)
def updateArrayAddress(self, arrayData, varName): """ Make the needed quads to get the real indexed memory address from an array Args: arrayData (Dictionary): A dict with the data from a variable varName (string): String with the variable name Raises: Exception: If the variable is actually a matrix """ # Check if the var is actually a matrix if (arrayData['numDimensions'] == 2): raise Exception('Variable {} is a matrix'.format(varName)) # Get expresion as index index = self.stkOperand.pop() self.stkType.pop() # Add the dimension to constant context dimAddr = memoryObj.getMemoryAddressToConstant('int', arrayData['dimensions']) baseAddr = memoryObj.getMemoryAddressToConstant( 'int', arrayData['memoryAddress']) # Make the verify quad self.stkQuadruples.append(Quadruple('VERIFY', index, dimAddr, None)) # Create memory address to store the sum of base address and index sumAddr = memoryObj.getMemoryAddress('int', 1, self.currentFunction, True) # Make the sum to get the actual memory address self.stkQuadruples.append(Quadruple('+', index, baseAddr, sumAddr)) # Append the pointer to the stack self.stkOperand.append('->' + str(sumAddr)) self.stkType.append(arrayData['dataType'])
def generateAssignmentQuad(self): """ Function to generate the quadruplo of assignments Raises: Exception: If the operands types are different """ # Pop the last operands rgtOperand = self.stkOperand.pop() rgtOpndType = self.stkType.pop() lftOperand = self.stkOperand.pop() lftOpndType = self.stkType.pop() # Pop the operator operator = self.stkOperator.pop() # Raise exception if it is a invalid operation if (lftOpndType != rgtOpndType): if (not (lftOpndType == 'int' or rgtOpndType == 'float')): raise Exception("Cannot asign a {} to a {}".format( rgtOpndType, lftOpndType)) if (operator == '='): # Push the quadruple self.stkQuadruples.append( Quadruple(operator, rgtOperand, None, lftOperand)) elif (operator == '+='): # Push the quadruple self.stkQuadruples.append( Quadruple('+', lftOperand, rgtOperand, lftOperand)) elif (operator == '-='): # Push the quadruple self.stkQuadruples.append( Quadruple('-', lftOperand, rgtOperand, lftOperand))
def performPARAM(self, quad): # Writes a value for a parameter, given an argument from_address = quad.op1 # Out of bounds (deprecated, but won't touch) if from_address >= 5000: return # Get the type of the argument, param number and param data from_type = getDataType(from_address) param_num = int(quad.res[3:]) dest_addr, dest_type = self.func_table[ self.call_stack[-1].ctx].params[param_num] # Get value of parameter if from_address >= 4000: quad = Quadruple(Operator.PARAM, quad.res, self.pointer_mem.getAddress(from_address)) self.performPARAM(quad) return elif from_address >= 3000: val = self.cte_mem.getConstant(from_address) elif from_address >= 2000: val = self.ctx_stack[-1].temp_mem.getValue(from_address) elif from_address >= 1000: val = self.ctx_stack[-1].local_mem.getValue(from_address) else: val = self.global_mem.getValue(from_address) # Check if it is valid result_type = semantic_cube[dest_type][from_type][Operator.ASGN] if result_type != None: if result_type == Type.INT: val = int(val) elif result_type == Type.FLOAT: val = float(val) self.call_stack[-1].local_mem.writeAddress(dest_addr, val) else: print("[Error]: Argument type does not match parameter type") sys.exit()
def elseConditionQuad(self): """ Function to generate the GOTO quad when uing a else statement Also, filling the past GOTOF quad """ # Push the Goto quad self.stkQuadruples.append(Quadruple('GOTO', None, None, None)) # Pop the jump quad falseLine = self.stkJumps.pop() # Append the new jump self.stkJumps.append(len(self.stkQuadruples) - 1) # Store the jump quad gotoAddr = memoryObj.getMemoryAddressToConstant( 'int', len(self.stkQuadruples)) # Fill the GotoF self.stkQuadruples[falseLine].result = gotoAddr
def returnFunctionQuad(self, funcName, funcTable): """ Generate the RETURN Quad of the return statement. Making the needed validation. Args: funcName (string): Name of the function the return is inside returnType (string): Data type of the returned value varAddr(integer | None): Memory address where is store the returned value if the function is not void Raises: Exception: If the function is void and has a return Exception: If the returned data type is different than the expected """ varAddr = None actualType = self.stkType.pop() # Search the function data funcData = funcTable.searchFunction(self.currentFunction) # If the function is void and have a return raise error if (funcData['returnType'] == 'void'): raise Exception( 'Function "{}" is void and does not need a return'.format( funcName)) # If not, get the global memory address else: varAddr = funcTable.searchVariable( 'global', self.currentFunction)['memoryAddress'] # If the returned value is different from the function return type if (funcData['returnType'] != actualType): raise Exception( 'Error trying to return a {} when function "{}" returns a {}'. format(actualType, funcName, funcData['returnType'])) # Push the returned value self.stkQuadruples.append( Quadruple('RETURN', self.stkOperand.pop(), None, varAddr))
def generateConditionQuad(self): """ Generate the GOTOF quadruple when start a IF/Then statement Raises: Exception: If the expression inside the parenthesis is not a bool """ # Pop the last operands resultValue = self.stkOperand.pop() resultType = self.stkType.pop() # Check the result data type if (resultType != 'bool'): raise Exception( "Invalid operation, the condition need to result on a bool.") # Push the quadruple self.stkQuadruples.append(Quadruple('GOTOF', resultValue, None, None)) # Add the jump quad to come back later self.stkJumps.append(len(self.stkQuadruples) - 1)
def endWhileQuad(self): """ Generate the GOTO Quad when starting a While """ # Get the jump endLine = self.stkJumps.pop() # Get the return jump returnLine = self.stkJumps.pop() # Store on memory the constant value gotoAddr = memoryObj.getMemoryAddressToConstant('int', returnLine) # Push the return quad self.stkQuadruples.append(Quadruple('GOTO', None, None, gotoAddr)) # Store the jump quad gotoAddr = memoryObj.getMemoryAddressToConstant( 'int', len(self.stkQuadruples)) # Fill the end line self.stkQuadruples[endLine].result = gotoAddr
def generateVControlQuad(self, funcName): """ Generate the Quadruple where the VControl get the value Args: funcName (string): Name of the current function to know if the memory address needs to be global or local. """ # Pop the memory address of the ID expOperand = self.stkOperand[-1] # Generate the memory address of the VControl VControl = memoryObj.getMemoryAddress('int', 1, self.currentFunction, True) # Generate the quad self.stkQuadruples.append(Quadruple('=', expOperand, None, VControl)) # Push the VC memory address self.stkOperand.append(VControl) self.stkType.append('int')
def endQuad(self): """ Generate the END Quad """ self.stkQuadruples.append(Quadruple('END', None, None, None))
def generateOperatorQuadruple(self, funcName, groupOperators=None, flgArithmetic=True): """ Function to generate the operation quadruples Args: funcName (string): The name of the function (To generate the temporal memory space) groupOperators (list, optional): List with the arithmetic operators to look for flgArithmetic (bool, optional): If the quadruple is going to be a arithmetic operation or not Raises: Exception: If the operation is invalid """ # Flag to know if is time to push a quadruple insertQuad = False # If it is a arithmetic operator, make the validations... if (flgArithmetic): # Check that there are operands and if the # if the las operator is on the searched operators group if (self.stkOperator): if (self.stkOperator[-1] in groupOperators): insertQuad = True # Or just push the quad if it is a logical # or relational operator else: insertQuad = True if (insertQuad): # Pop the last operands rgtOperand = self.stkOperand.pop() rgtOpndType = self.stkType.pop() lftOperand = self.stkOperand.pop() lftOpndType = self.stkType.pop() # Pop the operator operator = self.stkOperator.pop() # Validate the operation resultType = semanticCube.verifyOperations(operator, lftOpndType, rgtOpndType) # Raise exception if it is a invalid operation if (resultType == "error"): raise Exception( "Invalid operation {} between {} and {}".format( operator, lftOpndType, rgtOpndType)) # Calculate the memory address resultAddress = memoryObj.getMemoryAddress(resultType, 1, self.currentFunction, True) # Push the result and it's type self.stkOperand.append(resultAddress) self.stkType.append(resultType) # Push the quadruple self.stkQuadruples.append( Quadruple(operator, lftOperand, rgtOperand, resultAddress))
def generateGOTOMain(self): """ Generate the quad to go to the main """ self.stkQuadruples.append(Quadruple('GOTO', None, None, None))