diff --git a/Rakefile b/Rakefile index 43eae73..22fdddb 100644 --- a/Rakefile +++ b/Rakefile @@ -20,13 +20,15 @@ task default: ['source/main.elna', TMP + 'boot/elna'] do |t| end rule(/boot\/.+\.o$/ => ->(file) { - Pathname.new('source') + + source = Pathname.new('source') + Pathname.new(file).relative_path_from(TMP + 'boot').sub_ext('.elna') + + [HOST_INSTALL + 'bin/gelna', source] }) do |t| Pathname.new(t.name).dirname.mkpath - compiler = HOST_INSTALL + 'bin/gelna' + sources, compiler = t.prerequisites.partition { |source| source.end_with? '.elna' } - sh compiler.to_path, '-c', '-o', t.name, *t.prerequisites + sh *compiler, '-c', '-O0', '-g', '-o', t.name, *sources end file TMP + 'boot/elna' => FileList['source/**/*.elna'].reject { |file| diff --git a/boot/semantic.cc b/boot/semantic.cc index 02caae7..afbc132 100644 --- a/boot/semantic.cc +++ b/boot/semantic.cc @@ -17,6 +17,8 @@ along with GCC; see the file COPYING3. If not see #include "elna/boot/semantic.h" +#include + namespace elna::boot { undeclared_error::undeclared_error(const std::string& identifier, const char *path, const struct position position) @@ -46,6 +48,17 @@ namespace elna::boot { } + field_duplication_error::field_duplication_error(const std::string& field_name, + const char *path, const struct position) + : error(path, position), field_name(field_name) + { + } + + std::string field_duplication_error::what() const + { + return "Repeated field name '" + field_name + "'"; + } + procedure_type declaration_visitor::build_procedure(procedure_type_expression& type_expression) { procedure_type::return_t result_return; @@ -122,15 +135,33 @@ namespace elna::boot 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 result; + std::set field_names; + + for (auto& field : fields) + { + if (field_names.find(field.first) != field_names.cend()) + { + add_error(field.first, this->input_file, field.second->position()); + } + else + { + field_names.insert(field.first); + field.second->accept(this); + result.push_back(std::make_pair(field.first, this->current_type)); + } + } + return result; + } + void declaration_visitor::visit(record_type_expression *type_expression) { auto result_type = std::make_shared(); - for (auto& field : type_expression->fields) - { - field.second->accept(this); - result_type->fields.push_back(std::make_pair(field.first, this->current_type)); - } + result_type->fields = build_composite_type(type_expression->fields); + this->current_type = type(result_type); } @@ -138,11 +169,8 @@ namespace elna::boot { auto result_type = std::make_shared(); - for (const field_declaration& field : type_expression->fields) - { - field.second->accept(this); - result_type->fields.push_back(std::make_pair(field.first, this->current_type)); - } + result_type->fields = build_composite_type(type_expression->fields); + this->current_type = type(result_type); } @@ -179,14 +207,15 @@ namespace elna::boot void declaration_visitor::visit(procedure_declaration *definition) { - std::shared_ptr info = std::make_shared( - build_procedure(definition->heading()), definition->parameter_names); - - this->symbols->enter(definition->identifier.identifier, info); - this->symbols = std::make_shared(this->symbols); + std::shared_ptr info; if (definition->body.has_value()) { + info = std::make_shared(build_procedure(definition->heading()), + definition->parameter_names, this->symbols); + + this->symbols = info->symbols; + for (constant_declaration *const constant : definition->body.value().constants()) { constant->accept(this); @@ -199,8 +228,14 @@ namespace elna::boot { statement->accept(this); } + this->symbols = this->symbols->scope(); } - this->symbols = this->symbols->scope(); + else + { + info = std::make_shared(build_procedure(definition->heading()), + definition->parameter_names); + } + this->symbols->enter(definition->identifier.identifier, info); } void declaration_visitor::visit(assign_statement *statement) @@ -283,6 +318,13 @@ namespace elna::boot statement->accept(this); } } + if (statement->alternative != nullptr) + { + for (struct statement *const statement : *statement->alternative) + { + statement->accept(this); + } + } } void declaration_visitor::visit(procedure_call *call) @@ -330,6 +372,7 @@ namespace elna::boot if (!trait->parameters.empty()) { trait->parameters.front()->accept(this); + trait->types.push_back(this->current_type); } } @@ -337,6 +380,7 @@ namespace elna::boot { expression->value().accept(this); expression->target().accept(this); + expression->expression_type = this->current_type; } void declaration_visitor::visit(binary_expression *expression) diff --git a/boot/symbol.cc b/boot/symbol.cc index af03159..a943774 100644 --- a/boot/symbol.cc +++ b/boot/symbol.cc @@ -312,9 +312,14 @@ namespace elna::boot return std::static_pointer_cast(shared_from_this()); } - procedure_info::procedure_info(const procedure_type symbol, const std::vector names) + procedure_info::procedure_info(const procedure_type symbol, const std::vector names, + std::shared_ptr parent_table) : symbol(symbol), names(names) { + if (parent_table != nullptr) + { + this->symbols = std::make_shared(parent_table); + } } std::shared_ptr procedure_info::is_procedure() diff --git a/gcc/elna-builtins.cc b/gcc/elna-builtins.cc index 904aeb7..8c63405 100644 --- a/gcc/elna-builtins.cc +++ b/gcc/elna-builtins.cc @@ -15,6 +15,8 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ +#include + #include "elna/gcc/elna-builtins.h" #include "elna/gcc/elna1.h" #include "stor-layout.h" @@ -79,4 +81,190 @@ namespace elna::gcc return symbol_table; } + + tree build_type_declaration(const std::string& identifier, tree type) + { + tree definition_tree = build_decl(UNKNOWN_LOCATION, TYPE_DECL, + get_identifier(identifier.c_str()), type); + + TREE_PUBLIC(definition_tree) = true; + if (is_unique_type(type)) + { + TYPE_NAME(type) = DECL_NAME(definition_tree); + TYPE_STUB_DECL(type) = definition_tree; + } + else + { + TYPE_NAME(type) = definition_tree; + } + return definition_tree; + } + + tree build_composite_type(const std::vector& fields, tree composite_type_node, + std::shared_ptr symbols, std::vector& path) + { + for (auto& field : fields) + { + tree rewritten_field = get_inner_alias(field.second, symbols, path); + tree field_declaration = build_field(UNKNOWN_LOCATION, + composite_type_node, field.first, rewritten_field); + TYPE_FIELDS(composite_type_node) = chainon(TYPE_FIELDS(composite_type_node), field_declaration); + } + layout_type(composite_type_node); + return composite_type_node; + } + + tree build_procedure_type(const boot::procedure_type& procedure, std::shared_ptr symbols, + std::vector& path) + { + std::vector parameter_types(procedure.parameters.size()); + + for (std::size_t i = 0; i < procedure.parameters.size(); ++i) + { + parameter_types[i] = get_inner_alias(procedure.parameters.at(i), symbols, path); + } + tree return_type = void_type_node; + + if (!procedure.return_type.proper_type.empty()) + { + return_type = get_inner_alias(procedure.return_type.proper_type, symbols, path); + } + return build_function_type_array(return_type, procedure.parameters.size(), parameter_types.data()); + } + + tree get_inner_alias(const boot::type& type, std::shared_ptr symbols, std::vector& path) + { + if (auto reference = type.get()) + { + auto looked_up = symbols->lookup(reference->identifier); + gcc_assert(looked_up != NULL_TREE); + + return TREE_TYPE(looked_up); + } + else if (auto reference = type.get()) + { + tree composite_type_node = make_node(RECORD_TYPE); + + build_composite_type(reference->fields, composite_type_node, symbols, path); + + return composite_type_node; + } + else if (auto reference = type.get()) + { + tree composite_type_node = make_node(UNION_TYPE); + + build_composite_type(reference->fields, composite_type_node, symbols, path); + + return composite_type_node; + } + else if (auto reference = type.get()) + { + return build_enumeration_type(reference->members); + } + else if (auto reference = type.get()) + { + return build_global_pointer_type(get_inner_alias(reference->base, symbols, path)); + } + else if (auto reference = type.get()) + { + tree base = get_inner_alias(reference->base, symbols, path); + + return build_static_array_type(base, reference->size); + } + else if (auto reference = type.get()) + { + auto procedure = build_procedure_type(*reference, symbols, path); + + return build_global_pointer_type(procedure); + } + else if (auto reference = type.get()) + { + return handle_symbol(reference->name, reference, symbols, path); + } + return error_mark_node; + } + + tree handle_symbol(const std::string& symbol_name, std::shared_ptr reference, + std::shared_ptr symbols, std::vector& path) + { + path.push_back(symbol_name); + std::vector::const_iterator head_peace = std::cbegin(path); + + if (std::find(std::next(head_peace), std::cend(path), *head_peace) != std::cend(path)) + { + return error_mark_node; + } + tree looked_up = symbols->lookup(symbol_name); + + if (looked_up == NULL_TREE) + { + looked_up = get_inner_alias(reference->reference, symbols, path); + + symbols->enter(symbol_name, build_type_declaration(symbol_name, looked_up)); + } + else + { + looked_up = TREE_TYPE(looked_up); + } + return looked_up; + } + + void declare_procedure(const std::string& name, const boot::procedure_info& info, + std::shared_ptr symbols) + { + std::vector path; + tree declaration_type = gcc::build_procedure_type(info.symbol, symbols, path); + tree fndecl = build_fn_decl(name.c_str(), declaration_type); + symbols->enter(name, fndecl); + + if (info.symbol.return_type.no_return) + { + TREE_THIS_VOLATILE(fndecl) = 1; + } + tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, TREE_TYPE(declaration_type)); + DECL_CONTEXT(resdecl) = fndecl; + DECL_RESULT(fndecl) = resdecl; + + tree argument_chain = NULL_TREE; + function_args_iterator parameter_type; + function_args_iter_init(¶meter_type, declaration_type); + + std::vector::const_iterator parameter_name = info.names.cbegin(); + + for (boot::type parameter : info.symbol.parameters) + { + tree declaration_tree = build_decl(UNKNOWN_LOCATION, PARM_DECL, + get_identifier(parameter_name->c_str()), function_args_iter_cond(¶meter_type)); + DECL_CONTEXT(declaration_tree) = fndecl; + DECL_ARG_TYPE(declaration_tree) = function_args_iter_cond(¶meter_type); + + argument_chain = chainon(argument_chain, declaration_tree); + function_args_iter_next(¶meter_type); + ++parameter_name; + } + DECL_ARGUMENTS(fndecl) = argument_chain; + TREE_ADDRESSABLE(fndecl) = 1; + DECL_EXTERNAL(fndecl) = info.symbols == nullptr; + } + + void do_semantic_analysis(std::shared_ptr info_table, std::shared_ptr symbols) + { + for (auto& [symbol_name, symbol_info] : *info_table) + { + std::vector type_path; + + if (auto type_info = symbol_info->is_type()) + { + // The top level symbol table has basic (builtin) types in it which are not aliases. + if (auto alias_type = type_info->symbol.get()) + { + handle_symbol(symbol_name, alias_type, symbols, type_path); + } + } + 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 1e45b7f..2574035 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -16,13 +16,11 @@ along with GCC; see the file COPYING3. If not see . */ #include -#include #include "elna/gcc/elna-generic.h" #include "elna/gcc/elna-diagnostic.h" #include "elna/gcc/elna1.h" - -#include +#include "elna/gcc/elna-builtins.h" #include "ggc.h" #include "function.h" @@ -38,91 +36,9 @@ along with GCC; see the file COPYING3. If not see namespace elna::gcc { - tree get_inner_alias(const boot::type& type, std::shared_ptr symbols, - std::unordered_map& unresolved, std::vector& path) - { - if (auto reference = type.get()) - { - auto looked_up = symbols->lookup(reference->identifier); - if (looked_up != NULL_TREE) - { - return TREE_TYPE(looked_up); - } - } - else if (auto reference = type.get()) - { - return make_node(RECORD_TYPE); - } - else if (auto reference = type.get()) - { - return make_node(UNION_TYPE); - } - else if (auto reference = type.get()) - { - return make_node(ENUMERAL_TYPE); - } - else if (auto reference = type.get()) - { - return build_global_pointer_type(get_inner_alias(reference->base, symbols, unresolved, path)); - } - else if (auto reference = type.get()) - { - tree lower_bound = build_int_cst_type(integer_type_node, 0); - tree upper_bound = build_int_cst_type(integer_type_node, reference->size); - tree range_type = build_range_type(integer_type_node, lower_bound, upper_bound); - - return build_array_type(get_inner_alias(reference->base, symbols, unresolved, path), range_type); - } - else if (auto reference = type.get()) - { - return handle_symbol(reference->name, reference, symbols, unresolved, path); - } - return error_mark_node; - } - - tree handle_symbol(const std::string& symbol_name, std::shared_ptr reference, - std::shared_ptr symbols, std::unordered_map& unresolved, - std::vector& path) - { - path.push_back(symbol_name); - std::vector::const_iterator head_peace = std::cbegin(path); - - if (std::find(std::next(head_peace), std::cend(path), *head_peace) != std::cend(path)) - { - return error_mark_node; - } - auto looked_up = get_inner_alias(reference->reference, symbols, unresolved, path); - - unresolved.insert({ symbol_name, looked_up }); - - return looked_up; - - } - - std::unordered_map do_semantic_analysis(std::shared_ptr info_table, - std::shared_ptr symbols) - { - std::unordered_map unresolved; - - for (auto& [symbol_name, symbol_info] : *info_table) - { - std::vector type_path; - - // The top level symbol table has basic (builtin) types in it which are not aliases. - if (auto type_info = symbol_info->is_type()) - { - if (auto alias_type = type_info->symbol.get()) - { - handle_symbol(symbol_name, alias_type, symbols, unresolved, type_path); - } - } - } - return unresolved; - } - generic_visitor::generic_visitor(std::shared_ptr symbol_table, - std::unordered_map&& unresolved) - : symbols(symbol_table), unresolved(std::move(unresolved)) + std::shared_ptr info_table) + : symbols(symbol_table), info_table(info_table) { } @@ -301,8 +217,8 @@ namespace elna::gcc void generic_visitor::visit(boot::cast_expression *expression) { - expression->target().accept(this); - tree cast_target = this->current_expression; + std::vector path; + tree cast_target = get_inner_alias(expression->expression_type, this->symbols->scope(), path); expression->value().accept(this); tree cast_source = TREE_TYPE(this->current_expression); @@ -320,43 +236,6 @@ namespace elna::gcc } } - void generic_visitor::declare_procedure(boot::procedure_declaration *const definition) - { - tree declaration_type = build_procedure_type(definition->heading()); - tree fndecl = build_fn_decl(definition->identifier.identifier.c_str(), declaration_type); - this->symbols->enter(definition->identifier.identifier, fndecl); - - if (definition->heading().return_type.no_return) - { - TREE_THIS_VOLATILE(fndecl) = 1; - } - tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, TREE_TYPE(declaration_type)); - DECL_CONTEXT(resdecl) = fndecl; - DECL_RESULT(fndecl) = resdecl; - - tree argument_chain = NULL_TREE; - function_args_iterator parameter_type; - function_args_iter_init(¶meter_type, declaration_type); - - std::vector::const_iterator parameter_name = definition->parameter_names.cbegin(); - - for (boot::type_expression *parameter : definition->heading().parameters) - { - tree declaration_tree = build_decl(get_location(¶meter->position()), PARM_DECL, - get_identifier(parameter_name->c_str()), function_args_iter_cond(¶meter_type)); - DECL_CONTEXT(declaration_tree) = fndecl; - DECL_ARG_TYPE(declaration_tree) = function_args_iter_cond(¶meter_type); - - argument_chain = chainon(argument_chain, declaration_tree); - function_args_iter_next(¶meter_type); - ++parameter_name; - } - DECL_ARGUMENTS(fndecl) = argument_chain; - TREE_PUBLIC(fndecl) = definition->identifier.exported; - TREE_ADDRESSABLE(fndecl) = 1; - DECL_EXTERNAL(fndecl) = !definition->body.has_value(); - } - void generic_visitor::visit(boot::program *program) { visit(static_cast(program)); @@ -424,10 +303,6 @@ namespace elna::gcc variable->accept(this); } for (boot::procedure_declaration *const procedure : unit->procedures) - { - declare_procedure(procedure); - } - for (boot::procedure_declaration *const procedure : unit->procedures) { procedure->accept(this); } @@ -435,16 +310,19 @@ namespace elna::gcc void generic_visitor::visit(boot::procedure_declaration *definition) { + tree fndecl = this->symbols->lookup(definition->identifier.identifier); + TREE_PUBLIC(fndecl) = definition->identifier.exported; + if (!definition->body.has_value()) { return; } - tree fndecl = this->symbols->lookup(definition->identifier.identifier); push_struct_function(fndecl, false); DECL_STRUCT_FUNCTION(fndecl)->language = ggc_cleared_alloc(); enter_scope(); + this->info_table = this->info_table->lookup(definition->identifier.identifier)->is_procedure()->symbols; tree argument_chain = DECL_ARGUMENTS(fndecl); for (; argument_chain != NULL_TREE; argument_chain = TREE_CHAIN(argument_chain)) @@ -462,6 +340,7 @@ namespace elna::gcc visit_statements(definition->body.value().body()); tree mapping = leave_scope(); + this->info_table = this->info_table->scope(); BLOCK_SUPERCONTEXT(BIND_EXPR_BLOCK(mapping)) = fndecl; DECL_INITIAL(fndecl) = BIND_EXPR_BLOCK(mapping); @@ -860,85 +739,17 @@ namespace elna::gcc this->current_expression = NULL_TREE; } - void generic_visitor::visit(boot::type_declaration *definition) + void generic_visitor::visit(boot::type_declaration *declaration) { - location_t definition_location = get_location(&definition->position()); - this->current_expression = this->unresolved.at(definition->identifier.identifier); - definition->body().accept(this); - - tree definition_tree = build_decl(definition_location, TYPE_DECL, - get_identifier(definition->identifier.identifier.c_str()), this->current_expression); - - TREE_PUBLIC(definition_tree) = definition->identifier.exported; - if (is_unique_type(this->current_expression)) - { - TYPE_NAME(this->current_expression) = DECL_NAME(definition_tree); - TYPE_STUB_DECL(this->current_expression) = definition_tree; - } - else - { - TYPE_NAME(this->current_expression) = definition_tree; - } - auto result = this->symbols->enter(definition->identifier.identifier, definition_tree); - gcc_assert(result); - - this->current_expression = NULL_TREE; - } - - tree generic_visitor::build_procedure_type(boot::procedure_type_expression& type) - { - std::vector parameter_types(type.parameters.size()); - - for (std::size_t i = 0; i < type.parameters.size(); ++i) - { - type.parameters.at(i)->accept(this); - parameter_types[i] = this->current_expression; - } - tree return_type = void_type_node; - - if (type.return_type.proper_type != nullptr) - { - type.return_type.proper_type->accept(this); - return_type = this->current_expression; - } - this->current_expression = NULL_TREE; - - return build_function_type_array(return_type, type.parameters.size(), parameter_types.data()); - } - - void generic_visitor::build_composite_type(const std::vector& fields, - tree composite_type_node) - { - std::set field_names; - - for (auto& field : fields) - { - if (field_names.find(field.first) != field_names.cend()) - { - error_at(get_location(&field.second->position()), "repeated field name"); - this->current_expression = error_mark_node; - return; - } - field_names.insert(field.first); - - field.second->accept(this); - if (this->current_expression == NULL_TREE || this->current_expression == error_mark_node) - { - return; - } - tree field_declaration = build_field(get_location(&field.second->position()), - composite_type_node, field.first, this->current_expression); - TYPE_FIELDS(composite_type_node) = chainon(TYPE_FIELDS(composite_type_node), field_declaration); - this->current_expression = NULL_TREE; - } - layout_type(composite_type_node); - - this->current_expression = composite_type_node; + TREE_PUBLIC(this->symbols->lookup(declaration->identifier.identifier)) = declaration->identifier.exported; } void generic_visitor::visit(boot::variable_declaration *declaration) { - declaration->variable_type().accept(this); + std::vector path; + this->current_expression = get_inner_alias( + this->info_table->lookup(declaration->identifier.identifier)->is_variable()->symbol, + this->symbols->scope(), path); location_t declaration_location = get_location(&declaration->position()); tree declaration_tree = build_decl(declaration_location, VAR_DECL, @@ -949,6 +760,7 @@ namespace elna::gcc { DECL_INITIAL(declaration_tree) = elna_pointer_nil_node; } + TREE_PUBLIC(declaration_tree) = declaration->identifier.exported; this->current_expression = NULL_TREE; if (!result) { @@ -1042,7 +854,8 @@ namespace elna::gcc this->current_expression = error_mark_node; return false; } - trait->parameters.front()->accept(this); + std::vector path; + this->current_expression = get_inner_alias(trait->types.front(), this->symbols, path); return this->current_expression != error_mark_node; } @@ -1106,7 +919,8 @@ namespace elna::gcc this->current_expression = error_mark_node; return; } - trait->parameters.front()->accept(this); + std::vector path; + this->current_expression = get_inner_alias(trait->types.front(), this->symbols, path); auto field_type = trait->parameters.at(1)->is_named(); if (field_type == nullptr) @@ -1383,45 +1197,12 @@ namespace elna::gcc void generic_visitor::visit(boot::named_type_expression *type) { - auto looked_up = this->unresolved.find(type->name); - tree symbol; - - if (looked_up == this->unresolved.cend()) - { - symbol = this->symbols->lookup(type->name); - if (symbol != NULL_TREE) - { - symbol = TREE_TYPE(symbol); - } - } - else - { - symbol = looked_up->second; - } - if (symbol == NULL_TREE || !TYPE_P(symbol)) - { - error_at(get_location(&type->position()), "Type '%s' not declared", type->name.c_str()); - - this->current_expression = error_mark_node; - } - else - { - this->current_expression = symbol; - } + this->current_expression = TREE_TYPE(this->symbols->lookup(type->name)); } - void generic_visitor::visit(boot::array_type_expression *type) + void generic_visitor::visit(boot::array_type_expression *) { - tree lower_bound = build_int_cst_type(integer_type_node, 0); - tree upper_bound = build_int_cst_type(integer_type_node, type->size); - type->base().accept(this); - - if (this->current_expression != NULL_TREE && this->current_expression != error_mark_node) - { - tree range_type = build_range_type(integer_type_node, lower_bound, upper_bound); - - this->current_expression = build_array_type(this->current_expression, range_type); - } + gcc_unreachable(); } void generic_visitor::visit(boot::pointer_type_expression *type) @@ -1434,66 +1215,24 @@ namespace elna::gcc } } - void generic_visitor::visit(boot::record_type_expression *type) + void generic_visitor::visit(boot::record_type_expression *) { - tree composite_type_node = this->current_expression == NULL_TREE - ? make_node(RECORD_TYPE) - : this->current_expression; - - build_composite_type(type->fields, composite_type_node); + gcc_unreachable(); } - void generic_visitor::visit(boot::union_type_expression *type) + void generic_visitor::visit(boot::union_type_expression *) { - tree composite_type_node = this->current_expression == NULL_TREE - ? make_node(UNION_TYPE) - : this->current_expression; - - build_composite_type(type->fields, composite_type_node); + gcc_unreachable(); } - void generic_visitor::visit(boot::procedure_type_expression *type) + void generic_visitor::visit(boot::procedure_type_expression *) { - tree procedure_type_node = build_procedure_type(*type); - this->current_expression = build_global_pointer_type(procedure_type_node); + gcc_unreachable(); } - void generic_visitor::visit(boot::enumeration_type_expression *type) + void generic_visitor::visit(boot::enumeration_type_expression *) { - tree composite_type_node = this->current_expression == NULL_TREE - ? make_node(ENUMERAL_TYPE) - : this->current_expression; - location_t enum_location = get_location(&type->position()); - const tree base_type = integer_type_node; - - TREE_TYPE(composite_type_node) = base_type; - ENUM_IS_SCOPED(composite_type_node) = 1; - - tree *pp = &TYPE_VALUES(composite_type_node); - std::size_t order{ 1 }; - - for (const std::string& member : type->members) - { - tree member_name = get_identifier(member.c_str()); - tree member_declaration = build_decl(enum_location, CONST_DECL, member_name, composite_type_node); - - DECL_CONTEXT(member_declaration) = composite_type_node; - DECL_INITIAL(member_declaration) = build_int_cst_type(composite_type_node, order++); - TREE_CONSTANT(member_declaration) = 1; - TREE_READONLY(member_declaration) = 1; - - TYPE_MAX_VALUE(composite_type_node) = DECL_INITIAL(member_declaration); - - *pp = build_tree_list(member_name, member_declaration); - pp = &TREE_CHAIN(*pp); - } - TYPE_MIN_VALUE(composite_type_node) = DECL_INITIAL(TREE_VALUE(TYPE_VALUES(composite_type_node))); - TYPE_UNSIGNED(composite_type_node) = TYPE_UNSIGNED(base_type); - SET_TYPE_ALIGN(composite_type_node, TYPE_ALIGN(base_type)); - TYPE_SIZE(composite_type_node) = NULL_TREE; - TYPE_PRECISION(composite_type_node) = TYPE_PRECISION(base_type); - - layout_type(composite_type_node); + gcc_unreachable(); } void generic_visitor::visit(boot::defer_statement *statement) diff --git a/gcc/elna-tree.cc b/gcc/elna-tree.cc index 6c16d84..d00a39a 100644 --- a/gcc/elna-tree.cc +++ b/gcc/elna-tree.cc @@ -246,6 +246,51 @@ namespace elna::gcc return build_pointer_type_for_mode(type, VOIDmode, true); } + tree build_static_array_type(tree type, const std::uint64_t size) + { + tree lower_bound = build_int_cst_type(integer_type_node, 0); + tree upper_bound = build_int_cst_type(integer_type_node, size); + tree range_type = build_range_type(integer_type_node, lower_bound, upper_bound); + + return build_array_type(type, range_type); + } + + tree build_enumeration_type(const std::vector& members) + { + tree composite_type_node = make_node(ENUMERAL_TYPE); + const tree base_type = integer_type_node; + + TREE_TYPE(composite_type_node) = base_type; + ENUM_IS_SCOPED(composite_type_node) = 1; + + tree *pp = &TYPE_VALUES(composite_type_node); + std::size_t order{ 1 }; + + for (const std::string& member : members) + { + tree member_name = get_identifier(member.c_str()); + tree member_declaration = build_decl(UNKNOWN_LOCATION, CONST_DECL, member_name, composite_type_node); + + DECL_CONTEXT(member_declaration) = composite_type_node; + DECL_INITIAL(member_declaration) = build_int_cst_type(composite_type_node, order++); + TREE_CONSTANT(member_declaration) = 1; + TREE_READONLY(member_declaration) = 1; + + TYPE_MAX_VALUE(composite_type_node) = DECL_INITIAL(member_declaration); + + *pp = build_tree_list(member_name, member_declaration); + pp = &TREE_CHAIN(*pp); + } + TYPE_MIN_VALUE(composite_type_node) = DECL_INITIAL(TREE_VALUE(TYPE_VALUES(composite_type_node))); + TYPE_UNSIGNED(composite_type_node) = TYPE_UNSIGNED(base_type); + SET_TYPE_ALIGN(composite_type_node, TYPE_ALIGN(base_type)); + TYPE_SIZE(composite_type_node) = NULL_TREE; + TYPE_PRECISION(composite_type_node) = TYPE_PRECISION(base_type); + + layout_type(composite_type_node); + return composite_type_node; + } + tree build_label_decl(const char *name, location_t loc) { auto label_decl = build_decl(loc, LABEL_DECL, get_identifier(name), void_type_node); diff --git a/gcc/elna1.cc b/gcc/elna1.cc index d5997bc..7b0bde3 100644 --- a/gcc/elna1.cc +++ b/gcc/elna1.cc @@ -90,10 +90,9 @@ static void elna_parse_file(const char *filename) if (declaration_visitor.errors().empty()) { - std::unordered_map unresolved = elna::gcc::do_semantic_analysis( - info_table, symbol_table); + elna::gcc::do_semantic_analysis(info_table, symbol_table); - elna::gcc::generic_visitor generic_visitor{ symbol_table, std::move(unresolved) }; + elna::gcc::generic_visitor generic_visitor{ symbol_table, info_table }; generic_visitor.visit(module_tree.get()); } else diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index 1e4f57e..a27318d 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see #include #include #include +#include "elna/boot/symbol.h" #include "elna/boot/result.h" namespace elna::boot @@ -423,6 +424,8 @@ namespace elna::boot expression *m_value; public: + type expression_type; + cast_expression(const struct position position, type_expression *target, expression *value); void accept(parser_visitor *visitor) override; cast_expression *is_cast() override; @@ -438,6 +441,7 @@ namespace elna::boot public: std::vector parameters; const std::string name; + std::vector types; traits_expression(const struct position position, const std::string& name); ~traits_expression(); diff --git a/include/elna/boot/semantic.h b/include/elna/boot/semantic.h index ac96667..3542896 100644 --- a/include/elna/boot/semantic.h +++ b/include/elna/boot/semantic.h @@ -48,6 +48,16 @@ namespace elna::boot std::string what() const override; }; + class field_duplication_error : public error + { + std::string field_name; + + public: + field_duplication_error(const std::string& field_name, const char *path, const struct position); + + std::string what() const override; + }; + class declaration_visitor final : public parser_visitor, public error_container { type current_type; @@ -57,6 +67,7 @@ namespace elna::boot std::unordered_map> unresolved; procedure_type build_procedure(procedure_type_expression& type_expression); + std::vector build_composite_type(const std::vector& fields); public: explicit declaration_visitor(const char *path, std::shared_ptr symbols); diff --git a/include/elna/boot/symbol.h b/include/elna/boot/symbol.h index b87f012..d28c656 100644 --- a/include/elna/boot/symbol.h +++ b/include/elna/boot/symbol.h @@ -168,46 +168,6 @@ namespace elna::boot virtual std::shared_ptr is_variable(); }; - class type_info : public info - { - public: - const type symbol; - - explicit type_info(const type symbol); - std::shared_ptr is_type() override; - }; - - class procedure_info : public info - { - public: - const procedure_type symbol; - const std::vector names; - - procedure_info(const procedure_type symbol, const std::vector names); - std::shared_ptr is_procedure() override; - }; - - class constant_info : public info - { - public: - using variant = typename - std::variant; - - const variant symbol; - - explicit constant_info(const variant& symbol); - std::shared_ptr is_constant() override; - }; - - class variable_info : public info - { - public: - const type symbol; - - variable_info(const type symbol); - std::shared_ptr is_variable() override; - }; - /** * Symbol table. */ @@ -322,5 +282,47 @@ namespace elna::boot using symbol_table = symbol_map, std::nullptr_t, nullptr>; + class type_info : public info + { + public: + const type symbol; + + explicit type_info(const type symbol); + std::shared_ptr is_type() override; + }; + + class procedure_info : public info + { + public: + const procedure_type symbol; + const std::vector names; + std::shared_ptr symbols; + + procedure_info(const procedure_type symbol, const std::vector names, + std::shared_ptr parent_table = nullptr); + std::shared_ptr is_procedure() override; + }; + + class constant_info : public info + { + public: + using variant = typename + std::variant; + + const variant symbol; + + explicit constant_info(const variant& symbol); + std::shared_ptr is_constant() override; + }; + + class variable_info : public info + { + public: + const type symbol; + + variable_info(const type symbol); + std::shared_ptr is_variable() override; + }; + std::shared_ptr builtin_symbol_table(); } diff --git a/include/elna/gcc/elna-builtins.h b/include/elna/gcc/elna-builtins.h index 251b894..1cf80dc 100644 --- a/include/elna/gcc/elna-builtins.h +++ b/include/elna/gcc/elna-builtins.h @@ -29,4 +29,12 @@ namespace elna::gcc { void init_ttree(); std::shared_ptr builtin_symbol_table(); + + void do_semantic_analysis(std::shared_ptr info_table, std::shared_ptr symbols); + tree handle_symbol(const std::string& symbol_name, std::shared_ptr reference, + std::shared_ptr symbols, std::vector& path); + tree get_inner_alias(const boot::type& type, std::shared_ptr symbols, + std::vector& path); + void declare_procedure(const std::string& name, const boot::procedure_info& info, + std::shared_ptr symbols); } diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index 94f0845..aabfce2 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -33,22 +33,11 @@ along with GCC; see the file COPYING3. If not see namespace elna::gcc { - std::unordered_map do_semantic_analysis(std::shared_ptr info_table, - std::shared_ptr symbols); - tree handle_symbol(const std::string& symbol_name, std::shared_ptr reference, - std::shared_ptr symbols, std::unordered_map& unresolved, - std::vector& path); - class generic_visitor final : public boot::parser_visitor { tree current_expression{ NULL_TREE }; std::shared_ptr symbols; - std::unordered_map unresolved; - - void declare_procedure(boot::procedure_declaration *const definition); - tree build_procedure_type(boot::procedure_type_expression& type); - void build_composite_type(const std::vector& fields, - tree composite_type_node); + std::shared_ptr info_table; void enter_scope(); tree leave_scope(); @@ -74,8 +63,7 @@ namespace elna::gcc bool assert_constant(location_t expression_location); public: - generic_visitor(std::shared_ptr symbol_table, - std::unordered_map&& unresolved); + generic_visitor(std::shared_ptr symbol_table, std::shared_ptr info_table); void visit(boot::program *program) override; void visit(boot::procedure_declaration *definition) override; @@ -92,7 +80,7 @@ namespace elna::gcc void visit(boot::binary_expression *expression) override; void visit(boot::unary_expression *expression) override; void visit(boot::constant_declaration *definition) override; - void visit(boot::type_declaration *definition) override; + void visit(boot::type_declaration *declaration) override; void visit(boot::variable_declaration *declaration) override; void visit(boot::variable_expression *expression) override; void visit(boot::array_access_expression *expression) override; @@ -104,12 +92,12 @@ namespace elna::gcc void visit(boot::import_declaration *) override; void visit(boot::while_statement *statement) override; void visit(boot::named_type_expression *type) override; - void visit(boot::array_type_expression *type) override; + void visit(boot::array_type_expression *) override; void visit(boot::pointer_type_expression *type) override; - void visit(boot::record_type_expression *type) override; - void visit(boot::union_type_expression *type) override; - void visit(boot::procedure_type_expression *type) override; - void visit(boot::enumeration_type_expression *type) override; + void visit(boot::record_type_expression *) override; + void visit(boot::union_type_expression *) override; + void visit(boot::procedure_type_expression *) override; + void visit(boot::enumeration_type_expression *) override; void visit(boot::return_statement *statement) override; void visit(boot::defer_statement *statement) override; void visit(boot::case_statement *statement) override; diff --git a/include/elna/gcc/elna-tree.h b/include/elna/gcc/elna-tree.h index c6b8429..e605d51 100644 --- a/include/elna/gcc/elna-tree.h +++ b/include/elna/gcc/elna-tree.h @@ -82,6 +82,8 @@ namespace elna::gcc tree build_field(location_t location, tree record_type, const std::string name, tree type); tree find_field_by_name(location_t expression_location, tree type, const std::string& field_name); tree build_global_pointer_type(tree type); + tree build_static_array_type(tree type, const std::uint64_t size); + tree build_enumeration_type(const std::vector& members); tree build_label_decl(const char *name, location_t loc); tree extract_constant(tree expression); diff --git a/source/main.elna b/source/main.elna index d29c813..946e32e 100644 --- a/source/main.elna +++ b/source/main.elna @@ -75,24 +75,24 @@ type _defer, exclamation, arrow, - trait, - _program, - _module, - _import + trait, + _program, + _module, + _import ); Position* = record line: Word; - column: Word + column: Word end; Location* = record first: Position; - last: Position + last: Position end; SourceFile* = record - buffer: [1024]Char; - handle: ^FILE; - size: Word; - index: Word + buffer: [1024]Char; + handle: ^FILE; + size: Word; + index: Word end; FILE* = record end; StringBuffer* = record @@ -103,28 +103,28 @@ type SourceCode = record position: Position; - input: Pointer; - empty: proc(Pointer) -> Bool; - advance: proc(Pointer); - head: proc(Pointer) -> Char + input: Pointer; + empty: proc(Pointer) -> Bool; + advance: proc(Pointer); + head: proc(Pointer) -> Char end; Token* = record kind: TokenKind; value: union int_value: Int; string: String; - boolean_value: Bool; - char_value: Char + boolean_value: Bool; + char_value: Char end; - location: Location + location: Location end; CommandLine* = record input: ^Char; - lex: Bool; - parse: Bool + lex: Bool; + parse: Bool end; Lexer* = record - length: Word; + length: Word; data: ^Token end; @@ -314,7 +314,7 @@ begin if source_file^.index > source_file^.size then source_file^.size := fread(cast(@source_file^.buffer: Pointer), 1u, 1024u, source_file^.handle); - source_file^.index := 1u + source_file^.index := 1u end; return source_file^.size = 0u