From cd949c4be722708f6ff17d9176e6cb08cbd106ad Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Wed, 12 Feb 2025 00:56:21 +0100 Subject: [PATCH] Implement string comparison --- gcc/Make-lang.in | 1 - gcc/elna-builtins.cc | 29 ++++- gcc/elna-convert.cc | 31 ----- gcc/elna-generic.cc | 214 +++++++++++++++++-------------- gcc/elna-tree.cc | 92 ++++--------- gcc/elna1.cc | 40 +++--- include/elna/gcc/elna-builtins.h | 17 +++ include/elna/gcc/elna-generic.h | 8 +- include/elna/gcc/elna-tree.h | 57 +------- include/elna/gcc/elna1.h | 47 ++++++- source.elna | 72 +++++------ 11 files changed, 287 insertions(+), 321 deletions(-) delete mode 100644 gcc/elna-convert.cc diff --git a/gcc/Make-lang.in b/gcc/Make-lang.in index ae1a410..e8d5369 100644 --- a/gcc/Make-lang.in +++ b/gcc/Make-lang.in @@ -39,7 +39,6 @@ gelna$(exeext): $(ELNA_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBDEPS) elna_OBJS = \ elna/elna1.o \ elna/elna-generic.o \ - elna/elna-convert.o \ elna/elna-diagnostic.o \ elna/elna-tree.o \ elna/elna-builtins.o \ diff --git a/gcc/elna-builtins.cc b/gcc/elna-builtins.cc index 0f71e1c..a2e6ee0 100644 --- a/gcc/elna-builtins.cc +++ b/gcc/elna-builtins.cc @@ -1,3 +1,20 @@ +/* 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 "elna/gcc/elna-builtins.h" #include "elna/gcc/elna1.h" #include "stor-layout.h" @@ -18,13 +35,15 @@ namespace gcc elna_float_type_node = double_type_node; elna_string_type_node = make_node(RECORD_TYPE); - tree_chain record_chain; + tree string_ptr_type = build_pointer_type_for_mode(elna_char_type_node, VOIDmode, true); + tree record_chain = NULL_TREE; - record_chain.append(build_field(UNKNOWN_LOCATION, elna_string_type_node, "length", elna_word_type_node)); - record_chain.append(build_field(UNKNOWN_LOCATION, elna_string_type_node, "ptr", - build_pointer_type_for_mode(elna_char_type_node, VOIDmode, true))); + record_chain = chainon(record_chain, + build_field(UNKNOWN_LOCATION, elna_string_type_node, "length", elna_word_type_node)); + record_chain = chainon(record_chain, + build_field(UNKNOWN_LOCATION, elna_string_type_node, "ptr", string_ptr_type)); - TYPE_FIELDS(elna_string_type_node) = record_chain.head(); + TYPE_FIELDS(elna_string_type_node) = record_chain; layout_type(elna_string_type_node); } } diff --git a/gcc/elna-convert.cc b/gcc/elna-convert.cc deleted file mode 100644 index c21d3cc..0000000 --- a/gcc/elna-convert.cc +++ /dev/null @@ -1,31 +0,0 @@ -/* Data type conversion routines. - 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 "config.h" -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "fold-const.h" -#include "convert.h" - -/* Creates an expression whose value is that of EXPR, converted to type TYPE. - This function implements all reasonable scalar conversions. */ - -tree convert(tree /* type */, tree expr) -{ - return expr; -} diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index f130d25..4739f29 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see #include "stor-layout.h" #include "varasm.h" #include "fold-const.h" +#include "langhooks.h" #include namespace elna @@ -69,7 +70,7 @@ namespace gcc if (return_type == void_type_node) { - this->scope.front().append_statement(stmt); + append_statement(stmt); this->current_expression = NULL_TREE; } else @@ -96,11 +97,6 @@ namespace gcc this->current_expression = build1(CONVERT_EXPR, elna_word_type_node, size_in_bytes(body_type)); } - bool generic_visitor::is_numeric_type(tree type) - { - return is_integral_type(type) || type == elna_float_type_node; - } - void generic_visitor::visit(boot::program *program) { for (boot::constant_definition *const constant : program->constants) @@ -119,11 +115,8 @@ namespace gcc { procedure->accept(this); } - std::array parameter_types{ - integer_type_node, - build_pointer_type(build_pointer_type(char_type_node)) - }; - tree declaration_type = build_function_type_array(integer_type_node, 2, parameter_types.data()); + tree declaration_type = build_function_type_list(integer_type_node, integer_type_node, + build_pointer_type(build_pointer_type(char_type_node)), NULL_TREE); tree fndecl = build_fn_decl("main", declaration_type); tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, integer_type_node); @@ -132,23 +125,21 @@ namespace gcc push_struct_function(fndecl, false); DECL_STRUCT_FUNCTION(fndecl)->language = ggc_cleared_alloc(); - DECL_STRUCT_FUNCTION(fndecl)->language->binding_level = ggc_cleared_alloc(); enter_scope(); - tree_chain argument_chain; - for (std::size_t i = 0; i < 2; ++i) + tree parameter_type = TYPE_ARG_TYPES(declaration_type); + for (const char *argument_name : std::array{ "count", "parameters" }) { - std::string argument_name = i == 0 ? "count" : "parameters"; - tree argc_declaration_tree = build_decl(UNKNOWN_LOCATION, PARM_DECL, - get_identifier(argument_name.c_str()), parameter_types[i]); - DECL_CONTEXT(argc_declaration_tree) = fndecl; - DECL_ARG_TYPE(argc_declaration_tree) = parameter_types[i]; + tree declaration_tree = build_decl(UNKNOWN_LOCATION, PARM_DECL, + get_identifier(argument_name), TREE_VALUE(parameter_type)); + DECL_CONTEXT(declaration_tree) = fndecl; + DECL_ARG_TYPE(declaration_tree) = TREE_VALUE(parameter_type); - argument_chain.append(argc_declaration_tree); + this->symbol_map->enter(argument_name, declaration_tree); + DECL_ARGUMENTS(fndecl) = chainon(DECL_ARGUMENTS(fndecl), declaration_tree); + parameter_type = TREE_CHAIN(parameter_type); } - DECL_ARGUMENTS(fndecl) = argument_chain.head(); - for (boot::statement *const body_statement : program->body) { body_statement->accept(this); @@ -156,12 +147,12 @@ namespace gcc tree set_result = build2(INIT_EXPR, void_type_node, DECL_RESULT(fndecl), build_int_cst_type(integer_type_node, 0)); tree return_stmt = build1(RETURN_EXPR, void_type_node, set_result); - this->scope.front().append_statement(return_stmt); - tree_symbol_mapping mapping = leave_scope(); + append_statement(return_stmt); + tree mapping = leave_scope(); - BLOCK_SUPERCONTEXT(mapping.block()) = fndecl; - DECL_INITIAL(fndecl) = mapping.block(); - DECL_SAVED_TREE(fndecl) = mapping.bind_expression(); + BLOCK_SUPERCONTEXT(BIND_EXPR_BLOCK(mapping)) = fndecl; + DECL_INITIAL(fndecl) = BIND_EXPR_BLOCK(mapping); + DECL_SAVED_TREE(fndecl) = mapping; DECL_EXTERNAL(fndecl) = 0; DECL_PRESERVE_P(fndecl) = 1; @@ -189,14 +180,16 @@ namespace gcc if (definition->body() != nullptr) { - current_function_decl = fndecl; tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, return_type); DECL_CONTEXT(resdecl) = fndecl; DECL_RESULT(fndecl) = resdecl; + push_struct_function(fndecl, false); + DECL_STRUCT_FUNCTION(fndecl)->language = ggc_cleared_alloc(); + enter_scope(); } - tree_chain argument_chain; + tree argument_chain = NULL_TREE; for (std::size_t i = 0; i < definition->parameters.size(); ++i) { auto parameter = definition->parameters.at(i); @@ -210,24 +203,24 @@ namespace gcc { this->symbol_map->enter(parameter->identifier, declaration_tree); } - argument_chain.append(declaration_tree); + argument_chain = chainon(argument_chain, declaration_tree); } - DECL_ARGUMENTS(fndecl) = argument_chain.head(); + DECL_ARGUMENTS(fndecl) = argument_chain; TREE_PUBLIC(fndecl) = definition->exported; if (definition->body() != nullptr) { definition->body()->accept(this); - tree_symbol_mapping mapping = leave_scope(); + tree mapping = leave_scope(); - BLOCK_SUPERCONTEXT(mapping.block()) = fndecl; - DECL_INITIAL(fndecl) = mapping.block(); - DECL_SAVED_TREE(fndecl) = mapping.bind_expression(); + BLOCK_SUPERCONTEXT(BIND_EXPR_BLOCK(mapping)) = fndecl; + DECL_INITIAL(fndecl) = BIND_EXPR_BLOCK(mapping); + DECL_SAVED_TREE(fndecl) = mapping; DECL_EXTERNAL(fndecl) = 0; DECL_PRESERVE_P(fndecl) = 1; - current_function_decl = NULL_TREE; + pop_cfun(); gimplify_function_tree(fndecl); cgraph_node::finalize_function(fndecl, true); } @@ -239,30 +232,35 @@ namespace gcc void generic_visitor::enter_scope() { - scope.emplace_front(); this->symbol_map = std::make_shared>(this->symbol_map); + + // Chain the binding levels. + struct binding_level *new_level = ggc_cleared_alloc(); + new_level->level_chain = f_binding_level; + new_level->statement_list = alloc_stmt_list(); + f_binding_level = new_level; } - tree_symbol_mapping generic_visitor::leave_scope() + tree generic_visitor::leave_scope() { - tree new_block = build_block(this->scope.front().variables.head(), - this->scope.front().blocks.head(), NULL_TREE, NULL_TREE); + // Variables are only defined in the top function scope. + tree variables = f_binding_level->level_chain == nullptr ? f_names : NULL_TREE; + tree new_block = build_block(variables, f_binding_level->blocks, NULL_TREE, NULL_TREE); - for (tree it = this->scope.front().blocks.head(); it != NULL_TREE; it = BLOCK_CHAIN(it)) + for (tree it = f_binding_level->blocks; it != NULL_TREE; it = BLOCK_CHAIN(it)) { BLOCK_SUPERCONTEXT(it) = new_block; } - tree bind_expr = build3(BIND_EXPR, void_type_node, this->scope.front().variables.head(), - this->scope.front().chain_defer(), new_block); + tree bind_expr = build3(BIND_EXPR, void_type_node, variables, chain_defer(), new_block); this->symbol_map = this->symbol_map->scope(); - scope.pop_front(); + f_binding_level = f_binding_level->level_chain; - if (!scope.empty()) + if (f_binding_level != nullptr) { - scope.front().blocks.append(new_block); + f_binding_level->blocks = chainon(f_binding_level->blocks, new_block); } - return tree_symbol_mapping{ bind_expr, new_block }; + return bind_expr; } tree generic_visitor::lookup(const std::string& name) @@ -295,16 +293,6 @@ namespace gcc { return elna_string_type_node; } - if (current_function_decl != NULL_TREE) - { - for (tree decl = DECL_ARGUMENTS(current_function_decl); decl; decl = DECL_CHAIN(decl)) - { - if (name == IDENTIFIER_POINTER(DECL_NAME(decl))) - { - return decl; - } - } - } return this->symbol_map->lookup(name); } @@ -392,11 +380,52 @@ namespace gcc expression, operator_code, left, right, elna_bool_type_node); } - tree generic_visitor::build_equality_operation(boot::binary_expression *expression, - tree_code operator_code, tree left, tree right) + tree generic_visitor::build_equality_operation(boot::binary_expression *expression, tree left, tree right) { - return build_binary_operation(true, expression, - operator_code, left, right, elna_bool_type_node); + location_t expression_location = get_location(&expression->position()); + tree_code equality_code, combination_code; + + if (expression->operation() == boot::binary_operator::equals) + { + equality_code = EQ_EXPR; + combination_code = TRUTH_ANDIF_EXPR; + } + else if (expression->operation() == boot::binary_operator::not_equals) + { + equality_code = NE_EXPR; + combination_code = TRUTH_ORIF_EXPR; + } + else + { + gcc_unreachable(); + } + if (TREE_TYPE(left) == elna_string_type_node) + { + tree length_field = TYPE_FIELDS(elna_string_type_node); + tree ptr_field = TREE_CHAIN(length_field); + + tree lhs_length = build3(COMPONENT_REF, TREE_TYPE(length_field), left, length_field, NULL_TREE); + tree lhs_ptr = build3(COMPONENT_REF, TREE_TYPE(ptr_field), left, ptr_field, NULL_TREE); + + tree rhs_length = build3(COMPONENT_REF, TREE_TYPE(length_field), right, length_field, NULL_TREE); + tree rhs_ptr = build3(COMPONENT_REF, TREE_TYPE(ptr_field), right, ptr_field, NULL_TREE); + + tree length_equality = build2(equality_code, elna_bool_type_node, lhs_length, rhs_length); + tree *memcmp = elna_global_decls->get("__builtin_memcmp"); + gcc_assert(memcmp != nullptr); + + tree fndecl_type = build_function_type(integer_type_node, TYPE_ARG_TYPES(*memcmp)); + tree memcmp_addr = build1(ADDR_EXPR, build_pointer_type(fndecl_type), *memcmp); + tree memcmp_call = build_call_nary(integer_type_node, memcmp_addr, 3, lhs_ptr, rhs_ptr, lhs_length); + + tree equals_zero = build2(equality_code, elna_bool_type_node, memcmp_call, integer_zero_node); + + return build2(combination_code, elna_bool_type_node, length_equality, equals_zero); + } + else + { + return build2_loc(expression_location, equality_code, elna_bool_type_node, left, right); + } } void generic_visitor::visit(boot::binary_expression *expression) @@ -473,10 +502,10 @@ namespace gcc this->current_expression = build_logic_operation(expression, TRUTH_ORIF_EXPR, left, right); break; case boot::binary_operator::equals: - this->current_expression = build_equality_operation(expression, EQ_EXPR, left, right); + this->current_expression = build_equality_operation(expression, left, right); break; case boot::binary_operator::not_equals: - this->current_expression = build_equality_operation(expression, NE_EXPR, left, right); + this->current_expression = build_equality_operation(expression, left, right); break; } } @@ -520,11 +549,11 @@ namespace gcc TREE_READONLY(definition_tree) = 1; TREE_PUBLIC(definition_tree) = definition->exported; - if (!scope.empty()) + if (!lang_hooks.decls.global_bindings_p()) { auto declaration_statement = build1_loc(definition_location, DECL_EXPR, void_type_node, definition_tree); - this->scope.front().append_statement(declaration_statement); + append_statement(declaration_statement); } } else @@ -599,7 +628,6 @@ namespace gcc { std::set field_names; tree record_type_node = make_node(RECORD_TYPE); - tree_chain record_chain; for (auto& field : record_type->fields) { @@ -617,9 +645,8 @@ namespace gcc } tree field_declaration = build_field(get_location(&field.second->position()), record_type_node, field.first, field_type); - record_chain.append(field_declaration); + TYPE_FIELDS(record_type_node) = chainon(TYPE_FIELDS(record_type_node), field_declaration); } - TYPE_FIELDS(record_type_node) = record_chain.head(); layout_type(record_type_node); return record_type_node; @@ -628,7 +655,6 @@ namespace gcc { std::set field_names; tree union_type_node = make_node(UNION_TYPE); - tree_chain union_chain; for (auto& field : union_type->fields) { @@ -646,9 +672,8 @@ namespace gcc } tree field_declaration = build_field(get_location(&field.second->position()), union_type_node, field.first, field_type); - union_chain.append(field_declaration); + TYPE_FIELDS(union_type_node) = chainon(TYPE_FIELDS(union_type_node), field_declaration); } - TYPE_FIELDS(union_type_node) = union_chain.head(); layout_type(union_type_node); return union_type_node; @@ -671,7 +696,7 @@ namespace gcc error_at(declaration_location, "variable '%s' already declared in this scope", declaration->identifier.c_str()); } - else if (current_function_decl == NULL_TREE) + else if (lang_hooks.decls.global_bindings_p()) { TREE_STATIC(declaration_tree) = 1; varpool_node::get_create(declaration_tree); @@ -680,11 +705,11 @@ namespace gcc else { DECL_CONTEXT(declaration_tree) = current_function_decl; - this->scope.front().variables.append(declaration_tree); + f_names = chainon(f_names, declaration_tree); auto declaration_statement = build1_loc(declaration_location, DECL_EXPR, void_type_node, declaration_tree); - this->scope.front().append_statement(declaration_statement); + append_statement(declaration_statement); } } @@ -779,7 +804,7 @@ namespace gcc tree assignment = build2_loc(statement_location, MODIFY_EXPR, void_type_node, lvalue, this->current_expression); - this->scope.front().append_statement(assignment); + append_statement(assignment); this->current_expression = NULL_TREE; } else @@ -810,11 +835,11 @@ namespace gcc { body_statement->accept(this); } - tree_symbol_mapping mapping = leave_scope(); - scope.front().append_statement(mapping.bind_expression()); + tree mapping = leave_scope(); + append_statement(mapping); } tree endif_label_expr = build1(LABEL_EXPR, void_type_node, endif_label_decl); - this->scope.front().append_statement(endif_label_expr); + append_statement(endif_label_expr); this->current_expression = NULL_TREE; } @@ -837,22 +862,22 @@ namespace gcc tree goto_else = build1(GOTO_EXPR, void_type_node, else_label_decl); auto cond_expr = build3(COND_EXPR, void_type_node, this->current_expression, goto_then, goto_else); - this->scope.front().append_statement(cond_expr); + append_statement(cond_expr); tree then_label_expr = build1(LABEL_EXPR, void_type_node, then_label_decl); - this->scope.front().append_statement(then_label_expr); + append_statement(then_label_expr); enter_scope(); for (const auto body_statement : branch.statements) { body_statement->accept(this); } - tree_symbol_mapping mapping = leave_scope(); - this->scope.front().append_statement(mapping.bind_expression()); - this->scope.front().append_statement(goto_endif); + tree mapping = leave_scope(); + append_statement(mapping); + append_statement(goto_endif); tree else_label_expr = build1(LABEL_EXPR, void_type_node, else_label_decl); - this->scope.front().append_statement(else_label_expr); + append_statement(else_label_expr); } tree generic_visitor::build_label_decl(const char *name, location_t loc) @@ -885,7 +910,7 @@ namespace gcc auto prerequisite_label_decl = build_label_decl("while_check", prerequisite_location); auto prerequisite_label_expr = build1_loc(prerequisite_location, LABEL_EXPR, void_type_node, prerequisite_label_decl); - this->scope.front().append_statement(prerequisite_label_expr); + append_statement(prerequisite_label_expr); auto body_label_decl = build_label_decl("while_body", body_location); auto end_label_decl = build_label_decl("end_while", UNKNOWN_LOCATION); @@ -897,24 +922,24 @@ namespace gcc auto cond_expr = build3_loc(prerequisite_location, COND_EXPR, void_type_node, this->current_expression, goto_body, goto_end); - this->scope.front().append_statement(cond_expr); + append_statement(cond_expr); auto body_label_expr = build1_loc(body_location, LABEL_EXPR, void_type_node, body_label_decl); - this->scope.front().append_statement(body_label_expr); + append_statement(body_label_expr); for (const auto body_statement : statement->body().statements) { body_statement->accept(this); } - tree_symbol_mapping mapping = leave_scope(); - this->scope.front().append_statement(mapping.bind_expression()); + tree mapping = leave_scope(); + append_statement(mapping); auto goto_check = build1(GOTO_EXPR, void_type_node, prerequisite_label_decl); - this->scope.front().append_statement(goto_check); + append_statement(goto_check); auto endif_label_expr = build1(LABEL_EXPR, void_type_node, end_label_decl); - this->scope.front().append_statement(endif_label_expr); + append_statement(endif_label_expr); this->current_expression = NULL_TREE; } @@ -922,7 +947,7 @@ namespace gcc void generic_visitor::visit(boot::call_statement *statement) { statement->body().accept(this); - this->scope.front().append_statement(this->current_expression); + append_statement(this->current_expression); this->current_expression = NULL_TREE; } @@ -939,7 +964,7 @@ namespace gcc tree set_result = build2(INIT_EXPR, void_type_node, DECL_RESULT(current_function_decl), this->current_expression); tree return_stmt = build1(RETURN_EXPR, void_type_node, set_result); - this->scope.front().append_statement(return_stmt); + append_statement(return_stmt); } void generic_visitor::visit(boot::defer_statement *statement) @@ -949,8 +974,7 @@ namespace gcc { body_statement->accept(this); } - tree_symbol_mapping mapping = leave_scope(); - scope.front().defer(mapping.bind_expression()); + defer(leave_scope()); } } } diff --git a/gcc/elna-tree.cc b/gcc/elna-tree.cc index 41c6458..300a9cf 100644 --- a/gcc/elna-tree.cc +++ b/gcc/elna-tree.cc @@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see #include "elna/gcc/elna-diagnostic.h" #include "elna/gcc/elna1.h" +#include "function.h" #include "stor-layout.h" #include "fold-const.h" #include "diagnostic-core.h" @@ -39,6 +40,11 @@ namespace gcc return TREE_CODE(type) == INTEGER_TYPE; } + bool is_numeric_type(tree type) + { + return is_integral_type(type) || type == elna_float_type_node; + } + bool are_compatible_pointers(tree lhs, tree rhs) { tree lhs_type = TREE_TYPE(lhs); @@ -48,90 +54,42 @@ namespace gcc || (is_pointer_type(lhs_type) && lhs_type == rhs_type); } - tree tree_chain_base::head() + void append_statement(tree statement_tree) { - return first; - } - - void tree_chain_base::append(tree t) - { - gcc_assert(t != NULL_TREE); - - if (this->first == NULL_TREE) + if (!vec_safe_is_empty(f_binding_level->defers)) { - this->first = this->last = t; + append_to_statement_list(statement_tree, &f_binding_level->defers->begin()->try_statements); } else { - chain(t); - this->last = t; + append_to_statement_list(statement_tree, &f_binding_level->statement_list); } } - void tree_chain::chain(tree t) + void defer(tree statement_tree) { - TREE_CHAIN(this->last) = t; + defer_scope new_defer{ statement_tree, alloc_stmt_list() }; + vec_safe_insert(f_binding_level->defers, 0, new_defer); } - void block_chain::chain(tree t) + tree chain_defer() { - BLOCK_CHAIN(this->last) = t; - } - - tree_symbol_mapping::tree_symbol_mapping(tree bind_expression, tree block) - : m_bind_expression(bind_expression), m_block(block) - { - } - - tree tree_symbol_mapping::bind_expression() - { - return m_bind_expression; - } - - tree tree_symbol_mapping::block() - { - return m_block; - } - - block_scope::block_scope() - : m_statement_list(alloc_stmt_list()) - { - } - - void block_scope::append_statement(tree statement_tree) - { - if (!defers.empty()) + if (vec_safe_is_empty(f_binding_level->defers)) { - append_to_statement_list(statement_tree, &this->defers.front().second); + return f_binding_level->statement_list; } - else - { - append_to_statement_list(statement_tree, &this->m_statement_list); - } - } + defer_scope *defer_iterator = f_binding_level->defers->begin(); + tree defer_tree = build2(TRY_FINALLY_EXPR, void_type_node, + defer_iterator->try_statements, defer_iterator->defer_block); + int i; - void block_scope::defer(tree statement_tree) - { - defers.push_front({ statement_tree, alloc_stmt_list() }); - } - - tree block_scope::chain_defer() - { - if (this->defers.empty()) + FOR_EACH_VEC_ELT_FROM(*f_binding_level->defers, i, defer_iterator, 1) { - return m_statement_list; + append_to_statement_list(defer_tree, &defer_iterator->try_statements); + defer_tree = build2(TRY_FINALLY_EXPR, void_type_node, + defer_iterator->try_statements, defer_iterator->defer_block); } - std::forward_list>::iterator defer_iterator = - this->defers.begin(); - tree defer_tree = build2(TRY_FINALLY_EXPR, void_type_node, defer_iterator->second, defer_iterator->first); - - ++defer_iterator; - for (; defer_iterator != this->defers.end(); ++defer_iterator) - { - append_to_statement_list(defer_tree, &defer_iterator->second); - defer_tree = build2(TRY_FINALLY_EXPR, void_type_node, defer_iterator->second, defer_iterator->first); - } - return build2(COMPOUND_EXPR, TREE_TYPE(defer_tree), m_statement_list, defer_tree); + return build2(COMPOUND_EXPR, TREE_TYPE(defer_tree), f_binding_level->statement_list, defer_tree); } tree build_field(location_t location, tree record_type, const std::string name, tree type) diff --git a/gcc/elna1.cc b/gcc/elna1.cc index 2ac2a69..5ea5ab4 100644 --- a/gcc/elna1.cc +++ b/gcc/elna1.cc @@ -1,5 +1,5 @@ /* Language-dependent hooks for Elna. - Copyright (C) 2006-2024 Free Software Foundation, Inc. + 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 @@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see #include "parser.hh" tree elna_global_trees[ELNA_TI_MAX]; +hash_map *elna_global_decls = nullptr; /* The resulting tree type. */ @@ -53,7 +54,9 @@ union GTY ((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"), static bool elna_langhook_init(void) { build_common_tree_nodes(false); + elna::gcc::init_ttree(); + elna_global_decls = hash_map::create_ggc(default_hash_map_size); build_common_builtin_nodes(); @@ -172,30 +175,32 @@ static bool global_bindings_p(void) return current_function_decl == NULL_TREE; } -tree getdecls(void) +static tree pushdecl(tree decl) { - if (current_function_decl != NULL_TREE) - { - return f_binding_level->names; - } - return NULL_TREE; -} - -tree pushdecl(tree decl) -{ - if (current_function_decl != NULL_TREE) - { - TREE_CHAIN(decl) = f_binding_level->names; - f_binding_level->names = decl; - } return decl; } static tree elna_langhook_builtin_function(tree decl) { + elna_global_decls->put(IDENTIFIER_POINTER(DECL_NAME(decl)), decl); return decl; } +/* Creates an expression whose value is that of EXPR, converted to type TYPE. + This function implements all reasonable scalar conversions. */ +tree convert(tree type, tree expr) +{ + if (error_operand_p(type) || error_operand_p(expr)) + { + return error_mark_node; + } + if (TREE_TYPE(expr) == type) + { + return expr; + } + return error_mark_node; +} + #undef LANG_HOOKS_NAME #define LANG_HOOKS_NAME "GNU Elna" @@ -208,6 +213,9 @@ static tree elna_langhook_builtin_function(tree decl) #undef LANG_HOOKS_TYPE_FOR_MODE #define LANG_HOOKS_TYPE_FOR_MODE elna_langhook_type_for_mode +#undef LANG_HOOKS_GETDECLS +#define LANG_HOOKS_GETDECLS hook_tree_void_null + #undef LANG_HOOKS_BUILTIN_FUNCTION #define LANG_HOOKS_BUILTIN_FUNCTION elna_langhook_builtin_function diff --git a/include/elna/gcc/elna-builtins.h b/include/elna/gcc/elna-builtins.h index 83e3cfe..a7d6b9f 100644 --- a/include/elna/gcc/elna-builtins.h +++ b/include/elna/gcc/elna-builtins.h @@ -1,3 +1,20 @@ +/* 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 "config.h" #include "system.h" #include "coretypes.h" diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index fe74cab..6bd2b4c 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -36,7 +36,6 @@ namespace gcc { class generic_visitor final : public boot::empty_visitor { - std::forward_list scope; tree current_expression{ NULL_TREE }; std::shared_ptr> symbol_map; @@ -44,22 +43,19 @@ namespace gcc tree build_type(boot::type_expression& type); void enter_scope(); - tree_symbol_mapping leave_scope(); + tree leave_scope(); tree lookup(const std::string& name); void make_if_branch(boot::conditional_statements& branch, tree goto_endif); - bool is_numeric_type(tree type); - tree build_arithmetic_operation(boot::binary_expression *expression, tree_code operator_code, tree left, tree right); tree build_comparison_operation(boot::binary_expression *expression, tree_code operator_code, tree left, tree right); tree build_logic_operation(boot::binary_expression *expression, tree_code operator_code, tree left, tree right); - tree build_equality_operation(boot::binary_expression *expression, - tree_code operator_code, tree left, tree right); + tree build_equality_operation(boot::binary_expression *expression, tree left, tree right); public: generic_visitor(std::shared_ptr> symbol_table); diff --git a/include/elna/gcc/elna-tree.h b/include/elna/gcc/elna-tree.h index cb09caf..8586355 100644 --- a/include/elna/gcc/elna-tree.h +++ b/include/elna/gcc/elna-tree.h @@ -35,6 +35,7 @@ namespace gcc { bool is_pointer_type(tree type); bool is_integral_type(tree type); + bool is_numeric_type(tree type); /** * \param lhs Left hand value. @@ -43,59 +44,9 @@ namespace gcc */ bool are_compatible_pointers(tree lhs, tree rhs); - class tree_chain_base - { - protected: - tree first{}; - tree last{}; - - public: - tree head(); - void append(tree t); - - protected: - virtual void chain(tree t) = 0; - }; - - class tree_chain final : public tree_chain_base - { - protected: - void chain(tree t) override; - }; - - class block_chain final : public tree_chain_base - { - protected: - void chain(tree t) override; - }; - - class tree_symbol_mapping final - { - tree m_bind_expression; - tree m_block; - - public: - tree_symbol_mapping(tree bind_expression, tree block); - - tree bind_expression(); - tree block(); - }; - - class block_scope - { - tree m_statement_list{ NULL_TREE }; - std::forward_list> defers; - - public: - tree_chain variables; - block_chain blocks; - - block_scope(); - - void append_statement(tree statement_tree); - void defer(tree statement_tree); - tree chain_defer(); - }; + void append_statement(tree statement_tree); + void defer(tree statement_tree); + tree chain_defer(); tree do_pointer_arithmetic(boot::binary_operator binary_operator, tree left, tree right); tree build_binary_operation(bool condition, boot::binary_expression *expression, diff --git a/include/elna/gcc/elna1.h b/include/elna/gcc/elna1.h index b43dbac..93d0043 100644 --- a/include/elna/gcc/elna1.h +++ b/include/elna/gcc/elna1.h @@ -1,3 +1,20 @@ +/* Language-dependent hooks for Elna. + 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 +. */ + enum elna_tree_index { ELNA_TI_INT_TYPE, @@ -11,6 +28,7 @@ enum elna_tree_index }; extern GTY(()) tree elna_global_trees[ELNA_TI_MAX]; +extern GTY(()) hash_map *elna_global_decls; #define elna_int_type_node elna_global_trees[ELNA_TI_INT_TYPE] #define elna_word_type_node elna_global_trees[ELNA_TI_WORD_TYPE] @@ -30,18 +48,35 @@ struct GTY (()) lang_decl { }; -struct GTY (()) binding_level +struct GTY (()) defer_scope { - // A chain of all declarations in this binding level. - tree names; + tree defer_block; + tree try_statements; +}; + +struct GTY ((chain_next ("%h.level_chain"))) binding_level +{ + // A block chain is needed to call defer statements beloning to each block. + tree blocks; + + // Parent level. + struct binding_level *level_chain; + + // Statements before the first defer has been seen. + tree statement_list; + + // Defer statement coupled with statements following it. + vec *defers; }; struct GTY (()) language_function { + // Local variables and constants. + tree names; + + // Lexical scope. struct binding_level *binding_level; }; #define f_binding_level DECL_STRUCT_FUNCTION(current_function_decl)->language->binding_level - -extern tree pushdecl(tree); -extern tree getdecls(void); +#define f_names DECL_STRUCT_FUNCTION(current_function_decl)->language->names diff --git a/source.elna b/source.elna index 4d41524..b069d86 100644 --- a/source.elna +++ b/source.elna @@ -174,14 +174,6 @@ begin return c = ' ' or c = '\n' or c = '\t' end -proc string_equals(this: String, that: String): Bool; -begin - if this.length <> that.length then - return false - end; - return strncmp(this.ptr, that.ptr, this.length) = 0 -end - proc open_substring(string: String, start: Word): String; begin string.ptr := string.ptr + start; @@ -560,67 +552,67 @@ proc categorize_identifier(token_content: String): Token; var current_token: Token; begin - if string_equals("if", token_content) then + if "if" = token_content then current_token.kind := TOKEN_IF - elsif string_equals("then", token_content) then + elsif "then" = token_content then current_token.kind := TOKEN_THEN - elsif string_equals("else", token_content) then + elsif "else" = token_content then current_token.kind := TOKEN_ELSE - elsif string_equals("elsif", token_content) then + elsif "elsif" = token_content then current_token.kind := TOKEN_ELSIF - elsif string_equals("while", token_content) then + elsif "while" = token_content then current_token.kind := TOKEN_WHILE - elsif string_equals("do", token_content) then + elsif "do" = token_content then current_token.kind := TOKEN_DO - elsif string_equals("proc", token_content) then + elsif "proc" = token_content then current_token.kind := TOKEN_PROC - elsif string_equals("begin", token_content) then + elsif "begin" = token_content then current_token.kind := TOKEN_BEGIN - elsif string_equals("end", token_content) then + elsif "end" = token_content then current_token.kind := TOKEN_END - elsif string_equals("extern", token_content) then + elsif "extern" = token_content then current_token.kind := TOKEN_EXTERN - elsif string_equals("const", token_content) then + elsif "const" = token_content then current_token.kind := TOKEN_CONST - elsif string_equals("var", token_content) then + elsif "var" = token_content then current_token.kind := TOKEN_VAR - elsif string_equals("array", token_content) then + elsif "array" = token_content then current_token.kind := TOKEN_ARRAY - elsif string_equals("of", token_content) then + elsif "of" = token_content then current_token.kind := TOKEN_OF - elsif string_equals("type", token_content) then + elsif "type" = token_content then current_token.kind := TOKEN_TYPE - elsif string_equals("record", token_content) then + elsif "record" = token_content then current_token.kind := TOKEN_RECORD - elsif string_equals("union", token_content) then + elsif "union" = token_content then current_token.kind := TOKEN_UNION - elsif string_equals("pointer", token_content) then + elsif "pointer" = token_content then current_token.kind := TOKEN_POINTER - elsif string_equals("to", token_content) then + elsif "to" = token_content then current_token.kind := TOKEN_TO - elsif string_equals("true", token_content) then + elsif "true" = token_content then current_token.kind := TOKEN_BOOLEAN; current_token.value.boolean_value := true - elsif string_equals("false", token_content) then + elsif "false" = token_content then current_token.kind := TOKEN_BOOLEAN; current_token.value.boolean_value := false - elsif string_equals("nil", token_content) then + elsif "nil" = token_content then current_token.kind := TOKEN_NIL - elsif string_equals("and", token_content) then + elsif "and" = token_content then current_token.kind := TOKEN_AND - elsif string_equals("or", token_content) then + elsif "or" = token_content then current_token.kind := TOKEN_OR - elsif string_equals("not", token_content) then + elsif "not" = token_content then current_token.kind := TOKEN_NOT - elsif string_equals("return", token_content) then + elsif "return" = token_content then current_token.kind := TOKEN_RETURN - elsif string_equals("cast", token_content) then + elsif "cast" = token_content then current_token.kind := TOKEN_CAST - elsif string_equals("as", token_content) then + elsif "as" = token_content then current_token.kind := TOKEN_AS - elsif string_equals("sizeof", token_content) then + elsif "sizeof" = token_content then current_token.kind := TOKEN_SIZEOF - elsif string_equals("defer", token_content) then + elsif "defer" = token_content then current_token.kind := TOKEN_DEFER else current_token.kind := TOKEN_IDENTIFIER; @@ -650,9 +642,7 @@ begin if is_alpha(first_char) or first_char = '_' then lex_identifier(@source_code, @token_content); - current_token^ := categorize_identifier(token_content); - - source_code := advance_source(source_code, 1u) + current_token^ := categorize_identifier(token_content) elsif is_digit(first_char) then token_end := nil; current_token^.value.int_value := strtol(source_code.text.ptr, @token_end, 10);