def generate_code_for_load_ith_bit(number_reg: int, i_reg: int) -> str:
        number_shifted_i_reg = 10
        number_shifted_i_minus_one_reg = 11
        decremented_i = 12
        minus_decremented_i = 13
        negated_i = 14
        result: List[str] = [
            f'LOAD {i_reg}',
            negate_number(),
            f'STORE {negated_i}',
            f'INC',
            f'STORE {minus_decremented_i}',
            negate_number(),
            f'STORE {decremented_i}',
            f'LOAD {number_reg}',
            f'SHIFT {minus_decremented_i}',
            f'SHIFT {decremented_i}',
            f'STORE {number_shifted_i_minus_one_reg}',
            f'LOAD {number_reg}',
            f'SHIFT {negated_i}',
            f'SHIFT {i_reg}',
            f'STORE {number_shifted_i_reg}',
            f'LOAD {number_shifted_i_minus_one_reg}',
            f'SUB {number_shifted_i_reg}',
            f'SHIFT {minus_decremented_i}',
        ]

        return '\n'.join(result) + '\n'
 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]
    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'