Implement elsif do
This commit is contained in:
parent
994b91e0e5
commit
39750f4656
@ -944,6 +944,10 @@ namespace boot
|
|||||||
while_statement::~while_statement()
|
while_statement::~while_statement()
|
||||||
{
|
{
|
||||||
delete m_body;
|
delete m_body;
|
||||||
|
for (const auto branch : branches)
|
||||||
|
{
|
||||||
|
delete branch;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *print_binary_operator(const binary_operator operation)
|
const char *print_binary_operator(const binary_operator operation)
|
||||||
|
@ -119,7 +119,7 @@ along with GCC; see the file COPYING3. If not see
|
|||||||
%type <elna::boot::block *> block;
|
%type <elna::boot::block *> block;
|
||||||
%type <elna::boot::field_t> field_declaration;
|
%type <elna::boot::field_t> field_declaration;
|
||||||
%type <std::vector<std::pair<std::string, std::shared_ptr<elna::boot::top_type>>>> optional_fields fields;
|
%type <std::vector<std::pair<std::string, std::shared_ptr<elna::boot::top_type>>>> optional_fields fields;
|
||||||
%type <std::vector<elna::boot::conditional_statements *>> elsif_statement_list;
|
%type <std::vector<elna::boot::conditional_statements *>> elsif_then_statements elsif_do_statements;
|
||||||
%type <elna::boot::cast_expression *> cast_expression;
|
%type <elna::boot::cast_expression *> cast_expression;
|
||||||
%type <elna::boot::defer_statement *> defer_statement;
|
%type <elna::boot::defer_statement *> defer_statement;
|
||||||
%type <std::pair<std::string, bool>> identifier_definition;
|
%type <std::pair<std::string, bool>> identifier_definition;
|
||||||
@ -201,14 +201,24 @@ cast_expression: CAST LEFT_PAREN expression COLON type_expression RIGHT_PAREN
|
|||||||
{
|
{
|
||||||
$$ = new elna::boot::cast_expression(elna::boot::make_position(@1), $5, $3);
|
$$ = new elna::boot::cast_expression(elna::boot::make_position(@1), $5, $3);
|
||||||
}
|
}
|
||||||
while_statement: WHILE expression DO optional_statements END_BLOCK
|
elsif_do_statements:
|
||||||
|
ELSIF expression DO optional_statements elsif_do_statements
|
||||||
|
{
|
||||||
|
elna::boot::conditional_statements *branch = new elna::boot::conditional_statements($2);
|
||||||
|
std::swap(branch->statements, $4);
|
||||||
|
std::swap($5, $$);
|
||||||
|
$$.emplace($$.begin(), branch);
|
||||||
|
}
|
||||||
|
| {}
|
||||||
|
while_statement: WHILE expression DO optional_statements elsif_do_statements END_BLOCK
|
||||||
{
|
{
|
||||||
auto body = new elna::boot::conditional_statements($2);
|
auto body = new elna::boot::conditional_statements($2);
|
||||||
std::swap($4, body->statements);
|
std::swap($4, body->statements);
|
||||||
$$ = new elna::boot::while_statement(elna::boot::make_position(@1), body);
|
$$ = new elna::boot::while_statement(elna::boot::make_position(@1), body);
|
||||||
|
std::swap($5, $$->branches);
|
||||||
}
|
}
|
||||||
elsif_statement_list:
|
elsif_then_statements:
|
||||||
ELSIF expression THEN optional_statements elsif_statement_list
|
ELSIF expression THEN optional_statements elsif_then_statements
|
||||||
{
|
{
|
||||||
elna::boot::conditional_statements *branch = new elna::boot::conditional_statements($2);
|
elna::boot::conditional_statements *branch = new elna::boot::conditional_statements($2);
|
||||||
std::swap(branch->statements, $4);
|
std::swap(branch->statements, $4);
|
||||||
@ -217,14 +227,14 @@ elsif_statement_list:
|
|||||||
}
|
}
|
||||||
| {}
|
| {}
|
||||||
if_statement:
|
if_statement:
|
||||||
IF expression THEN optional_statements elsif_statement_list END_BLOCK
|
IF expression THEN optional_statements elsif_then_statements END_BLOCK
|
||||||
{
|
{
|
||||||
auto then = new elna::boot::conditional_statements($2);
|
auto then = new elna::boot::conditional_statements($2);
|
||||||
std::swap($4, then->statements);
|
std::swap($4, then->statements);
|
||||||
$$ = new elna::boot::if_statement(elna::boot::make_position(@1), then);
|
$$ = new elna::boot::if_statement(elna::boot::make_position(@1), then);
|
||||||
std::swap($5, $$->branches);
|
std::swap($5, $$->branches);
|
||||||
}
|
}
|
||||||
| IF expression THEN optional_statements elsif_statement_list ELSE optional_statements END_BLOCK
|
| IF expression THEN optional_statements elsif_then_statements ELSE optional_statements END_BLOCK
|
||||||
{
|
{
|
||||||
auto then = new elna::boot::conditional_statements($2);
|
auto then = new elna::boot::conditional_statements($2);
|
||||||
std::swap($4, then->statements);
|
std::swap($4, then->statements);
|
||||||
|
@ -38,7 +38,7 @@ namespace elna
|
|||||||
{
|
{
|
||||||
namespace gcc
|
namespace gcc
|
||||||
{
|
{
|
||||||
generic_visitor::generic_visitor(std::shared_ptr<boot::symbol_table<tree>> symbol_table)
|
generic_visitor::generic_visitor(std::shared_ptr<symbol_table> symbol_table)
|
||||||
{
|
{
|
||||||
this->symbol_map = symbol_table;
|
this->symbol_map = symbol_table;
|
||||||
}
|
}
|
||||||
@ -310,7 +310,7 @@ namespace gcc
|
|||||||
|
|
||||||
void generic_visitor::enter_scope()
|
void generic_visitor::enter_scope()
|
||||||
{
|
{
|
||||||
this->symbol_map = std::make_shared<boot::symbol_table<tree>>(this->symbol_map);
|
this->symbol_map = std::make_shared<symbol_table>(this->symbol_map);
|
||||||
|
|
||||||
// Chain the binding levels.
|
// Chain the binding levels.
|
||||||
struct binding_level *new_level = ggc_cleared_alloc<binding_level>();
|
struct binding_level *new_level = ggc_cleared_alloc<binding_level>();
|
||||||
@ -1071,7 +1071,7 @@ namespace gcc
|
|||||||
{
|
{
|
||||||
branch.prerequisite().accept(this);
|
branch.prerequisite().accept(this);
|
||||||
|
|
||||||
if (TREE_TYPE(this->current_expression) != boolean_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",
|
||||||
@ -1116,55 +1116,19 @@ namespace gcc
|
|||||||
|
|
||||||
void generic_visitor::visit(boot::while_statement *statement)
|
void generic_visitor::visit(boot::while_statement *statement)
|
||||||
{
|
{
|
||||||
statement->body().prerequisite().accept(this);
|
|
||||||
|
|
||||||
if (TREE_TYPE(this->current_expression) != boolean_type_node)
|
|
||||||
{
|
|
||||||
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)).c_str());
|
|
||||||
this->current_expression = error_mark_node;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
enter_scope();
|
|
||||||
|
|
||||||
auto prerequisite_location = get_location(&statement->body().prerequisite().position());
|
auto prerequisite_location = get_location(&statement->body().prerequisite().position());
|
||||||
auto body_location = get_location(&statement->position());
|
|
||||||
|
|
||||||
auto prerequisite_label_decl = build_label_decl("while_check", prerequisite_location);
|
auto prerequisite_label_decl = build_label_decl("while_check", 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);
|
||||||
append_statement(prerequisite_label_expr);
|
|
||||||
|
|
||||||
auto body_label_decl = build_label_decl("while_body", body_location);
|
|
||||||
auto end_label_decl = build_label_decl("end_while", UNKNOWN_LOCATION);
|
|
||||||
|
|
||||||
auto goto_body = build1_loc(prerequisite_location, GOTO_EXPR,
|
|
||||||
void_type_node, body_label_decl);
|
|
||||||
auto goto_end = build1_loc(prerequisite_location, GOTO_EXPR,
|
|
||||||
void_type_node, end_label_decl);
|
|
||||||
|
|
||||||
auto cond_expr = build3_loc(prerequisite_location, COND_EXPR,
|
|
||||||
void_type_node, this->current_expression, goto_body, goto_end);
|
|
||||||
append_statement(cond_expr);
|
|
||||||
|
|
||||||
auto body_label_expr = build1_loc(body_location, LABEL_EXPR,
|
|
||||||
void_type_node, body_label_decl);
|
|
||||||
append_statement(body_label_expr);
|
|
||||||
|
|
||||||
for (const auto body_statement : statement->body().statements)
|
|
||||||
{
|
|
||||||
body_statement->accept(this);
|
|
||||||
}
|
|
||||||
tree mapping = leave_scope();
|
|
||||||
append_statement(mapping);
|
|
||||||
|
|
||||||
auto goto_check = build1(GOTO_EXPR, void_type_node, prerequisite_label_decl);
|
auto goto_check = build1(GOTO_EXPR, void_type_node, prerequisite_label_decl);
|
||||||
append_statement(goto_check);
|
|
||||||
|
|
||||||
auto endif_label_expr = build1(LABEL_EXPR, void_type_node, end_label_decl);
|
append_statement(prerequisite_label_expr);
|
||||||
append_statement(endif_label_expr);
|
make_if_branch(statement->body(), goto_check);
|
||||||
|
|
||||||
|
for (const auto branch : statement->branches)
|
||||||
|
{
|
||||||
|
make_if_branch(*branch, goto_check);
|
||||||
|
}
|
||||||
this->current_expression = NULL_TREE;
|
this->current_expression = NULL_TREE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ static void elna_parse_file(const char *filename)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
elna::gcc::generic_visitor generic_visitor{ std::make_shared<elna::boot::symbol_table<tree>>() };
|
elna::gcc::generic_visitor generic_visitor{ std::make_shared<elna::gcc::symbol_table>() };
|
||||||
|
|
||||||
generic_visitor.visit(driver.tree.get());
|
generic_visitor.visit(driver.tree.get());
|
||||||
}
|
}
|
||||||
|
@ -617,6 +617,7 @@ namespace boot
|
|||||||
conditional_statements *m_body;
|
conditional_statements *m_body;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
std::vector<conditional_statements *> branches;
|
||||||
while_statement(const struct position position, conditional_statements *body);
|
while_statement(const struct position position, conditional_statements *body);
|
||||||
virtual void accept(parser_visitor *visitor) override;
|
virtual void accept(parser_visitor *visitor) override;
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ namespace boot
|
|||||||
/**
|
/**
|
||||||
* Symbol table.
|
* Symbol table.
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T, T nothing>
|
||||||
class symbol_table
|
class symbol_table
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -73,7 +73,7 @@ namespace boot
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks for symbol in the table by name. Returns nullptr if the symbol
|
* Looks for symbol in the table by name. Returns nothing if the symbol
|
||||||
* can not be found.
|
* can not be found.
|
||||||
*
|
*
|
||||||
* \param name Symbol name.
|
* \param name Symbol name.
|
||||||
@ -91,7 +91,7 @@ namespace boot
|
|||||||
{
|
{
|
||||||
return this->outer_scope->lookup(name);
|
return this->outer_scope->lookup(name);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -103,9 +103,16 @@ namespace boot
|
|||||||
* \return Whether the insertion took place.
|
* \return Whether the insertion took place.
|
||||||
*/
|
*/
|
||||||
bool enter(const std::string& name, symbol_ptr entry)
|
bool enter(const std::string& name, symbol_ptr entry)
|
||||||
|
{
|
||||||
|
if (lookup(name) == nothing)
|
||||||
{
|
{
|
||||||
return entries.insert({ name, entry }).second;
|
return entries.insert({ name, entry }).second;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the outer scope or nullptr if the this is the global scope.
|
* Returns the outer scope or nullptr if the this is the global scope.
|
||||||
|
@ -37,7 +37,7 @@ namespace gcc
|
|||||||
class generic_visitor final : public boot::empty_visitor
|
class generic_visitor final : public boot::empty_visitor
|
||||||
{
|
{
|
||||||
tree current_expression{ NULL_TREE };
|
tree current_expression{ NULL_TREE };
|
||||||
std::shared_ptr<boot::symbol_table<tree>> symbol_map;
|
std::shared_ptr<symbol_table> symbol_map;
|
||||||
|
|
||||||
tree build_label_decl(const char *name, location_t loc);
|
tree build_label_decl(const char *name, location_t loc);
|
||||||
tree build_type(boot::top_type& type);
|
tree build_type(boot::top_type& type);
|
||||||
@ -61,7 +61,7 @@ namespace gcc
|
|||||||
tree symbol, const std::vector<boot::expression *>& arguments);
|
tree symbol, const std::vector<boot::expression *>& arguments);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
generic_visitor(std::shared_ptr<boot::symbol_table<tree>> symbol_table);
|
generic_visitor(std::shared_ptr<symbol_table> symbol_table);
|
||||||
|
|
||||||
void visit(boot::program *program) override;
|
void visit(boot::program *program) override;
|
||||||
void visit(boot::procedure_definition *definition) override;
|
void visit(boot::procedure_definition *definition) override;
|
||||||
|
@ -33,6 +33,8 @@ namespace elna
|
|||||||
{
|
{
|
||||||
namespace gcc
|
namespace gcc
|
||||||
{
|
{
|
||||||
|
using symbol_table = boot::symbol_table<tree, NULL_TREE>;
|
||||||
|
|
||||||
bool is_pointer_type(tree type);
|
bool is_pointer_type(tree type);
|
||||||
bool is_integral_type(tree type);
|
bool is_integral_type(tree type);
|
||||||
bool is_numeric_type(tree type);
|
bool is_numeric_type(tree type);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user