def binaryOperation(operation, reg1, reg2, outputReg, props): resultLines = [] standardComment = utils.formatComment('{} = {} {} {}'.format(outputReg, reg1, operation, reg2), props, 2) operationComment = utils.formatComment('{} {} {}'.format(reg1, '/' if operation == '%' else operation, reg2), props, 2) if reg1 == '0': reg1 = '$0' if reg2 == '0': reg2 = '$0' reg1 = utils.getRegister(reg1) reg2 = utils.getRegister(reg2) didChangeReg1 = False if (not operation in BIN_OPERATORS_IMM and utils.isIntOrChar(reg1)) or (utils.isIntOrChar(reg1) and utils.isIntOrChar(reg2)): tempReg = utils.getTempRegister(props['tempRegisters'], 0) resultLines.append(general.loadIntOrChar(reg1, tempReg, props)) reg1 = tempReg didChangeReg1 = True if not operation in BIN_OPERATORS_IMM and utils.isIntOrChar(reg2): tempReg = utils.getTempRegister(props['tempRegisters'], 1 if didChangeReg1 else 0) resultLines.append(general.loadIntOrChar(reg2, tempReg, props)) reg2 = tempReg # Using 2 registers if utils.isRegister(reg1) and utils.isRegister(reg2): if operation in BIN_RESULT_REGS: # Move from hi/lo resultLines.append('{} {}, {}{}'.format(BIN_OPERATORS[operation], reg1, reg2, operationComment)) resultLines.append(general.loadRegHiLo(BIN_RESULT_REGS[operation], outputReg, {**props, 'comment': standardComment})) else: resultLines.append('{} {}, {}, {}{}'.format(BIN_OPERATORS[operation], utils.getRegister(outputReg), reg1, reg2, standardComment)) else: # Immediate regNum, number = (reg1, utils.getIntOrChar(reg2)) if utils.isRegister(reg1) else (reg2, utils.getIntOrChar(reg1)) resultLines.append('{} {}, {}, {}{}'.format(BIN_OPERATORS_IMM[operation], utils.getRegister(outputReg), regNum, number, standardComment)) return { 'lines': resultLines, 'reg': outputReg }
def unaryOperation(operation, reg1, outputReg, props): resultLines = [] if utils.isIntOrChar(reg1): tempReg = utils.getTempRegister(props['tempRegisters'], 0) resultLines.append(general.loadIntOrChar(reg1, tempReg, props)) reg1 = tempReg comment = utils.formatComment('{} = {} {}'.format(outputReg, operation, reg1), props, 2) resultLines.append('{} {}, {}{}'.format(UN_OPERATORS[operation], utils.getRegister(outputReg), utils.getRegister(reg1), comment)) return { 'lines': resultLines, 'reg': outputReg }
def parseSingleRHS(expression, props, outputReg, inferredType='any', loadAsAddress=False): resultLines = [] resultAddr = None resultType = inferredType if loadAsAddress and (utils.isRegister(expression) or utils.isSysFunc(expression)): raise utils.CompileException('Can\'t get address of register') # System functions if utils.isSysFunc(expression): resultLines += functions.parseSysFunc(expression, props, True) resultType = definitions.updateType(resultType, 'number') if outputReg != '$v0': resultLines.append(general.loadRegister('$v0', outputReg, props)) # Array elif addresses.isArray(expression): parsedAddr = addresses.parseArray(expression, props, outputReg) outerInner = (parsedAddr['outer'], parsedAddr['inner']) resultLines += parsedAddr['lines'] if loadAsAddress: resultType = definitions.updateType('address', resultType) if parsedAddr['reg'] != outputReg: resultLines.append( general.loadAsAddress(parsedAddr['address'], outputReg, props, outerInner)) if parsedAddr['reg'] == None: resultAddr = parsedAddr['address'] else: loadType = definitions.updateType(resultType, parsedAddr['elemtype']) resultLines.append( general.loadFromAddress(parsedAddr['address'], loadType, outputReg, props, outerInner)) resultType = definitions.updateType(loadType, resultType) # Register elif utils.isRegister(expression): if general.isRegHiLo(expression): resultLines.append( general.loadRegHiLo(expression, outputReg, props)) elif utils.getRegister(expression) != utils.getRegister(outputReg): resultLines.append( general.loadRegister(expression, outputReg, props)) # Variable elif expression in props['variables']: varName, varType = props['variables'][expression]['name'], props[ 'variables'][expression]['type'] if definitions.getSupertype(varType) == 'address' or loadAsAddress: resultLines.append(general.loadAsAddress(varName, outputReg, props)) resultType = definitions.updateType(varType, resultType) resultAddr = varName else: resultLines.append( general.loadFromAddress(varName, varType, outputReg, props)) resultType = definitions.updateType(varType, resultType) # Integer or char literal elif utils.isIntOrChar(expression): resultType = definitions.updateType( resultType, 'char' if utils.isChar(expression) else 'number') resultLines.append(general.loadIntOrChar(expression, outputReg, props)) # Address elif addresses.isAddress(expression, props): resultType = definitions.updateType('address', resultType) if definitions.getSupertype(resultType) == 'address': resultLines.append( general.loadAsAddress(expression, outputReg, props)) else: resultLines.append( general.loadFromAddress(expression, resultType, outputReg, props)) resultAddr = expression return { 'lines': resultLines, 'type': resultType, 'reg': outputReg, 'address': resultAddr }
def parseRHS(expression, props, outputReg='any', inferredType='any'): # Convert the expression to postfix (RPN) notation splitExp = parser.infixToPostfix(parser.splitExpression(expression)) allTempRegs = props['tempRegisters'] resultLines = [] resultAddr = None # Parse the expression as a stack of operations equationStack = [] typeStack = [] asAddressStack = [] availableTempRegIdx = 0 for i, item in enumerate(splitExp): val1, val2 = item, None val1Type, val2Type = inferredType, inferredType val1AsAddress, val2AsAddress = False, False val1Addr, val2Addr = None, None # Haven't optimized address addition yet reg1, reg2 = None, None limitedProps = utils.propsWithTempRegOffset(props, availableTempRegIdx) finalIteration = i == len(splitExp) - 1 or ( i == len(splitExp) - 3 and (splitExp[-1] == 'as' or splitExp[-1] == 'addressof')) targetReg = utils.getTempRegister(limitedProps['tempRegisters'], 0) if finalIteration: if utils.isSysFunc(item) and outputReg == 'any': targetReg = '$v0' elif outputReg == 'any': targetReg = utils.getTempRegister(allTempRegs, 0) else: targetReg = outputReg prevTempReg = None if availableTempRegIdx < 1 else utils.getTempRegister( allTempRegs, availableTempRegIdx - 1) prevPrevTempReg = None if availableTempRegIdx < 2 else utils.getTempRegister( allTempRegs, availableTempRegIdx - 2) if item in operations.BIN_OPERATORS or item == 'as': val1, val2 = equationStack[-2], equationStack[-1] val1Type, val2Type = typeStack[-2], typeStack[-1] val1AsAddress, val2AsAddress = asAddressStack[-2], asAddressStack[ -1] elif item in operations.UN_OPERATORS or item == 'addressof': val1, val1Type, val1AsAddress = equationStack[-1], typeStack[ -1], asAddressStack[-1] # Special operators if item == 'as': equationStack.pop() asAddressStack.pop() typeStack.pop() typeStack.pop() typeStack.append(val2) val1, val1Type, val1AsAddress = equationStack[-1], typeStack[ -1], asAddressStack[-1] elif item == 'addressof': asAddressStack.pop() asAddressStack.append(True) val1, val1Type, val1AsAddress = equationStack[-1], typeStack[ -1], asAddressStack[-1] else: # Get first register if item in operations.BIN_OPERATORS or item in operations.UN_OPERATORS: if utils.isIntOrChar(val1): reg1 = val1 else: if utils.isRegister(val1): reg1 = val1 else: reg1 = targetReg parsed = parseSingleRHS(val1, limitedProps, reg1, val1Type, val1AsAddress) resultLines += parsed['lines'] val1Type, val1Addr = parsed['type'], parsed['address'] if not utils.isRegister(val1): limitedProps = utils.propsWithTempRegOffset( limitedProps, 1) # Get Second register if item in operations.BIN_OPERATORS: if utils.isIntOrChar(val2): reg2 = val2 else: if utils.isRegister(val2): reg2 = val2 elif reg1 == targetReg: reg2 = utils.getTempRegister( limitedProps['tempRegisters'], 0) else: reg2 = targetReg parsed = parseSingleRHS(val2, limitedProps, reg2, val2Type, val2AsAddress) resultLines += parsed['lines'] val2Type, val2Addr = parsed['type'], parsed['address'] if not utils.isRegister(val2): limitedProps = utils.propsWithTempRegOffset( limitedProps, 1) # Do binary operation if item in operations.BIN_OPERATORS: # Try to re-use/free-up temporary registers where possible equationReg = targetReg if utils.isTempRegister(equationReg, allTempRegs): if val1 == prevPrevTempReg: equationReg = val1 elif val2 == prevTempReg: equationReg = val2 else: availableTempRegIdx += 1 if val1 == prevPrevTempReg and val2 == prevTempReg: # Suggested Optimization: Even though it frees up a register, it doesn't # keep track of the value inside it. This could potentially prevent # the same value from being re-loaded. availableTempRegIdx -= 1 # Parse the operation parsedOperation = operations.binaryOperation( item, reg1, reg2, equationReg, limitedProps) resultLines += parsedOperation['lines'] equationStack.pop() equationStack.pop() typeStack.pop() typeStack.pop() asAddressStack.pop() asAddressStack.pop() equationStack.append(parsedOperation['reg']) typeStack.append(definitions.mergeType(val1Type, val2Type)) asAddressStack.append(False) # Do unary operation elif item in operations.UN_OPERATORS: # Try to re-use/free-up temporary registers where possible equationReg = targetReg if utils.isTempRegister(equationReg, allTempRegs): if val1 == prevTempReg: equationReg = val1 else: availableTempRegIdx += 1 # Parse the operation parsedOperation = operations.unaryOperation( item, reg1, equationReg, limitedProps) resultLines += parsedOperation['lines'] equationStack.pop() typeStack.pop() asAddressStack.pop() equationStack.append(parsedOperation['reg']) typeStack.append(val1Type) asAddressStack.append(False) # Handle expressions without operators elif i == len(splitExp) - 1: if outputReg == 'any': if val1 == '0': val1 = '$0' if utils.isRegister(val1): targetReg = val1 parsed = parseSingleRHS(val1, limitedProps, targetReg, val1Type, val1AsAddress) resultLines += parsed['lines'] val1Type, val1Addr = parsed['type'], parsed['address'] resultAddr = val1Addr equationStack.append(targetReg) typeStack.append(val1Type) asAddressStack.append(False) # Add to stack elif item != 'as' and item != 'of': equationStack.append(item) if utils.isInt(item): typeStack.append('number') elif utils.isChar(item): typeStack.append('char') else: typeStack.append('any') asAddressStack.append(False) return { 'lines': resultLines, 'type': typeStack[-1], 'reg': equationStack[-1], 'address': resultAddr }
def parseArray(expression, props, addressReg='any'): resultLines = [] resultReg = None resultType = 'address' elemType = 'any' resultAddress = 'none' outer, inner = None, None outerAddr = expression[:expression.index('[')] innerExpr = expression[expression.index('[') + 1:-1].strip() if outerAddr in props['variables'] and 'elemtype' in props['variables'][ outerAddr]: resultType = definitions.updateType( props['variables'][outerAddr]['type'], 'address') if 'elemtype' in props['variables'][outerAddr]: elemType = props['variables'][outerAddr]['elemtype'] # Optimize offset literals if utils.isIntOrChar(innerExpr): value = utils.getIntOrChar(innerExpr) if utils.isRegister(outerAddr): if value == 0: resultAddress = '({})'.format(utils.getRegister(outerAddr)) else: resultAddress = '{}({})'.format(value, utils.getRegister(outerAddr)) else: if value == 0: resultAddress = outerAddr else: resultAddress = '{}+{}'.format(outerAddr, value) outer, inner = outerAddr, value else: # Parse inner expression exprReg = None if utils.isRegister(innerExpr): exprReg = innerExpr else: parsedExpr = expressions.parseRHS(innerExpr, props, 'any', 'number') resultLines += parsedExpr['lines'] exprReg = parsedExpr['reg'] limitedProps = utils.propsWithTempRegExcl(props, [exprReg]) resultReg = addressReg if resultReg is 'any' or resultReg == exprReg: resultReg = utils.getTempRegister(limitedProps['tempRegisters'], 0) newAddress = outerAddr if utils.isRegister(outerAddr): newAddress = '({})'.format(utils.getRegister(outerAddr)) resultLines.append( general.loadAsAddress(newAddress, resultReg, props, (outerAddr, '0'))) addOperation = operations.binaryOperation('+', resultReg, exprReg, resultReg, limitedProps) resultLines += addOperation['lines'] resultAddress = '({})'.format(utils.getRegister(resultReg)) outer, inner = resultReg, '0' return { 'lines': resultLines, 'type': resultType, 'elemtype': elemType, 'reg': resultReg, 'address': resultAddress, 'outer': outer, 'inner': inner }