コード例 #1
0
    def compile(self, assembler):
        """Compile this statement

        Args:
            assembler (Assembler): the assembler to use

        Returns:
            CompiledObject: the compiled version of this statement
        """
        value = bytearray()
        relocation_objects = []
        for statement in self.statement_sequence:
            compiled_object = statement.compile(assembler)
            if compiled_object is None:
                continue
            reloc_objects = compiled_object.relocation_objects
            for relocation_object in reloc_objects:
                additional_offset = len(value)
                relocation_object.offset += additional_offset
                relocation_objects.append(relocation_object)
            value += compiled_object.value

        size = len(value)
        compiled_object = CompiledObject('compoundStatement', size, value,
                                         CompiledObjectType.code,
                                         relocation_objects)
        return compiled_object
コード例 #2
0
ファイル: assignment.py プロジェクト: eternalSeeker/pcc
    def compile_stack_variable(self, assembler, stack_variable):
        """Compile an assignment of an stack variable.

        Args:
            assembler (Assembler): the assembler to use
            stack_variable (StackVariable): the retrieved stack variable

        Returns:
            CompiledObject: the compiled version of this assignment
        """
        value = bytearray()
        stack_offset = stack_variable.stack_offset
        size = stack_variable.size
        if stack_variable.type_name == 'double':
            register = ProcessorRegister.double_scalar_0
        elif stack_variable.type_name == 'float':
            register = ProcessorRegister.single_scalar_0
        else:
            register = ProcessorRegister.accumulator
        compiled_code, relocation_objects = \
            self.initializer_exp.load_result_to_reg(register, assembler)
        for relocation_object in relocation_objects:
            additional_offset = len(value)
            relocation_object.offset += additional_offset
        value += compiled_code
        value += assembler.copy_reg_to_stack(stack_offset, register)
        compiled_object = CompiledObject(self.id, size, value,
                                         CompiledObjectType.code,
                                         relocation_objects)
        return compiled_object
コード例 #3
0
    def compile(self, assembler):
        """Compile this statement

        Args:
            assembler (Assembler): the assembler to use

        Returns:
            CompiledObject: the compiled version of this statement
        """
        value = bytearray()

        if_part = self.if_statement.compile(assembler)

        # compare the value from the condition, to 0. If not equal,
        # go to the if part, else to the else part if present.
        condition_reg = ProcessorRegister.accumulator
        condition_code, relocation_objects = \
            self.condition.load_result_to_reg(condition_reg, assembler)
        value += condition_code

        compare_register = ProcessorRegister.counter
        value_to_load = 0
        value += assembler.copy_value_to_reg(value_to_load, compare_register)

        value += assembler.cmp(condition_reg, compare_register)

        jump_distance = len(if_part.value)
        if self.else_statement:
            else_part = self.else_statement.compile(assembler)
            jump_distance_else = len(else_part.value)
            # if there if an else part, the last instruction of the if part
            # is the jump over the else part.
            jump_distance += len(assembler.jmp(jump_distance_else))

        value += assembler.je(jump_distance)
        for relocation_object in if_part.relocation_objects:
            additional_offset = len(value)
            relocation_object.offset += additional_offset
            relocation_objects.append(relocation_object)
        value += if_part.value

        if self.else_statement:
            # jump over the else part (for the if part)
            value += assembler.jmp(jump_distance_else)
            for relocation_object in else_part.relocation_objects:
                additional_offset = len(value)
                relocation_object.offset += additional_offset
                relocation_objects.append(relocation_object)
            # the actual else part
            value += else_part.value

        size = len(value)
        compiled_object = CompiledObject('if', size, value,
                                         CompiledObjectType.code,
                                         relocation_objects)
        return compiled_object
コード例 #4
0
    def compile_internal_variable(self, assembler, size):
        """Compile a non-external variable

        Args:
            assembler (Assembler): the assembler to use
            size (int): the size of the type of this variable

        Returns:
            CompiledObject: the compiled version of this variable
        """
        value = bytearray()
        if self.parent_node.parent_node:
            if self.initializer:
                stack_variable = self.stack_var
                stack_offset = stack_variable.stack_offset
                if stack_variable.type_name == 'double':
                    register = ProcessorRegister.double_scalar_0
                elif stack_variable.type_name == 'float':
                    register = ProcessorRegister.single_scalar_0
                else:
                    register = ProcessorRegister.accumulator

                compiled_code, relocation_objects = \
                    self.initializer.load_result_to_reg(register, assembler)
                value += compiled_code
                value += assembler.copy_reg_to_stack(stack_offset, register)
                compiled_object = CompiledObject(self.name, size, value,
                                                 CompiledObjectType.data,
                                                 relocation_objects)
            else:
                compiled_object = CompiledObject(self.name, size, value,
                                                 CompiledObjectType.data)
        else:
            if self.initializer:
                value = self.initializer_to_bytearray(size)
            compiled_object = CompiledObject(self.name, size, value,
                                             CompiledObjectType.data)
        return compiled_object
コード例 #5
0
    def compile(self, _):
        """Compile this statement.

        Args:
            _ (Assembler): the assembler to use, unused but required because
                inheritance prototype.

        Returns:
            CompiledObject: the compiled version of this statement
        """
        value = bytearray()
        size = 0
        compiled_object = CompiledObject(self.name, size, value,
                                         CompiledObjectType.code)

        return compiled_object
コード例 #6
0
ファイル: assignment.py プロジェクト: eternalSeeker/pcc
    def compile_global_variable(self, assembler, identifier):
        """Compile an assignment of an stack variable.

        Args:
            assembler (Assembler): the assembler to use
            identifier (str): the identifier of the resulting variable

        Returns:
            CompiledObject: the compiled version of this assignment
        """
        value = bytearray()
        node = self.get_global_symbol(identifier)
        if node is None:
            file_name = 'unknown'
            line_number = -1
            message = f'could not fine the identifier {identifier}'
            pcc.utils.warning.error(file_name, line_number, message)
            return None
        variable_type = node.variable_type
        if variable_type.name == 'double':
            register = ProcessorRegister.double_scalar_0
        elif variable_type.name == 'float':
            register = ProcessorRegister.single_scalar_0
        else:
            register = ProcessorRegister.accumulator

        compiled_code, relocation_objects = \
            self.initializer_exp.load_result_to_reg(register, assembler)

        value += compiled_code

        # use a 0 displacement as the linker will fill it in
        compiled_code, displacement_offset = \
            assembler.mov_to_displacement(register, displacement=0)
        offset = len(value) + displacement_offset
        value += compiled_code
        # the offset in the symbol is 4
        addend = -4
        size = len(value)
        relocation_object = RelocationObject(node.name, offset,
                                             CompiledObjectType.data, addend)
        relocation_objects.append(relocation_object)
        compiled_object = CompiledObject(self.id, size, value,
                                         CompiledObjectType.code,
                                         relocation_objects)

        return compiled_object
コード例 #7
0
    def compile(self, assembler):
        """Compile this statement

        Args:
            assembler (Assembler): the assembler to use

        Returns:
            CompiledObject: the compiled version of this statement
        """
        value = bytearray()

        if self.expression:
            return_type = self.get_return_type()
            if return_type == 'double':
                reg = ProcessorRegister.double_scalar_0
            elif return_type == 'float':
                reg = ProcessorRegister.single_scalar_0
            else:
                reg = ProcessorRegister.accumulator
            compiled_code, rela_objects = \
                self.expression.load_result_to_reg(reg, assembler)
            value += compiled_code
        else:
            rela_objects = []

        # set the base pointer as the new stack pointer
        src = ProcessorRegister.base_pointer
        dest = ProcessorRegister.frame_pointer
        ret = assembler.copy_from_reg_to_reg(destination=dest,
                                             source=src)
        value.extend(ret)

        # restore the frame pointer from stack
        ret = assembler.pop_from_stack(ProcessorRegister.base_pointer)
        value.extend(ret)

        # return to the called function
        ret = assembler.return_to_caller()
        value.extend(ret)

        size = len(value)
        compiled_object = CompiledObject(self.expression, size,
                                         value, CompiledObjectType.code,
                                         rela_objects)
        return compiled_object
コード例 #8
0
ファイル: while_statement.py プロジェクト: eternalSeeker/pcc
    def compile(self, assembler):
        """Compile this statement

        Args:
            assembler (Assembler): the assembler to use

        Returns:
            CompiledObject: the compiled version of this statement
        """
        value = bytearray()

        body_part = self.body_statement.compile(assembler)

        # compare the value from the condition, to 0. If not equal,
        # go to the if part, else to the else part if present.
        condition_reg = ProcessorRegister.accumulator
        condition_code, relocation_objects = \
            self.condition.load_result_to_reg(condition_reg, assembler)
        value += condition_code

        body_len = len(body_part.value)

        # the distance over the body is the length of the body as well as the
        # jump back at the end. Just encode a random length to calc this length
        jump_over_body = body_len + len(assembler.jmp(body_len))

        value += assembler.cmp_against_const(condition_reg, const=0)
        value += assembler.je(jump_over_body)

        len_condition = len(value)

        value += body_part.value
        # the distance to jump back, is the relative distance after the jump
        # instruction. So the complete distance is the length of the body,
        # the length of the condition and this jump (use the length of a
        # random jump to know the length)
        jump_back_dist = -len_condition - body_len - \
            len(assembler.jmp(0))
        value += assembler.jmp(jump_back_dist)

        size = len(value)
        compiled_object = CompiledObject('if', size, value,
                                         CompiledObjectType.code,
                                         relocation_objects)
        return compiled_object
コード例 #9
0
    def compile(self, assembler):
        """Compile this statement

        Args:
            assembler (Assembler): the assembler to use

        Returns:
            CompiledObject: the compiled version of this statement
        """
        size = self.variable_type.size
        value = bytearray()
        if self.is_extern:
            size = 0
            compiled_object = CompiledObject(self.name, size, value,
                                             CompiledObjectType.data)
        else:
            compiled_object = self.compile_internal_variable(assembler, size)

        return compiled_object
コード例 #10
0
ファイル: function_call.py プロジェクト: eternalSeeker/pcc
    def compile(self, assembler):
        """Compile this statement

        Args:
            assembler (Assembler): the assembler to use

        Returns:
            CompiledObject: the compiled version of this statement
        """
        pass
        value = bytearray()
        relocation_objects = []

        # load all variables in the registers
        compiled_code, rela_objs = \
            self._copy_argmuments_to_registers(assembler)
        relocation_objects += rela_objs
        value += compiled_code

        node = self.get_global_symbol(self.id)
        compiled_code, displacement_offset = \
            assembler.call(displacement=0)
        offset = len(value) + displacement_offset
        value += compiled_code
        # the offset in the symbol is 4
        addend = -4
        relocation_object = RelocationObject(node.name, offset,
                                             CompiledObjectType.code, addend)
        relocation_objects.append(relocation_object)

        size = len(value)
        compiled_object = CompiledObject(self.id, size, value,
                                         CompiledObjectType.code,
                                         relocation_objects)

        return compiled_object
コード例 #11
0
    def compile(self, assembler):
        """Compile this statement.

        Args:
            assembler (Assembler): the assembler to use

        Returns:
            CompiledObject: the compiled version of this statement
        """
        value = bytearray()

        # save the frame pointer on stack
        ret = assembler.push_to_stack(ProcessorRegister.base_pointer)
        value.extend(ret)

        # set the stack pointer as the new base pointer
        dest = ProcessorRegister.base_pointer
        src = ProcessorRegister.frame_pointer
        ret = assembler.copy_from_reg_to_reg(destination=dest,
                                             source=src)
        value.extend(ret)

        current_list = []
        self.add_stack_variable(current_list)
        # first the frame pointer has been saved to stack
        stack_offset = 0
        for stack_var in current_list:
            stack_var.stack_start = stack_offset
            value_array = stack_var.initializer_byte_array
            value, stack_offset = push_variable_on_stack(assembler,
                                                         stack_offset,
                                                         value,
                                                         value_array)
            stack_var.stack_offset = stack_offset

        self.stack_variable_list = current_list

        reg = ProcessorRegister.counter
        # allign the stack to a multiple of 16
        # stack_offset is a negative number that is rounded to a multiple
        # of 16, stack_offset=12 -> allinged_stack_size=16
        allinged_stack_size = 16*((-stack_offset)//16 + 1)
        value += assembler.copy_value_to_reg(imm_value=allinged_stack_size,
                                             destination=reg)
        value += assembler.sub(source=reg,
                               destination=ProcessorRegister.frame_pointer)

        # add a nop
        ret = assembler.nop()
        value.extend(ret)

        value += self._copy_argmuments_to_stack(assembler)

        relocation_objects = []
        for statement in self.statement_sequence:
            compiled_object = statement.compile(assembler)
            if compiled_object is None:
                continue
            reloc_objects = compiled_object.relocation_objects
            for relocation_object in reloc_objects:
                additional_offset = len(value)
                relocation_object.offset += additional_offset
                relocation_objects.append(relocation_object)
            value += compiled_object.value

        size = len(value)
        compiled_object = CompiledObject(self.statement_sequence[0].name, size,
                                         value, CompiledObjectType.code,
                                         relocation_objects)

        return compiled_object