Implement elsif do
This commit is contained in:
		| @@ -944,6 +944,10 @@ namespace boot | ||||
|     while_statement::~while_statement() | ||||
|     { | ||||
|         delete m_body; | ||||
|         for (const auto branch : branches) | ||||
|         { | ||||
|             delete branch; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     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::field_t> field_declaration; | ||||
| %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::defer_statement *> defer_statement; | ||||
| %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); | ||||
|         } | ||||
| 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); | ||||
|             std::swap($4, body->statements); | ||||
|             $$ = new elna::boot::while_statement(elna::boot::make_position(@1), body); | ||||
|             std::swap($5, $$->branches); | ||||
|         } | ||||
| elsif_statement_list: | ||||
|     ELSIF expression THEN optional_statements elsif_statement_list | ||||
| elsif_then_statements: | ||||
|     ELSIF expression THEN optional_statements elsif_then_statements | ||||
|         { | ||||
|             elna::boot::conditional_statements *branch = new elna::boot::conditional_statements($2); | ||||
|             std::swap(branch->statements, $4); | ||||
| @@ -217,14 +227,14 @@ elsif_statement_list: | ||||
|         } | ||||
|     | {} | ||||
| 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); | ||||
|             std::swap($4, then->statements); | ||||
|             $$ = new elna::boot::if_statement(elna::boot::make_position(@1), then); | ||||
|             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); | ||||
|             std::swap($4, then->statements); | ||||
|   | ||||
| @@ -38,7 +38,7 @@ namespace elna | ||||
| { | ||||
| 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; | ||||
|     } | ||||
| @@ -310,7 +310,7 @@ namespace gcc | ||||
|  | ||||
|     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. | ||||
|         struct binding_level *new_level = ggc_cleared_alloc<binding_level>(); | ||||
| @@ -1071,7 +1071,7 @@ namespace gcc | ||||
|     { | ||||
|         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()), | ||||
|                     "expected expression of boolean type but its type is %s", | ||||
| @@ -1116,55 +1116,19 @@ namespace gcc | ||||
|  | ||||
|     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 body_location = get_location(&statement->position()); | ||||
|  | ||||
|         auto prerequisite_label_decl = build_label_decl("while_check", prerequisite_location); | ||||
|         auto prerequisite_label_expr = build1_loc(prerequisite_location, LABEL_EXPR, | ||||
|                 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); | ||||
|         append_statement(goto_check); | ||||
|  | ||||
|         auto endif_label_expr = build1(LABEL_EXPR, void_type_node, end_label_decl); | ||||
|         append_statement(endif_label_expr); | ||||
|         append_statement(prerequisite_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; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -88,7 +88,7 @@ static void elna_parse_file(const char *filename) | ||||
|     } | ||||
|     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()); | ||||
|     } | ||||
|   | ||||
| @@ -617,6 +617,7 @@ namespace boot | ||||
|         conditional_statements *m_body; | ||||
|  | ||||
|     public: | ||||
|         std::vector<conditional_statements *> branches; | ||||
|         while_statement(const struct position position, conditional_statements *body); | ||||
|         virtual void accept(parser_visitor *visitor) override; | ||||
|  | ||||
|   | ||||
| @@ -29,7 +29,7 @@ namespace boot | ||||
|     /** | ||||
|      * Symbol table. | ||||
|      */ | ||||
|     template<typename T> | ||||
|     template<typename T, T nothing> | ||||
|     class symbol_table | ||||
|     { | ||||
|     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. | ||||
|          * | ||||
|          * \param name Symbol name. | ||||
| @@ -91,7 +91,7 @@ namespace boot | ||||
|             { | ||||
|                 return this->outer_scope->lookup(name); | ||||
|             } | ||||
|             return nullptr; | ||||
|             return nothing; | ||||
|         } | ||||
|  | ||||
|         /** | ||||
| @@ -104,7 +104,14 @@ namespace boot | ||||
|          */ | ||||
|         bool enter(const std::string& name, symbol_ptr entry) | ||||
|         { | ||||
|             return entries.insert({ name, entry }).second; | ||||
|             if (lookup(name) == nothing) | ||||
|             { | ||||
|                 return entries.insert({ name, entry }).second; | ||||
|             } | ||||
|             else  | ||||
|             { | ||||
|                 return nothing; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|   | ||||
| @@ -37,7 +37,7 @@ namespace gcc | ||||
|     class generic_visitor final : public boot::empty_visitor | ||||
|     { | ||||
|         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_type(boot::top_type& type); | ||||
| @@ -61,7 +61,7 @@ namespace gcc | ||||
|                 tree symbol, const std::vector<boot::expression *>& arguments); | ||||
|  | ||||
|     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::procedure_definition *definition) override; | ||||
|   | ||||
| @@ -33,6 +33,8 @@ namespace elna | ||||
| { | ||||
| namespace gcc | ||||
| { | ||||
|     using symbol_table = boot::symbol_table<tree, NULL_TREE>; | ||||
|  | ||||
|     bool is_pointer_type(tree type); | ||||
|     bool is_integral_type(tree type); | ||||
|     bool is_numeric_type(tree type); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user