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 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 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 parseAssignment(line, props): resultLines = [] lhs, rhs = [s.strip() for s in line.split('=')] if utils.isRegister(lhs): reg = lhs.split(' as ')[0].strip() if ' as ' in lhs else lhs parsedRHS = expressions.parseRHS(rhs, props, reg) resultLines += parsedRHS['lines'] else: inferredType = expressions.parseLHS(lhs, props)['type'] parsedRHS = expressions.parseRHS(rhs, props, 'any', inferredType) resultLines += parsedRHS['lines'] resultType = parsedRHS['type'] limitedProps = utils.propsWithTempRegExcl(props, [parsedRHS['reg']]) parsedLHS = expressions.parseLHS(lhs, limitedProps) resultLines += parsedLHS['lines'] resultType = definitions.updateType(resultType, parsedLHS['elemtype']) resultLines.append( general.storeToAddress(parsedLHS['address'], resultType, parsedRHS['reg'], props)) lastLine = resultLines[-1] if '#' in lastLine: lastLine = lastLine[:lastLine.index('#')].strip() resultLines[-1] = lastLine + utils.formatComment(line, props) return resultLines
def parseSysFunc(expr, props, isInExpression=False): comment = utils.formatComment(None if isInExpression else expr, props) if expr.startswith(utils.SYS_FUNCTIONS[0]): return [general.setMode(5, props), 'syscall{}'.format(comment)] elif expr.startswith(utils.SYS_FUNCTIONS[1]): params = expr[expr.index('(') + 1:-1].strip() parsedSize = expressions.parseRHS(params, props, '$a0') return parsedSize['lines'] + [ general.setMode(9, props), 'syscall{}'.format(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 setMode(mode, props): modes = { 1: 'print integer', 4: 'print string', 5: 'input integer', 8: 'input string', 9: 'allocate memory', 10: 'exit', 11: 'print character' } comment = utils.formatComment("set mode to '{}'".format(modes[mode]), props, 2) return 'addi $v0, $0, {}{}'.format(mode, comment)
def parseGoto(line, props, link=False): location = line[len('goto'):].strip() parsedExpr = expressions.parseRHS(location, props, 'any', 'address') locationReg = parsedExpr['reg'] newComment = utils.formatComment(line, props) gotoInstructions = ['jal', 'jalr'] if link else ['j', 'jr'] if parsedExpr['address'] != None: return '{} {}{}'.format(gotoInstructions[0], parsedExpr['address'], newComment) else: return parsedExpr['lines'] + [ '{} {}{}'.format(gotoInstructions[1], locationReg, newComment) ]
def parsePrint(line, props): parsedExpr = expressions.parseRHS(line[line.index(' '):].strip(), props, '$a0') printOperations = {'number': 1, 'address': 4, 'char': 11} resultType = 'char' if parsedExpr[ 'type'] == 'char' else definitions.getSupertype(parsedExpr['type']) if resultType == 'any': resultType = 'number' printOperation = printOperations[resultType if resultType in printOperations else 'number'] return parsedExpr['lines'] + [ general.setMode(printOperation, props), 'syscall{}'.format( utils.formatComment(line, props)) ]
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 parseInputStr(line, props): resultLines = [] argumentStr = line[len(line.split()[0]):] arguments = [s.strip() for s in argumentStr.split(',')] parsedAddr = expressions.parseRHS(arguments[0], props, '$a0', 'address') resultLines += parsedAddr['lines'] maxSize = '20' if len(arguments) > 1: maxSize = arguments[1] elif arguments[0] in props['variables']: maxSize = str(props['variables'][arguments[0]]['initsize']) parsedSize = expressions.parseRHS(maxSize, props, '$a1', 'number') resultLines += parsedSize['lines'] return resultLines + [ general.setMode(8, props), 'syscall{}'.format( utils.formatComment(line, props)) ]
def loadRegHiLo(reg, outputReg, props): comment = utils.formatComment('{} = {}'.format(outputReg, reg), props, 2) return 'mf{} {}{}'.format(reg[1:], utils.getRegister(outputReg), comment)
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 parseDefinition(line, props): newLine = '' newVariable = {} varDefinition, varValue = '', None if '=' in line: varDefinition, varValue = [s.strip() for s in line.split('=')] else: varDefinition = line.strip() varType, varName = varDefinition.split() comment = utils.formatComment(varDefinition, props) # Numberic numTypeMap = { 'int': 'word', 'short': 'half', 'byte': 'byte', 'char': 'byte' } for numType in NUM_TYPES: if varValue == None: varValue = '0' if varType == numType: parsedValue = utils.getIntOrChar(varValue) newLine = '{}: .{} {}{}'.format(varName, numTypeMap[numType], parsedValue, comment) newVariable = { 'name': varName, 'type': varType, 'supertype': getSupertype(varType), 'init': varValue } # Array or string or address if varType in ADDRESS_TYPES or '[' in varType: initSize = 0 if '[' in varType: initSizeStr = varType[varType.index('[') + 1:varType.index(']')] initSize = utils.getIntOrChar(initSizeStr) if utils.isInt( initSizeStr) else 0 varType = varType[:varType.index('[')].strip() + '[]' elemType = ADDRESS_ELEMENT_TYPE_MAP[varType] if varValue[0] == '\'' and varValue[-1] == '\'': varValue = '"' + varValue[1:-1] + '"' if varValue.startswith('"'): newLine = '{}: .asciiz {}{}'.format(varName, varValue, comment) elif varValue.startswith('['): newLine = '{}: .{} {}{}'.format(varName, numTypeMap[elemType], varValue[1:-1].strip(), comment) else: numBytes = NUM_SIZES[elemType] newLine = '{}: .space {}{}'.format(varName, initSize, comment) if numBytes != 1: newLine = '.align {}{}{}'.format(numBytes - 1, os.linesep, newLine) newVariable = { 'name': varName, 'type': varType, 'supertype': 'address', 'elemtype': ADDRESS_ELEMENT_TYPE_MAP[varType], 'init': varValue, 'initsize': initSize } if props['comment'] is not None: newLine += props['comment'] return (newLine, newVariable)
def parseExit(line, props): return [ general.setMode(10, props), 'syscall{}'.format(utils.formatComment('exit', props)) ]
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