Example #1
0
    def semantic_analysis(self, messenger):
        if not super().semantic_analysis(messenger):
            return False

        self._type_stack = [
            type_specifier.TypeSpecifier(type_specifier.TypeSpecifier.BOOL)
        ]
        return True
Example #2
0
 def enterBase_type(self, ctx: CParser.Base_typeContext):
     """
     Leaf of base_type, adds base_type to parent node.
     :param ctx:
     :return:
     """
     value = ctx.getText()
     self._parent_node: TypedNode.TypedNode
     self._parent_node.set_base_type(type_specifier.TypeSpecifier(value))
Example #3
0
    def semantic_analysis(self, messenger: messages.MessageGenerator):
        """
        add printf and scanf to the symbol table
        :param messenger:
        :return:
        """

        # printf
        var_id = "printf"
        ret_type = type_specifier.TypeSpecifier(type_specifier.TypeSpecifier.INT)
        signature = [
            [type_specifier.TypeSpecifier(type_specifier.TypeSpecifier.CHAR),
             type_specifier.TypeSpecifier(type_specifier.TypeSpecifier.POINTER)],

            [type_specifier.TypeSpecifier(type_specifier.TypeSpecifier.ANY)]
        ]

        func_type = type_specifier.TypeSpecifier(type_specifier.TypeSpecifier.FUNCTION)
        func_type.function_signature = signature

        type_stack = [ret_type, func_type]

        printf_attr = Attributes.Attributes(type_stack, 0, 0)
        printf_attr.llvm_name = var_id

        self._parent_node.add_to_scope_symbol_table(var_id, printf_attr)

        # scanf
        var_id = "scanf"
        ret_type = type_specifier.TypeSpecifier(type_specifier.TypeSpecifier.INT)
        signature = [
            [type_specifier.TypeSpecifier(type_specifier.TypeSpecifier.CHAR),
             type_specifier.TypeSpecifier(type_specifier.TypeSpecifier.POINTER)],

            [type_specifier.TypeSpecifier(type_specifier.TypeSpecifier.ANY)]
        ]
        func_type = type_specifier.TypeSpecifier(type_specifier.TypeSpecifier.FUNCTION)
        func_type.function_signature = signature
        type_stack = [ret_type, func_type]
        scanf_attr = Attributes.Attributes(type_stack, 0, 0)
        scanf_attr.llvm_name = "scanf"
        self._parent_node.add_to_scope_symbol_table(var_id, scanf_attr)

        return True
    def constant_folding(self):

        super().constant_folding()

        if isinstance(self._left_expression, ConstantExpressionNode) and \
                isinstance(self._right_expression, ConstantExpressionNode):

            val1 = self._left_expression.constant
            val2 = self._right_expression.constant

            type = self._left_expression.type_stack[-1]
            spec = None
            if type == type_specifier.TypeSpecifier.INT or type == type_specifier.TypeSpecifier.POINTER:
                val1 = int(val1)
                val2 = int(val2)
                spec = type_specifier.TypeSpecifier.INT
            elif type == type_specifier.TypeSpecifier.FLOAT:
                val1 = float(val1)
                val2 = float(val2)
                spec = type_specifier.TypeSpecifier.FLOAT
            elif type == type_specifier.TypeSpecifier.CHAR:
                val1 = ord(val1)
                val2 = ord(val2)
                spec = type_specifier.TypeSpecifier.CHAR
            res_val = 0
            if self._operator == Operator.PLUS:
                res_val = val1 + val2

            elif self._operator == Operator.MINUS:
                res_val = val1 - val2

            elif self._operator == Operator.MULTIPLY:
                res_val = val1 * val2

            elif self._operator == Operator.DIVIDE:
                res_val = val1 / val2

            node = ConstantExpressionNode(self._parent_node, self._ctx)
            node.type_stack_ref().append(type_specifier.TypeSpecifier(spec))
            node.constant = str(res_val)
            index = self._parent_node.get_child_index(self)
            self._parent_node.remove_child(self)
            self._parent_node.add_child(node, index)
    def generate_secondary_type(self, node: "ExpressionNode.ExpressionNode",
                                messenger: messages.MessageGenerator):
        """
        Function requires an expressionNode and adjust this node's type trough it's type stack.
        This node modifies the ExpressionNode state in type_stack and l_value(bool that tell's if l or r val)

        :param ExpressionNode node: ExpressionNode that we are modifying.
        :param MessageGenerator messenger: A messageGenerator that we use to generate error messages
        :return: bool: True if the modification's are legal, False if they are not.
        """
        if not self._type_modifier_node:
            if len(self._children) < 1:
                self._param_list_node = None
        else:
            if len(self._children) < 2:
                self._param_list_node = None

        # Check the type_modifier subtree. Children of this type modifier node get to modify the type stack first.
        if self._type_modifier_node:
            if not self._type_modifier_node.generate_secondary_type(
                    node, messenger):
                return False

        # else this node should be applied first == base

        # Meaning the Dereference operator
        if self._modifier_type == type_specifier.TypeSpecifier.POINTER:
            # We can only dereference pointer types.
            if node.type_stack_ref(
            )[-1].value == type_specifier.TypeSpecifier.POINTER:
                # If we dereference the type loses it's 'ptr' type
                node.type_stack_ref().pop()
                # Dereference operator returns a lvalue
                node.l_value = True

            else:
                messenger.error_unary_not_ptr(self._line, self._column)
                return False

        # Ref operator value becomes an address
        elif self._modifier_type == type_specifier.TypeSpecifier.ADDRESS:
            if node.l_value:
                # At the right side POINTER means address of. Used for type matching but maybe i should create
                # an alias to make this line more clear.
                node.type_stack_ref().append(
                    type_specifier.TypeSpecifier(
                        type_specifier.TypeSpecifier.POINTER))
                node.l_value = False

            else:
                messenger.error_lvalue_required_addr(node.line, node.column)
                return False

        # Function call,
        elif self._modifier_type == type_specifier.TypeSpecifier.FUNCTION:
            # We require a function. In C you can call pointers to functions so this must be extended.
            if node.type_stack_ref(
            )[-1] == type_specifier.TypeSpecifier.FUNCTION:
                # The parameter's calls their expression's need to be checked for correctness.
                self._param_list_node.semantic_analysis(messenger)
                # for simplicity we == is overloaded. We can go in more detail about the function signatures as
                # extension

                if self.get_function_signature() == node.type_stack_ref(
                )[-1].function_signature:
                    node.type_stack_ref().pop()

                else:
                    if not self._check_any_consistent(
                            node.type_stack_ref()[-1].function_signature):
                        messenger.error_signature_does_not_match(
                            self._line, self._column)
                        return False

            else:
                messenger.error_object_not_function(self._line, self._column)
                return False

        # Array's
        elif self._modifier_type == type_specifier.TypeSpecifier.ARRAY:
            # First check if we can subscript.
            if not node.type_stack_ref(
            )[-1] == type_specifier.TypeSpecifier.ARRAY:
                messenger.error_subscript_not_array(self.line, self.column)
                return False

            if not self._param_list_node:
                messenger.error_expected_expression(self.line, self.column)
                return False
            self._param_list_node.semantic_analysis(messenger)
            if not self._param_list_node.type_stack[
                    -1] == type_specifier.TypeSpecifier.INT:
                messenger.error_subscript_not_integer(self.line, self.column)
                return False
            node.type_stack_ref().pop()

        return True
Example #6
0
 def modifier_type(self, val):
     if isinstance(val, str):
         val = type_specifier.TypeSpecifier(val)
     self._modifier_type = val
Example #7
0
    def llvm_load(self, get_l_val: bool = False) -> str:
        """
        Will load this variable into a register
        :return: a string that loaded the value of the var into the register
        """

        # Modification
        stack: type_specifier.TypeStack = []

        # If marked as an natural l val (like identifier's) we need to dereference once in LLVM
        if self.code_l_value and not get_l_val:
            stack = [
                type_specifier.TypeSpecifier(
                    type_specifier.TypeSpecifier.POINTER)
            ]

        stack += self._generate_type_operator_stack()
        # Type of node
        attr = self._parent_node.get_attribute(self._place_of_value)
        type_stack = list(attr.operator_stack)
        self._place_of_value = attr.llvm_name
        ret_string = ''
        if self._type_modifier_node:
            self._type_modifier_node.reset_used_switches()
        while stack:
            element: type_specifier.TypeSpecifier = stack.pop()
            if element == type_specifier.TypeSpecifier.FUNCTION:

                # Function calls are trickier we need to have the call argument's in place we do that in the next block
                param_node = self._get_param_node()
                ret_string += param_node.llvm_load_params()

                # Next up we make a string for the parameter call
                child_list: List[ExpressionNode] = param_node.get_children()
                # the children know where there values are loaded into in child.llv_value
                children_their_strings = []
                for child in child_list:
                    child_string = ''.join([
                        type_child.llvm_type for type_child in child.type_stack
                    ])
                    child_string += f' {child.llvm_value}'
                    children_their_strings.append(child_string)
                call_string = '(' + ', '.join(children_their_strings) + ')'

                stack.pop()
                self._is_global = False
                # Now for the actual call we will load the call value into a new temporal register
                self.increment_register_index()

                ret_string += f'{self.code_indent_string()}%{self.register_index} = call'
                ret_string += f' {"".join([child.llvm_type for child in self._type_stack])}'

                if self._parent_node.is_in_table(self._place_of_value):
                    attr_stack = self._parent_node.get_attribute(
                        self._place_of_value).operator_stack
                    if attr_stack[-1].function_signature and attr_stack[
                            -1].function_signature[-1] == [
                                type_specifier.TypeSpecifier.ANY
                            ]:
                        ret_string += '( i8*, ...) '

                ret_string += f' @{self._place_of_value}{call_string}\n'
                self._place_of_value = self.register_index

            elif element == type_specifier.TypeSpecifier.POINTER:

                stack_string = "".join(
                    [child.llvm_type for child in type_stack])
                call_global = '@' if self.is_in_global_table(
                    str(self._place_of_value)) else '%'
                self.increment_register_index()
                ret_string += f'{self.code_indent_string()}%{self.register_index} = load '
                ret_string += f'{stack_string}, '
                ret_string += f'{stack_string}* {call_global}{self._place_of_value}\n'
                self._place_of_value = self.register_index
                self._is_global = False
                if type_stack:
                    type_stack.pop()

            elif element == type_specifier.TypeSpecifier.ADDRESS:
                item = stack.pop()
                assert (item == type_specifier.TypeSpecifier.POINTER), f"We dereference something else then addr " \
                    f"type This: {item} "

            elif element == type_specifier.TypeSpecifier.ARRAY:
                arr_node = self._type_modifier_node.get_bottom_arr()

                ret_string += arr_node.expression_node.llvm_load()
                self.increment_register_index()

                inbound_type = "".join(
                    [child.llvm_type for child in type_stack])
                arr_type = f'[{attr.array_size} x {inbound_type}]'
                ret_string += f'{self.code_indent_string()}%{self.register_index} = getelementptr {arr_type},'
                ret_string += f' {arr_type}* %{self._place_of_value}, i32 0, '
                ret_string += f'i32 {arr_node.expression_node.llvm_value}\n'
                self._place_of_value = self.register_index
                # stack.append(type_specifier.TypeSpecifier(type_specifier.TypeSpecifier.POINTER))

        return ret_string
Example #8
0
    def set_base_type(self, tp):

        if isinstance(tp, str):
            tp = type_specifier.TypeSpecifier(tp)

        self._type_stack.append(tp)
Example #9
0
    def enterExpression_postfix(self, ctx: CParser.Expression_postfixContext):
        val = ctx.getChild(0).getChild(0).getText()

        val = '[]' if val == '[' else '()'
        self._parent_node.modifier_type = type_specifier.TypeSpecifier(val)
Example #10
0
 def enterExpression_prefix(self, ctx: CParser.Expression_prefixContext):
     val = ctx.getChild(0).getText()
     self._parent_node.modifier_type = type_specifier.TypeSpecifier(val)