Allow only one return statement

This commit is contained in:
Eugen Wissner 2025-05-17 23:12:44 +02:00
parent 573d812f1c
commit 8206b48dbd
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
6 changed files with 69 additions and 91 deletions

View File

@ -795,7 +795,7 @@ namespace elna::boot
} }
return_statement::return_statement(const struct position position, expression *return_expression) return_statement::return_statement(const struct position position, expression *return_expression)
: node(position), return_expression(return_expression) : node(position), m_return_expression(return_expression)
{ {
} }
@ -804,9 +804,14 @@ namespace elna::boot
visitor->visit(this); visitor->visit(this);
} }
expression& return_statement::return_expression()
{
return *m_return_expression;
}
return_statement::~return_statement() return_statement::~return_statement()
{ {
delete this->return_expression; delete m_return_expression;
} }
case_statement::case_statement(const struct position position, case_statement::case_statement(const struct position position,
@ -914,13 +919,6 @@ namespace elna::boot
{ {
} }
while_statement::while_statement(const struct position position, conditional_statements *body,
std::vector<conditional_statements *>&& branches, const std::string& label,
std::vector<statement *> *alternative)
: node(position), m_body(body), branches(std::move(branches)), label(label), alternative(alternative)
{
}
void while_statement::accept(parser_visitor *visitor) void while_statement::accept(parser_visitor *visitor)
{ {
visitor->visit(this); visitor->visit(this);

View File

@ -145,10 +145,9 @@ along with GCC; see the file COPYING3. If not see
%type <std::vector<elna::boot::expression *>> expressions actual_parameter_list; %type <std::vector<elna::boot::expression *>> expressions actual_parameter_list;
%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::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 *>> required_statements optional_statements statement_part;
%type <elna::boot::procedure_definition *> procedure_definition; %type <elna::boot::procedure_definition *> procedure_definition;
%type <std::pair<std::vector<std::string>, elna::boot::procedure_type_expression *>> procedure_heading; %type <std::pair<std::vector<std::string>, elna::boot::procedure_type_expression *>> procedure_heading;
%type <elna::boot::procedure_type_expression::return_t> return_declaration; %type <elna::boot::procedure_type_expression::return_t> return_declaration;
@ -158,7 +157,7 @@ along with GCC; see the file COPYING3. If not see
%type <std::unique_ptr<elna::boot::block>> block; %type <std::unique_ptr<elna::boot::block>> block;
%type <elna::boot::field_declaration> field_declaration formal_parameter; %type <elna::boot::field_declaration> field_declaration formal_parameter;
%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 formal_parameter_list;
%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 <std::vector<elna::boot::statement *> *> else_statements;
%type <elna::boot::cast_expression *> cast_expression; %type <elna::boot::cast_expression *> cast_expression;
@ -168,7 +167,7 @@ along with GCC; see the file COPYING3. If not see
%type <std::vector<elna::boot::import_declaration *>> import_declarations import_part; %type <std::vector<elna::boot::import_declaration *>> import_declarations import_part;
%% %%
program: program:
"program" import_part constant_part type_part variable_part procedure_part "begin" statements "end" "." "program" import_part constant_part type_part variable_part procedure_part "begin" optional_statements "end" "."
{ {
auto tree = new boot::program(boot::make_position(@7)); auto tree = new boot::program(boot::make_position(@7));
@ -193,9 +192,18 @@ program:
driver.tree.reset(tree); driver.tree.reset(tree);
} }
block: constant_part variable_part "begin" statements "end" block: constant_part variable_part statement_part "end"
{ {
$$ = std::make_unique<boot::block>(std::move($1), std::move($2), std::move($4)); $$ = std::make_unique<boot::block>(std::move($1), std::move($2), std::move($3));
}
statement_part:
/* no statements */ {}
| "begin" required_statements { std::swap($$, $2); }
| return_statement { $$.push_back($1); }
| "begin" required_statements ";" return_statement
{
std::swap($$, $2);
$$.push_back($4);
} }
identifier_definition: identifier_definition:
IDENTIFIER "*" { $$ = boot::identifier_definition{ $1, true }; } IDENTIFIER "*" { $$ = boot::identifier_definition{ $1, true }; }
@ -211,11 +219,10 @@ return_declaration:
/* proper procedure */ {} /* proper procedure */ {}
| "->" "!" { $$ = boot::procedure_type_expression::return_t(std::monostate{}); } | "->" "!" { $$ = boot::procedure_type_expression::return_t(std::monostate{}); }
| "->" type_expression { $$ = boot::procedure_type_expression::return_t($2); } | "->" type_expression { $$ = boot::procedure_type_expression::return_t($2); }
procedure_heading: procedure_heading: formal_parameter_list return_declaration
"(" formal_parameters ")" return_declaration
{ {
$$.second = new boot::procedure_type_expression(boot::make_position(@1), std::move($4)); $$.second = new boot::procedure_type_expression(boot::make_position(@1), std::move($2));
for (auto& [name, type] : $2) for (auto& [name, type] : $1)
{ {
$$.first.emplace_back(std::move(name)); $$.first.emplace_back(std::move(name));
$$.second->parameters.push_back(type); $$.second->parameters.push_back(type);
@ -250,7 +257,7 @@ call_expression: designator_expression actual_parameter_list
cast_expression: "cast" "(" expression ":" type_expression ")" cast_expression: "cast" "(" expression ":" type_expression ")"
{ $$ = new boot::cast_expression(boot::make_position(@1), $5, $3); } { $$ = new boot::cast_expression(boot::make_position(@1), $5, $3); }
elsif_do_statements: elsif_do_statements:
"elsif" expression "do" statements elsif_do_statements "elsif" expression "do" optional_statements elsif_do_statements
{ {
boot::conditional_statements *branch = new boot::conditional_statements($2, std::move($4)); boot::conditional_statements *branch = new boot::conditional_statements($2, std::move($4));
std::swap($5, $$); std::swap($5, $$);
@ -258,36 +265,18 @@ elsif_do_statements:
} }
| {} | {}
else_statements: else_statements:
"else" statements { $$ = new std::vector<boot::statement *>(std::move($2)); } "else" optional_statements { $$ = new std::vector<boot::statement *>(std::move($2)); }
| { $$ = nullptr; } | { $$ = nullptr; }
while_statement:
"while" expression "do" statements elsif_do_statements else_statements "end"
{
boot::conditional_statements *body = new boot::conditional_statements($2, std::move($4));
$$ = new boot::while_statement(boot::make_position(@1), body, std::move($5), $6);
}
| "while" expression "," IDENTIFIER "do" statements elsif_do_statements else_statements "end"
{
boot::conditional_statements *body = new boot::conditional_statements($2, std::move($6));
$$ = new boot::while_statement(boot::make_position(@1), body, std::move($7), $4, $8);
}
elsif_then_statements: elsif_then_statements:
"elsif" expression "then" statements elsif_then_statements "elsif" expression "then" optional_statements elsif_then_statements
{ {
boot::conditional_statements *branch = new boot::conditional_statements($2, std::move($4)); boot::conditional_statements *branch = new boot::conditional_statements($2, std::move($4));
std::swap($5, $$); std::swap($5, $$);
$$.emplace($$.begin(), branch); $$.emplace($$.begin(), branch);
} }
| {} | {}
return_statement: return_statement: "return" expression
"return" expression { $$ = new boot::return_statement(boot::make_position(@1), $2); }
{
$$ = new boot::return_statement(boot::make_position(@1), $2);
}
| "return"
{
$$ = new boot::return_statement(boot::make_position(@1));
}
literal: literal:
INTEGER { $$ = new boot::literal<std::int32_t>(boot::make_position(@1), $1); } INTEGER { $$ = new boot::literal<std::int32_t>(boot::make_position(@1), $1); }
| WORD { $$ = new boot::literal<std::uint32_t>(boot::make_position(@1), $1); } | WORD { $$ = new boot::literal<std::uint32_t>(boot::make_position(@1), $1); }
@ -421,18 +410,23 @@ designator_expression:
statement: 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" expression "do" optional_statements elsif_do_statements else_statements "end"
| "if" expression "then" statements elsif_then_statements else_statements "end" {
boot::conditional_statements *body = new boot::conditional_statements($2, std::move($4));
$$ = new boot::while_statement(boot::make_position(@1), body, std::move($5), $6);
}
| "if" expression "then" optional_statements elsif_then_statements else_statements "end"
{ {
boot::conditional_statements *then = new boot::conditional_statements($2, std::move($4)); boot::conditional_statements *then = new boot::conditional_statements($2, std::move($4));
$$ = new boot::if_statement(boot::make_position(@1), then, std::move($5), $6); $$ = new boot::if_statement(boot::make_position(@1), then, std::move($5), $6);
} }
| return_statement { $$ = $1; }
| call_expression { $$ = $1; } | call_expression { $$ = $1; }
| "defer" statements "end" { $$ = new boot::defer_statement(boot::make_position(@1), std::move($2)); } | "defer" optional_statements "end"
{ $$ = new boot::defer_statement(boot::make_position(@1), std::move($2)); }
| "case" expression "of" switch_cases else_statements "end" | "case" expression "of" switch_cases else_statements "end"
{ $$ = new boot::case_statement(boot::make_position(@1), $2, std::move($4), $5); } { $$ = 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 ":" optional_statements
{ $$ = { .labels = std::move($1), .statements = std::move($3) }; }
switch_cases: switch_cases:
switch_case "|" switch_cases switch_case "|" switch_cases
{ {
@ -447,13 +441,15 @@ case_labels:
$$.emplace($$.cbegin(), $1); $$.emplace($$.cbegin(), $1);
} }
| expression { $$.push_back($1); } | expression { $$.push_back($1); }
statements: required_statements:
statement ";" statements required_statements ";" statement
{ {
std::swap($$, $3); std::swap($$, $1);
$$.insert($$.cbegin(), $1); $$.insert($$.cend(), $3);
} }
| statement { $$.push_back($1); } | statement { $$.push_back($1); }
optional_statements:
required_statements { std::swap($$, $1); }
| /* no statements */ {} | /* no statements */ {}
field_declaration: field_declaration:
IDENTIFIER ":" type_expression { $$ = std::make_pair($1, $3); } IDENTIFIER ":" type_expression { $$ = std::make_pair($1, $3); }
@ -578,9 +574,11 @@ type_part:
| "type" type_definitions { std::swap($$, $2); } | "type" type_definitions { std::swap($$, $2); }
formal_parameter: formal_parameter:
IDENTIFIER ":" type_expression { $$ = std::make_pair($1, $3); } IDENTIFIER ":" type_expression { $$ = std::make_pair($1, $3); }
formal_parameter_list:
"(" ")" {}
| "(" formal_parameters ")" { std::swap($$, $2); }
formal_parameters: formal_parameters:
/* no formal parameters */ {} formal_parameter "," formal_parameters
| formal_parameter "," formal_parameters
{ {
std::swap($$, $3); std::swap($$, $3);
$$.emplace($$.cbegin(), std::move($1)); $$.emplace($$.cbegin(), std::move($1));

View File

@ -252,10 +252,7 @@ namespace elna::boot
void declaration_visitor::visit(return_statement *statement) void declaration_visitor::visit(return_statement *statement)
{ {
if (statement->return_expression != nullptr) statement->return_expression().accept(this);
{
statement->return_expression->accept(this);
}
} }
void declaration_visitor::visit(defer_statement *statement) void declaration_visitor::visit(defer_statement *statement)

View File

@ -1297,13 +1297,12 @@ namespace elna::gcc
void generic_visitor::visit(boot::while_statement *statement) void generic_visitor::visit(boot::while_statement *statement)
{ {
std::string loop_identifier = statement->label.value_or("while");
location_t prerequisite_location = get_location(&statement->body().prerequisite().position()); location_t prerequisite_location = get_location(&statement->body().prerequisite().position());
tree prerequisite_label_decl = build_label_decl(loop_identifier.c_str(), prerequisite_location); tree prerequisite_label_decl = build_label_decl("while_do", prerequisite_location);
auto prerequisite_label_expr = build1_loc(prerequisite_location, LABEL_EXPR, auto prerequisite_label_expr = build1_loc(prerequisite_location, LABEL_EXPR,
void_type_node, prerequisite_label_decl); void_type_node, prerequisite_label_decl);
auto goto_check = build1(GOTO_EXPR, void_type_node, prerequisite_label_decl); auto goto_check = build1(GOTO_EXPR, void_type_node, prerequisite_label_decl);
tree branch_end_declaration = build_label_decl(loop_identifier.c_str(), UNKNOWN_LOCATION); tree branch_end_declaration = build_label_decl("while_end", UNKNOWN_LOCATION);
tree branch_end_expression = build1_loc(UNKNOWN_LOCATION, LABEL_EXPR, void_type_node, branch_end_declaration); tree branch_end_expression = build1_loc(UNKNOWN_LOCATION, LABEL_EXPR, void_type_node, branch_end_declaration);
append_statement(prerequisite_label_expr); append_statement(prerequisite_label_expr);
@ -1340,7 +1339,7 @@ namespace elna::gcc
void generic_visitor::visit(boot::return_statement *statement) void generic_visitor::visit(boot::return_statement *statement)
{ {
boot::expression *return_expression = statement->return_expression; boot::expression *return_expression = &statement->return_expression();
location_t statement_position = get_location(&statement->position()); location_t statement_position = get_location(&statement->position());
tree set_result{ NULL_TREE }; tree set_result{ NULL_TREE };
tree return_type = TREE_TYPE(TREE_TYPE(current_function_decl)); tree return_type = TREE_TYPE(TREE_TYPE(current_function_decl));

View File

@ -466,11 +466,13 @@ namespace elna::boot
class return_statement : public statement class return_statement : public statement
{ {
public: public:
expression *const return_expression{ nullptr }; expression *m_return_expression;
return_statement(const struct position position, expression *return_expression = nullptr); return_statement(const struct position position, expression *return_expression);
void accept(parser_visitor *visitor) override; void accept(parser_visitor *visitor) override;
expression& return_expression();
virtual ~return_statement() override; virtual ~return_statement() override;
}; };
@ -653,14 +655,10 @@ namespace elna::boot
public: public:
const std::vector<conditional_statements *> branches; const std::vector<conditional_statements *> branches;
const std::optional<std::string> label;
const std::vector<statement *> *alternative; const std::vector<statement *> *alternative;
while_statement(const struct position position, conditional_statements *body, while_statement(const struct position position, conditional_statements *body,
std::vector<conditional_statements *>&& branches, std::vector<statement *> *alternative = nullptr); std::vector<conditional_statements *>&& branches, std::vector<statement *> *alternative = nullptr);
while_statement(const struct position position, conditional_statements *body,
std::vector<conditional_statements *>&& branches, const std::string& label,
std::vector<statement *> *alternative = nullptr);
void accept(parser_visitor *visitor) override; void accept(parser_visitor *visitor) override;
conditional_statements& body(); conditional_statements& body();

View File

@ -154,7 +154,6 @@ proc exit(code: Int) -> !; extern
*) *)
proc reallocarray(ptr: ^Byte, n: Word, size: Word) -> ^Byte; proc reallocarray(ptr: ^Byte, n: Word, size: Word) -> ^Byte;
begin
return realloc(ptr, n * size) return realloc(ptr, n * size)
end end
@ -212,32 +211,26 @@ begin
end end
proc is_digit(c: Char) -> Bool; proc is_digit(c: Char) -> Bool;
begin
return cast(c: Int) >= cast('0': Int) & cast(c: Int) <= cast('9': Int) return cast(c: Int) >= cast('0': Int) & cast(c: Int) <= cast('9': Int)
end end
proc is_alpha(c: Char) -> Bool; proc is_alpha(c: Char) -> Bool;
begin
return cast(c: Int) >= cast('A': Int) & cast(c: Int) <= cast('z': Int) return cast(c: Int) >= cast('A': Int) & cast(c: Int) <= cast('z': Int)
end end
proc is_alnum(c: Char) -> Bool; proc is_alnum(c: Char) -> Bool;
begin
return is_digit(c) or is_alpha(c) return is_digit(c) or is_alpha(c)
end end
proc is_space(c: Char) -> Bool; proc is_space(c: Char) -> Bool;
begin
return c = ' ' or c = '\n' or c = '\t' return c = ' ' or c = '\n' or c = '\t'
end end
proc substring(string: String, start: Word, count: Word) -> String; proc substring(string: String, start: Word, count: Word) -> String;
begin
return String(string.ptr + start, count) return String(string.ptr + start, count)
end end
proc open_substring(string: String, start: Word) -> String; proc open_substring(string: String, start: Word) -> String;
begin
return substring(string, start, string.length - start) return substring(string, start, string.length - start)
end end
@ -339,12 +332,10 @@ begin
end end
proc source_code_empty(source_code: ^SourceCode) -> Bool; proc source_code_empty(source_code: ^SourceCode) -> Bool;
begin
return source_code^.empty(source_code^.input) return source_code^.empty(source_code^.input)
end end
proc source_code_head(source_code: SourceCode) -> Char; proc source_code_head(source_code: SourceCode) -> Char;
begin
return source_code.head(source_code.input) return source_code.head(source_code.input)
end end
@ -361,7 +352,6 @@ begin
end end
proc source_code_expect(source_code: ^SourceCode, expected: Char) -> Bool; proc source_code_expect(source_code: ^SourceCode, expected: Char) -> Bool;
begin
return ~source_code_empty(source_code) & source_code_head(source_code^) = expected return ~source_code_empty(source_code) & source_code_head(source_code^) = expected
end end
@ -375,7 +365,7 @@ var
begin begin
if escape = 'n' then if escape = 'n' then
result^ := '\n'; result^ := '\n';
successful := true; successful := true
elsif escape = 'a' then elsif escape = 'a' then
result^ := '\a'; result^ := '\a';
successful := true successful := true
@ -419,12 +409,10 @@ proc skip_spaces(source_code: ^SourceCode);
var var
current: Char current: Char
begin begin
while ~source_code_empty(source_code) do while ~source_code_empty(source_code) & is_space(source_code_head(source_code^)) do
current := source_code_head(source_code^); current := source_code_head(source_code^);
if ~is_space(current) then if current = '\n' then
return
elsif current = '\n' then
source_code_break(source_code) source_code_break(source_code)
end; end;
source_code_advance(source_code) source_code_advance(source_code)
@ -432,7 +420,6 @@ begin
end end
proc is_ident(char: Char) -> Bool; proc is_ident(char: Char) -> Bool;
begin
return is_alnum(char) or char = '_' return is_alnum(char) or char = '_'
end end
@ -681,7 +668,7 @@ begin
end; end;
write_c(' '); write_c(' ');
i := i + 1u; i := i + 1u
end; end;
write_c('\n') write_c('\n')
end end
@ -962,7 +949,7 @@ begin
result^.parse := false; result^.parse := false;
result^.input := nil; result^.input := nil;
while i < argc do while i < argc & result <> nil do
parameter := argv + i; parameter := argv + i;
if strcmp(parameter^, "--lex\0".ptr) = 0 then if strcmp(parameter^, "--lex\0".ptr) = 0 then
@ -972,23 +959,24 @@ begin
elsif parameter^^ <> '-' then elsif parameter^^ <> '-' then
if result^.input <> nil then if result^.input <> nil then
write_s("Fatal error: Only one source file can be given.\n"); write_s("Fatal error: Only one source file can be given.\n");
return nil result := nil
end; else
result^.input := parameter^ result^.input := parameter^
end
else else
write_s("Fatal error: Unknown command line options: "); write_s("Fatal error: Unknown command line options: ");
write_z(parameter^); write_z(parameter^);
write_s(".\n"); write_s(".\n");
return nil result := nil
end; end;
i := i + 1 i := i + 1
end; end;
if result^.input = nil then if result <> nil & result^.input = nil then
write_s("Fatal error: no input files.\n"); write_s("Fatal error: no input files.\n");
return nil result := nil
end; end;
return result return result