예제 #1
0
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 }
예제 #2
0
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)
예제 #3
0
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
예제 #4
0
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)
예제 #5
0
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)
예제 #6
0
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
    }
예제 #7
0
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
    }
예제 #8
0
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
    }
예제 #9
0
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