Add an else to the case statement

This commit is contained in:
Eugen Wissner 2025-04-11 15:28:43 +02:00
parent f68667d5e5
commit 6fd1bda112
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
6 changed files with 173 additions and 169 deletions

View File

@ -794,8 +794,8 @@ namespace elna::boot
} }
case_statement::case_statement(const struct position position, case_statement::case_statement(const struct position position,
expression *condition, std::vector<switch_case>&& cases) expression *condition, std::vector<switch_case>&& cases, std::vector<statement *> *alternative)
: node(position), m_condition(condition), cases(std::move(cases)) : 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, if_statement::if_statement(const struct position position, conditional_statements *body,
std::vector<statement *> *alternative) std::vector<statement *> *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; return *m_body;
} }
std::vector<statement *> *if_statement::alternative()
{
return m_alternative;
}
if_statement::~if_statement() if_statement::~if_statement()
{ {
delete m_body; delete m_body;
@ -893,7 +888,7 @@ namespace elna::boot
{ {
delete branch; delete branch;
} }
delete m_alternative; delete this->alternative;
} }
while_statement::while_statement(const struct position position, conditional_statements *body) while_statement::while_statement(const struct position position, conditional_statements *body)

View File

@ -143,7 +143,6 @@ along with GCC; see the file COPYING3. If not see
%type <elna::boot::designator_expression *> designator_expression; %type <elna::boot::designator_expression *> designator_expression;
%type <elna::boot::procedure_call*> call_expression; %type <elna::boot::procedure_call*> call_expression;
%type <elna::boot::while_statement *> while_statement; %type <elna::boot::while_statement *> while_statement;
%type <elna::boot::if_statement *> if_statement;
%type <elna::boot::return_statement *> return_statement; %type <elna::boot::return_statement *> return_statement;
%type <elna::boot::statement *> statement; %type <elna::boot::statement *> statement;
%type <std::vector<elna::boot::statement *>> statements; %type <std::vector<elna::boot::statement *>> statements;
@ -158,6 +157,7 @@ along with GCC; see the file COPYING3. If not see
%type <std::vector<std::pair<std::string, elna::boot::type_expression *>>> %type <std::vector<std::pair<std::string, elna::boot::type_expression *>>>
optional_fields required_fields formal_parameters; optional_fields required_fields formal_parameters;
%type <std::vector<elna::boot::conditional_statements *>> elsif_then_statements elsif_do_statements; %type <std::vector<elna::boot::conditional_statements *>> elsif_then_statements elsif_do_statements;
%type <std::vector<elna::boot::statement *> *> else_statements;
%type <elna::boot::cast_expression *> cast_expression; %type <elna::boot::cast_expression *> cast_expression;
%type <std::pair<std::string, bool>> identifier_definition; %type <std::pair<std::string, bool>> identifier_definition;
%type <std::vector<std::pair<std::string, bool>>> identifier_definitions; %type <std::vector<std::pair<std::string, bool>>> identifier_definitions;
@ -253,6 +253,9 @@ elsif_do_statements:
$$.emplace($$.begin(), branch); $$.emplace($$.begin(), branch);
} }
| {} | {}
else_statements:
"else" statements { $$ = new std::vector<boot::statement *>(std::move($2)); }
| { $$ = nullptr; }
while_statement: "while" expression "do" statements elsif_do_statements "end" while_statement: "while" expression "do" statements elsif_do_statements "end"
{ {
auto body = new boot::conditional_statements($2); auto body = new boot::conditional_statements($2);
@ -269,22 +272,6 @@ elsif_then_statements:
$$.emplace($$.begin(), branch); $$.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<boot::statement *>(std::move($7));
$$ = new boot::if_statement(boot::make_position(@1), then, _else);
std::swap($5, $$->branches);
}
return_statement: return_statement:
"return" expression "return" expression
{ {
@ -428,12 +415,19 @@ statement:
designator_expression ":=" expression designator_expression ":=" expression
{ $$ = new boot::assign_statement(boot::make_position(@1), $1, $3); } { $$ = new boot::assign_statement(boot::make_position(@1), $1, $3); }
| while_statement { $$ = $1; } | 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; } | return_statement { $$ = $1; }
| call_expression { $$ = $1; } | call_expression { $$ = $1; }
| "defer" statements "end" { $$ = new boot::defer_statement(boot::make_position(@1), std::move($2)); } | "defer" statements "end" { $$ = new boot::defer_statement(boot::make_position(@1), std::move($2)); }
| "case" expression "of" switch_cases "end" | "case" expression "of" switch_cases else_statements "end"
{ $$ = new boot::case_statement(boot::make_position(@1), $2, std::move($4)); } { $$ = 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_case: case_labels ":" statements { $$ = { .labels = std::move($1), .statements = std::move($3) }; }
switch_cases: switch_cases:
switch_case "|" switch_cases switch_case "|" switch_cases

View File

@ -230,9 +230,9 @@ namespace elna::boot
statement->accept(this); 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); statement->accept(this);
} }

View File

@ -1183,10 +1183,10 @@ namespace elna::gcc
{ {
make_if_branch(*branch, goto_endif); make_if_branch(*branch, goto_endif);
} }
if (statement->alternative() != nullptr) if (statement->alternative != nullptr)
{ {
enter_scope(); enter_scope();
visit_statements(*statement->alternative()); visit_statements(*statement->alternative);
tree mapping = leave_scope(); tree mapping = leave_scope();
append_statement(mapping); append_statement(mapping);
} }
@ -1465,11 +1465,24 @@ namespace elna::gcc
enter_scope(); enter_scope();
visit_statements(case_block.statements); visit_statements(case_block.statements);
append_to_statement_list(leave_scope(), &switch_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); append_to_statement_list(goto_end, &switch_statements);
TREE_USED(end_label_declaration) = 1; 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), tree switch_expression = build2(SWITCH_EXPR, TREE_TYPE(condition_expression),
condition_expression, switch_statements); condition_expression, switch_statements);

View File

@ -461,8 +461,10 @@ namespace elna::boot
public: public:
const std::vector<switch_case> cases; const std::vector<switch_case> cases;
const std::vector<statement *> *alternative;
case_statement(const struct position position, expression *condition, std::vector<switch_case>&& cases); case_statement(const struct position position, expression *condition,
std::vector<switch_case>&& cases, std::vector<statement *> *alternative = nullptr);
void accept(parser_visitor *visitor) override; void accept(parser_visitor *visitor) override;
expression& condition(); expression& condition();
}; };
@ -592,10 +594,10 @@ namespace elna::boot
class if_statement : public statement class if_statement : public statement
{ {
conditional_statements *m_body; conditional_statements *m_body;
std::vector<statement *> *m_alternative;
public: public:
std::vector<conditional_statements *> branches; std::vector<conditional_statements *> branches;
const std::vector<statement *> *alternative;
if_statement(const struct position position, conditional_statements *body, if_statement(const struct position position, conditional_statements *body,
std::vector<statement *> *alternative = nullptr); std::vector<statement *> *alternative = nullptr);
@ -603,7 +605,6 @@ namespace elna::boot
virtual if_statement *is_if() override; virtual if_statement *is_if() override;
conditional_statements& body(); conditional_statements& body();
std::vector<statement *> *alternative();
virtual ~if_statement() override; virtual ~if_statement() override;
}; };

View File

@ -518,138 +518,139 @@ begin
while i < tokens_size do while i < tokens_size do
current_token := tokens + i; current_token := tokens + i;
if current_token^.kind = TokenKind._if then case current_token^.kind of
write_s("IF") TokenKind._if:
elsif current_token^.kind = TokenKind._then then write_s("IF")
write_s("THEN") | TokenKind._then:
elsif current_token^.kind = TokenKind._else then write_s("THEN")
write_s("ELSE") | TokenKind._else:
elsif current_token^.kind = TokenKind._elsif then write_s("ELSE")
write_s("ELSIF") | TokenKind._elsif:
elsif current_token^.kind = TokenKind._while then write_s("ELSIF")
write_s("WHILE") | TokenKind._while:
elsif current_token^.kind = TokenKind._do then write_s("WHILE")
write_s("DO") | TokenKind._do:
elsif current_token^.kind = TokenKind._proc then write_s("DO")
write_s("PROC") | TokenKind._proc:
elsif current_token^.kind = TokenKind._begin then write_s("PROC")
write_s("BEGIN") | TokenKind._begin:
elsif current_token^.kind = TokenKind._end then write_s("BEGIN")
write_s("END") | TokenKind._end:
elsif current_token^.kind = TokenKind._extern then write_s("END")
write_s("EXTERN") | TokenKind._extern:
elsif current_token^.kind = TokenKind._const then write_s("EXTERN")
write_s("CONST") | TokenKind._const:
elsif current_token^.kind = TokenKind._var then write_s("CONST")
write_s("VAR") | TokenKind._var:
elsif current_token^.kind = TokenKind.array then write_s("VAR")
write_s("ARRAY") | TokenKind.array:
elsif current_token^.kind = TokenKind._of then write_s("ARRAY")
write_s("OF") | TokenKind._of:
elsif current_token^.kind = TokenKind._type then write_s("OF")
write_s("TYPE") | TokenKind._type:
elsif current_token^.kind = TokenKind._record then write_s("TYPE")
write_s("RECORD") | TokenKind._record:
elsif current_token^.kind = TokenKind._union then write_s("RECORD")
write_s("UNION") | TokenKind._union:
elsif current_token^.kind = TokenKind.pointer then write_s("UNION")
write_s("POINTER") | TokenKind.pointer:
elsif current_token^.kind = TokenKind.to then write_s("POINTER")
write_s("TO") | TokenKind.to:
elsif current_token^.kind = TokenKind.boolean then write_s("TO")
write_s("BOOLEAN<"); | TokenKind.boolean:
write_b(current_token^.value.boolean_value); write_s("BOOLEAN<");
write_c('>') write_b(current_token^.value.boolean_value);
elsif current_token^.kind = TokenKind._nil then write_c('>')
write_s("NIL") | TokenKind._nil:
elsif current_token^.kind = TokenKind.and then write_s("NIL")
write_s("AND") | TokenKind.and:
elsif current_token^.kind = TokenKind._or then write_s("AND")
write_s("OR") | TokenKind._or:
elsif current_token^.kind = TokenKind.not then write_s("OR")
write_s("NOT") | TokenKind.not:
elsif current_token^.kind = TokenKind._return then write_s("NOT")
write_s("RETURN") | TokenKind._return:
elsif current_token^.kind = TokenKind._cast then write_s("RETURN")
write_s("CAST") | TokenKind._cast:
elsif current_token^.kind = TokenKind.shift_left then write_s("CAST")
write_s("<<") | TokenKind.shift_left:
elsif current_token^.kind = TokenKind.shift_right then write_s("<<")
write_s(">>") | TokenKind.shift_right:
elsif current_token^.kind = TokenKind.identifier then write_s(">>")
write_c('<'); | TokenKind.identifier:
write_s(current_token^.value.string); write_c('<');
write_c('>') write_s(current_token^.value.string);
elsif current_token^.kind = TokenKind.left_paren then write_c('>')
write_s("(") | TokenKind.left_paren:
elsif current_token^.kind = TokenKind.right_paren then write_s("(")
write_s(")") | TokenKind.right_paren:
elsif current_token^.kind = TokenKind.left_square then write_s(")")
write_s("[") | TokenKind.left_square:
elsif current_token^.kind = TokenKind.right_square then write_s("[")
write_s("]") | TokenKind.right_square:
elsif current_token^.kind = TokenKind.greater_equal then write_s("]")
write_s(">=") | TokenKind.greater_equal:
elsif current_token^.kind = TokenKind.less_equal then write_s(">=")
write_s("<=") | TokenKind.less_equal:
elsif current_token^.kind = TokenKind.greater_than then write_s("<=")
write_s(">") | TokenKind.greater_than:
elsif current_token^.kind = TokenKind.less_than then write_s(">")
write_s("<") | TokenKind.less_than:
elsif current_token^.kind = TokenKind.equal then write_s("<")
write_s("=") | TokenKind.equal:
elsif current_token^.kind = TokenKind.not_equal then write_s("=")
write_s("<>") | TokenKind.not_equal:
elsif current_token^.kind = TokenKind.semicolon then write_s("<>")
write_c(';') | TokenKind.semicolon:
elsif current_token^.kind = TokenKind.dot then write_c(';')
write_c('.') | TokenKind.dot:
elsif current_token^.kind = TokenKind.comma then write_c('.')
write_c(',') | TokenKind.comma:
elsif current_token^.kind = TokenKind.plus then write_c(',')
write_c('+') | TokenKind.plus:
elsif current_token^.kind = TokenKind.minus then write_c('+')
write_c('-') | TokenKind.minus:
elsif current_token^.kind = TokenKind.multiplication then write_c('-')
write_c('*') | TokenKind.multiplication:
elsif current_token^.kind = TokenKind.division then write_c('*')
write_c('/') | TokenKind.division:
elsif current_token^.kind = TokenKind.remainder then write_c('/')
write_c('%') | TokenKind.remainder:
elsif current_token^.kind = TokenKind.assignment then write_c('%')
write_s(":=") | TokenKind.assignment:
elsif current_token^.kind = TokenKind.colon then write_s(":=")
write_c(':') | TokenKind.colon:
elsif current_token^.kind = TokenKind.hat then write_c(':')
write_c('^') | TokenKind.hat:
elsif current_token^.kind = TokenKind.at then write_c('^')
write_c('@') | TokenKind.at:
elsif current_token^.kind = TokenKind.comment then write_c('@')
write_s("(* COMMENT *)") | TokenKind.comment:
elsif current_token^.kind = TokenKind.integer then write_s("(* COMMENT *)")
write_c('<'); | TokenKind.integer:
write_i(current_token^.value.int_value); write_c('<');
write_c('>') write_i(current_token^.value.int_value);
elsif current_token^.kind = TokenKind.word then write_c('>')
write_c('<'); | TokenKind.word:
write_i(current_token^.value.int_value); write_c('<');
write_s("u>") write_i(current_token^.value.int_value);
elsif current_token^.kind = TokenKind.character then write_s("u>")
write_c('<'); | TokenKind.character:
write_i(cast(current_token^.value.char_value: Int)); write_c('<');
write_s("c>") write_i(cast(current_token^.value.char_value: Int));
elsif current_token^.kind = TokenKind.string then write_s("c>")
write_s("\"...\"") | TokenKind.string:
elsif current_token^.kind = TokenKind._defer then write_s("\"...\"")
write_s("DEFER") | TokenKind._defer:
elsif current_token^.kind = TokenKind.exclamation then write_s("DEFER")
write_c('!') | TokenKind.exclamation:
elsif current_token^.kind = TokenKind.arrow then write_c('!')
write_s("->") | TokenKind.arrow:
else write_s("->")
write_s("UNKNOWN<"); else
write_i(cast(current_token^.kind: Int)); write_s("UNKNOWN<");
write_c('>') write_i(cast(current_token^.kind: Int));
write_c('>')
end; end;
write_c(' '); write_c(' ');