def add_type(self, name: str, lineno, col_num, storage, eltype=None, check=True): """Add a new type definition with the details""" if check and self.is_defined(name): print_error() print(f"Re-declaration of type '{name}' at line {lineno}") print_line(lineno) pos = col_num - 1 width = len(name) print_marker(pos, width) other_type = self.get_type(name) print(f"{name} previously declared at line {other_type.lineno}") print_line(other_type.lineno) pos = other_type.col_num - 1 print_marker(pos, width) new_type = TypeInfo(name, lineno, col_num, storage, eltype) self.type_map[name] = new_type
def check_unused(self): func_type = self.type_table.get_type("FUNCTION") for symbol in self.symbols: if (symbol.uses == [] and symbol.scope_id != "1" and symbol.type_ != func_type): print_error("Unused variable", kind="ERROR") print( f"Variable {symbol.name} is defined at line {symbol.lineno} " "but never used.") print_line(symbol.lineno) pos = symbol.col_num - 1 width = len(symbol.name) print_marker(pos, width) if utils.package_name == "main": main_fn = self.get_symbol("main") if main_fn is None: print_error("main is undeclared in package main", kind="ERROR") print( "main function is not declared in a file with 'main' package" )
def p_error(p: lex.LexToken): print(f"{Fore.RED}SYNTAX ERROR:{Style.RESET_ALL}") if p is not None: col = find_column(p) print(f"at line {p.lineno}, column {col}") print_line(p.lineno) # print(" " * 10, " \t", " " * (col - 1), "^", sep="") print_marker(col - 1, len(p.value)) else: print("Unexpected end of file")
def t_ANY_error(t): print_lexer_error(f"Illegal character {t.value[0]}") col = find_column(t) print(f"at line {t.lineno}, column {col}") print( f"{Fore.GREEN}{t.lineno:>10}:\t{Style.RESET_ALL}", lines[t.lineno - 1], sep="", ) print_marker(col - 1, 1) t.lexer.skip(1)
def t_ANY_UNCLOSED_MULTI_COMMENT(t): r"/\*(.|\n)*" print_lexer_error("Unclosed Multiline comment") col = find_column(t) print(f"at line {t.lineno}, column {col}") print( f"{Fore.GREEN}{t.lineno:>10}:\t{Style.RESET_ALL}", lines[t.lineno - 1], sep="", ) print_marker(col - 1, 1)
def p_OperandName(p): """OperandName : IDENTIFIER %prec '=' | QualifiedIdent """ if not isinstance(p[1], syntree.QualifiedIdent): ident: Tuple = p[1] sym = symtab.get_symbol(ident[1]) lineno = p.lineno(1) if not symtab.is_declared(ident[1]): print_error() print(f"Undeclared symbol '{ident[1]}' at line {lineno}") print_line(lineno) line: str = utils.lines[lineno - 1] # TODO: get correct position of token rather than searching pos = ident[2] - 1 width = len(ident[1]) print_marker(pos, width) else: sym.uses.append(lineno) p[0] = p[1]
def t_STRING_LIT(t): r"\"[^\"]*\"" # if r"\s*\*/": # print_error("ERROR: Wrong Multiline Comment") # return if "\n" in t.value: print_lexer_error("string cannot contain line breaks") lineno = t.lexer.lineno pos = find_column(t) splits = list(t.value.split("\n")) for i, line_ in enumerate(splits): print_line(lineno) line_actual = lines[lineno - 1] if i == 0: print_marker(pos - 1, len(line_actual) - pos + 1) elif i == len(splits) - 1: print_marker(0, line_actual.find('"') + 1) else: print_marker(0, len(line_actual)) lineno += 1 t.lexer.lineno += t.value.count("\n") return t.value = ("string", t.value) t.lexer.begin("InsertSemi") return t
def declare_new_variable( self, symbol: str, lineno: int, col_num: int, type_=None, const=False, value=None, ): """Helper function to add symbol to the Symbol Table with declaration set to given line number. Prints an error if the symbol is already declared at current depth. """ if self.is_declared_in_cur_symtab(symbol): print_error() print(f"Re-declaration of symbol '{symbol}' at line {lineno}") print_line(lineno) pos = col_num - 1 width = len(symbol) print_marker(pos, width) other_sym = self.get_symbol(symbol) print(f"{symbol} previously declared at line {other_sym.lineno}") print_line(other_sym.lineno) pos = other_sym.col_num - 1 print_marker(pos, width) else: self.update_info(symbol, lineno, col_num=col_num, type_=type_, const=const, value=value)
def update_info(self, symbol: str, lineno, col_num=None, type_=None, const=None, value=None): sym = self.get_symbol(symbol) sym.lineno = lineno sym.type_ = None sym.col_num = col_num # TODO: infer type from value if not given typename = None composite_type = False eltype = None if type_ is not None: # sym.storage = self.storage[type_.data] valid_type = True typename = "" # type_ can sometimes be syntree.Type if hasattr(type_, "data") and hasattr(type_, "name"): if type_.name == "BasicType": typename = type_.data elif type_.name == "ARRAY" or type_.name == "SLICE": typename = type_.typename composite_type = True eltype = type_.eltype else: print(f"Unknown node {type_}. Could not determine type") valid_type = False elif isinstance(type_, str): typename = type_ else: print( f"Could not determine type, issue in code. Found {type_}") valid_type = False if valid_type: if not self.type_table.is_defined(typename): print_error() print(f"Type '{typename}' is not defined at line {lineno}") print_line(lineno) line = utils.lines[lineno] pos = line.find(typename) width = len(typename) print_marker(pos, width) else: sym.type_ = self.type_table.get_type(typename) # elif composite_type: # self.type_table.add_type(f"{typename}_{eltype}") if value is not None: sym.value = value if const is not None: sym.const = const