Label loops

This commit is contained in:
Eugen Wissner 2025-04-12 12:05:32 +02:00
parent 6fd1bda112
commit 8ec407515a
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
9 changed files with 134 additions and 103 deletions

View File

@ -33,36 +33,6 @@ namespace elna::boot
return this->source_position; return this->source_position;
} }
assign_statement *statement::is_assign()
{
return nullptr;
}
if_statement *statement::is_if()
{
return nullptr;
}
while_statement *statement::is_while()
{
return nullptr;
}
return_statement *statement::is_return()
{
return nullptr;
}
defer_statement *statement::is_defer()
{
return nullptr;
}
procedure_call *statement::is_call_statement()
{
return nullptr;
}
cast_expression *expression::is_cast() cast_expression *expression::is_cast()
{ {
return nullptr; return nullptr;
@ -447,11 +417,6 @@ namespace elna::boot
visitor->visit(this); visitor->visit(this);
} }
defer_statement *defer_statement::is_defer()
{
return this;
}
defer_statement::~defer_statement() defer_statement::~defer_statement()
{ {
for (statement *body_statement : statements) for (statement *body_statement : statements)
@ -676,11 +641,6 @@ namespace elna::boot
visitor->visit(this); visitor->visit(this);
} }
procedure_call *procedure_call::is_call_statement()
{
return this;
}
procedure_call *procedure_call::is_call_expression() procedure_call *procedure_call::is_call_expression()
{ {
return this; return this;
@ -754,8 +714,8 @@ namespace elna::boot
return this; return this;
} }
conditional_statements::conditional_statements(expression *prerequisite) conditional_statements::conditional_statements(expression *prerequisite, std::vector<statement *>&& statements)
: m_prerequisite(prerequisite) : m_prerequisite(prerequisite), statements(std::move(statements))
{ {
} }
@ -783,11 +743,6 @@ namespace elna::boot
visitor->visit(this); visitor->visit(this);
} }
return_statement *return_statement::is_return()
{
return this;
}
return_statement::~return_statement() return_statement::~return_statement()
{ {
delete this->return_expression; delete this->return_expression;
@ -820,11 +775,6 @@ namespace elna::boot
visitor->visit(this); visitor->visit(this);
} }
assign_statement *assign_statement::is_assign()
{
return this;
}
variable_expression *designator_expression::is_variable() variable_expression *designator_expression::is_variable()
{ {
return nullptr; return nullptr;
@ -871,11 +821,6 @@ namespace elna::boot
visitor->visit(this); visitor->visit(this);
} }
if_statement *if_statement::is_if()
{
return this;
}
conditional_statements& if_statement::body() conditional_statements& if_statement::body()
{ {
return *m_body; return *m_body;
@ -891,8 +836,26 @@ namespace elna::boot
delete this->alternative; delete this->alternative;
} }
while_statement::while_statement(const struct position position, conditional_statements *body) escape_statement::escape_statement(const struct position position,
: node(position), m_body(body) escape_direction direction, const std::string& label)
: node(position), direction(direction), label(label)
{
}
void escape_statement::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
while_statement::while_statement(const struct position position, conditional_statements *body,
std::vector<conditional_statements *>&& branches)
: node(position), m_body(body), branches(std::move(branches))
{
}
while_statement::while_statement(const struct position position, conditional_statements *body,
std::vector<conditional_statements *>&& branches, const std::string& label)
: node(position), m_body(body), branches(std::move(branches)), label(label)
{ {
} }
@ -901,11 +864,6 @@ namespace elna::boot
visitor->visit(this); visitor->visit(this);
} }
while_statement *while_statement::is_while()
{
return this;
}
conditional_statements& while_statement::body() conditional_statements& while_statement::body()
{ {
return *m_body; return *m_body;

View File

@ -125,6 +125,12 @@ or {
return { return {
return yy::parser::make_RETURN(this->location); return yy::parser::make_RETURN(this->location);
} }
break {
return yy::parser::make_BREAK(this->location);
}
repeat {
return yy::parser::make_REPEAT(this->location);
}
cast { cast {
return yy::parser::make_CAST(this->location); return yy::parser::make_CAST(this->location);
} }

View File

@ -108,6 +108,8 @@ along with GCC; see the file COPYING3. If not see
ELSE "else" ELSE "else"
ELSIF "elsif" ELSIF "elsif"
RETURN "return" RETURN "return"
REPEAT "repeat"
BREAK "break"
BEGIN_BLOCK "begin" BEGIN_BLOCK "begin"
END_BLOCK "end" END_BLOCK "end"
DEFER "defer" DEFER "defer"
@ -247,8 +249,7 @@ cast_expression: "cast" "(" expression ":" type_expression ")"
elsif_do_statements: elsif_do_statements:
"elsif" expression "do" statements elsif_do_statements "elsif" expression "do" statements elsif_do_statements
{ {
boot::conditional_statements *branch = new boot::conditional_statements($2); boot::conditional_statements *branch = new boot::conditional_statements($2, std::move($4));
std::swap(branch->statements, $4);
std::swap($5, $$); std::swap($5, $$);
$$.emplace($$.begin(), branch); $$.emplace($$.begin(), branch);
} }
@ -256,18 +257,21 @@ elsif_do_statements:
else_statements: else_statements:
"else" statements { $$ = new std::vector<boot::statement *>(std::move($2)); } "else" statements { $$ = new std::vector<boot::statement *>(std::move($2)); }
| { $$ = nullptr; } | { $$ = 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); boot::conditional_statements *body = new boot::conditional_statements($2, std::move($4));
std::swap($4, body->statements); $$ = new boot::while_statement(boot::make_position(@1), body, std::move($5));
$$ = new boot::while_statement(boot::make_position(@1), body); }
std::swap($5, $$->branches); | "while" expression "," IDENTIFIER "do" statements elsif_do_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);
} }
elsif_then_statements: elsif_then_statements:
"elsif" expression "then" statements elsif_then_statements "elsif" expression "then" statements elsif_then_statements
{ {
boot::conditional_statements *branch = new boot::conditional_statements($2); boot::conditional_statements *branch = new boot::conditional_statements($2, std::move($4));
std::swap(branch->statements, $4);
std::swap($5, $$); std::swap($5, $$);
$$.emplace($$.begin(), branch); $$.emplace($$.begin(), branch);
} }
@ -417,13 +421,16 @@ statement:
| while_statement { $$ = $1; } | while_statement { $$ = $1; }
| "if" expression "then" statements elsif_then_statements else_statements "end" | "if" expression "then" statements elsif_then_statements else_statements "end"
{ {
auto then = new boot::conditional_statements($2); boot::conditional_statements *then = new boot::conditional_statements($2, std::move($4));
std::swap($4, then->statements);
auto result = new boot::if_statement(boot::make_position(@1), then, $6); auto result = new boot::if_statement(boot::make_position(@1), then, $6);
std::swap($5, result->branches); std::swap($5, result->branches);
$$ = result; $$ = result;
} }
| return_statement { $$ = $1; } | return_statement { $$ = $1; }
| "break" IDENTIFIER
{ $$ = new boot::escape_statement(boot::make_position(@1), boot::escape_direction::end, $2); }
| "repeat" IDENTIFIER
{ $$ = new boot::escape_statement(boot::make_position(@1), boot::escape_direction::begin, $2); }
| 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 else_statements "end" | "case" expression "of" switch_cases else_statements "end"
@ -523,7 +530,7 @@ variable_declarations:
variable_part: variable_part:
/* no variable declarations */ {} /* no variable declarations */ {}
| "var" variable_declarations { std::swap($$, $2); } | "var" variable_declarations { std::swap($$, $2); }
constant_definition: identifier_definition "=" expression constant_definition: identifier_definition ":=" expression
{ {
$$ = new boot::constant_definition(boot::make_position(@1), $1.first, $1.second, $3); $$ = new boot::constant_definition(boot::make_position(@1), $1.first, $1.second, $3);
} }

View File

@ -239,6 +239,10 @@ namespace elna::boot
} }
} }
void declaration_visitor::visit(escape_statement *)
{
}
void declaration_visitor::visit(while_statement *statement) void declaration_visitor::visit(while_statement *statement)
{ {
statement->body().prerequisite().accept(this); statement->body().prerequisite().accept(this);

View File

@ -1174,7 +1174,7 @@ namespace elna::gcc
void generic_visitor::visit(boot::if_statement *statement) void generic_visitor::visit(boot::if_statement *statement)
{ {
tree endif_label_decl = build_label_decl("endif", UNKNOWN_LOCATION); tree endif_label_decl = create_artificial_label(UNKNOWN_LOCATION);
tree goto_endif = build1(GOTO_EXPR, void_type_node, endif_label_decl); tree goto_endif = build1(GOTO_EXPR, void_type_node, endif_label_decl);
make_if_branch(statement->body(), goto_endif); make_if_branch(statement->body(), goto_endif);
@ -1202,7 +1202,7 @@ namespace elna::gcc
if (TREE_TYPE(this->current_expression) != elna_bool_type_node) if (TREE_TYPE(this->current_expression) != elna_bool_type_node)
{ {
error_at(get_location(&branch.prerequisite().position()), error_at(get_location(&branch.prerequisite().position()),
"expected expression of boolean type but its type is %s", "Expected expression of boolean type but its type is %s",
print_type(TREE_TYPE(this->current_expression)).c_str()); print_type(TREE_TYPE(this->current_expression)).c_str());
this->current_expression = error_mark_node; this->current_expression = error_mark_node;
return; return;
@ -1229,13 +1229,46 @@ namespace elna::gcc
append_statement(else_label_expr); append_statement(else_label_expr);
} }
void generic_visitor::visit(boot::escape_statement *statement)
{
for (const auto& [begin, end] : this->loops)
{
if (statement->label == IDENTIFIER_POINTER(DECL_NAME(begin)))
{
tree target_declaration{ NULL_TREE };
switch (statement->direction)
{
case boot::escape_direction::begin:
target_declaration = begin;
break;
case boot::escape_direction::end:
target_declaration = end;
break;
default:
gcc_unreachable();
}
tree goto_expression = build1(GOTO_EXPR, void_type_node, target_declaration);
TREE_USED(target_declaration) = 1;
append_statement(goto_expression);
return;
}
}
error_at(get_location(&statement->position()), "Unknown loop labeled '%s'", statement->label.c_str());
}
void generic_visitor::visit(boot::while_statement *statement) void generic_visitor::visit(boot::while_statement *statement)
{ {
auto prerequisite_location = get_location(&statement->body().prerequisite().position()); std::string loop_identifier = statement->label.value_or("while");
auto prerequisite_label_decl = build_label_decl("while_check", prerequisite_location); location_t prerequisite_location = get_location(&statement->body().prerequisite().position());
tree prerequisite_label_decl = build_label_decl(loop_identifier.c_str(), 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_expression = build1_loc(UNKNOWN_LOCATION, LABEL_EXPR, void_type_node, branch_end_declaration);
this->loops.push_front({ prerequisite_label_decl, branch_end_declaration });
append_statement(prerequisite_label_expr); append_statement(prerequisite_label_expr);
make_if_branch(statement->body(), goto_check); make_if_branch(statement->body(), goto_check);
@ -1244,6 +1277,7 @@ namespace elna::gcc
{ {
make_if_branch(*branch, goto_check); make_if_branch(*branch, goto_check);
} }
append_statement(branch_end_expression);
this->current_expression = NULL_TREE; this->current_expression = NULL_TREE;
} }

View File

@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
#include <optional>
#include "elna/boot/result.h" #include "elna/boot/result.h"
namespace elna::boot namespace elna::boot
@ -52,6 +53,12 @@ namespace elna::boot
minus minus
}; };
enum class escape_direction
{
begin,
end
};
class variable_declaration; class variable_declaration;
class constant_definition; class constant_definition;
class procedure_definition; class procedure_definition;
@ -60,6 +67,7 @@ namespace elna::boot
class cast_expression; class cast_expression;
class assign_statement; class assign_statement;
class if_statement; class if_statement;
class escape_statement;
class while_statement; class while_statement;
class return_statement; class return_statement;
class case_statement; class case_statement;
@ -99,6 +107,7 @@ namespace elna::boot
virtual void visit(traits_expression *) = 0; virtual void visit(traits_expression *) = 0;
virtual void visit(assign_statement *) = 0; virtual void visit(assign_statement *) = 0;
virtual void visit(if_statement *) = 0; virtual void visit(if_statement *) = 0;
virtual void visit(escape_statement *) = 0;
virtual void visit(while_statement *) = 0; virtual void visit(while_statement *) = 0;
virtual void visit(return_statement *) = 0; virtual void visit(return_statement *) = 0;
virtual void visit(defer_statement *) = 0; virtual void visit(defer_statement *) = 0;
@ -152,13 +161,6 @@ namespace elna::boot
class statement : public virtual node class statement : public virtual node
{ {
public:
virtual assign_statement *is_assign();
virtual if_statement *is_if();
virtual while_statement *is_while();
virtual return_statement *is_return();
virtual defer_statement *is_defer();
virtual procedure_call *is_call_statement();
}; };
class expression : public virtual node class expression : public virtual node
@ -428,9 +430,9 @@ namespace elna::boot
expression *m_prerequisite; expression *m_prerequisite;
public: public:
std::vector<statement *> statements; const std::vector<statement *> statements;
conditional_statements(expression *prerequisite); conditional_statements(expression *prerequisite, std::vector<statement *>&& statements);
expression& prerequisite(); expression& prerequisite();
@ -444,7 +446,6 @@ namespace elna::boot
return_statement(const struct position position, expression *return_expression = nullptr); return_statement(const struct position position, expression *return_expression = nullptr);
void accept(parser_visitor *visitor) override; void accept(parser_visitor *visitor) override;
virtual return_statement *is_return() override;
virtual ~return_statement() override; virtual ~return_statement() override;
}; };
@ -558,7 +559,6 @@ namespace elna::boot
procedure_call(const struct position position, designator_expression *callable); procedure_call(const struct position position, designator_expression *callable);
void accept(parser_visitor *visitor) override; void accept(parser_visitor *visitor) override;
virtual procedure_call *is_call_statement() override;
virtual procedure_call *is_call_expression() override; virtual procedure_call *is_call_expression() override;
designator_expression& callable(); designator_expression& callable();
@ -585,7 +585,6 @@ namespace elna::boot
expression& rvalue(); expression& rvalue();
virtual ~assign_statement() override; virtual ~assign_statement() override;
assign_statement *is_assign() override;
}; };
/** /**
@ -602,13 +601,23 @@ namespace elna::boot
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);
void accept(parser_visitor *visitor) override; void accept(parser_visitor *visitor) override;
virtual if_statement *is_if() override;
conditional_statements& body(); conditional_statements& body();
virtual ~if_statement() override; virtual ~if_statement() override;
}; };
class escape_statement : public statement
{
public:
const escape_direction direction;
const std::string label;
escape_statement(const struct position position,
escape_direction direction, const std::string& label);
void accept(parser_visitor *visitor) override;
};
/** /**
* While-statement. * While-statement.
*/ */
@ -617,10 +626,14 @@ namespace elna::boot
conditional_statements *m_body; conditional_statements *m_body;
public: public:
std::vector<conditional_statements *> branches; const std::vector<conditional_statements *> branches;
while_statement(const struct position position, conditional_statements *body); const std::optional<std::string> label;
while_statement(const struct position position, conditional_statements *body,
std::vector<conditional_statements *>&& branches);
while_statement(const struct position position, conditional_statements *body,
std::vector<conditional_statements *>&& branches, const std::string& label);
void accept(parser_visitor *visitor) override; void accept(parser_visitor *visitor) override;
while_statement *is_while() override;
conditional_statements& body(); conditional_statements& body();
@ -676,7 +689,6 @@ namespace elna::boot
defer_statement(const struct position position, std::vector<statement *>&& statements); defer_statement(const struct position position, std::vector<statement *>&& statements);
void accept(parser_visitor *visitor) override; void accept(parser_visitor *visitor) override;
defer_statement *is_defer() override;
virtual ~defer_statement() override; virtual ~defer_statement() override;
}; };

View File

@ -75,6 +75,7 @@ namespace elna::boot
void visit(procedure_definition *definition) override; void visit(procedure_definition *definition) override;
void visit(assign_statement *statement) override; void visit(assign_statement *statement) override;
void visit(if_statement *statement) override; void visit(if_statement *statement) override;
void visit(escape_statement *) override;
void visit(while_statement *statement) override; void visit(while_statement *statement) override;
void visit(return_statement *statement) override; void visit(return_statement *statement) override;
void visit(defer_statement *statement) override; void visit(defer_statement *statement) override;

View File

@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-iterator.h" #include "tree-iterator.h"
#include <string> #include <string>
#include <forward_list>
namespace elna::gcc namespace elna::gcc
{ {
@ -45,6 +46,7 @@ namespace elna::gcc
tree current_expression{ NULL_TREE }; tree current_expression{ NULL_TREE };
std::shared_ptr<symbol_table> symbols; std::shared_ptr<symbol_table> symbols;
std::unordered_map<std::string, tree> unresolved; std::unordered_map<std::string, tree> unresolved;
std::forward_list<std::pair<tree, tree>> loops;
void declare_procedure(boot::procedure_definition *const definition); void declare_procedure(boot::procedure_definition *const definition);
tree build_procedure_type(boot::procedure_type_expression& type); tree build_procedure_type(boot::procedure_type_expression& type);
@ -100,6 +102,7 @@ namespace elna::gcc
void visit(boot::block *block) override; void visit(boot::block *block) override;
void visit(boot::assign_statement *statement) override; void visit(boot::assign_statement *statement) override;
void visit(boot::if_statement *statement) override; void visit(boot::if_statement *statement) override;
void visit(boot::escape_statement *statement) override;
void visit(boot::while_statement *statement) override; void visit(boot::while_statement *statement) override;
void visit(boot::named_type_expression *type) override; void visit(boot::named_type_expression *type) override;
void visit(boot::array_type_expression *type) override; void visit(boot::array_type_expression *type) override;

View File

@ -1,7 +1,7 @@
const const
SEEK_SET* = 0; SEEK_SET* := 0;
SEEK_CUR* = 1; SEEK_CUR* := 1;
SEEK_END* = 2; SEEK_END* := 2;
type type
TokenKind* = ( TokenKind* = (
@ -404,9 +404,15 @@ begin
end end
proc skip_spaces(source_code: ^SourceCode); proc skip_spaces(source_code: ^SourceCode);
var
current: Char;
begin begin
while ~source_code_empty(source_code) & is_space(source_code_head(source_code^)) do while ~source_code_empty(source_code), loop do
if source_code_head(source_code^) = '\n' then current := source_code_head(source_code^);
if ~is_space(current) then
break loop
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)