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 loadFromAddress(address, loadType, outputReg, props, outerInner=None): numLoadFuncs = { 'int': 'lw', 'short': 'lh', 'byte': 'lb', 'char': 'lb', 'number': 'lw', 'address': 'lw' } loadFunc = 'lw' if definitions.getSupertype(loadType) == 'address': loadType = 'address' if loadType in numLoadFuncs: loadFunc = numLoadFuncs[loadType] if utils.isRegister(address): raise utils.CompileException('Can\'t load directly from register') if outerInner == None: comment = utils.formatComment('{} = {}'.format(outputReg, address), props, 2) else: comment = utils.formatComment( '{} = {}[{}]'.format(outputReg, outerInner[0], outerInner[1]), props, 2) return '{} {}, {}{}'.format(loadFunc, utils.getRegister(outputReg), address, comment)
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 loadAsAddress(address, outputReg, props, outerInner=None): if utils.isRegister(address): raise utils.CompileException('Can\'t load register as address') if outerInner == None: comment = utils.formatComment( '{} = address of {}'.format(outputReg, address), props, 2) else: comment = utils.formatComment( '{} = address of {}[{}]'.format(outputReg, outerInner[0], outerInner[1]), props, 2) return '{} {}, {}{}'.format('la', utils.getRegister(outputReg), address, comment)
def storeToAddress(address, storeType, outputReg, props): if utils.isRegister(address): raise utils.CompileException('Can\'t store to register') numStoreFuncs = { 'int': 'sw', 'short': 'sh', 'byte': 'sb', 'char': 'sb', 'number': 'sw' } storeFunc = 'sw' if storeType in definitions.NUM_TYPES: storeFunc = numStoreFuncs[storeType] comment = utils.formatComment('{} = {}'.format(address, outputReg), props, 2) return '{} {}, {}{}'.format(storeFunc, utils.getRegister(outputReg), address, comment)
def loadRegHiLo(reg, outputReg, props): comment = utils.formatComment('{} = {}'.format(outputReg, reg), props, 2) return 'mf{} {}{}'.format(reg[1:], utils.getRegister(outputReg), comment)
def isRegHiLo(reg): return utils.getRegister(reg) == '$hi' or utils.getRegister(reg) == '$lo'
def loadRegister(valueReg, outputReg, props): comment = utils.formatComment('{} = {}'.format(outputReg, valueReg), props, 2) return 'add {}, $0, {}{}'.format(utils.getRegister(outputReg), utils.getRegister(valueReg), comment)
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 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 }
def parseGotoConditional(line, props): resultLines = [] gotoFunc = line.split()[0] branchOperators = ['==', '!=', '<', '<=', '>', '>='] branchFuncs = { '==': 'beq', '!=': 'bne', '<': 'blt', '<=': 'ble', '>': 'bgt', '>=': 'bge' } branchFuncsWith0 = {'<': 'bltz', '<=': 'blez', '>': 'bgtz', '>=': 'bgez'} branchFuncsWith0Link = {'<': 'bltzal', '>=': 'bgezal'} condition = line.split(' if ')[1].strip() location = line.split(' if ')[0][len(gotoFunc):].strip() address = expressions.parseRHS(location, props, 'any', 'address')['address'] if address == None: raise utils.CompileException('Direct label is required') conditionLeft, conditionRight, conditionOperator = '', '', None splitCondition = parser.splitExpression(condition) rpnCondition = parser.infixToPostfix(splitCondition) if rpnCondition[-1] not in branchOperators: conditionLeft = '({})'.format(condition) conditionRight = '0' conditionOperator = '>' else: splitIdxCondition = [(item, idx) for idx, item in enumerate(splitCondition)] rpnIdxCondition = parser.infixToPostfix(splitIdxCondition, lambda item: item[0]) conditionOperator = rpnIdxCondition[-1][0] operatorIdx = rpnIdxCondition[-1][1] conditionLeft = ' '.join(splitCondition[:operatorIdx]) conditionRight = ' '.join(splitCondition[operatorIdx + 1:]) branchFunc = branchFuncs[conditionOperator] singleParam = False reg1, reg2 = 'any', 'any' if utils.isRegister(conditionLeft): reg1 = utils.getRegister(conditionLeft) else: parsed = expressions.parseRHS(conditionLeft, props, 'any', 'number') resultLines += parsed['lines'] reg1 = parsed['reg'] limitedProps = utils.propsWithTempRegExcl(props, [reg1]) if gotoFunc == 'gotolink': if conditionRight == '0' and conditionOperator in branchFuncsWith0Link: branchFunc = branchFuncsWith0Link[conditionOperator] singleParam = True else: raise utils.CompileException( 'Conditional gotolink only supports < 0 and >= 0 conditions') elif conditionRight == '0' and conditionOperator in branchFuncsWith0: branchFunc = branchFuncsWith0[conditionOperator] singleParam = True elif utils.isRegister(conditionRight): reg2 = utils.getRegister(conditionRight) else: parsed = expressions.parseRHS(conditionRight, limitedProps, 'any', 'number') resultLines += parsed['lines'] reg2 = parsed['reg'] comment = utils.formatComment(line, props) if singleParam: resultLines.append('{} {}, {}{}'.format(branchFunc, reg1, address, comment)) else: resultLines.append('{} {}, {}, {}{}'.format(branchFunc, reg1, reg2, address, comment)) return resultLines