From 6fd1bda112eeb52539434af200f90ad69c3997b6 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Fri, 11 Apr 2025 15:28:43 +0200 Subject: [PATCH] Add an else to the case statement --- boot/ast.cc | 13 +- boot/parser.yy | 34 +++--- boot/semantic.cc | 4 +- gcc/elna-generic.cc | 19 ++- include/elna/boot/ast.h | 7 +- source.elna | 265 ++++++++++++++++++++-------------------- 6 files changed, 173 insertions(+), 169 deletions(-) diff --git a/boot/ast.cc b/boot/ast.cc index 3dece9e..e43951c 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -794,8 +794,8 @@ namespace elna::boot } case_statement::case_statement(const struct position position, - expression *condition, std::vector&& cases) - : node(position), m_condition(condition), cases(std::move(cases)) + expression *condition, std::vector&& cases, std::vector *alternative) + : node(position), m_condition(condition), cases(std::move(cases)), alternative(alternative) { } @@ -862,7 +862,7 @@ namespace elna::boot if_statement::if_statement(const struct position position, conditional_statements *body, std::vector *alternative) - : node(position), m_body(body), m_alternative(alternative) + : node(position), m_body(body), alternative(alternative) { } @@ -881,11 +881,6 @@ namespace elna::boot return *m_body; } - std::vector *if_statement::alternative() - { - return m_alternative; - } - if_statement::~if_statement() { delete m_body; @@ -893,7 +888,7 @@ namespace elna::boot { delete branch; } - delete m_alternative; + delete this->alternative; } while_statement::while_statement(const struct position position, conditional_statements *body) diff --git a/boot/parser.yy b/boot/parser.yy index 9554372..57eabb7 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -143,7 +143,6 @@ along with GCC; see the file COPYING3. If not see %type designator_expression; %type call_expression; %type while_statement; -%type if_statement; %type return_statement; %type statement; %type > statements; @@ -158,6 +157,7 @@ along with GCC; see the file COPYING3. If not see %type >> optional_fields required_fields formal_parameters; %type > elsif_then_statements elsif_do_statements; +%type *> else_statements; %type cast_expression; %type > identifier_definition; %type >> identifier_definitions; @@ -253,6 +253,9 @@ elsif_do_statements: $$.emplace($$.begin(), branch); } | {} +else_statements: + "else" statements { $$ = new std::vector(std::move($2)); } + | { $$ = nullptr; } while_statement: "while" expression "do" statements elsif_do_statements "end" { auto body = new boot::conditional_statements($2); @@ -269,22 +272,6 @@ elsif_then_statements: $$.emplace($$.begin(), branch); } | {} -if_statement: - "if" expression "then" statements elsif_then_statements "end" - { - auto then = new boot::conditional_statements($2); - std::swap($4, then->statements); - $$ = new boot::if_statement(boot::make_position(@1), then); - std::swap($5, $$->branches); - } - | "if" expression "then" statements elsif_then_statements "else" statements "end" - { - auto then = new boot::conditional_statements($2); - std::swap($4, then->statements); - auto _else = new std::vector(std::move($7)); - $$ = new boot::if_statement(boot::make_position(@1), then, _else); - std::swap($5, $$->branches); - } return_statement: "return" expression { @@ -428,12 +415,19 @@ statement: designator_expression ":=" expression { $$ = new boot::assign_statement(boot::make_position(@1), $1, $3); } | while_statement { $$ = $1; } - | if_statement { $$ = $1; } + | "if" expression "then" statements elsif_then_statements else_statements "end" + { + auto then = new boot::conditional_statements($2); + std::swap($4, then->statements); + auto result = new boot::if_statement(boot::make_position(@1), then, $6); + std::swap($5, result->branches); + $$ = result; + } | return_statement { $$ = $1; } | call_expression { $$ = $1; } | "defer" statements "end" { $$ = new boot::defer_statement(boot::make_position(@1), std::move($2)); } - | "case" expression "of" switch_cases "end" - { $$ = new boot::case_statement(boot::make_position(@1), $2, std::move($4)); } + | "case" expression "of" switch_cases else_statements "end" + { $$ = new boot::case_statement(boot::make_position(@1), $2, std::move($4), $5); } switch_case: case_labels ":" statements { $$ = { .labels = std::move($1), .statements = std::move($3) }; } switch_cases: switch_case "|" switch_cases diff --git a/boot/semantic.cc b/boot/semantic.cc index 782d6ea..55c6fea 100644 --- a/boot/semantic.cc +++ b/boot/semantic.cc @@ -230,9 +230,9 @@ namespace elna::boot statement->accept(this); } } - if (statement->alternative() != nullptr) + if (statement->alternative != nullptr) { - for (struct statement *const statement : *statement->alternative()) + for (struct statement *const statement : *statement->alternative) { statement->accept(this); } diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 92ba0f2..10d7f85 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -1183,10 +1183,10 @@ namespace elna::gcc { make_if_branch(*branch, goto_endif); } - if (statement->alternative() != nullptr) + if (statement->alternative != nullptr) { enter_scope(); - visit_statements(*statement->alternative()); + visit_statements(*statement->alternative); tree mapping = leave_scope(); append_statement(mapping); } @@ -1465,11 +1465,24 @@ namespace elna::gcc enter_scope(); visit_statements(case_block.statements); append_to_statement_list(leave_scope(), &switch_statements); - tree goto_end = fold_build1(GOTO_EXPR, void_type_node, end_label_declaration); + tree goto_end = build1(GOTO_EXPR, void_type_node, end_label_declaration); append_to_statement_list(goto_end, &switch_statements); TREE_USED(end_label_declaration) = 1; } + if (statement->alternative != nullptr) + { + tree case_label_declaration = create_artificial_label(UNKNOWN_LOCATION); + tree case_expression = build_case_label(NULL_TREE, NULL_TREE, case_label_declaration); + + append_to_statement_list(case_expression, &switch_statements); + + enter_scope(); + visit_statements(*statement->alternative); + append_to_statement_list(leave_scope(), &switch_statements); + + TREE_USED(end_label_declaration) = 1; + } tree switch_expression = build2(SWITCH_EXPR, TREE_TYPE(condition_expression), condition_expression, switch_statements); diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index 4dacd85..3934447 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -461,8 +461,10 @@ namespace elna::boot public: const std::vector cases; + const std::vector *alternative; - case_statement(const struct position position, expression *condition, std::vector&& cases); + case_statement(const struct position position, expression *condition, + std::vector&& cases, std::vector *alternative = nullptr); void accept(parser_visitor *visitor) override; expression& condition(); }; @@ -592,10 +594,10 @@ namespace elna::boot class if_statement : public statement { conditional_statements *m_body; - std::vector *m_alternative; public: std::vector branches; + const std::vector *alternative; if_statement(const struct position position, conditional_statements *body, std::vector *alternative = nullptr); @@ -603,7 +605,6 @@ namespace elna::boot virtual if_statement *is_if() override; conditional_statements& body(); - std::vector *alternative(); virtual ~if_statement() override; }; diff --git a/source.elna b/source.elna index efbc560..cc903db 100644 --- a/source.elna +++ b/source.elna @@ -518,138 +518,139 @@ begin while i < tokens_size do current_token := tokens + i; - if current_token^.kind = TokenKind._if then - write_s("IF") - elsif current_token^.kind = TokenKind._then then - write_s("THEN") - elsif current_token^.kind = TokenKind._else then - write_s("ELSE") - elsif current_token^.kind = TokenKind._elsif then - write_s("ELSIF") - elsif current_token^.kind = TokenKind._while then - write_s("WHILE") - elsif current_token^.kind = TokenKind._do then - write_s("DO") - elsif current_token^.kind = TokenKind._proc then - write_s("PROC") - elsif current_token^.kind = TokenKind._begin then - write_s("BEGIN") - elsif current_token^.kind = TokenKind._end then - write_s("END") - elsif current_token^.kind = TokenKind._extern then - write_s("EXTERN") - elsif current_token^.kind = TokenKind._const then - write_s("CONST") - elsif current_token^.kind = TokenKind._var then - write_s("VAR") - elsif current_token^.kind = TokenKind.array then - write_s("ARRAY") - elsif current_token^.kind = TokenKind._of then - write_s("OF") - elsif current_token^.kind = TokenKind._type then - write_s("TYPE") - elsif current_token^.kind = TokenKind._record then - write_s("RECORD") - elsif current_token^.kind = TokenKind._union then - write_s("UNION") - elsif current_token^.kind = TokenKind.pointer then - write_s("POINTER") - elsif current_token^.kind = TokenKind.to then - write_s("TO") - elsif current_token^.kind = TokenKind.boolean then - write_s("BOOLEAN<"); - write_b(current_token^.value.boolean_value); - write_c('>') - elsif current_token^.kind = TokenKind._nil then - write_s("NIL") - elsif current_token^.kind = TokenKind.and then - write_s("AND") - elsif current_token^.kind = TokenKind._or then - write_s("OR") - elsif current_token^.kind = TokenKind.not then - write_s("NOT") - elsif current_token^.kind = TokenKind._return then - write_s("RETURN") - elsif current_token^.kind = TokenKind._cast then - write_s("CAST") - elsif current_token^.kind = TokenKind.shift_left then - write_s("<<") - elsif current_token^.kind = TokenKind.shift_right then - write_s(">>") - elsif current_token^.kind = TokenKind.identifier then - write_c('<'); - write_s(current_token^.value.string); - write_c('>') - elsif current_token^.kind = TokenKind.left_paren then - write_s("(") - elsif current_token^.kind = TokenKind.right_paren then - write_s(")") - elsif current_token^.kind = TokenKind.left_square then - write_s("[") - elsif current_token^.kind = TokenKind.right_square then - write_s("]") - elsif current_token^.kind = TokenKind.greater_equal then - write_s(">=") - elsif current_token^.kind = TokenKind.less_equal then - write_s("<=") - elsif current_token^.kind = TokenKind.greater_than then - write_s(">") - elsif current_token^.kind = TokenKind.less_than then - write_s("<") - elsif current_token^.kind = TokenKind.equal then - write_s("=") - elsif current_token^.kind = TokenKind.not_equal then - write_s("<>") - elsif current_token^.kind = TokenKind.semicolon then - write_c(';') - elsif current_token^.kind = TokenKind.dot then - write_c('.') - elsif current_token^.kind = TokenKind.comma then - write_c(',') - elsif current_token^.kind = TokenKind.plus then - write_c('+') - elsif current_token^.kind = TokenKind.minus then - write_c('-') - elsif current_token^.kind = TokenKind.multiplication then - write_c('*') - elsif current_token^.kind = TokenKind.division then - write_c('/') - elsif current_token^.kind = TokenKind.remainder then - write_c('%') - elsif current_token^.kind = TokenKind.assignment then - write_s(":=") - elsif current_token^.kind = TokenKind.colon then - write_c(':') - elsif current_token^.kind = TokenKind.hat then - write_c('^') - elsif current_token^.kind = TokenKind.at then - write_c('@') - elsif current_token^.kind = TokenKind.comment then - write_s("(* COMMENT *)") - elsif current_token^.kind = TokenKind.integer then - write_c('<'); - write_i(current_token^.value.int_value); - write_c('>') - elsif current_token^.kind = TokenKind.word then - write_c('<'); - write_i(current_token^.value.int_value); - write_s("u>") - elsif current_token^.kind = TokenKind.character then - write_c('<'); - write_i(cast(current_token^.value.char_value: Int)); - write_s("c>") - elsif current_token^.kind = TokenKind.string then - write_s("\"...\"") - elsif current_token^.kind = TokenKind._defer then - write_s("DEFER") - elsif current_token^.kind = TokenKind.exclamation then - write_c('!') - elsif current_token^.kind = TokenKind.arrow then - write_s("->") - else - write_s("UNKNOWN<"); - write_i(cast(current_token^.kind: Int)); - write_c('>') + case current_token^.kind of + TokenKind._if: + write_s("IF") + | TokenKind._then: + write_s("THEN") + | TokenKind._else: + write_s("ELSE") + | TokenKind._elsif: + write_s("ELSIF") + | TokenKind._while: + write_s("WHILE") + | TokenKind._do: + write_s("DO") + | TokenKind._proc: + write_s("PROC") + | TokenKind._begin: + write_s("BEGIN") + | TokenKind._end: + write_s("END") + | TokenKind._extern: + write_s("EXTERN") + | TokenKind._const: + write_s("CONST") + | TokenKind._var: + write_s("VAR") + | TokenKind.array: + write_s("ARRAY") + | TokenKind._of: + write_s("OF") + | TokenKind._type: + write_s("TYPE") + | TokenKind._record: + write_s("RECORD") + | TokenKind._union: + write_s("UNION") + | TokenKind.pointer: + write_s("POINTER") + | TokenKind.to: + write_s("TO") + | TokenKind.boolean: + write_s("BOOLEAN<"); + write_b(current_token^.value.boolean_value); + write_c('>') + | TokenKind._nil: + write_s("NIL") + | TokenKind.and: + write_s("AND") + | TokenKind._or: + write_s("OR") + | TokenKind.not: + write_s("NOT") + | TokenKind._return: + write_s("RETURN") + | TokenKind._cast: + write_s("CAST") + | TokenKind.shift_left: + write_s("<<") + | TokenKind.shift_right: + write_s(">>") + | TokenKind.identifier: + write_c('<'); + write_s(current_token^.value.string); + write_c('>') + | TokenKind.left_paren: + write_s("(") + | TokenKind.right_paren: + write_s(")") + | TokenKind.left_square: + write_s("[") + | TokenKind.right_square: + write_s("]") + | TokenKind.greater_equal: + write_s(">=") + | TokenKind.less_equal: + write_s("<=") + | TokenKind.greater_than: + write_s(">") + | TokenKind.less_than: + write_s("<") + | TokenKind.equal: + write_s("=") + | TokenKind.not_equal: + write_s("<>") + | TokenKind.semicolon: + write_c(';') + | TokenKind.dot: + write_c('.') + | TokenKind.comma: + write_c(',') + | TokenKind.plus: + write_c('+') + | TokenKind.minus: + write_c('-') + | TokenKind.multiplication: + write_c('*') + | TokenKind.division: + write_c('/') + | TokenKind.remainder: + write_c('%') + | TokenKind.assignment: + write_s(":=") + | TokenKind.colon: + write_c(':') + | TokenKind.hat: + write_c('^') + | TokenKind.at: + write_c('@') + | TokenKind.comment: + write_s("(* COMMENT *)") + | TokenKind.integer: + write_c('<'); + write_i(current_token^.value.int_value); + write_c('>') + | TokenKind.word: + write_c('<'); + write_i(current_token^.value.int_value); + write_s("u>") + | TokenKind.character: + write_c('<'); + write_i(cast(current_token^.value.char_value: Int)); + write_s("c>") + | TokenKind.string: + write_s("\"...\"") + | TokenKind._defer: + write_s("DEFER") + | TokenKind.exclamation: + write_c('!') + | TokenKind.arrow: + write_s("->") + else + write_s("UNKNOWN<"); + write_i(cast(current_token^.kind: Int)); + write_c('>') end; write_c(' ');