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
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))
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
def modifier_type(self, val): if isinstance(val, str): val = type_specifier.TypeSpecifier(val) self._modifier_type = val
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
def set_base_type(self, tp): if isinstance(tp, str): tp = type_specifier.TypeSpecifier(tp) self._type_stack.append(tp)
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)
def enterExpression_prefix(self, ctx: CParser.Expression_prefixContext): val = ctx.getChild(0).getText() self._parent_node.modifier_type = type_specifier.TypeSpecifier(val)