Ejemplo n.º 1
0
    def state9(self, char, output):
        """
        This state will deal with if statements. We begin by evaluating the left hand side and placing the result in
        register C2. Then we evaluate the right hand side and place in register D2.
        :param char:
        :param output:
        :return:
        """

        if char in IGNORE_CHARS and self.expectFlag == 0:
            pass
        elif char == "(" and self.expectFlag == 0:
            self.expectFlag = 1
        elif self.expectFlag == 1:
            if char in BOOLEAN_OPERATORS:
                tokens = tokenize(self.mathFormula)
                postfix = infixToPostfix(tokens)
                evaluatePostfix(postfix, self.varList, self.varLocation,
                                self.methodList[self.currentMethod], output)
                self.ifOperator = self.convertOperatorToFlags(char)
                self.expectFlag = 2
                self.mathFormula = ""
                output.write("    MOV $A $C2\n")
            else:
                self.mathFormula += char

        elif self.expectFlag == 2:
            if char == ")":
                tokens = tokenize(self.mathFormula)
                postfix = infixToPostfix(tokens)
                evaluatePostfix(postfix, self.varList, self.varLocation,
                                self.methodList[self.currentMethod], output)
                self.expectFlag = 2
                self.mathFormula = ""
                output.write("    MOV $A $D2\n")
                self.expectFlag = 3
            else:
                self.mathFormula += char
        elif self.expectFlag == 3:
            if char in IGNORE_CHARS:
                pass
            elif char == "{":
                output.write("    CMP $D2 $C2\n")
                output.write("    JMP " + self.ifOperator + " L" +
                             str(self.ifLabel) + "\n")
                self.ifLabel += 1
                self.nestedFlag += 1
                self.state = 5
                self.expectFlag = 0
                self.mathFormula = ""
            else:
                print(char)
                raise ValueError("Syntax error at line {}".format(self.lineno))
Ejemplo n.º 2
0
    def state7(self, char, output):
        """
        Begins variable assignment. This could either be a math formula, or a function call
        :param char:
        :param output:
        :return:
        """

        if char in IGNORE_CHARS and self.expectFlag == 0:
            pass

        elif char == "(" and self.expectFlag == 1:
            if self.mathFormula in self.methodList:
                self.functionCall = self.mathFormula
                self.state = 8
            else:
                self.mathFormula += char

        elif char == " " and self.expectFlag == 1:
            if self.mathFormula in self.methodList:
                self.functionCall = self.mathFormula
                self.state = 8
            else:
                self.mathFormula += char

        elif char == ";":
            # End of our math statement. We may begin the evaluation and assign the result to the current variable
            tokens = tokenize(self.mathFormula)
            postfix = infixToPostfix(tokens)
            evaluatePostfix(postfix, self.varList, self.varLocation,
                            self.methodList[self.currentMethod], output)

            if self.currentVar in self.methodList[self.currentMethod]:
                # The variable is an argument passed into the function. We use the stack pointer to fetch its
                # location before writing the value.
                output.write("    MOV $A2 $S2\n")
                output.write("    ADD #" + str(self.methodList[
                    self.currentMethod][self.currentVar][1] * 4) + " $A2\n")
                output.write("    MEMW [4] $A $A2\n")

            else:
                # The variable is local, so we just write the result to its memory location from the local list.
                output.write("    MEMW [4] $A #" +
                             str(self.varLocation[self.currentVar]) + "\n")

            # now we reset everything
            self.state = 5
            self.mathFormula = ""
            self.currentType = ""
            self.currentVar = ""
            self.expectFlag = 0

        else:
            self.mathFormula += char
            self.expectFlag = 1
    def state19(self, char, output):
        """
        Begins the evaluation of the left hand side for if boolean statement.
        :param char: token from line being read.
        :param output: output file to write to.
        :return:
        :return:
        """

        if char in BOOLEAN_OPERATORS:
            self.ifOperator = char

            if self.argCount == 1:
                # We only have one operand, so there's no need to pass the expression through the math parser.

                if self.mathFormula in self.varList:
                    # The operand is a variable from the local list. We read its value and write it to the variable
                    output.write("    MEMR [4] #" + str(self.varLocation[self.mathFormula]) + " $A2\n")

                elif self.mathFormula in self.methodList[self.currentMethod]:
                    # The operand is one of the function's arguments. We use the stack pointer to locate its memory
                    # location (we assume it was pushed onto the stack during function call), then we read its value
                    # before writing it to the variable.
                    output.write("    MOV $C2 $S2\n")
                    output.write("    ADD #" + str(self.methodList[self.currentMethod][self.mathFormula][1] * 4)
                                 + " $B2\n")
                    output.write("    MEMR [4] $C2 $A2\n")

                else:
                    # The operand is simply an immediate value (integer). We can move it to a register and write to the
                    # appropriate memory location.
                    output.write("    MOV #" + self.mathFormula + " $A2\n")

            else:
                tokens = tokenize(self.mathFormula)
                postfix = infixToPostfix(tokens)
                evaluatePostfix(postfix, self.varList, self.varLocation, self.methodList[self.currentMethod], output)
                output.write("    MEMW [4] $A $A2\n")

            self.mathFormula = ""
            self.argCount = 0
            self.state = 20

        else:
            self.mathFormula += char
            self.argCount += 1
    def state17(self, char, output):
        """
        Similar to state 10, this state evaluates a mathematical function, but following a return statement. We append
        each operand until we reach a semi-colon indicating the end of the expression. In this case, rather than
        assigning the result to a variable, we write it to register A. This follows the cdecl calling conventions which
        ensures the correct value is being returned. After a CALL function, any result will always be stored in register
        A. Once finished, we free up the memory used by pushed variables for the stack frame, and we return to state 7.
        :param char: token from line being read.
        :param output: output file to write to.
        :return:
        """

        if char == ";":
            if self.argCount == 1:
                # We only have one operand, no need to use the math parser
                if self.mathFormula in self.varList:
                    output.write("    MEMR [4] #" + str(self.varLocation[self.mathFormula]) + " $A\n")
                elif self.mathFormula in self.methodList[self.currentMethod]:
                    output.write("    MOV $B2 $S2\n")
                    output.write("    ADD #" + str(self.methodList[self.currentMethod][self.mathFormula][1] * 4)
                                                                                                     + " $B2\n")
                    output.write("    MEMR [4] $B2 $A\n")
                else:
                    output.write("    MOV #" + self.mathFormula + " $A\n")

            else:
                # We make use of the math parser to write the appropriate Capua ASM output
                tokens = tokenize(self.mathFormula)
                postfix = infixToPostfix(tokens)
                evaluatePostfix(postfix, self.varList, self.varLocation,
                                self.methodList[self.currentMethod], output)

            # Free up the memory used by variable declarations during this stack frame, then return
            self.memoryLocation -= self.variableCount * 4
            output.write("    SUB #" + str(self.variableCount * 4) + " $S\n")
            output.write("    RET\n")
            self.state = 7

        else:
            # We have more operands to read, so we append them to the math formula string
            self.mathFormula += str(char)
            self.argCount += 1
    def state10(self, char, output):
        """
        This is the state which handles parsing of math expressions for variable assignment.
        Once we're done, we jump back to state 7. However, if the first operand is a function call,
        we jump to state 11.
        :param char: token from line being read.
        :param output: output file to write to.
        :return:
        """

        if char == ";":
            # we reach the end of the formula, so we can evaluate it and assign the result to the variable.

            if self.argCount == 1:
                # We only have one operand, so there's no need to pass the expression through the math parser.

                if self.mathFormula in self.varList:
                    # The operand is a variable from the local list. We read its value and write it to the variable
                    output.write("    MEMR [4] #" + str(self.varLocation[self.mathFormula]) + " $A\n")

                elif self.mathFormula in self.methodList[self.currentMethod]:
                    # The operand is one of the function's arguments. We use the stack pointer to locate its memory
                    # location (we assume it was pushed onto the stack during function call), then we read its value
                    # before writing it to the variable.
                    output.write("    MOV $B2 $S2\n")
                    output.write("    ADD #" + str(self.methodList[self.currentMethod][self.mathFormula][1] * 4)
                                 + " $B2\n")
                    output.write("    MEMR [4] $B2 $A\n")

                else:
                    # The operand is simply an immediate value (integer). We can move it to a register and write to the
                    # appropriate memory location.
                    output.write("    MOV #" + self.mathFormula + " $A\n")

                if self.currentVariable in self.methodList[self.currentMethod]:
                    # The variable is an argument passed into the function. We use the stack pointer to fetch its
                    # location before writing the value.
                    output.write("    MOV $A2 $S2\n")
                    output.write("    ADD #" + str(self.methodList[self.currentMethod][char][1] * 4) + " $A2\n")
                    output.write("    MEMW [4] $A $A2\n")

                else:
                    # The variable is local, so we just write the result to its memory location from the local list.
                    output.write("    MEMW [4] $A #" + str(self.varLocation[self.currentVariable]) + "\n")

            elif self.argCount < 1:
                # This is in case we write something like "int a = ;", which is invalid.
                raise ValueError("Incorrect syntax: variable assignment has no operand!")

            else:
                # Otherwise, we have multiple operands to evaluate. We use the mathParser's functions to print out the
                # appropriate Capua ASM code. We tokenize the formula into individual tokens, determine its postfix
                # notation, then evaluate it.
                tokens = tokenize(self.mathFormula)
                postfix = infixToPostfix(tokens)
                evaluatePostfix(postfix, self.varList, self.varLocation,
                                self.methodList[self.currentMethod], output)

                if self.currentVariable in self.methodList[self.currentMethod]:
                    # The variable is an argument passed into the function. We use the stack pointer to fetch its
                    # location before writing the value.
                    output.write("    MOV $A2 $S2\n")
                    output.write("    ADD #" + str(self.methodList[self.currentMethod][self.currentVariable][1] * 4)
                                                                                                         + " $A2\n")
                    output.write("    MEMW [4] $A $A2\n")

                else:
                    # The variable is local, so we just write the result to its memory location from the local list.
                    output.write("    MEMW [4] $A #" + str(self.varLocation[self.currentVariable]) + "\n")

            self.state = 7

        elif char in self.methodList:
            # If we read a function call, we need to handle this case a special way.
            self.functionCall = char
            self.state = 11

        else:
            # We read another operand which we append to the formula list.
            self.mathFormula += str(char)
            self.argCount += 1