From 8fc60202ff6af5e9e43f212b6eff26b4748464e7 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Sat, 23 Aug 2025 00:48:58 +0200 Subject: [PATCH] Document symbol bag class and methods --- boot/semantic.cc | 32 ++++++----- boot/symbol.cc | 37 +++++++++--- gcc/elna-builtins.cc | 15 +++++ gcc/elna-generic.cc | 29 +++++----- gcc/elna1.cc | 5 +- include/elna/boot/dependency.h | 1 + include/elna/boot/semantic.h | 2 +- include/elna/boot/symbol.h | 97 +++++++++++++++++++++++++++++--- include/elna/gcc/elna-builtins.h | 2 + 9 files changed, 168 insertions(+), 52 deletions(-) diff --git a/boot/semantic.cc b/boot/semantic.cc index e6dd248..83e0c33 100644 --- a/boot/semantic.cc +++ b/boot/semantic.cc @@ -205,18 +205,16 @@ namespace elna::boot void name_analysis_visitor::visit(type_declaration *definition) { definition->body().accept(this); - auto unresolved_declaration = this->bag.unresolved.at(definition->identifier.identifier); - - unresolved_declaration->reference = this->current_type; + this->bag.resolve(definition->identifier.identifier, this->current_type); } void name_analysis_visitor::visit(named_type_expression *type_expression) { - auto unresolved_alias = this->bag.unresolved.find(type_expression->name); + auto unresolved_alias = this->bag.declared(type_expression->name); - if (unresolved_alias != this->bag.unresolved.end()) + if (unresolved_alias != nullptr) { - this->current_type = type(unresolved_alias->second); + this->current_type = type(unresolved_alias); } else if (auto from_symbol_table = this->bag.lookup(type_expression->name)) { @@ -301,7 +299,11 @@ namespace elna::boot for (const auto& variable_identifier : declaration->identifiers) { - this->bag.enter(variable_identifier.identifier, std::make_shared(this->current_type)); + if (!this->bag.enter(variable_identifier.identifier, std::make_shared(this->current_type))) + { + add_error(variable_identifier.identifier, this->input_file, + declaration->position()); + } } } @@ -441,17 +443,17 @@ namespace elna::boot } bool name_analysis_visitor::check_unresolved_symbol(std::shared_ptr alias, - std::vector& path) + std::vector& alias_path) { - if (std::find(std::cbegin(path), std::cend(path), alias->name) != std::cend(path)) + if (std::find(std::cbegin(alias_path), std::cend(alias_path), alias->name) != std::cend(alias_path)) { return false; } - path.push_back(alias->name); + alias_path.push_back(alias->name); if (auto another_alias = alias->reference.get()) { - return check_unresolved_symbol(another_alias, path); + return check_unresolved_symbol(another_alias, alias_path); } return true; } @@ -462,18 +464,18 @@ namespace elna::boot { type->accept(this); } - for (auto& unresolved : this->bag.unresolved) + for (auto& unresolved : this->bag) { - std::vector path; + std::vector alias_path; - if (check_unresolved_symbol(unresolved.second, path)) + if (check_unresolved_symbol(unresolved.second, alias_path)) { auto info = std::make_shared(type_info(type(unresolved.second))); this->bag.enter(unresolved.first, info); } else { - add_error(path, this->input_file, position{ 0, 0 }); + add_error(alias_path, this->input_file, position{ 0, 0 }); } } for (variable_declaration *const variable : unit->variables) diff --git a/boot/symbol.cc b/boot/symbol.cc index 1651cbb..bab0987 100644 --- a/boot/symbol.cc +++ b/boot/symbol.cc @@ -358,14 +358,20 @@ namespace elna::boot return result; } - symbol_bag::symbol_bag() + symbol_bag::symbol_bag(forward_table&& unresolved, std::shared_ptr global_table) + : unresolved(unresolved) { - this->symbols = std::make_shared(); + this->symbols = std::make_shared(global_table); } - symbol_bag::symbol_bag(forward_table&& unresolved, std::shared_ptr symbols) - : symbols(symbols), unresolved(unresolved) + forward_table::const_iterator symbol_bag::begin() { + return unresolved.cbegin(); + } + + forward_table::const_iterator symbol_bag::end() + { + return unresolved.cend(); } std::shared_ptr symbol_bag::lookup(const std::string& name) @@ -396,18 +402,31 @@ namespace elna::boot this->symbols = child; } - void symbol_bag::leave() + std::shared_ptr symbol_bag::leave() { - this->symbols = this->symbols->scope(); + std::shared_ptr result = this->symbols; + + this->symbols = result->scope(); + return result; } - void symbol_bag::add_import(std::shared_ptr table) + std::shared_ptr symbol_bag::declared(const std::string& symbol_name) { - this->imports.push_front(table); + auto unresolved_alias = this->unresolved.find(symbol_name); + + return unresolved_alias == this->unresolved.end() ? std::shared_ptr() : unresolved_alias->second; + } + + std::shared_ptr symbol_bag::resolve(const std::string& symbol_name, type& resolution) + { + auto unresolved_declaration = this->unresolved.at(symbol_name); + + unresolved_declaration->reference = resolution; + return unresolved_declaration; } void symbol_bag::add_import(const symbol_bag& bag) { - add_import(bag.symbols); + this->imports.push_front(bag.symbols); } } diff --git a/gcc/elna-builtins.cc b/gcc/elna-builtins.cc index 232cf28..fc89fa8 100644 --- a/gcc/elna-builtins.cc +++ b/gcc/elna-builtins.cc @@ -238,6 +238,17 @@ namespace elna::gcc DECL_EXTERNAL(fndecl) = info.symbols == nullptr; } + tree declare_variable(const std::string& name, const boot::variable_info& info, + std::shared_ptr symbols) + { + auto variable_type = get_inner_alias(info.symbol, symbols); + tree declaration_tree = build_decl(UNKNOWN_LOCATION, VAR_DECL, get_identifier(name.c_str()), variable_type); + + symbols->enter(name, declaration_tree); + + return declaration_tree; + } + void rewrite_symbol_table(std::shared_ptr info_table, std::shared_ptr symbols) { for (auto& [symbol_name, symbol_info] : *info_table) @@ -250,6 +261,10 @@ namespace elna::gcc handle_symbol(symbol_name, alias_type, symbols); } } + else if (auto variable_info = symbol_info->is_variable()) + { + declare_variable(symbol_name, *variable_info, symbols); + } else if (auto procedure_info = symbol_info->is_procedure()) { declare_procedure(symbol_name, *procedure_info, symbols); diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 5472061..3baaaa3 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -747,15 +747,15 @@ namespace elna::gcc { for (const auto& variable_identifier : declaration->identifiers) { - this->current_expression = get_inner_alias( - this->bag.lookup(variable_identifier.identifier)->is_variable()->symbol, - this->symbols); - location_t declaration_location = get_location(&declaration->position()); - tree declaration_tree = build_decl(declaration_location, VAR_DECL, - get_identifier(variable_identifier.identifier.c_str()), this->current_expression); - bool result = this->symbols->enter(variable_identifier.identifier, declaration_tree); + tree declaration_tree = this->symbols->lookup(variable_identifier.identifier); + if (declaration_tree == NULL_TREE) + { + auto variable_symbol = this->bag.lookup(variable_identifier.identifier)->is_variable(); + + declaration_tree = declare_variable(variable_identifier.identifier, *variable_symbol, this->symbols); + } // Set initializer if given. if (declaration->body != nullptr) { @@ -771,19 +771,18 @@ namespace elna::gcc print_type(TREE_TYPE(this->current_expression)).c_str()); } } - else if (POINTER_TYPE_P(this->current_expression)) + else if (declaration->is_extern) + { + DECL_EXTERNAL(declaration_tree) = declaration->is_extern; + } + else if (POINTER_TYPE_P(TREE_TYPE(declaration_tree))) { DECL_INITIAL(declaration_tree) = elna_pointer_nil_node; } - DECL_EXTERNAL(declaration_tree) = declaration->is_extern; TREE_PUBLIC(declaration_tree) = variable_identifier.exported; this->current_expression = NULL_TREE; - if (!result) - { - error_at(declaration_location, "Variable '%s' already declared in this scope", - variable_identifier.identifier.c_str()); - } - else if (lang_hooks.decls.global_bindings_p()) + + if (lang_hooks.decls.global_bindings_p()) { TREE_STATIC(declaration_tree) = 1; varpool_node::get_create(declaration_tree); diff --git a/gcc/elna1.cc b/gcc/elna1.cc index 017f30a..cb643c3 100644 --- a/gcc/elna1.cc +++ b/gcc/elna1.cc @@ -66,7 +66,6 @@ using dependency_state = elna::boot::dependency_state(state.globals); std::ifstream entry_point{ filename, std::ios::in }; if (!entry_point) @@ -80,7 +79,7 @@ static elna::boot::dependency elna_parse_file(dependency_state& state, const cha { elna::gcc::report_errors(outcome.errors()); } - elna::boot::symbol_bag outcome_bag = elna::boot::symbol_bag{ std::move(outcome.unresolved), module_table }; + elna::boot::symbol_bag outcome_bag = elna::boot::symbol_bag{ std::move(outcome.unresolved), state.globals }; for (const auto& sub_tree : outcome.tree->imports) { @@ -102,7 +101,7 @@ static elna::boot::dependency elna_parse_file(dependency_state& state, const cha elna::gcc::report_errors(semantic_errors); } state.cache.insert({ filename, outcome_bag }); - elna::gcc::rewrite_symbol_table(module_table, state.custom); + elna::gcc::rewrite_symbol_table(outcome_bag.leave(), state.custom); linemap_add(line_table, LC_LEAVE, 0, NULL, 0); return outcome; diff --git a/include/elna/boot/dependency.h b/include/elna/boot/dependency.h index 962578f..98d65c5 100644 --- a/include/elna/boot/dependency.h +++ b/include/elna/boot/dependency.h @@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see #include #include "elna/boot/result.h" #include "elna/boot/ast.h" +#include "elna/boot/symbol.h" namespace elna::boot { diff --git a/include/elna/boot/semantic.h b/include/elna/boot/semantic.h index 6648d60..72d6332 100644 --- a/include/elna/boot/semantic.h +++ b/include/elna/boot/semantic.h @@ -175,7 +175,7 @@ namespace elna::boot class declaration_visitor final : public empty_visitor, public error_container { public: - std::unordered_map> unresolved; + forward_table unresolved; explicit declaration_visitor(const char *path); diff --git a/include/elna/boot/symbol.h b/include/elna/boot/symbol.h index 9a7b24c..1a0c992 100644 --- a/include/elna/boot/symbol.h +++ b/include/elna/boot/symbol.h @@ -231,6 +231,7 @@ namespace elna::boot * can not be found. * * \param name Symbol name. + * * \return Symbol from the table if found. */ symbol_ptr lookup(const std::string& name) @@ -250,6 +251,7 @@ namespace elna::boot /** * \param name Symbol name. + * * \return Whether the table contains a symbol with the given name. */ bool contains(const std::string& name) @@ -328,24 +330,101 @@ namespace elna::boot std::shared_ptr builtin_symbol_table(); + /** + * Symbol bag contains: + * + * - the symbol table of a module itself + * - symbol tables of imported modules + * - forward declarations + */ class symbol_bag { std::shared_ptr symbols; std::forward_list> imports; - - public: forward_table unresolved; - symbol_bag(); - symbol_bag(forward_table&& unresolved, std::shared_ptr symbols); + public: + /** + * \param unresolved Forward declarations collected in the previous step. + * \param global_table Global symbols. + */ + symbol_bag(forward_table&& unresolved, std::shared_ptr global_table); + + /** + * \return Iterator pointing to the first forward declaration. + */ + forward_table::const_iterator begin(); + + /** + * \return Iterator pointing past the last forward declaration. + */ + forward_table::const_iterator end(); + + /** + * Looks up a symbol in the current and imported modules. + * + * \param name Symbol name to look up. + * + * \return Symbol from one of the symbol tables if found. + */ std::shared_ptr lookup(const std::string& name); - bool enter(const std::string& name, std::shared_ptr entry); - std::shared_ptr enter(); - void enter(std::shared_ptr child); - void leave(); - void add_import(std::shared_ptr table); + /** + * Inserts a symbol into the current scope. + * + * \param name Symbol name. + * \param entry Symbol info. + * + * \return Whether the insertion took place. + */ + bool enter(const std::string& name, std::shared_ptr entry); + + /** + * Enters a new scope. + * + * \return Reference to the allocated scope. + */ + std::shared_ptr enter(); + + /** + * Sets the current scope to \a child. + * + * \param child New scope. + */ + void enter(std::shared_ptr child); + + /** + * Leave the current scope. + * + * \return Left scope. + */ + std::shared_ptr leave(); + + /** + * Checks whether there is a forward declaration \a symbol_name and + * returns it if so. + * + * \param symbol_name Type name to look up. + * \return Forward declaration or `nullptr` if the symbol is not declared. + */ + std::shared_ptr declared(const std::string& symbol_name); + + /** + * Completes the forward-declared type \a symbol_name and defines it to + * be \a resolution. + * + * \param symbol_name Type name. + * \param resolution Type definition. + * \return Alias to the defined type. + */ + std::shared_ptr resolve(const std::string& symbol_name, type& resolution); + + /** + * Add imported symbols to the scope. + * + * \param bag Symbol bag of another module. + */ void add_import(const symbol_bag& bag); }; } diff --git a/include/elna/gcc/elna-builtins.h b/include/elna/gcc/elna-builtins.h index 1fe11e4..0cdf519 100644 --- a/include/elna/gcc/elna-builtins.h +++ b/include/elna/gcc/elna-builtins.h @@ -36,4 +36,6 @@ namespace elna::gcc tree get_inner_alias(const boot::type& type, std::shared_ptr symbols); void declare_procedure(const std::string& name, const boot::procedure_info& info, std::shared_ptr symbols); + tree declare_variable(const std::string& name, const boot::variable_info& info, + std::shared_ptr symbols); }