diff --git a/boot/dependency.cc b/boot/dependency.cc index 9811422..0e268d4 100644 --- a/boot/dependency.cc +++ b/boot/dependency.cc @@ -17,31 +17,52 @@ along with GCC; see the file COPYING3. If not see #include "elna/boot/dependency.h" +#include +#include +#include + #include "elna/boot/driver.h" +#include "elna/boot/semantic.h" #include "parser.hh" namespace elna::boot { - dependency_graph::dependency_graph() + source_path_error::source_path_error(const std::string& message, const char *path) + : error(path, { 0, 0 }), message(message) { } - dependency_graph::dependency_graph(error_list&& errors) + std::string source_path_error::what() const + { + std::stringstream output; + output << "Cannot open filename "; + output << this->path; + output << ": "; + output << this->message; + + return output.str(); + } + + dependency::dependency() + { + } + + dependency::dependency(error_list&& errors) : m_errors(std::move(errors)) { } - bool dependency_graph::has_errors() const + bool dependency::has_errors() const { return !errors().empty(); } - const error_list& dependency_graph::errors() const + const error_list& dependency::errors() const { return m_errors; } - dependency_graph read_sources(std::istream& entry_point, const char *entry_path) + dependency parse_source(std::istream& entry_point, const char *entry_path) { driver parse_driver{ entry_path }; lexer tokenizer(entry_point); @@ -49,14 +70,52 @@ namespace elna::boot if (parser()) { - return dependency_graph(std::move(parse_driver.errors())); + return dependency(std::move(parse_driver.errors())); } else { - dependency_graph outcome; - outcome.modules.emplace_back(std::move(parse_driver.tree)); + dependency outcome; + std::swap(outcome.tree, parse_driver.tree); return outcome; } } + + dependency read_sources(const char *entry_path, std::shared_ptr info_table, + std::shared_ptr imports) + { + std::ifstream entry_point{ entry_path, std::ios::in }; + + if (!entry_point) + { + error_list errors; + errors.push_back(std::make_unique(strerror(errno), entry_path)); + + return dependency(std::move(errors)); + } + auto outcome = parse_source(entry_point, entry_path); + + declaration_visitor declaration_visitor(entry_path); + outcome.tree->accept(&declaration_visitor); + + if (!declaration_visitor.errors().empty()) + { + return dependency(std::move(declaration_visitor.errors())); + } + outcome.unresolved = declaration_visitor.unresolved; + outcome.bag = symbol_bag{ std::move(declaration_visitor.unresolved), info_table }; + + if (imports != nullptr) + { + outcome.bag.add_import(imports); + } + elna::boot::name_analysis_visitor name_analysis_visitor(entry_path, outcome.bag); + outcome.tree->accept(&name_analysis_visitor); + + if (!name_analysis_visitor.errors().empty()) + { + return dependency(std::move(declaration_visitor.errors())); + } + return outcome; + } } diff --git a/boot/parser.yy b/boot/parser.yy index ab17bc9..af3f7a3 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -182,7 +182,7 @@ program: } | "module" ";" import_part constant_part type_part variable_part procedure_part "end" "." { - auto tree = new boot::program(boot::make_position(@1)); + auto tree = new boot::unit(boot::make_position(@1)); std::swap(tree->imports, $3); std::swap(tree->constants, $4); diff --git a/boot/semantic.cc b/boot/semantic.cc index 3ebccde..5489959 100644 --- a/boot/semantic.cc +++ b/boot/semantic.cc @@ -74,9 +74,8 @@ namespace elna::boot return message; } - 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)) + name_analysis_visitor::name_analysis_visitor(const char *path, symbol_bag bag) + : error_container(path), bag(bag) { } @@ -120,20 +119,20 @@ namespace elna::boot void name_analysis_visitor::visit(type_declaration *definition) { definition->body().accept(this); - auto unresolved_declaration = this->unresolved.at(definition->identifier.identifier); + auto unresolved_declaration = this->bag.unresolved.at(definition->identifier.identifier); unresolved_declaration->reference = this->current_type; } void name_analysis_visitor::visit(named_type_expression *type_expression) { - auto unresolved_alias = this->unresolved.find(type_expression->name); + auto unresolved_alias = this->bag.unresolved.find(type_expression->name); - if (unresolved_alias != this->unresolved.end()) + if (unresolved_alias != this->bag.unresolved.end()) { this->current_type = type(unresolved_alias->second); } - else if (auto from_symbol_table = this->symbols->lookup(type_expression->name)) + else if (auto from_symbol_table = this->bag.lookup(type_expression->name)) { this->current_type = from_symbol_table->is_type()->symbol; } @@ -214,28 +213,24 @@ namespace elna::boot { declaration->variable_type().accept(this); - this->symbols->enter(declaration->identifier.identifier, - std::make_shared(this->current_type)); + this->bag.enter(declaration->identifier.identifier, std::make_shared(this->current_type)); } void name_analysis_visitor::visit(constant_declaration *definition) { definition->body().accept(this); - this->symbols->enter(definition->identifier.identifier, - std::make_shared(this->current_literal)); + this->bag.enter(definition->identifier.identifier, std::make_shared(this->current_literal)); } void name_analysis_visitor::visit(procedure_declaration *definition) { std::shared_ptr info; + auto heading = build_procedure(definition->heading()); if (definition->body.has_value()) { - info = std::make_shared(build_procedure(definition->heading()), - definition->parameter_names, this->symbols); - - this->symbols = info->symbols; + info = std::make_shared(heading, definition->parameter_names, this->bag.enter()); for (constant_declaration *const constant : definition->body.value().constants()) { @@ -249,14 +244,13 @@ namespace elna::boot { statement->accept(this); } - this->symbols = this->symbols->scope(); + this->bag.leave(); } else { - info = std::make_shared(build_procedure(definition->heading()), - definition->parameter_names); + info = std::make_shared(heading, definition->parameter_names); } - this->symbols->enter(definition->identifier.identifier, info); + this->bag.enter(definition->identifier.identifier, info); } void name_analysis_visitor::visit(assign_statement *statement) @@ -379,14 +373,14 @@ namespace elna::boot { type->accept(this); } - for (auto& unresolved : this->unresolved) + for (auto& unresolved : this->bag.unresolved) { std::vector path; if (check_unresolved_symbol(unresolved.second, path)) { auto info = std::make_shared(type_info(type(unresolved.second))); - this->symbols->enter(std::move(unresolved.first), info); + this->bag.enter(unresolved.first, info); } else { diff --git a/boot/symbol.cc b/boot/symbol.cc index a943774..b46cd8f 100644 --- a/boot/symbol.cc +++ b/boot/symbol.cc @@ -313,13 +313,9 @@ namespace elna::boot } procedure_info::procedure_info(const procedure_type symbol, const std::vector names, - std::shared_ptr parent_table) - : symbol(symbol), names(names) + std::shared_ptr scope) + : symbol(symbol), names(names), symbols(scope) { - if (parent_table != nullptr) - { - this->symbols = std::make_shared(parent_table); - } } std::shared_ptr procedure_info::is_procedure() @@ -361,4 +357,51 @@ namespace elna::boot return result; } + + symbol_bag::symbol_bag() + { + this->symbols = std::make_shared(); + this->imports = std::make_shared(); + } + + symbol_bag::symbol_bag(forward_table&& unresolved, std::shared_ptr symbols) + : symbols(symbols), unresolved(unresolved) + { + this->imports = std::make_shared(); + } + + std::shared_ptr symbol_bag::lookup(const std::string& name) + { + if (auto result = this->imports->lookup(name)) + { + return result; + } + return this->symbols->lookup(name); + } + + bool symbol_bag::enter(const std::string& name, std::shared_ptr entry) + { + return this->symbols->enter(name, entry); + } + + std::shared_ptr symbol_bag::enter() + { + this->symbols = std::make_shared(this->symbols); + return this->symbols; + } + + void symbol_bag::enter(std::shared_ptr child) + { + this->symbols = child; + } + + void symbol_bag::leave() + { + this->symbols = this->symbols->scope(); + } + + void symbol_bag::add_import(std::shared_ptr table) + { + this->imports = table; + } } diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 5deffde..07d0727 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -29,16 +29,14 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "diagnostic.h" #include "realmpfr.h" -#include "stor-layout.h" #include "varasm.h" #include "fold-const.h" #include "langhooks.h" namespace elna::gcc { - generic_visitor::generic_visitor(std::shared_ptr symbol_table, - std::shared_ptr info_table) - : symbols(symbol_table), info_table(info_table) + generic_visitor::generic_visitor(std::shared_ptr symbol_table, elna::boot::symbol_bag bag) + : symbols(symbol_table), bag(bag) { } @@ -321,7 +319,7 @@ namespace elna::gcc DECL_STRUCT_FUNCTION(fndecl)->language = ggc_cleared_alloc(); enter_scope(); - this->info_table = this->info_table->lookup(definition->identifier.identifier)->is_procedure()->symbols; + this->bag.enter(this->bag.lookup(definition->identifier.identifier)->is_procedure()->symbols); tree argument_chain = DECL_ARGUMENTS(fndecl); for (; argument_chain != NULL_TREE; argument_chain = TREE_CHAIN(argument_chain)) @@ -339,7 +337,7 @@ namespace elna::gcc visit_statements(definition->body.value().body()); tree mapping = leave_scope(); - this->info_table = this->info_table->scope(); + this->bag.leave(); BLOCK_SUPERCONTEXT(BIND_EXPR_BLOCK(mapping)) = fndecl; DECL_INITIAL(fndecl) = BIND_EXPR_BLOCK(mapping); @@ -746,7 +744,7 @@ namespace elna::gcc void generic_visitor::visit(boot::variable_declaration *declaration) { this->current_expression = get_inner_alias( - this->info_table->lookup(declaration->identifier.identifier)->is_variable()->symbol, + this->bag.lookup(declaration->identifier.identifier)->is_variable()->symbol, this->symbols); location_t declaration_location = get_location(&declaration->position()); diff --git a/gcc/elna1.cc b/gcc/elna1.cc index ef13c57..9991778 100644 --- a/gcc/elna1.cc +++ b/gcc/elna1.cc @@ -64,15 +64,17 @@ static bool elna_langhook_init(void) static void elna_parse_file(const char *filename) { - std::ifstream file{ filename, std::ios::in }; - - if (!file) - { - fatal_error(UNKNOWN_LOCATION, "cannot open filename %s: %m", filename); - } - elna::boot::dependency_graph outcome = elna::boot::read_sources(file, filename); - std::shared_ptr info_table = elna::boot::builtin_symbol_table(); + auto x = std::make_shared(info_table); + elna::boot::dependency dependency = elna::boot::read_sources("source/Common.elna", x); + + linemap_add(line_table, LC_ENTER, 0, "source/Common.elna", 1); + if (dependency.has_errors()) + { + elna::gcc::report_errors(dependency.errors()); + } + auto y = std::make_shared(info_table); + elna::boot::dependency outcome = elna::boot::read_sources(filename, y, x); std::shared_ptr symbol_table = elna::gcc::builtin_symbol_table(); linemap_add(line_table, LC_ENTER, 0, filename, 1); @@ -82,34 +84,11 @@ static void elna_parse_file(const char *filename) } else { - for (const std::unique_ptr& module_tree : outcome.modules) - { - elna::boot::declaration_visitor declaration_visitor(filename); - declaration_visitor.visit(module_tree.get()); + elna::gcc::rewrite_symbol_table(x, symbol_table); + elna::gcc::rewrite_symbol_table(y, symbol_table); - if (declaration_visitor.errors().empty()) - { - elna::boot::name_analysis_visitor name_analysis_visitor(filename, info_table, - std::move(declaration_visitor.unresolved)); - name_analysis_visitor.visit(module_tree.get()); - - if (name_analysis_visitor.errors().empty()) - { - elna::gcc::rewrite_symbol_table(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 - { - elna::gcc::report_errors(declaration_visitor.errors()); - } - } + elna::gcc::generic_visitor generic_visitor{ symbol_table, outcome.bag }; + outcome.tree->accept(&generic_visitor); } linemap_add(line_table, LC_LEAVE, 0, NULL, 0); } diff --git a/include/elna/boot/dependency.h b/include/elna/boot/dependency.h index 64ed7dd..7a28f41 100644 --- a/include/elna/boot/dependency.h +++ b/include/elna/boot/dependency.h @@ -17,25 +17,39 @@ along with GCC; see the file COPYING3. If not see #pragma once +#include #include #include "elna/boot/result.h" #include "elna/boot/ast.h" namespace elna::boot { - class dependency_graph + class source_path_error : public error + { + const std::string message; + + public: + source_path_error(const std::string& message, const char *path); + + std::string what() const override; + }; + + class dependency { error_list m_errors; public: - std::vector> modules; + std::unique_ptr tree; + std::unordered_map> unresolved; + symbol_bag bag; bool has_errors() const; const error_list& errors() const; - dependency_graph(); - explicit dependency_graph(error_list&& errors); + dependency(); + explicit dependency(error_list&& errors); }; - dependency_graph read_sources(std::istream& entry_point, const char *entry_path); + dependency read_sources(const char *entry_path, std::shared_ptr info_table, + std::shared_ptr imports = nullptr); } diff --git a/include/elna/boot/driver.h b/include/elna/boot/driver.h index c9706bd..288aa0c 100644 --- a/include/elna/boot/driver.h +++ b/include/elna/boot/driver.h @@ -39,7 +39,7 @@ namespace elna::boot class driver : public error_container { public: - std::unique_ptr tree; + std::unique_ptr tree; driver(const char *input_file); }; diff --git a/include/elna/boot/semantic.h b/include/elna/boot/semantic.h index d8d87d6..a510c3c 100644 --- a/include/elna/boot/semantic.h +++ b/include/elna/boot/semantic.h @@ -77,8 +77,7 @@ namespace elna::boot type current_type; constant_info::variant current_literal; - std::shared_ptr symbols; - std::unordered_map> unresolved; + symbol_bag bag; procedure_type build_procedure(procedure_type_expression& type_expression); std::vector build_composite_type(const std::vector& fields); @@ -87,8 +86,7 @@ namespace elna::boot std::vector& path); public: - explicit name_analysis_visitor(const char *path, std::shared_ptr symbols, - std::unordered_map>&& unresolved); + name_analysis_visitor(const char *path, symbol_bag bag); void visit(named_type_expression *type_expression) override; void visit(array_type_expression *type_expression) override; diff --git a/include/elna/boot/symbol.h b/include/elna/boot/symbol.h index d28c656..365d3b6 100644 --- a/include/elna/boot/symbol.h +++ b/include/elna/boot/symbol.h @@ -281,6 +281,7 @@ namespace elna::boot }; using symbol_table = symbol_map, std::nullptr_t, nullptr>; + using forward_table = std::unordered_map>; class type_info : public info { @@ -299,7 +300,7 @@ namespace elna::boot std::shared_ptr symbols; procedure_info(const procedure_type symbol, const std::vector names, - std::shared_ptr parent_table = nullptr); + std::shared_ptr scope = nullptr); std::shared_ptr is_procedure() override; }; @@ -325,4 +326,24 @@ namespace elna::boot }; std::shared_ptr builtin_symbol_table(); + + class symbol_bag + { + std::shared_ptr symbols; + std::shared_ptr imports; + + public: + forward_table unresolved; + + symbol_bag(); + symbol_bag(forward_table&& unresolved, std::shared_ptr symbols); + + 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); + }; } diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index aabfce2..54cad5d 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -36,8 +36,8 @@ namespace elna::gcc class generic_visitor final : public boot::parser_visitor { tree current_expression{ NULL_TREE }; + elna::boot::symbol_bag bag; std::shared_ptr symbols; - std::shared_ptr info_table; void enter_scope(); tree leave_scope(); @@ -63,7 +63,7 @@ namespace elna::gcc bool assert_constant(location_t expression_location); public: - generic_visitor(std::shared_ptr symbol_table, std::shared_ptr info_table); + generic_visitor(std::shared_ptr symbol_table, elna::boot::symbol_bag bag); void visit(boot::program *program) override; void visit(boot::procedure_declaration *definition) override; diff --git a/source/Common.def b/source/Common.def deleted file mode 100644 index 9520230..0000000 --- a/source/Common.def +++ /dev/null @@ -1,12 +0,0 @@ -DEFINITION MODULE Common; - -TYPE - ShortString = ARRAY[1..256] OF CHAR; - Identifier = ARRAY[1..256] OF CHAR; - PIdentifier = POINTER TO Identifier; - TextLocation = RECORD - line: CARDINAL; - column: CARDINAL - END; - -END Common. diff --git a/source/Common.elna b/source/Common.elna index fa158b7..9d2185d 100644 --- a/source/Common.elna +++ b/source/Common.elna @@ -1,3 +1,12 @@ module; +type + ShortString = [256]Char; + Identifier = [256]Char; + PIdentifier = ^Identifier; + TextLocation* = record + line: Word; + column: Word + end; + end. diff --git a/source/main.elna b/source/main.elna index 946e32e..939639d 100644 --- a/source/main.elna +++ b/source/main.elna @@ -80,13 +80,9 @@ type _module, _import ); - Position* = record - line: Word; - column: Word - end; Location* = record - first: Position; - last: Position + first: TextLocation; + last: TextLocation end; SourceFile* = record buffer: [1024]Char; @@ -101,7 +97,7 @@ type capacity: Word end; SourceCode = record - position: Position; + position: TextLocation; input: Pointer; empty: proc(Pointer) -> Bool; @@ -1068,7 +1064,7 @@ begin fclose(source_file^.handle) end; - source_code.position := Position(1u, 1u); + source_code.position := TextLocation(1u, 1u); source_code.input := cast(source_file: Pointer); source_code.empty := source_file_empty; source_code.head := source_file_head;