From 6c14e7433b20364c8e2ec2a16ad7bae9b168804a Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Mon, 27 Jan 2025 01:16:27 +0100 Subject: [PATCH] Implement elsif --- gcc/elna-generic.cc | 92 +++++++++++++++------------------ include/elna/gcc/elna-generic.h | 2 + include/elna/source/ast.h | 2 + source/ast.cc | 5 +- source/parser.yy | 30 +++++++---- 5 files changed, 71 insertions(+), 60 deletions(-) diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 195c9e3..5162996 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -733,70 +733,62 @@ namespace gcc void generic_visitor::visit(source::if_statement *statement) { - statement->body().prerequisite().accept(this); + tree endif_label_decl = build_label_decl("endif", UNKNOWN_LOCATION); + tree goto_endif = build1(GOTO_EXPR, void_type_node, endif_label_decl); - if (TREE_TYPE(this->current_expression) != boolean_type_node) + make_if_branch(statement->body(), goto_endif); + + for (const auto branch : statement->branches) { - 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))); - this->current_expression = error_mark_node; - return; - } - auto then_location = get_location(&statement->position()); - auto prerequisite_location = get_location(&statement->body().prerequisite().position()); - - auto then_label_decl = build_label_decl("then", then_location); - auto endif_label_decl = build_label_decl("end_if", then_location); - - auto goto_then = build1_loc(prerequisite_location, GOTO_EXPR, - void_type_node, then_label_decl); - auto goto_endif = build1_loc(prerequisite_location, GOTO_EXPR, - void_type_node, endif_label_decl); - - tree else_label_decl = NULL_TREE; - tree goto_else_or_endif = NULL_TREE; - if (statement->alternative() != nullptr) - { - auto else_location = get_location(&statement->position()); - else_label_decl = build_label_decl("else", else_location); - goto_else_or_endif = build1_loc(else_location, GOTO_EXPR, void_type_node, else_label_decl); - } - else - { - goto_else_or_endif = goto_endif; - } - - auto cond_expr = build3_loc(prerequisite_location, COND_EXPR, - void_type_node, this->current_expression, goto_then, goto_else_or_endif); - append_to_statement_list(cond_expr, &this->current_statements); - - auto then_label_expr = build1_loc(then_location, LABEL_EXPR, - void_type_node, then_label_decl); - append_to_statement_list(then_label_expr, &this->current_statements); - - for (const auto body_statement : statement->body().statements) - { - body_statement->accept(this); + make_if_branch(*branch, goto_endif); } if (statement->alternative() != nullptr) { - append_to_statement_list(goto_endif, &this->current_statements); - - auto else_label_expr = build1(LABEL_EXPR, void_type_node, else_label_decl); - append_to_statement_list(else_label_expr, &this->current_statements); - for (const auto body_statement : *statement->alternative()) { body_statement->accept(this); } } - auto endif_label_expr = build1(LABEL_EXPR, void_type_node, endif_label_decl); - append_to_statement_list(endif_label_expr, &this->current_statements); + tree endif_label_expr = build1(LABEL_EXPR, void_type_node, endif_label_decl); + append_to_statement_list(endif_label_expr, &this->current_statements); this->current_expression = NULL_TREE; } + void generic_visitor::make_if_branch(source::conditional_statements& branch, tree goto_endif) + { + branch.prerequisite().accept(this); + + if (TREE_TYPE(this->current_expression) != boolean_type_node) + { + error_at(get_location(&branch.prerequisite().position()), + "expected expression of boolean type but its type is %s", + print_type(TREE_TYPE(this->current_expression))); + this->current_expression = error_mark_node; + return; + } + tree then_label_decl = build_label_decl("then", UNKNOWN_LOCATION); + tree goto_then = build1(GOTO_EXPR, void_type_node, then_label_decl); + + tree else_label_decl = build_label_decl("else", UNKNOWN_LOCATION); + 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); + append_to_statement_list(cond_expr, &this->current_statements); + + tree then_label_expr = build1(LABEL_EXPR, void_type_node, then_label_decl); + append_to_statement_list(then_label_expr, &this->current_statements); + + for (const auto body_statement : branch.statements) + { + body_statement->accept(this); + } + append_to_statement_list(goto_endif, &this->current_statements); + + tree else_label_expr = build1(LABEL_EXPR, void_type_node, else_label_decl); + append_to_statement_list(else_label_expr, &this->current_statements); + } + tree generic_visitor::build_label_decl(const char *name, location_t loc) { auto label_decl = build_decl(loc, diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index 8169126..207041f 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -34,6 +34,8 @@ namespace gcc void build_binary_operation(bool condition, source::binary_expression *expression, tree_code operator_code, tree left, tree right, tree target_type); + void make_if_branch(source::conditional_statements& branch, tree goto_endif); + public: generic_visitor(std::shared_ptr> symbol_table); diff --git a/include/elna/source/ast.h b/include/elna/source/ast.h index 8c759c6..cb40570 100644 --- a/include/elna/source/ast.h +++ b/include/elna/source/ast.h @@ -617,6 +617,8 @@ namespace source std::vector *m_alternative; public: + std::vector branches; + if_statement(const struct position position, conditional_statements *body, std::vector *alternative = nullptr); virtual void accept(parser_visitor *visitor) override; diff --git a/source/ast.cc b/source/ast.cc index 385c5f8..3fbbf98 100644 --- a/source/ast.cc +++ b/source/ast.cc @@ -898,7 +898,10 @@ namespace source if_statement::~if_statement() { delete m_body; - + for (const auto branch : branches) + { + delete branch; + } if (m_alternative != nullptr) { delete m_alternative; diff --git a/source/parser.yy b/source/parser.yy index bbda45f..bf8cd09 100644 --- a/source/parser.yy +++ b/source/parser.yy @@ -96,6 +96,7 @@ %type block; %type > field_declaration; %type >> field_list; +%type > elsif_statement_list; %% program: type_part constant_part procedure_part variable_part BEGIN_BLOCK optional_statements END_BLOCK DOT @@ -121,7 +122,7 @@ program: { *value_definition++ = variable; } - auto tree = new elna::source::program(elna::source::position{}, + auto tree = new elna::source::program(elna::source::make_position(@5), std::move(definitions), std::move(value_definitions), std::move($6)); driver.tree.reset(tree); @@ -139,28 +140,28 @@ block: constant_part variable_part BEGIN_BLOCK optional_statements END_BLOCK { *definition++ = variable; } - $$ = new elna::source::block(elna::source::position{}, + $$ = new elna::source::block(elna::source::make_position(@3), std::move(definitions), std::move($4)); } procedure_definition: PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON block SEMICOLON { - $$ = new elna::source::procedure_definition(elna::source::position{}, + $$ = new elna::source::procedure_definition(elna::source::make_position(@1), $2, std::move($3), nullptr, $5); } | PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON EXTERN SEMICOLON { - $$ = new elna::source::procedure_definition(elna::source::position{}, + $$ = new elna::source::procedure_definition(elna::source::make_position(@1), $2, std::move($3), nullptr, nullptr); } | PROCEDURE IDENTIFIER formal_parameter_list COLON type_expression SEMICOLON block SEMICOLON { - $$ = new elna::source::procedure_definition(elna::source::position{}, + $$ = new elna::source::procedure_definition(elna::source::make_position(@1), $2, std::move($3), $5, $7); } | PROCEDURE IDENTIFIER formal_parameter_list COLON type_expression SEMICOLON EXTERN SEMICOLON { - $$ = new elna::source::procedure_definition(elna::source::position{}, + $$ = new elna::source::procedure_definition(elna::source::make_position(@1), $2, std::move($3), $5, nullptr); } procedure_definitions: @@ -188,19 +189,30 @@ while_statement: WHILE expression DO optional_statements END_BLOCK std::swap($4, body->statements); $$ = new elna::source::while_statement(elna::source::make_position(@1), body); } +elsif_statement_list: + ELSIF expression THEN optional_statements elsif_statement_list + { + elna::source::conditional_statements *branch = new elna::source::conditional_statements($2); + std::swap(branch->statements, $4); + std::swap($5, $$); + $$.emplace($$.begin(), branch); + } + | {} if_statement: - IF expression THEN optional_statements END_BLOCK + IF expression THEN optional_statements elsif_statement_list END_BLOCK { auto then = new elna::source::conditional_statements($2); std::swap($4, then->statements); $$ = new elna::source::if_statement(elna::source::make_position(@1), then); + std::swap($5, $$->branches); } - | IF expression THEN optional_statements ELSE optional_statements END_BLOCK + | IF expression THEN optional_statements elsif_statement_list ELSE optional_statements END_BLOCK { auto then = new elna::source::conditional_statements($2); std::swap($4, then->statements); - auto _else = new std::vector(std::move($6)); + auto _else = new std::vector(std::move($7)); $$ = new elna::source::if_statement(elna::source::make_position(@1), then, _else); + std::swap($5, $$->branches); } return_statement: RETURN expression