Implement elsif
This commit is contained in:
parent
1f7c1b4cb8
commit
6c14e7433b
@ -733,70 +733,62 @@ namespace gcc
|
||||
|
||||
void generic_visitor::visit(source::if_statement *statement)
|
||||
{
|
||||
statement->body().prerequisite().accept(this);
|
||||
tree endif_label_decl = build_label_decl("endif", UNKNOWN_LOCATION);
|
||||
tree goto_endif = build1(GOTO_EXPR, void_type_node, endif_label_decl);
|
||||
|
||||
if (TREE_TYPE(this->current_expression) != boolean_type_node)
|
||||
make_if_branch(statement->body(), goto_endif);
|
||||
|
||||
for (const auto branch : statement->branches)
|
||||
{
|
||||
error_at(get_location(&statement->body().prerequisite().position()),
|
||||
"expected expression of boolean type but its type is %s",
|
||||
print_type(TREE_TYPE(this->current_expression)));
|
||||
this->current_expression = error_mark_node;
|
||||
return;
|
||||
}
|
||||
auto then_location = get_location(&statement->position());
|
||||
auto prerequisite_location = get_location(&statement->body().prerequisite().position());
|
||||
|
||||
auto then_label_decl = build_label_decl("then", then_location);
|
||||
auto endif_label_decl = build_label_decl("end_if", then_location);
|
||||
|
||||
auto goto_then = build1_loc(prerequisite_location, GOTO_EXPR,
|
||||
void_type_node, then_label_decl);
|
||||
auto goto_endif = build1_loc(prerequisite_location, GOTO_EXPR,
|
||||
void_type_node, endif_label_decl);
|
||||
|
||||
tree else_label_decl = NULL_TREE;
|
||||
tree goto_else_or_endif = NULL_TREE;
|
||||
if (statement->alternative() != nullptr)
|
||||
{
|
||||
auto else_location = get_location(&statement->position());
|
||||
else_label_decl = build_label_decl("else", else_location);
|
||||
goto_else_or_endif = build1_loc(else_location, GOTO_EXPR, void_type_node, else_label_decl);
|
||||
}
|
||||
else
|
||||
{
|
||||
goto_else_or_endif = goto_endif;
|
||||
}
|
||||
|
||||
auto cond_expr = build3_loc(prerequisite_location, COND_EXPR,
|
||||
void_type_node, this->current_expression, goto_then, goto_else_or_endif);
|
||||
append_to_statement_list(cond_expr, &this->current_statements);
|
||||
|
||||
auto then_label_expr = build1_loc(then_location, LABEL_EXPR,
|
||||
void_type_node, then_label_decl);
|
||||
append_to_statement_list(then_label_expr, &this->current_statements);
|
||||
|
||||
for (const auto body_statement : statement->body().statements)
|
||||
{
|
||||
body_statement->accept(this);
|
||||
make_if_branch(*branch, goto_endif);
|
||||
}
|
||||
if (statement->alternative() != nullptr)
|
||||
{
|
||||
append_to_statement_list(goto_endif, &this->current_statements);
|
||||
|
||||
auto else_label_expr = build1(LABEL_EXPR, void_type_node, else_label_decl);
|
||||
append_to_statement_list(else_label_expr, &this->current_statements);
|
||||
|
||||
for (const auto body_statement : *statement->alternative())
|
||||
{
|
||||
body_statement->accept(this);
|
||||
}
|
||||
}
|
||||
auto endif_label_expr = build1(LABEL_EXPR, void_type_node, endif_label_decl);
|
||||
append_to_statement_list(endif_label_expr, &this->current_statements);
|
||||
|
||||
tree endif_label_expr = build1(LABEL_EXPR, void_type_node, endif_label_decl);
|
||||
append_to_statement_list(endif_label_expr, &this->current_statements);
|
||||
this->current_expression = NULL_TREE;
|
||||
}
|
||||
|
||||
void generic_visitor::make_if_branch(source::conditional_statements& branch, tree goto_endif)
|
||||
{
|
||||
branch.prerequisite().accept(this);
|
||||
|
||||
if (TREE_TYPE(this->current_expression) != boolean_type_node)
|
||||
{
|
||||
error_at(get_location(&branch.prerequisite().position()),
|
||||
"expected expression of boolean type but its type is %s",
|
||||
print_type(TREE_TYPE(this->current_expression)));
|
||||
this->current_expression = error_mark_node;
|
||||
return;
|
||||
}
|
||||
tree then_label_decl = build_label_decl("then", UNKNOWN_LOCATION);
|
||||
tree goto_then = build1(GOTO_EXPR, void_type_node, then_label_decl);
|
||||
|
||||
tree else_label_decl = build_label_decl("else", UNKNOWN_LOCATION);
|
||||
tree goto_else = build1(GOTO_EXPR, void_type_node, else_label_decl);
|
||||
|
||||
auto cond_expr = build3(COND_EXPR, void_type_node, this->current_expression, goto_then, goto_else);
|
||||
append_to_statement_list(cond_expr, &this->current_statements);
|
||||
|
||||
tree then_label_expr = build1(LABEL_EXPR, void_type_node, then_label_decl);
|
||||
append_to_statement_list(then_label_expr, &this->current_statements);
|
||||
|
||||
for (const auto body_statement : branch.statements)
|
||||
{
|
||||
body_statement->accept(this);
|
||||
}
|
||||
append_to_statement_list(goto_endif, &this->current_statements);
|
||||
|
||||
tree else_label_expr = build1(LABEL_EXPR, void_type_node, else_label_decl);
|
||||
append_to_statement_list(else_label_expr, &this->current_statements);
|
||||
}
|
||||
|
||||
tree generic_visitor::build_label_decl(const char *name, location_t loc)
|
||||
{
|
||||
auto label_decl = build_decl(loc,
|
||||
|
@ -34,6 +34,8 @@ namespace gcc
|
||||
void build_binary_operation(bool condition, source::binary_expression *expression,
|
||||
tree_code operator_code, tree left, tree right, tree target_type);
|
||||
|
||||
void make_if_branch(source::conditional_statements& branch, tree goto_endif);
|
||||
|
||||
public:
|
||||
generic_visitor(std::shared_ptr<source::symbol_table<tree>> symbol_table);
|
||||
|
||||
|
@ -617,6 +617,8 @@ namespace source
|
||||
std::vector<statement *> *m_alternative;
|
||||
|
||||
public:
|
||||
std::vector<conditional_statements *> branches;
|
||||
|
||||
if_statement(const struct position position, conditional_statements *body,
|
||||
std::vector<statement *> *alternative = nullptr);
|
||||
virtual void accept(parser_visitor *visitor) override;
|
||||
|
@ -898,7 +898,10 @@ namespace source
|
||||
if_statement::~if_statement()
|
||||
{
|
||||
delete m_body;
|
||||
|
||||
for (const auto branch : branches)
|
||||
{
|
||||
delete branch;
|
||||
}
|
||||
if (m_alternative != nullptr)
|
||||
{
|
||||
delete m_alternative;
|
||||
|
@ -96,6 +96,7 @@
|
||||
%type <elna::source::block *> block;
|
||||
%type <std::pair<std::string, elna::source::type_expression *>> field_declaration;
|
||||
%type <std::vector<std::pair<std::string, elna::source::type_expression *>>> field_list;
|
||||
%type <std::vector<elna::source::conditional_statements *>> elsif_statement_list;
|
||||
%%
|
||||
program:
|
||||
type_part constant_part procedure_part variable_part BEGIN_BLOCK optional_statements END_BLOCK DOT
|
||||
@ -121,7 +122,7 @@ program:
|
||||
{
|
||||
*value_definition++ = variable;
|
||||
}
|
||||
auto tree = new elna::source::program(elna::source::position{},
|
||||
auto tree = new elna::source::program(elna::source::make_position(@5),
|
||||
std::move(definitions), std::move(value_definitions), std::move($6));
|
||||
|
||||
driver.tree.reset(tree);
|
||||
@ -139,28 +140,28 @@ block: constant_part variable_part BEGIN_BLOCK optional_statements END_BLOCK
|
||||
{
|
||||
*definition++ = variable;
|
||||
}
|
||||
$$ = new elna::source::block(elna::source::position{},
|
||||
$$ = new elna::source::block(elna::source::make_position(@3),
|
||||
std::move(definitions), std::move($4));
|
||||
}
|
||||
procedure_definition:
|
||||
PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON block SEMICOLON
|
||||
{
|
||||
$$ = new elna::source::procedure_definition(elna::source::position{},
|
||||
$$ = new elna::source::procedure_definition(elna::source::make_position(@1),
|
||||
$2, std::move($3), nullptr, $5);
|
||||
}
|
||||
| PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON EXTERN SEMICOLON
|
||||
{
|
||||
$$ = new elna::source::procedure_definition(elna::source::position{},
|
||||
$$ = new elna::source::procedure_definition(elna::source::make_position(@1),
|
||||
$2, std::move($3), nullptr, nullptr);
|
||||
}
|
||||
| PROCEDURE IDENTIFIER formal_parameter_list COLON type_expression SEMICOLON block SEMICOLON
|
||||
{
|
||||
$$ = new elna::source::procedure_definition(elna::source::position{},
|
||||
$$ = new elna::source::procedure_definition(elna::source::make_position(@1),
|
||||
$2, std::move($3), $5, $7);
|
||||
}
|
||||
| PROCEDURE IDENTIFIER formal_parameter_list COLON type_expression SEMICOLON EXTERN SEMICOLON
|
||||
{
|
||||
$$ = new elna::source::procedure_definition(elna::source::position{},
|
||||
$$ = new elna::source::procedure_definition(elna::source::make_position(@1),
|
||||
$2, std::move($3), $5, nullptr);
|
||||
}
|
||||
procedure_definitions:
|
||||
@ -188,19 +189,30 @@ while_statement: WHILE expression DO optional_statements END_BLOCK
|
||||
std::swap($4, body->statements);
|
||||
$$ = new elna::source::while_statement(elna::source::make_position(@1), body);
|
||||
}
|
||||
elsif_statement_list:
|
||||
ELSIF expression THEN optional_statements elsif_statement_list
|
||||
{
|
||||
elna::source::conditional_statements *branch = new elna::source::conditional_statements($2);
|
||||
std::swap(branch->statements, $4);
|
||||
std::swap($5, $$);
|
||||
$$.emplace($$.begin(), branch);
|
||||
}
|
||||
| {}
|
||||
if_statement:
|
||||
IF expression THEN optional_statements END_BLOCK
|
||||
IF expression THEN optional_statements elsif_statement_list END_BLOCK
|
||||
{
|
||||
auto then = new elna::source::conditional_statements($2);
|
||||
std::swap($4, then->statements);
|
||||
$$ = new elna::source::if_statement(elna::source::make_position(@1), then);
|
||||
std::swap($5, $$->branches);
|
||||
}
|
||||
| IF expression THEN optional_statements ELSE optional_statements END_BLOCK
|
||||
| IF expression THEN optional_statements elsif_statement_list ELSE optional_statements END_BLOCK
|
||||
{
|
||||
auto then = new elna::source::conditional_statements($2);
|
||||
std::swap($4, then->statements);
|
||||
auto _else = new std::vector<elna::source::statement *>(std::move($6));
|
||||
auto _else = new std::vector<elna::source::statement *>(std::move($7));
|
||||
$$ = new elna::source::if_statement(elna::source::make_position(@1), then, _else);
|
||||
std::swap($5, $$->branches);
|
||||
}
|
||||
return_statement:
|
||||
RETURN expression
|
||||
|
Loading…
x
Reference in New Issue
Block a user