From 67a8d2c05743c14d58f0475a8f3750b081b1c4e5 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Fri, 20 Jun 2025 22:33:37 +0200 Subject: [PATCH] Declare an additional name analysis visitor --- boot/semantic.cc | 291 +++++++++++++++++++++++++++-------- gcc/elna-generic.cc | 2 +- gcc/elna1.cc | 20 ++- include/elna/boot/semantic.h | 73 ++++++++- 4 files changed, 312 insertions(+), 74 deletions(-) diff --git a/boot/semantic.cc b/boot/semantic.cc index afbc132..81e85ed 100644 --- a/boot/semantic.cc +++ b/boot/semantic.cc @@ -43,11 +43,6 @@ namespace elna::boot return "Symbol '" + identifier + "' has been already declared"; } - declaration_visitor::declaration_visitor(const char *path, std::shared_ptr symbols) - : error_container(path), symbols(symbols) - { - } - field_duplication_error::field_duplication_error(const std::string& field_name, const char *path, const struct position) : error(path, position), field_name(field_name) @@ -59,7 +54,24 @@ namespace elna::boot return "Repeated field name '" + field_name + "'"; } - procedure_type declaration_visitor::build_procedure(procedure_type_expression& type_expression) + cyclic_declaration_error::cyclic_declaration_error(const std::vector& cycle, + const char *path, const struct position) + : error(path, position), cycle(cycle) + { + } + + std::string cyclic_declaration_error::what() const + { + return "Type declaration forms a cycle"; + } + + name_analysis_visitor::name_analysis_visitor(const char *path, std::shared_ptr symbols, + std::unordered_map>&& unresolved) + : error_container(path), symbols(symbols), unresolved(std::move(unresolved)) + { + } + + procedure_type name_analysis_visitor::build_procedure(procedure_type_expression& type_expression) { procedure_type::return_t result_return; @@ -86,7 +98,7 @@ namespace elna::boot return result_type; } - void declaration_visitor::visit(program *program) + void name_analysis_visitor::visit(program *program) { visit(static_cast(program)); @@ -96,7 +108,7 @@ namespace elna::boot } } - void declaration_visitor::visit(type_declaration *definition) + void name_analysis_visitor::visit(type_declaration *definition) { definition->body().accept(this); auto unresolved_declaration = this->unresolved.at(definition->identifier.identifier); @@ -104,7 +116,7 @@ namespace elna::boot unresolved_declaration->reference = this->current_type; } - void declaration_visitor::visit(named_type_expression *type_expression) + void name_analysis_visitor::visit(named_type_expression *type_expression) { auto unresolved_alias = this->unresolved.find(type_expression->name); @@ -123,19 +135,19 @@ namespace elna::boot } } - void declaration_visitor::visit(pointer_type_expression *type_expression) + void name_analysis_visitor::visit(pointer_type_expression *type_expression) { type_expression->base().accept(this); this->current_type = type(std::make_shared(this->current_type)); } - void declaration_visitor::visit(array_type_expression *type_expression) + void name_analysis_visitor::visit(array_type_expression *type_expression) { type_expression->base().accept(this); this->current_type = type(std::make_shared(this->current_type, type_expression->size)); } - std::vector declaration_visitor::build_composite_type(const std::vector& fields) + std::vector name_analysis_visitor::build_composite_type(const std::vector& fields) { std::vector result; std::set field_names; @@ -156,7 +168,7 @@ namespace elna::boot return result; } - void declaration_visitor::visit(record_type_expression *type_expression) + void name_analysis_visitor::visit(record_type_expression *type_expression) { auto result_type = std::make_shared(); @@ -165,7 +177,7 @@ namespace elna::boot this->current_type = type(result_type); } - void declaration_visitor::visit(union_type_expression *type_expression) + void name_analysis_visitor::visit(union_type_expression *type_expression) { auto result_type = std::make_shared(); @@ -174,7 +186,7 @@ namespace elna::boot this->current_type = type(result_type); } - void declaration_visitor::visit(procedure_type_expression *type_expression) + void name_analysis_visitor::visit(procedure_type_expression *type_expression) { std::shared_ptr result_type = std::make_shared(std::move(build_procedure(*type_expression))); @@ -182,14 +194,14 @@ namespace elna::boot this->current_type = type(result_type); } - void declaration_visitor::visit(enumeration_type_expression *type_expression) + void name_analysis_visitor::visit(enumeration_type_expression *type_expression) { std::shared_ptr result_type = std::make_shared(type_expression->members); this->current_type = type(result_type); } - void declaration_visitor::visit(variable_declaration *declaration) + void name_analysis_visitor::visit(variable_declaration *declaration) { declaration->variable_type().accept(this); @@ -197,7 +209,7 @@ namespace elna::boot std::make_shared(this->current_type)); } - void declaration_visitor::visit(constant_declaration *definition) + void name_analysis_visitor::visit(constant_declaration *definition) { definition->body().accept(this); @@ -205,7 +217,7 @@ namespace elna::boot std::make_shared(this->current_literal)); } - void declaration_visitor::visit(procedure_declaration *definition) + void name_analysis_visitor::visit(procedure_declaration *definition) { std::shared_ptr info; @@ -238,13 +250,13 @@ namespace elna::boot this->symbols->enter(definition->identifier.identifier, info); } - void declaration_visitor::visit(assign_statement *statement) + void name_analysis_visitor::visit(assign_statement *statement) { statement->lvalue().accept(this); statement->rvalue().accept(this); } - void declaration_visitor::visit(if_statement *statement) + void name_analysis_visitor::visit(if_statement *statement) { statement->body().prerequisite().accept(this); for (struct statement *const statement : statement->body().statements) @@ -269,11 +281,11 @@ namespace elna::boot } } - void declaration_visitor::visit(import_declaration *) + void name_analysis_visitor::visit(import_declaration *) { } - void declaration_visitor::visit(while_statement *statement) + void name_analysis_visitor::visit(while_statement *statement) { statement->body().prerequisite().accept(this); for (struct statement *const statement : statement->body().statements) @@ -291,12 +303,12 @@ namespace elna::boot } } - void declaration_visitor::visit(return_statement *statement) + void name_analysis_visitor::visit(return_statement *statement) { statement->return_expression().accept(this); } - void declaration_visitor::visit(defer_statement *statement) + void name_analysis_visitor::visit(defer_statement *statement) { for (struct statement *const statement : statement->statements) { @@ -304,7 +316,7 @@ namespace elna::boot } } - void declaration_visitor::visit(case_statement *statement) + void name_analysis_visitor::visit(case_statement *statement) { statement->condition().accept(this); for (const switch_case& case_block : statement->cases) @@ -327,7 +339,7 @@ namespace elna::boot } } - void declaration_visitor::visit(procedure_call *call) + void name_analysis_visitor::visit(procedure_call *call) { call->callable().accept(this); for (expression *const argument: call->arguments) @@ -336,18 +348,8 @@ namespace elna::boot } } - void declaration_visitor::visit(unit *unit) + void name_analysis_visitor::visit(unit *unit) { - for (type_declaration *const type : unit->types) - { - const std::string& type_identifier = type->identifier.identifier; - - if (!this->unresolved.insert({ type_identifier, std::make_shared(type_identifier) }).second - || this->symbols->contains(type_identifier)) - { - add_error(type->identifier.identifier, this->input_file, type->position()); - } - } for (type_declaration *const type : unit->types) { type->accept(this); @@ -367,7 +369,7 @@ namespace elna::boot } } - void declaration_visitor::visit(traits_expression *trait) + void name_analysis_visitor::visit(traits_expression *trait) { if (!trait->parameters.empty()) { @@ -376,76 +378,239 @@ namespace elna::boot } } - void declaration_visitor::visit(cast_expression *expression) + void name_analysis_visitor::visit(cast_expression *expression) { expression->value().accept(this); expression->target().accept(this); expression->expression_type = this->current_type; } - void declaration_visitor::visit(binary_expression *expression) + void name_analysis_visitor::visit(binary_expression *expression) { expression->lhs().accept(this); expression->rhs().accept(this); } - void declaration_visitor::visit(unary_expression *expression) + void name_analysis_visitor::visit(unary_expression *expression) { expression->operand().accept(this); } + void name_analysis_visitor::visit(variable_expression *) + { + } + + void name_analysis_visitor::visit(array_access_expression *expression) + { + expression->base().accept(this); + expression->index().accept(this); + } + + void name_analysis_visitor::visit(field_access_expression *expression) + { + expression->base().accept(this); + } + + void name_analysis_visitor::visit(dereference_expression *expression) + { + expression->base().accept(this); + } + + void name_analysis_visitor::visit(literal *literal) + { + this->current_literal = literal->value; + } + + void name_analysis_visitor::visit(literal *literal) + { + this->current_literal = literal->value; + } + + void name_analysis_visitor::visit(literal *literal) + { + this->current_literal = literal->value; + } + + void name_analysis_visitor::visit(literal *literal) + { + this->current_literal = literal->value; + } + + void name_analysis_visitor::visit(literal *literal) + { + this->current_literal = literal->value; + } + + void name_analysis_visitor::visit(literal *literal) + { + this->current_literal = literal->value; + } + + void name_analysis_visitor::visit(literal *literal) + { + this->current_literal = literal->value; + } + + declaration_visitor::declaration_visitor(const char *path) + : error_container(path) + { + } + + void declaration_visitor::visit(named_type_expression *) + { + } + + void declaration_visitor::visit(array_type_expression *) + { + } + + void declaration_visitor::visit(pointer_type_expression *) + { + } + + void declaration_visitor::visit(program *program) + { + visit(static_cast(program)); + } + + void declaration_visitor::visit(type_declaration *) + { + } + + void declaration_visitor::visit(record_type_expression *) + { + } + + void declaration_visitor::visit(union_type_expression *) + { + } + + void declaration_visitor::visit(procedure_type_expression *) + { + } + + void declaration_visitor::visit(enumeration_type_expression *) + { + } + + void declaration_visitor::visit(variable_declaration *) + { + } + + void declaration_visitor::visit(constant_declaration *) + { + } + + void declaration_visitor::visit(procedure_declaration *) + { + } + + void declaration_visitor::visit(assign_statement *) + { + } + + void declaration_visitor::visit(if_statement *) + { + } + + void declaration_visitor::visit(import_declaration *) + { + } + + void declaration_visitor::visit(while_statement *) + { + } + + void declaration_visitor::visit(return_statement *) + { + } + + void declaration_visitor::visit(defer_statement *) + { + } + + void declaration_visitor::visit(case_statement *) + { + } + + void declaration_visitor::visit(procedure_call *) + { + } + + void declaration_visitor::visit(unit *unit) + { + for (type_declaration *const type : unit->types) + { + const std::string& type_identifier = type->identifier.identifier; + + if (!this->unresolved.insert({ type_identifier, std::make_shared(type_identifier) }).second) + { + add_error(type->identifier.identifier, this->input_file, type->position()); + } + else + { + type->accept(this); + } + } + } + + void declaration_visitor::visit(cast_expression *) + { + } + + void declaration_visitor::visit(traits_expression *) + { + } + + void declaration_visitor::visit(binary_expression *) + { + } + + void declaration_visitor::visit(unary_expression *) + { + } + void declaration_visitor::visit(variable_expression *) { } - void declaration_visitor::visit(array_access_expression *expression) + void declaration_visitor::visit(array_access_expression *) { - expression->base().accept(this); - expression->index().accept(this); } - void declaration_visitor::visit(field_access_expression *expression) + void declaration_visitor::visit(field_access_expression *) { - expression->base().accept(this); } - void declaration_visitor::visit(dereference_expression *expression) + void declaration_visitor::visit(dereference_expression *) { - expression->base().accept(this); } - void declaration_visitor::visit(literal *literal) + void declaration_visitor::visit(literal *) { - this->current_literal = literal->value; } - void declaration_visitor::visit(literal *literal) + void declaration_visitor::visit(literal *) { - this->current_literal = literal->value; } - void declaration_visitor::visit(literal *literal) + void declaration_visitor::visit(literal *) { - this->current_literal = literal->value; } - void declaration_visitor::visit(literal *literal) + void declaration_visitor::visit(literal *) { - this->current_literal = literal->value; } - void declaration_visitor::visit(literal *literal) + void declaration_visitor::visit(literal *) { - this->current_literal = literal->value; } - void declaration_visitor::visit(literal *literal) + void declaration_visitor::visit(literal *) { - this->current_literal = literal->value; } - void declaration_visitor::visit(literal *literal) + void declaration_visitor::visit(literal *) { - this->current_literal = literal->value; } } diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 2574035..00203af 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -764,7 +764,7 @@ namespace elna::gcc this->current_expression = NULL_TREE; if (!result) { - error_at(declaration_location, "variable '%s' already declared in this scope", + error_at(declaration_location, "Variable '%s' already declared in this scope", declaration->identifier.identifier.c_str()); } else if (lang_hooks.decls.global_bindings_p()) diff --git a/gcc/elna1.cc b/gcc/elna1.cc index 7b0bde3..533d4c1 100644 --- a/gcc/elna1.cc +++ b/gcc/elna1.cc @@ -84,16 +84,26 @@ static void elna_parse_file(const char *filename) { for (const std::unique_ptr& module_tree : outcome.modules) { - elna::boot::declaration_visitor declaration_visitor(filename, info_table); - + elna::boot::declaration_visitor declaration_visitor(filename); declaration_visitor.visit(module_tree.get()); if (declaration_visitor.errors().empty()) { - elna::gcc::do_semantic_analysis(info_table, symbol_table); + elna::boot::name_analysis_visitor name_analysis_visitor(filename, info_table, + std::move(declaration_visitor.unresolved)); + name_analysis_visitor.visit(module_tree.get()); - elna::gcc::generic_visitor generic_visitor{ symbol_table, info_table }; - generic_visitor.visit(module_tree.get()); + if (name_analysis_visitor.errors().empty()) + { + elna::gcc::do_semantic_analysis(info_table, symbol_table); + + elna::gcc::generic_visitor generic_visitor{ symbol_table, info_table }; + generic_visitor.visit(module_tree.get()); + } + else + { + elna::gcc::report_errors(name_analysis_visitor.errors()); + } } else { diff --git a/include/elna/boot/semantic.h b/include/elna/boot/semantic.h index 3542896..cc4fab8 100644 --- a/include/elna/boot/semantic.h +++ b/include/elna/boot/semantic.h @@ -30,7 +30,7 @@ namespace elna::boot { class undeclared_error : public error { - std::string identifier; + const std::string identifier; public: undeclared_error(const std::string& identifier, const char *path, const struct position position); @@ -40,7 +40,7 @@ namespace elna::boot class already_declared_error : public error { - std::string identifier; + const std::string identifier; public: already_declared_error(const std::string& identifier, const char *path, const struct position position); @@ -50,7 +50,7 @@ namespace elna::boot class field_duplication_error : public error { - std::string field_name; + const std::string field_name; public: field_duplication_error(const std::string& field_name, const char *path, const struct position); @@ -58,7 +58,20 @@ namespace elna::boot std::string what() const override; }; - class declaration_visitor final : public parser_visitor, public error_container + class cyclic_declaration_error : public error + { + const std::vector cycle; + + public: + cyclic_declaration_error(const std::vector& cycle, const char *path, const struct position); + + std::string what() const override; + }; + + /** + * Performs name analysis. + */ + class name_analysis_visitor final : public parser_visitor, public error_container { type current_type; constant_info::variant current_literal; @@ -70,7 +83,8 @@ namespace elna::boot std::vector build_composite_type(const std::vector& fields); public: - explicit declaration_visitor(const char *path, std::shared_ptr symbols); + explicit name_analysis_visitor(const char *path, std::shared_ptr symbols, + std::unordered_map>&& unresolved); void visit(named_type_expression *type_expression) override; void visit(array_type_expression *type_expression) override; @@ -110,4 +124,53 @@ namespace elna::boot void visit(literal *literal) override; void visit(literal *literal) override; }; + + /** + * Collects global declarations. + */ + class declaration_visitor final : public parser_visitor, public error_container + { + public: + std::unordered_map> unresolved; + + explicit declaration_visitor(const char *path); + + void visit(named_type_expression *) override; + void visit(array_type_expression *) override; + void visit(pointer_type_expression *) override; + void visit(program *program) override; + void visit(type_declaration *) override; + void visit(record_type_expression *) override; + void visit(union_type_expression *) override; + void visit(procedure_type_expression *) override; + void visit(enumeration_type_expression *) override; + + void visit(variable_declaration *) override; + void visit(constant_declaration *) override; + void visit(procedure_declaration *) override; + void visit(assign_statement *) override; + void visit(if_statement *) override; + void visit(import_declaration *) override; + void visit(while_statement *) override; + void visit(return_statement *) override; + void visit(defer_statement *) override; + void visit(case_statement *) override; + void visit(procedure_call *) override; + void visit(unit *unit) override; + void visit(cast_expression *) override; + void visit(traits_expression *) override; + void visit(binary_expression *) override; + void visit(unary_expression *) override; + void visit(variable_expression *) override; + void visit(array_access_expression *) override; + void visit(field_access_expression *) override; + void visit(dereference_expression *) override; + void visit(literal *) override; + void visit(literal *) override; + void visit(literal *) override; + void visit(literal *) override; + void visit(literal *) override; + void visit(literal *) override; + void visit(literal *) override; + }; }