From 39750f46560c9b4202752c8afd5bf3909c2dfb31 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Mon, 17 Feb 2025 19:36:25 +0100 Subject: [PATCH] Implement elsif do --- boot/ast.cc | 4 +++ boot/parser.yy | 22 ++++++++++---- gcc/elna-generic.cc | 54 ++++++--------------------------- gcc/elna1.cc | 2 +- include/elna/boot/ast.h | 1 + include/elna/boot/symbol.h | 15 ++++++--- include/elna/gcc/elna-generic.h | 4 +-- include/elna/gcc/elna-tree.h | 2 ++ 8 files changed, 46 insertions(+), 58 deletions(-) diff --git a/boot/ast.cc b/boot/ast.cc index 103faec..a1ff75d 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -944,6 +944,10 @@ namespace boot while_statement::~while_statement() { delete m_body; + for (const auto branch : branches) + { + delete branch; + } } const char *print_binary_operator(const binary_operator operation) diff --git a/boot/parser.yy b/boot/parser.yy index 86f0b06..bf12292 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -119,7 +119,7 @@ along with GCC; see the file COPYING3. If not see %type block; %type field_declaration; %type >>> optional_fields fields; -%type > elsif_statement_list; +%type > elsif_then_statements elsif_do_statements; %type cast_expression; %type defer_statement; %type > identifier_definition; @@ -201,14 +201,24 @@ cast_expression: CAST LEFT_PAREN expression COLON type_expression RIGHT_PAREN { $$ = new elna::boot::cast_expression(elna::boot::make_position(@1), $5, $3); } -while_statement: WHILE expression DO optional_statements END_BLOCK +elsif_do_statements: + ELSIF expression DO optional_statements elsif_do_statements + { + elna::boot::conditional_statements *branch = new elna::boot::conditional_statements($2); + std::swap(branch->statements, $4); + std::swap($5, $$); + $$.emplace($$.begin(), branch); + } + | {} +while_statement: WHILE expression DO optional_statements elsif_do_statements END_BLOCK { auto body = new elna::boot::conditional_statements($2); std::swap($4, body->statements); $$ = new elna::boot::while_statement(elna::boot::make_position(@1), body); + std::swap($5, $$->branches); } -elsif_statement_list: - ELSIF expression THEN optional_statements elsif_statement_list +elsif_then_statements: + ELSIF expression THEN optional_statements elsif_then_statements { elna::boot::conditional_statements *branch = new elna::boot::conditional_statements($2); std::swap(branch->statements, $4); @@ -217,14 +227,14 @@ elsif_statement_list: } | {} if_statement: - IF expression THEN optional_statements elsif_statement_list END_BLOCK + IF expression THEN optional_statements elsif_then_statements END_BLOCK { auto then = new elna::boot::conditional_statements($2); std::swap($4, then->statements); $$ = new elna::boot::if_statement(elna::boot::make_position(@1), then); std::swap($5, $$->branches); } - | IF expression THEN optional_statements elsif_statement_list ELSE optional_statements END_BLOCK + | IF expression THEN optional_statements elsif_then_statements ELSE optional_statements END_BLOCK { auto then = new elna::boot::conditional_statements($2); std::swap($4, then->statements); diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 2049d42..292c0c6 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -38,7 +38,7 @@ namespace elna { namespace gcc { - generic_visitor::generic_visitor(std::shared_ptr> symbol_table) + generic_visitor::generic_visitor(std::shared_ptr symbol_table) { this->symbol_map = symbol_table; } @@ -310,7 +310,7 @@ namespace gcc void generic_visitor::enter_scope() { - this->symbol_map = std::make_shared>(this->symbol_map); + this->symbol_map = std::make_shared(this->symbol_map); // Chain the binding levels. struct binding_level *new_level = ggc_cleared_alloc(); @@ -1071,7 +1071,7 @@ namespace gcc { branch.prerequisite().accept(this); - if (TREE_TYPE(this->current_expression) != boolean_type_node) + if (TREE_TYPE(this->current_expression) != elna_bool_type_node) { error_at(get_location(&branch.prerequisite().position()), "expected expression of boolean type but its type is %s", @@ -1116,55 +1116,19 @@ namespace gcc void generic_visitor::visit(boot::while_statement *statement) { - statement->body().prerequisite().accept(this); - - if (TREE_TYPE(this->current_expression) != boolean_type_node) - { - error_at(get_location(&statement->body().prerequisite().position()), - "expected expression of boolean type but its type is %s", - print_type(TREE_TYPE(this->current_expression)).c_str()); - this->current_expression = error_mark_node; - return; - } - enter_scope(); - auto prerequisite_location = get_location(&statement->body().prerequisite().position()); - auto body_location = get_location(&statement->position()); - 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); - 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); - - auto goto_body = build1_loc(prerequisite_location, GOTO_EXPR, - void_type_node, body_label_decl); - auto goto_end = build1_loc(prerequisite_location, GOTO_EXPR, - void_type_node, end_label_decl); - - auto cond_expr = build3_loc(prerequisite_location, COND_EXPR, - void_type_node, this->current_expression, goto_body, goto_end); - append_statement(cond_expr); - - auto body_label_expr = build1_loc(body_location, LABEL_EXPR, - void_type_node, body_label_decl); - append_statement(body_label_expr); - - for (const auto body_statement : statement->body().statements) - { - body_statement->accept(this); - } - tree mapping = leave_scope(); - append_statement(mapping); - auto goto_check = build1(GOTO_EXPR, void_type_node, prerequisite_label_decl); - append_statement(goto_check); - auto endif_label_expr = build1(LABEL_EXPR, void_type_node, end_label_decl); - append_statement(endif_label_expr); + append_statement(prerequisite_label_expr); + make_if_branch(statement->body(), goto_check); + for (const auto branch : statement->branches) + { + make_if_branch(*branch, goto_check); + } this->current_expression = NULL_TREE; } diff --git a/gcc/elna1.cc b/gcc/elna1.cc index e2361b6..d083ead 100644 --- a/gcc/elna1.cc +++ b/gcc/elna1.cc @@ -88,7 +88,7 @@ static void elna_parse_file(const char *filename) } else { - elna::gcc::generic_visitor generic_visitor{ std::make_shared>() }; + elna::gcc::generic_visitor generic_visitor{ std::make_shared() }; generic_visitor.visit(driver.tree.get()); } diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index 60bd64c..cbb437e 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -617,6 +617,7 @@ namespace boot conditional_statements *m_body; public: + std::vector branches; while_statement(const struct position position, conditional_statements *body); virtual void accept(parser_visitor *visitor) override; diff --git a/include/elna/boot/symbol.h b/include/elna/boot/symbol.h index 8f5839b..30bac72 100644 --- a/include/elna/boot/symbol.h +++ b/include/elna/boot/symbol.h @@ -29,7 +29,7 @@ namespace boot /** * Symbol table. */ - template + template class symbol_table { public: @@ -73,7 +73,7 @@ namespace boot } /** - * Looks for symbol in the table by name. Returns nullptr if the symbol + * Looks for symbol in the table by name. Returns nothing if the symbol * can not be found. * * \param name Symbol name. @@ -91,7 +91,7 @@ namespace boot { return this->outer_scope->lookup(name); } - return nullptr; + return nothing; } /** @@ -104,7 +104,14 @@ namespace boot */ bool enter(const std::string& name, symbol_ptr entry) { - return entries.insert({ name, entry }).second; + if (lookup(name) == nothing) + { + return entries.insert({ name, entry }).second; + } + else + { + return nothing; + } } /** diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index 638ca07..dfd2caa 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -37,7 +37,7 @@ namespace gcc class generic_visitor final : public boot::empty_visitor { tree current_expression{ NULL_TREE }; - std::shared_ptr> symbol_map; + std::shared_ptr symbol_map; tree build_label_decl(const char *name, location_t loc); tree build_type(boot::top_type& type); @@ -61,7 +61,7 @@ namespace gcc tree symbol, const std::vector& arguments); public: - generic_visitor(std::shared_ptr> symbol_table); + generic_visitor(std::shared_ptr symbol_table); void visit(boot::program *program) override; void visit(boot::procedure_definition *definition) override; diff --git a/include/elna/gcc/elna-tree.h b/include/elna/gcc/elna-tree.h index 5339135..5274b0b 100644 --- a/include/elna/gcc/elna-tree.h +++ b/include/elna/gcc/elna-tree.h @@ -33,6 +33,8 @@ namespace elna { namespace gcc { + using symbol_table = boot::symbol_table; + bool is_pointer_type(tree type); bool is_integral_type(tree type); bool is_numeric_type(tree type);