def _generate_code_for_subtraction(
         self, expression: ExpressionHavingTwoValues) -> str:
     if isinstance(expression.valueRight, IdentifierValue):
         return generate_code_for_loading_value(
             expression.valueLeft, self.visitor) + \
                f'SUB {compute_value_register(expression.valueRight, self.visitor)}\n'
     elif isinstance(expression.valueRight, IntNumberValue):
         return generate_code_for_loading_value(expression.valueRight, self.visitor) + \
                'STORE 6\n' + generate_code_for_loading_value(
             expression.valueLeft, self.visitor) + 'SUB 6\n'
     else:
         raise ValueError(
             'Unknown instance of Value occurred as a rightValue field in provided expression.\n'
         )
 def _generate_code_for_addition(
         self, expression: ExpressionHavingTwoValues) -> str:
     if isinstance(expression.valueRight, IdentifierValue):
         if isinstance(expression.valueRight.identifier,
                       ArrayElementByVariableIdentifier):  # dynamic
             return generate_code_for_loading_value(
                 expression.valueRight, self.visitor) + \
                    'STORE 6\n' + generate_code_for_loading_value(
                 expression.valueLeft, self.visitor) + 'ADD 6\n'
         else:
             return generate_code_for_loading_value(
                 expression.valueLeft, self.visitor) + \
                    f'ADD {compute_value_register(expression.valueRight, self.visitor)}\n'
     elif isinstance(expression.valueRight, IntNumberValue):
         return generate_code_for_loading_value(
             expression.valueRight, self.visitor) + \
                'STORE 6\n' + generate_code_for_loading_value(
             expression.valueLeft, self.visitor) + 'ADD 6\n'
     else:
         raise ValueError(
             'Unknown instance of Value occurred as a rightValue field in provided expression.\n'
         )
示例#3
0
    def visit_increment_decrement_command(self, increment_decrement_command: IncrementDecrementCommand) -> None:
        """
            Writes code for incrementing or decrementing a variable included in increment_decrement_command argument
            as variableIdentifier. It loads this variable, perform operation and saves result in this variable.
        """
        code: str = generate_code_for_loading_value(
            IdentifierValue(increment_decrement_command.identifier), self)
        if increment_decrement_command.is_decrement:
            code = code + 'DEC\n'
        else:
            code = code + 'INC\n'

        if increment_decrement_command.identifier.identifier_name in self.local_variables:
            code = code + f'STORE {self.local_variables[increment_decrement_command.identifier.identifier_name]}\n'
        else:
            code = code + f'STORE {self.declared_variables[increment_decrement_command.identifier.identifier_name]}\n'
        self.generated_code.append(code)
示例#4
0
def generate_code_for_expression(expression: Expression,
                                 visitor: 'ASTInterpreter') -> str:
    math_code_generator = MathOperationsCodeGenerator(visitor)
    if expression.number_of_values() == 1:
        return generate_code_for_loading_value(expression.value, visitor)
    elif expression.number_of_values() == 2:
        if expression.operation not in math_code_generator.expressions.keys():
            raise ValueError(
                'Unknown operator. It is not present in expressions dictionary in expression_utils.'
            )
        result: str = math_code_generator.expressions.get(
            expression.operation)(math_code_generator, expression)
        return result
    else:
        raise ValueError(
            'Unknown instance of Expression occurred.\n'
            'Provided expression is neither OneValueExpression nor TwoValueExpression'
        )
示例#5
0
def write_code_for_for_loop_command(
        loop: ForCommand,
        visitor: 'ASTInterpreter'
) -> None:
    loop_name: str = visitor.loop_name_provider.get_label()
    iterator_variable: str = loop.iterator_identifier
    end_variable: str = f'{loop_name}_@end'

    # iterator and counter_var declaration (as a local variables)
    # check if iterator name can be declared will be performed, error if there is a variable with the same name declared
    visitor.add_local_variable(iterator_variable)
    visitor.add_local_variable(end_variable)

    end_reg = visitor.local_variables[end_variable]
    iterator_reg = visitor.local_variables[iterator_variable]

    # generate caption
    to_or_downto = 'DOWN TO' if loop.is_down_to else 'TO'
    start_str = loop.start.value if isinstance(loop.start, IntNumberValue) else '?'
    end_str = loop.end.value if isinstance(loop.end, IntNumberValue) else '?'
    code: str = f'## BEGIN for loop: {loop_name} FROM {loop.iterator_identifier} := {start_str} {to_or_downto}' \
                    f' {end_str}\n'
    # load loop.start value into iterator_reg
    code = code + generate_code_for_loading_value(loop.start, visitor)
    code = code + f'STORE {iterator_reg} # {iterator_variable}\n'  # loop.start load into iteration_register

    code = code + generate_code_for_loading_value(loop.end, visitor) + \
        f'STORE {end_reg} # {end_variable}\n'
    visitor.generated_code.append(code)
    # now iterator and end variables are computed and are resistant to start/end variables modification inside the loop

    comparison_operations = {False: 'JPOS', True: 'JNEG'}

    # comparison_signs = {False: 'LEQ', True: 'GEQ'}
    # old for loop implementation
    # while_do = WhileDoCommand(
    #     TwoValueCondition(
    #         IdentifierValue(VariableIdentifier(iterator_variable)),
    #         IdentifierValue(VariableIdentifier(end_variable)),
    #         comparison_signs[loop.is_down_to]),
    #     Commands(loop.commands.commands + [IncrementDecrementCommand(
    #         VariableIdentifier(iterator_variable),
    #         is_decrement=loop.is_down_to)]),
    #     is_user_command=False)

    label_start = visitor.label_provider.get_label()
    label_end = visitor.label_provider.get_label()

    loop_code_part_1 = [
        f'{label_start}',
        f'LOAD {iterator_reg}',
        f'SUB {end_reg}',
        f'{comparison_operations[loop.is_down_to]} {label_end}',
    ]

    visitor.generated_code.append('\n'.join(loop_code_part_1) + '\n')
    loop.commands.accept(visitor)
    IncrementDecrementCommand(VariableIdentifier(iterator_variable), is_decrement=loop.is_down_to).accept(visitor)

    loop_code_part_2 = [
        f'JUMP {label_start}',
        f'{label_end}',
    ]
    visitor.generated_code.append('\n'.join(loop_code_part_2) + '\n')

    # while_do.accept(visitor)
    code = f'## END loop: {loop_name}\n'
    visitor.generated_code.append(code)

    # iterator and counter_var local variables removal
    visitor.remove_local_variable(iterator_variable)
    visitor.remove_local_variable(end_variable)
    def generate_code_for_division_with_remainder(
            self,
            expr: ExpressionHavingTwoValues,
            return_remainder=False) -> str:
        if isinstance(expr.valueLeft, IntNumberValue) and isinstance(
                expr.valueRight, IntNumberValue):
            if expr.valueRight.value != 0:
                if return_remainder:
                    return generate_number(
                        expr.valueLeft.value % expr.valueRight.value,
                        self.visitor.constants, 0)
                else:
                    return generate_number(
                        expr.valueLeft.value // expr.valueRight.value,
                        self.visitor.constants, 0)
            else:
                return generate_number(0, self.visitor.constants)

        left = 10
        right = 11
        quotient = 12
        remainder = 13
        iterations = 14
        log_right = 15

        # we return left since remainder value is not updated and there is no need to do so, value we want is stored
        # in left register
        def code_for_return(mode: str) -> str:
            labels_remainder_zero: List[str] = list(
                map(lambda x: self.visitor.label_provider.get_label(),
                    range(5)))
            return {
                'L_POSITIVE_R_POSITIVE_REMAINDER':
                f'LOAD {left}',
                'L_POSITIVE_R_NEGATIVE_REMAINDER':
                '\n'.join([
                    f'LOAD {left}',
                    f'JZERO {labels_remainder_zero[1]}',
                    f'SUB {right}',
                    f'{labels_remainder_zero[1]}',
                ]),
                'L_NEGATIVE_R_POSITIVE_REMAINDER':
                '\n'.join([
                    f'LOAD {left}', f'JZERO {labels_remainder_zero[2]}',
                    f'LOAD {right}', f'SUB {left}',
                    f'{labels_remainder_zero[2]}'
                ]),
                'L_NEGATIVE_R_NEGATIVE_REMAINDER':
                '\n'.join([
                    f'LOAD {left}',
                    f'JZERO {labels_remainder_zero[0]}',
                    negate_number(),
                    f'{labels_remainder_zero[0]}',
                ]),
                'L_POSITIVE_R_POSITIVE_QUOTIENT':
                f'LOAD {quotient}',
                'L_R_DIFFERENT_SIGN_QUOTIENT':
                '\n'.join([
                    f'LOAD {left}',
                    f'JZERO {labels_remainder_zero[3]}',
                    f'LOAD {quotient}',
                    f'INC',
                    f'JUMP {labels_remainder_zero[4]}',
                    f'{labels_remainder_zero[3]}',
                    f'LOAD {quotient}',
                    f'{labels_remainder_zero[4]}',
                    negate_number(),
                ]),
                'L_NEGATIVE_R_NEGATIVE_QUOTIENT':
                f'LOAD {quotient}',
            }[mode]

        minus_one = self.visitor.declared_variables[self.MINUS_ONE_VAR_NAME]
        one = self.visitor.declared_variables[self.ONE_VAR_NAME]

        label_right_negative_left_positive = self.visitor.label_provider.get_label(
        )
        label_right_positive_left_negative = self.visitor.label_provider.get_label(
        )
        label_right_negative_left_negative = self.visitor.label_provider.get_label(
        )
        label_return_zero = self.visitor.label_provider.get_label()
        labels_return = list(
            map(lambda x: self.visitor.label_provider.get_label(), range(7)))
        labels_return_minus_one_or_zero_for_mod = list(
            map(lambda x: self.visitor.label_provider.get_label(), range(2)))

        # labels_return_one_or_zero_for_mod = list(map(lambda x: self.visitor.label_provider.get_label(), range(2)))

        def code_computing_number_of_iterations() -> str:
            return '\n'.join([
                self.generate_code_for_log(right, quotient, remainder),
                f'STORE {log_right}',
                self.generate_code_for_log(left, quotient, remainder),
                f'SUB {log_right}',
                f'STORE {log_right}',
                f'INC',
                f'STORE {iterations}',
            ])

        def code_start_algorithm() -> str:
            label_right_bigger = self.visitor.label_provider.get_label()
            start_loop_label_1 = self.visitor.label_provider.get_label()
            start_loop_label_2 = self.visitor.label_provider.get_label()
            end_loop_label = self.visitor.label_provider.get_label()
            return '\n'.join([
                code_computing_number_of_iterations(),
                # initialize quotient
                f'SUB 0',
                f'STORE {quotient}',
                f'LOAD {right}',
                f'SHIFT {log_right}',
                f'STORE {remainder}',
                f'{start_loop_label_1}',
                f'{start_loop_label_2}',
                f'LOAD {iterations}',
                f'DEC',
                f'JNEG {end_loop_label}',
                f'STORE {iterations}',
                f'LOAD {left}',
                f'SUB {remainder}',
                f'JNEG {label_right_bigger}',
                f'STORE {left}',
                f'LOAD {quotient}',
                f'SHIFT {one}',
                f'INC',
                f'STORE {quotient}',
                f'LOAD {remainder}',
                f'SHIFT {minus_one}',
                f'STORE {remainder}',
                f'JUMP {start_loop_label_1}',
                f'{label_right_bigger}',
                f'LOAD {quotient}',
                f'SHIFT {one}',
                f'STORE {quotient}',
                f'LOAD {remainder}',
                f'SHIFT {minus_one}',
                f'STORE {remainder}',
                f'JUMP {start_loop_label_2}',
                f'{end_loop_label}',
            ])

        code_loading_data_and_both_positive = [
            generate_code_for_loading_value(expr.valueRight, self.visitor),
            f'JZERO {label_return_zero}',
            f'JNEG {label_right_negative_left_positive}',
            f'STORE {right}',
            generate_code_for_loading_value(expr.valueLeft, self.visitor),
            f'JNEG {label_right_positive_left_negative}',
            f'STORE {left}',
            # f'SUB {right}',
            # f'JZERO {labels_return_one_or_zero_for_mod[0]}',
            code_start_algorithm(),
            code_for_return('L_POSITIVE_R_POSITIVE_REMAINDER')
            if return_remainder else
            code_for_return('L_POSITIVE_R_POSITIVE_QUOTIENT'),
            f'JUMP {labels_return[1]}',
        ]

        code_right_positive_left_negative = [
            f'{label_right_positive_left_negative}',
            negate_number(),
            f'STORE {left}',
            # f'SUB {right}',
            # f'JZERO {labels_return_minus_one_or_zero_for_mod[1]}',
            code_start_algorithm(),
            code_for_return('L_NEGATIVE_R_POSITIVE_REMAINDER')
            if return_remainder else
            code_for_return('L_R_DIFFERENT_SIGN_QUOTIENT'),
            f'JUMP {labels_return[2]}',
        ]

        code_right_negative_left_positive = [
            f'{label_right_negative_left_positive}',
            negate_number(),
            f'STORE {right}',
            generate_code_for_loading_value(expr.valueLeft, self.visitor),
            f'JNEG {label_right_negative_left_negative}',
            f'STORE {left}',
            # f'SUB {right}',
            # f'JZERO {labels_return_minus_one_or_zero_for_mod[0]}',
            code_start_algorithm(),
            code_for_return('L_POSITIVE_R_NEGATIVE_REMAINDER')
            if return_remainder else
            code_for_return('L_R_DIFFERENT_SIGN_QUOTIENT'),
            f'JUMP {labels_return[3]}',
        ]
        code_right_negative_left_negative = [
            f'{label_right_negative_left_negative}',
            negate_number(),
            f'STORE {left}',
            # f'SUB {right}',
            # f'JZERO {labels_return_one_or_zero_for_mod[1]}',
            code_start_algorithm(),
            code_for_return('L_NEGATIVE_R_NEGATIVE_REMAINDER')
            if return_remainder else
            code_for_return('L_NEGATIVE_R_NEGATIVE_QUOTIENT'),
            f'JUMP {labels_return[4]}',
        ]

        code_return_zero = [
            f'{label_return_zero}',
            f'SUB 0',
            f'JUMP {labels_return[0]}',
        ]

        # return_action = f'LOAD {minus_one}' if not return_remainder else f'SUB 0'
        # code_return_minus_one_or_zero_for_mod = [
        #     f'{labels_return_minus_one_or_zero_for_mod[0]}',
        #     f'{labels_return_minus_one_or_zero_for_mod[1]}',
        #     return_action,
        #     f'JUMP {labels_return[5]}',
        # ]
        #
        # return_action = f'LOAD {one}' if not return_remainder else f'SUB 0'
        # code_return_one_or_zero_for_mod = [
        #     f'{labels_return_one_or_zero_for_mod[0]}',
        #     f'{labels_return_one_or_zero_for_mod[1]}',
        #     return_action,
        #     f'JUMP {labels_return[6]}',
        #
        # ]

        code_return_section = [
            f'{labels_return[0]}',
            f'{labels_return[1]}',
            f'{labels_return[2]}',
            f'{labels_return[3]}',
            f'{labels_return[4]}',
            # f'{labels_return[5]}',
            # f'{labels_return[6]}',
        ]

        return '\n'.join([
            '\n'.join(code_loading_data_and_both_positive),
            '\n'.join(code_right_positive_left_negative),
            '\n'.join(code_right_negative_left_positive),
            '\n'.join(code_right_negative_left_negative),
            '\n'.join(code_return_zero),
            # '\n'.join(code_return_minus_one_or_zero_for_mod),
            # '\n'.join(code_return_one_or_zero_for_mod),
            '\n'.join(code_return_section),
        ]) + '\n'
    def _generate_code_for_multiplication(
            self, expression: ExpressionHavingTwoValues) -> str:
        if isinstance(expression.valueLeft, IntNumberValue) and isinstance(
                expression.valueRight, IntNumberValue):
            return generate_number(
                expression.valueLeft.value * expression.valueRight.value,
                self.visitor.constants, 0)
        left_reg = 6
        right_reg = 7
        right_copy = 11
        res_reg = 8
        label_do_nothing = self.visitor.label_provider.get_label()
        label_again = self.visitor.label_provider.get_label()
        label_r_positive = self.visitor.label_provider.get_label()
        label_r_positive2 = self.visitor.label_provider.get_label()
        end = self.visitor.label_provider.get_label()
        minus_one_reg = self.visitor.declared_variables[
            self.MINUS_ONE_VAR_NAME]
        one_reg = self.visitor.declared_variables[self.ONE_VAR_NAME]

        result = [
            f'SUB 0',
            f'STORE {res_reg}',
            generate_code_for_loading_value(expression.valueLeft,
                                            self.visitor),
            f'STORE {left_reg}',
            generate_code_for_loading_value(expression.valueRight,
                                            self.visitor),
            f'STORE {right_reg}',
            f'JPOS {label_r_positive}',
            negate_number(),
            f'{label_r_positive}',
            f'STORE {right_copy}',  # if right >0 then nothing
            f'{label_again}',
            f'LOAD {right_copy}',
            f'SHIFT {minus_one_reg}',  # else add left to res ^
            f'SHIFT {one_reg}',
            compare_values_knowing_registers(0, right_copy),
            f'JZERO {label_do_nothing}',
            f'LOAD {res_reg}',
            f'ADD {left_reg}',
            f'STORE {res_reg}',
            f'{label_do_nothing}',
            f'LOAD {right_copy}',
            f'SHIFT {minus_one_reg}',
            f'STORE {right_copy}',
            f'LOAD {left_reg}',
            f'SHIFT {one_reg}',
            f'STORE {left_reg}',
            f'LOAD {right_copy}',
            f'JPOS {label_again}',
            f'LOAD {right_reg}',
            f'JPOS {label_r_positive2}',
            f'LOAD {res_reg}',
            negate_number(),
            f'JUMP {end}',
            f'{label_r_positive2}',
            f'LOAD {res_reg}',
            f'{end}'  # right > 0
        ]

        return '\n'.join(result) + '\n'
    def _generate_code_for_restoring_division(
            self, expression: ExpressionHavingTwoValues) -> str:
        if isinstance(expression.valueLeft, IntNumberValue) and isinstance(
                expression.valueRight, IntNumberValue):
            if expression.valueRight.value != 0:
                return generate_number(
                    expression.valueLeft.value // expression.valueRight.value,
                    self.visitor.constants, 0)
            else:
                return generate_number(0, self.visitor.constants)

        minus_one = self.visitor.declared_variables[self.MINUS_ONE_VAR_NAME]
        one = self.visitor.declared_variables[self.ONE_VAR_NAME]
        divisor = 20
        number = 19
        reminder = 17
        quotient = 18
        log = 16

        label_zero_end = self.visitor.label_provider.get_label()
        label_d_negative = self.visitor.label_provider.get_label()
        label_d_positive_n_negative = self.visitor.label_provider.get_label()
        label_d_negative_n_negative = self.visitor.label_provider.get_label()
        label_start_loop = list(
            map(lambda x: self.visitor.label_provider.get_label(), range(4)))
        label_end_loop = list(
            map(lambda x: self.visitor.label_provider.get_label(), range(4)))
        label_return = list(
            map(lambda x: self.visitor.label_provider.get_label(), range(8)))
        label_reminder_negative = list(
            map(lambda x: self.visitor.label_provider.get_label(), range(4)))
        label_reminder_positive_end = list(
            map(lambda x: self.visitor.label_provider.get_label(), range(4)))

        label_return_one = self.visitor.label_provider.get_label()
        label_return_one2 = self.visitor.label_provider.get_label()
        label_return_m_one = self.visitor.label_provider.get_label()
        label_return_m_one2 = self.visitor.label_provider.get_label()

        code_start: List[str] = [
            generate_code_for_loading_value(expression.valueRight,
                                            self.visitor),
            f'JZERO {label_zero_end}',  # if right value is 0, we can end returning 0
            f'JNEG {label_d_negative}',
            f'STORE {divisor}',  # save right value
            generate_code_for_loading_value(expression.valueLeft,
                                            self.visitor),
            f'JNEG {label_d_positive_n_negative}',
            f'STORE{number}',  # save left value
            f'STORE {reminder}',
            compare_values_knowing_registers(divisor, number),
            f'JZERO {label_return_one}',
            self.generate_code_for_log(number, log, quotient),
            f'STORE {log}',
            f'LOAD {divisor}',
            f'SHIFT {log}',  # shift log(N)
            f'STORE {divisor}',
            f'SUB 0',
            f'STORE {quotient}',
            f'{label_start_loop[0]}',
            f'LOAD {log}',
            f'DEC',
            f'STORE {log}',
            f'JNEG {label_end_loop[0]}',
            f'LOAD {reminder}',
            f'SHIFT {one}',
            f'SUB {divisor}',
            f'STORE {reminder}',
            f'JNEG {label_reminder_negative[0]}',
            f'LOAD {quotient}',
            f'SHIFT {one}',
            f'INC',
            f'STORE {quotient}',
            f'JUMP {label_reminder_positive_end[0]}',
            f'{label_reminder_negative[0]}',
            f'LOAD {quotient}',
            f'SHIFT {one}',
            f'STORE {quotient}',
            f'LOAD {reminder}',
            f'ADD {divisor}',
            f'STORE {reminder}',
            f'{label_reminder_positive_end[0]}',
            f'JUMP {label_start_loop[0]}',
            f'{label_end_loop[0]}',
            f'LOAD {quotient}',
            f'JUMP {label_return[0]}',
            f'{label_zero_end}',
            f'SUB 0',
            f'JUMP {label_return[1]}',
            f'{label_return_one}',
            f'LOAD {one}',
            f'JUMP {label_return[4]}',
        ]

        code_d_positive_n_negative: List[str] = [
            f'{label_d_positive_n_negative}',
            negate_number(),
            f'STORE{number}',  # save left value
            f'STORE {reminder}',
            compare_values_knowing_registers(divisor, number),
            f'JZERO {label_return_m_one}',
            self.generate_code_for_log(number, log, quotient),
            f'STORE {log}',
            f'LOAD {divisor}',
            f'SHIFT {log}',  # shift log(N)
            f'STORE {divisor}',
            f'SUB 0',
            f'STORE {quotient}',
            f'{label_start_loop[3]}',
            f'LOAD {log}',
            f'DEC',
            f'STORE {log}',
            f'JNEG {label_end_loop[3]}',
            f'LOAD {reminder}',
            f'SHIFT {one}',
            f'SUB {divisor}',
            f'STORE {reminder}',
            f'JNEG {label_reminder_negative[2]}',
            f'LOAD {quotient}',
            f'SHIFT {one}',
            f'INC',
            f'STORE {quotient}',
            f'JUMP {label_reminder_positive_end[2]}',
            f'{label_reminder_negative[2]}',
            f'LOAD {quotient}',
            f'SHIFT {one}',
            f'STORE {quotient}',
            f'LOAD {reminder}',
            f'ADD {divisor}',
            f'STORE {reminder}',
            f'{label_reminder_positive_end[2]}',
            f'JUMP {label_start_loop[3]}',
            f'{label_end_loop[3]}',
            f'LOAD {quotient}',
            f'INC',
            negate_number(),
            f'JUMP {label_return[3]}',
            f'{label_return_m_one}',
            f'LOAD {minus_one}',
            f'JUMP {label_return[5]}',
        ]

        code_d_negative: List[str] = [
            f'{label_d_negative}',
            negate_number(),
            f'STORE {divisor}',  # save right value
            generate_code_for_loading_value(expression.valueLeft,
                                            self.visitor),
            f'JNEG {label_d_negative_n_negative}',
            f'STORE{number}',  # save left value
            f'STORE {reminder}',
            compare_values_knowing_registers(divisor, number),
            f'JZERO {label_return_m_one2}',
            self.generate_code_for_log(number, log, quotient),
            f'STORE {log}',
            f'LOAD {divisor}',
            f'SHIFT {log}',  # shift log(N)
            f'STORE {divisor}',
            f'SUB 0',
            f'STORE {quotient}',
            f'{label_start_loop[2]}',
            f'LOAD {log}',
            f'DEC',
            f'STORE {log}',
            f'JNEG {label_end_loop[2]}',
            f'LOAD {reminder}',
            f'SHIFT {one}',
            f'SUB {divisor}',
            f'STORE {reminder}',
            f'JNEG {label_reminder_negative[1]}',
            f'LOAD {quotient}',
            f'SHIFT {one}',
            f'INC',
            f'STORE {quotient}',
            f'JUMP {label_reminder_positive_end[1]}',
            f'{label_reminder_negative[1]}',
            f'LOAD {quotient}',
            f'SHIFT {one}',
            f'STORE {quotient}',
            f'LOAD {reminder}',
            f'ADD {divisor}',
            f'STORE {reminder}',
            f'{label_reminder_positive_end[1]}',
            f'JUMP {label_start_loop[2]}',
            f'{label_end_loop[2]}',
            f'LOAD {quotient}',
            f'INC',
            negate_number(),
            f'JUMP {label_return[2]}',
            f'{label_return_m_one2}',
            f'LOAD {minus_one}',
            f'JUMP {label_return[6]}',
        ]

        code_d_negative_n_negative: List[str] = [
            f'{label_d_negative_n_negative}',
            negate_number(),
            f'STORE{number}',  # save left value
            f'STORE {reminder}',
            compare_values_knowing_registers(divisor, number),
            f'JZERO {label_return_one2}',
            self.generate_code_for_log(number, log, quotient),
            f'STORE {log}',
            f'LOAD {divisor}',
            f'SHIFT {log}',  # shift log(N)
            f'STORE {divisor}',
            f'SUB 0',
            f'STORE {quotient}',
            f'{label_start_loop[1]}',
            f'LOAD {log}',
            f'DEC',
            f'STORE {log}',
            f'JNEG {label_end_loop[1]}',
            f'LOAD {reminder}',
            f'SHIFT {one}',
            f'SUB {divisor}',
            f'STORE {reminder}',
            f'JNEG {label_reminder_negative[3]}',
            f'LOAD {quotient}',
            f'SHIFT {one}',
            f'INC',
            f'STORE {quotient}',
            f'JUMP {label_reminder_positive_end[3]}',
            f'{label_reminder_negative[3]}',
            f'LOAD {quotient}',
            f'SHIFT {one}',
            f'STORE {quotient}',
            f'LOAD {reminder}',
            f'ADD {divisor}',
            f'STORE {reminder}',
            f'{label_reminder_positive_end[3]}',
            f'JUMP {label_start_loop[1]}',
            f'{label_end_loop[1]}',
            f'LOAD {quotient}',
            f'JUMP {label_return[7]}',
            f'{label_return_one2}',
            f'LOAD {one}',
            f'{label_return[0]}',
            f'{label_return[1]}',
            f'{label_return[2]}',
            f'{label_return[3]}',
            f'{label_return[4]}',
            f'{label_return[5]}',
            f'{label_return[6]}',
            f'{label_return[7]}',
        ]

        return f'## BEGIN restoring div\n' + '\n'.join(code_start) + '\n' + '\n'.join(code_d_positive_n_negative) + \
               '\n' + '\n'.join(code_d_negative) + '\n' + '\n'.join(code_d_negative_n_negative) + '\n' +\
               f'## END restoring div\n'
    def _generate_code_for_division_or_modulo(
            self, expression: ExpressionHavingTwoValues,
            is_modulo: bool) -> str:
        if isinstance(expression.valueLeft, IntNumberValue) and isinstance(
                expression.valueRight, IntNumberValue):
            if expression.valueRight.value != 0:
                if is_modulo:
                    return generate_number(
                        expression.valueLeft.value %
                        expression.valueRight.value, self.visitor.constants, 0)
                else:
                    return generate_number(
                        expression.valueLeft.value //
                        expression.valueRight.value, self.visitor.constants, 0)
            else:
                return generate_number(0, self.visitor.constants)

        divisor = 22
        divisor_abs = 15
        number = 23
        number_abs = 16
        reminder = 17
        quotient = 18
        counter = 19
        log = 20
        register_to_return = reminder if is_modulo else quotient
        minus_one = self.visitor.declared_variables[self.MINUS_ONE_VAR_NAME]
        one = self.visitor.declared_variables[self.ONE_VAR_NAME]

        label_zero = self.visitor.label_provider.get_label()
        label_start = self.visitor.label_provider.get_label()
        label_end = self.visitor.label_provider.get_label()
        label_if = self.visitor.label_provider.get_label()
        label_end2 = self.visitor.label_provider.get_label()
        label_divisor_neg = self.visitor.label_provider.get_label()
        label_number_neg = self.visitor.label_provider.get_label()
        label_both_neg = self.visitor.label_provider.get_label()
        label_finish = self.visitor.label_provider.get_label()
        label_finish1 = self.visitor.label_provider.get_label()
        label_finish2 = self.visitor.label_provider.get_label()

        code_1: List[str] = [
            f'## BEGIN div',
            generate_code_for_loading_value(expression.valueRight,
                                            self.visitor),
            f'STORE {divisor}',  # save right value
            f'JZERO {label_zero}',  # if right value is 0, we can end returning 0
            f'SUB 0',
            f'STORE {reminder}',
            f'STORE {quotient}',  # quotient = 0, reminder = 0
            generate_code_for_loading_value(expression.valueLeft,
                                            self.visitor),
            f'STORE{number}',  # save left value
            generate_abs(self.visitor.label_provider),
            f'STORE{number_abs}',
            f'LOAD{divisor}',
            generate_abs(self.visitor.label_provider),
            f'STORE{divisor_abs}',  # division uses only positive numbers, so abs was called
            # f'LOAD {number_abs}',
            # f'SHIFT {one}',
            # f'STORE {number_copy}',
            self.generate_code_for_log(number_abs, counter,
                                       21),  # we iterate log(n) + 1 times
            f'INC',
            f'STORE {counter}',  # counter = log(n) + 1
            f'INC',
            f'STORE {log}',
        ]
        code_2: List[str] = [
            f'{label_start}',  # beginning of a loop
            f'LOAD {log}',
            f'DEC',
            f'STORE {log}',
            f'JZERO {label_end}',
            f'LOAD {reminder}',
            f'SHIFT {one}',
            f'STORE {reminder}',  # reminder = reminder << 1
            self.generate_code_for_load_ith_bit(number_abs, counter),
            f'ADD {reminder}',
            f'STORE {reminder}',  # reminder = reminder + counter'th bit of number; R(0) = N(counter)
            compare_values_knowing_registers(reminder, divisor_abs),
            f'JNEG {label_if}',  # if reminder >= divisor_abs, if not jump to label_if
            f'STORE {reminder}',  # reminder = reminder - divisor_abs
            f'LOAD {quotient}',
            f'INC',
            f'STORE {quotient}',  # quotient++
            f'{label_if}',
            f'LOAD {quotient}',
            f'SHIFT {one}',
            f'STORE {quotient}',  # quotient << 1
            f'LOAD {counter}',
            f'DEC',
            f'STORE {counter}',  # counter--
            f'JUMP {label_start}',
        ]

        code_3 = [
            f'{label_zero}',
            f'SUB 0',  # load zero
            f'JUMP {label_end2}',  # work is done
            f'{label_end}',  # end of loop, almost ready to return values
            f'LOAD {quotient}',
            f'SHIFT {minus_one}',
            f'STORE {quotient}',  # quotient = quotient >> 1,
            # because in the last iteration it was shifted left unnecessarily
        ]
        #  return
        code_4 = [
            f'LOAD {divisor}',
            f'JNEG {label_divisor_neg}',  # here divisor is positive so reminder will be positive
            f'LOAD {number}',
            f'JNEG {label_number_neg}',
            f'JUMP {label_finish}',
            f'{label_divisor_neg}',
            f'LOAD {number}',
            f'JNEG {label_both_neg}',
            f'LOAD {quotient}',
            f'INC',
            negate_number(),
            f'STORE {quotient}',
            f'LOAD {reminder}',
            f'SUB {divisor_abs}',
            f'STORE {reminder}',
            f'JUMP {label_finish1}',
            f'{label_number_neg}',  # here divisor is positive and number is negative
            f'LOAD {quotient}',
            f'INC',
            negate_number(),
            f'STORE {quotient}',
            f'LOAD {divisor_abs}',
            f'SUB {reminder}',
            f'STORE {reminder}',
            f'JUMP {label_finish2}',
            f'{label_both_neg}',
            f'LOAD {reminder}',
            negate_number(),
            f'STORE {reminder}',
            f'{label_finish}',
            f'{label_finish1}',
            f'{label_finish2}',
            f'LOAD {register_to_return}',
            f'{label_end2}',
        ]
        return '\n'.join(code_1) + '\n' + \
               '\n'.join(code_2) + '\n' + \
               '\n'.join(code_3) + '\n' + \
               '\n'.join(code_4) + '\n## END div\n'
示例#10
0
def generate_code_for_write_command(write_command: WriteCommand,
                                    visitor: 'ASTInterpreter') -> str:
    result: str = '## BEGIN write command\n' + \
        generate_code_for_loading_value(write_command.value, visitor)
    return result + 'PUT\n' + '## END write command\n'