/* Builtin definitions. Copyright (C) 2025 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 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" #include "stringpool.h" #include "elna/gcc/elna-tree.h" namespace elna::gcc { void init_ttree() { elna_int_type_node = long_integer_type_node; elna_word_type_node = size_type_node; elna_char_type_node = unsigned_char_type_node; elna_pointer_type_node = ptr_type_node; elna_float_type_node = double_type_node; elna_bool_type_node = boolean_type_node; elna_bool_true_node = boolean_true_node; elna_bool_false_node = boolean_false_node; elna_pointer_nil_node = null_pointer_node; elna_string_type_node = make_node(RECORD_TYPE); tree string_ptr_type = build_pointer_type_for_mode(elna_char_type_node, VOIDmode, true); elna_string_length_field_node = build_field(UNKNOWN_LOCATION, elna_string_type_node, "length", build_qualified_type(elna_word_type_node, TYPE_QUAL_CONST)); elna_string_ptr_field_node = build_field(UNKNOWN_LOCATION, elna_string_type_node, "ptr", build_qualified_type(string_ptr_type, TYPE_QUAL_CONST)); TYPE_FIELDS(elna_string_type_node) = chainon(elna_string_ptr_field_node, elna_string_length_field_node); layout_type(elna_string_type_node); } static tree declare_builtin_type(std::shared_ptr symbol_table, const char *name, tree type) { tree identifier = get_identifier(name); tree type_declaration = build_decl(UNKNOWN_LOCATION, TYPE_DECL, identifier, type); TREE_PUBLIC(type_declaration) = 1; symbol_table->enter(name, type_declaration); return type_declaration; } std::shared_ptr builtin_symbol_table() { std::shared_ptr symbol_table = std::make_shared(); declare_builtin_type(symbol_table, "Int", elna_int_type_node); declare_builtin_type(symbol_table, "Word", elna_word_type_node); declare_builtin_type(symbol_table, "Char", elna_char_type_node); declare_builtin_type(symbol_table, "Bool", elna_bool_type_node); declare_builtin_type(symbol_table, "Pointer", elna_pointer_type_node); declare_builtin_type(symbol_table, "Float", elna_float_type_node); tree string_declaration = declare_builtin_type(symbol_table, "String", elna_string_type_node); TYPE_NAME(elna_string_type_node) = DECL_NAME(string_declaration); TYPE_STUB_DECL(elna_string_type_node) = string_declaration; 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); } } } }