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,
expression *condition, std::vector<switch_case>&& cases)
: node(position), m_condition(condition), cases(std::move(cases))
expression *condition, std::vector<switch_case>&& cases, std::vector<statement *> *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<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;
}
std::vector<statement *> *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)

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::procedure_call*> call_expression;
%type <elna::boot::while_statement *> while_statement;
%type <elna::boot::if_statement *> if_statement;
%type <elna::boot::return_statement *> return_statement;
%type <elna::boot::statement *> statement;
%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 *>>>
optional_fields required_fields formal_parameters;
%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 <std::pair<std::string, bool>> identifier_definition;
%type <std::vector<std::pair<std::string, bool>>> identifier_definitions;
@ -253,6 +253,9 @@ elsif_do_statements:
$$.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"
{
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<boot::statement *>(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

View File

@ -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);
}

View File

@ -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);

View File

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

View File

@ -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(' ');