Check for duplicate fields in the declaration visitor
This commit is contained in:
		| @@ -15,8 +15,6 @@ You should have received a copy of the GNU General Public License | ||||
| along with GCC; see the file COPYING3.  If not see | ||||
| <http://www.gnu.org/licenses/>.  */ | ||||
|  | ||||
| #include <set> | ||||
|  | ||||
| #include "elna/boot/semantic.h" | ||||
|  | ||||
| namespace elna | ||||
| @@ -110,57 +108,17 @@ namespace boot | ||||
|         this->current_type = type(std::make_shared<array_type>(this->current_type, type_expression->size)); | ||||
|     } | ||||
|  | ||||
|     bool declaration_visitor::build_composite_type(const std::vector<field_declaration>& declarations, | ||||
|             std::vector<type_field>& fields) | ||||
|     void declaration_visitor::visit(record_type_expression *) | ||||
|     { | ||||
|         std::set<std::string> field_names; | ||||
|  | ||||
|         for (auto& field : declarations) | ||||
|         { | ||||
|             if (field_names.find(field.first) != field_names.cend()) | ||||
|             { | ||||
|                 add_error<already_declared_error>(field.first, this->input_file, field.second->position()); | ||||
|                 this->current_type = type(); | ||||
|                 return false; | ||||
|             } | ||||
|             field.second->accept(this); | ||||
|             if (!this->current_type.empty()) | ||||
|             { | ||||
|                 fields.push_back({ field.first, type(this->current_type) }); | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|         this->current_type = type(std::make_shared<record_type>()); | ||||
|     } | ||||
|  | ||||
|     void declaration_visitor::visit(record_type_expression *type_expression) | ||||
|     void declaration_visitor::visit(union_type_expression *) | ||||
|     { | ||||
|         auto type_definition = std::make_shared<record_type>(); | ||||
|  | ||||
|         if (build_composite_type(type_expression->fields, type_definition->fields)) | ||||
|         { | ||||
|             this->current_type = type(type_definition); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             this->current_type = type(); | ||||
|         } | ||||
|         this->current_type = type(std::make_shared<union_type>()); | ||||
|     } | ||||
|  | ||||
|     void declaration_visitor::visit(union_type_expression *type_expression) | ||||
|     { | ||||
|         auto type_definition = std::make_shared<union_type>(); | ||||
|  | ||||
|         if (build_composite_type(type_expression->fields, type_definition->fields)) | ||||
|         { | ||||
|             this->current_type = type(type_definition); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             this->current_type = type(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void declaration_visitor::visit(procedure_type_expression *type_expression) | ||||
|     void declaration_visitor::visit(procedure_type_expression *) | ||||
|     { | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -22,7 +22,6 @@ namespace elna | ||||
| namespace boot | ||||
| { | ||||
|     type::type() | ||||
|         : tag(type_tag::alias) | ||||
|     { | ||||
|     } | ||||
|  | ||||
| @@ -145,6 +144,7 @@ namespace boot | ||||
|         case type_tag::empty: | ||||
|             break; | ||||
|         case type_tag::alias: | ||||
|             this->alias.~weak_ptr<alias_type>(); | ||||
|             break; | ||||
|         case type_tag::primitive: | ||||
|             this->primitive.~shared_ptr<primitive_type>(); | ||||
|   | ||||
| @@ -50,5 +50,20 @@ namespace gcc | ||||
|         TYPE_FIELDS(elna_string_type_node) = chainon(elna_string_ptr_field_node, elna_string_length_field_node); | ||||
|         layout_type(elna_string_type_node); | ||||
|     } | ||||
|  | ||||
|     std::shared_ptr<symbol_table> builtin_symbol_table() | ||||
|     { | ||||
|         std::shared_ptr<elna::gcc::symbol_table> symbol_table = std::make_shared<elna::gcc::symbol_table>(); | ||||
|  | ||||
|         symbol_table->enter("Int", elna_int_type_node); | ||||
|         symbol_table->enter("Word", elna_word_type_node); | ||||
|         symbol_table->enter("Char", elna_char_type_node); | ||||
|         symbol_table->enter("Bool", elna_bool_type_node); | ||||
|         symbol_table->enter("Byte", elna_byte_type_node); | ||||
|         symbol_table->enter("Float", elna_float_type_node); | ||||
|         symbol_table->enter("String", elna_string_type_node); | ||||
|  | ||||
|         return symbol_table; | ||||
|     } | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -16,6 +16,7 @@ along with GCC; see the file COPYING3.  If not see | ||||
| <http://www.gnu.org/licenses/>.  */ | ||||
|  | ||||
| #include <array> | ||||
| #include <set> | ||||
|  | ||||
| #include "elna/gcc/elna-generic.h" | ||||
| #include "elna/gcc/elna-diagnostic.h" | ||||
| @@ -32,21 +33,16 @@ along with GCC; see the file COPYING3.  If not see | ||||
| #include "varasm.h" | ||||
| #include "fold-const.h" | ||||
| #include "langhooks.h" | ||||
| #include <set> | ||||
|  | ||||
| namespace elna | ||||
| { | ||||
| namespace gcc | ||||
| { | ||||
|     tree handle_symbol(const std::string& symbol_name, const boot::type& type, | ||||
|             std::shared_ptr<boot::symbol_table> from, std::shared_ptr<symbol_table> to); | ||||
|  | ||||
|     tree get_inner_alias(const boot::type& type, | ||||
|             std::shared_ptr<boot::symbol_table> from, std::shared_ptr<symbol_table> to) | ||||
|     tree get_inner_alias(const boot::type& type, std::shared_ptr<symbol_table> symbols) | ||||
|     { | ||||
|         if (auto reference = type.get<boot::primitive_type>()) | ||||
|         { | ||||
|             return to->lookup(reference->identifier); | ||||
|             return symbols->lookup(reference->identifier); | ||||
|         } | ||||
|         else if (auto reference = type.get<boot::record_type>()) | ||||
|         { | ||||
| @@ -58,7 +54,7 @@ namespace gcc | ||||
|         } | ||||
|         else if (auto reference = type.get<boot::pointer_type>()) | ||||
|         { | ||||
|             return build_pointer_type_for_mode(get_inner_alias(reference->base, from, to), VOIDmode, true); | ||||
|             return build_pointer_type_for_mode(get_inner_alias(reference->base, symbols), VOIDmode, true); | ||||
|         } | ||||
|         else if (auto reference = type.get<boot::array_type>()) | ||||
|         { | ||||
| @@ -66,45 +62,40 @@ namespace gcc | ||||
|             tree upper_bound = build_int_cst_type(integer_type_node, reference->size); | ||||
|             tree range_type = build_range_type(integer_type_node, lower_bound, upper_bound); | ||||
|  | ||||
|             return build_array_type(get_inner_alias(reference->base, from, to), range_type); | ||||
|             return build_array_type(get_inner_alias(reference->base, symbols), range_type); | ||||
|         } | ||||
|         else if (auto reference = type.get<boot::alias_type>()) | ||||
|         { | ||||
|             return handle_symbol(reference->name, reference->reference, from, to); | ||||
|             return handle_symbol(reference->name, reference->reference, symbols); | ||||
|         } | ||||
|         return error_mark_node; | ||||
|     } | ||||
|  | ||||
|     tree handle_symbol(const std::string& symbol_name, const boot::type& type, | ||||
|             std::shared_ptr<boot::symbol_table> from, std::shared_ptr<symbol_table> to) | ||||
|     tree handle_symbol(const std::string& symbol_name, const boot::type& type, std::shared_ptr<symbol_table> symbols) | ||||
|     { | ||||
|         auto looked_up = to->lookup(symbol_name); | ||||
|         auto looked_up = symbols->lookup(symbol_name); | ||||
|  | ||||
|         if (looked_up == NULL_TREE) | ||||
|         { | ||||
|             looked_up = get_inner_alias(type, from, to); | ||||
|             to->enter(symbol_name, looked_up); | ||||
|             looked_up = get_inner_alias(type, symbols); | ||||
|             symbols->enter(symbol_name, looked_up); | ||||
|         } | ||||
|         return looked_up; | ||||
|     } | ||||
|  | ||||
|     std::deque<std::unique_ptr<boot::error>> do_semantic_analysis(const char *path, | ||||
|             std::unique_ptr<boot::program>& ast, std::shared_ptr<symbol_table> symbols) | ||||
|             std::unique_ptr<boot::program>& ast, std::shared_ptr<boot::symbol_table> info_table, | ||||
|             std::shared_ptr<symbol_table> symbols) | ||||
|     { | ||||
|         auto info_table = boot::builtin_symbol_table(); | ||||
|         boot::declaration_visitor declaration_visitor(path, info_table); | ||||
|  | ||||
|         declaration_visitor.visit(ast.get()); | ||||
|  | ||||
|         if (declaration_visitor.errors().empty()) | ||||
|         { | ||||
|             for (auto& [symbol_name, symbol_info] : *info_table) | ||||
|             for (auto& [symbol_name, symbol_info] : declaration_visitor.unresolved) | ||||
|             { | ||||
|                 handle_symbol(symbol_name, symbol_info->is_type()->symbol, info_table, symbols); | ||||
|             } | ||||
|             for (auto& [symbol_name, symbol_info] : *info_table) | ||||
|             { | ||||
|                 // printf("%s\n", symbol_name.c_str()); | ||||
|                 handle_symbol(symbol_name, boot::type(symbol_info), symbols); | ||||
|             } | ||||
|         } | ||||
|         return std::move(declaration_visitor.errors()); | ||||
| @@ -418,11 +409,6 @@ namespace gcc | ||||
|         return bind_expr; | ||||
|     } | ||||
|  | ||||
|     tree generic_visitor::lookup(const std::string& name) | ||||
|     { | ||||
|         return this->symbols->lookup(name); | ||||
|     } | ||||
|  | ||||
|     void generic_visitor::visit(boot::number_literal<std::int32_t> *literal) | ||||
|     { | ||||
|         this->current_expression = build_int_cst(elna_int_type_node, literal->value); | ||||
| @@ -775,7 +761,7 @@ namespace gcc | ||||
|     void generic_visitor::visit(boot::type_definition *definition) | ||||
|     { | ||||
|         location_t definition_location = get_location(&definition->position()); | ||||
|         this->current_expression = lookup(definition->identifier); | ||||
|         this->current_expression = this->symbols->lookup(definition->identifier); | ||||
|         definition->body().accept(this); | ||||
|  | ||||
|         tree definition_tree = build_decl(definition_location, TYPE_DECL, | ||||
| @@ -809,6 +795,36 @@ namespace gcc | ||||
|         return build_function_type_array(return_type, type.parameters.size(), parameter_types.data()); | ||||
|     } | ||||
|  | ||||
|     void generic_visitor::build_composite_type(const std::vector<boot::field_declaration>& fields, | ||||
|             tree composite_type_node) | ||||
|     { | ||||
|         std::set<std::string> field_names; | ||||
|  | ||||
|         for (auto& field : fields) | ||||
|         { | ||||
|             if (field_names.find(field.first) != field_names.cend()) | ||||
|             { | ||||
|                 error_at(get_location(&field.second->position()), "repeated field name"); | ||||
|                 this->current_expression = error_mark_node; | ||||
|                 return; | ||||
|             } | ||||
|             field_names.insert(field.first); | ||||
|  | ||||
|             field.second->accept(this); | ||||
|             if (this->current_expression == NULL_TREE || this->current_expression == error_mark_node) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
|             tree field_declaration = build_field(get_location(&field.second->position()), | ||||
|                     composite_type_node, field.first, this->current_expression); | ||||
|             TYPE_FIELDS(composite_type_node) = chainon(TYPE_FIELDS(composite_type_node), field_declaration); | ||||
|             this->current_expression = NULL_TREE; | ||||
|         } | ||||
|         layout_type(composite_type_node); | ||||
|  | ||||
|         this->current_expression = composite_type_node; | ||||
|     } | ||||
|  | ||||
|     void generic_visitor::visit(boot::variable_declaration *declaration) | ||||
|     { | ||||
|         declaration->variable_type().accept(this); | ||||
| @@ -847,7 +863,7 @@ namespace gcc | ||||
|  | ||||
|     void generic_visitor::visit(boot::variable_expression *expression) | ||||
|     { | ||||
|         auto symbol = lookup(expression->name); | ||||
|         auto symbol = this->symbols->lookup(expression->name); | ||||
|  | ||||
|         if (symbol == NULL_TREE) | ||||
|         { | ||||
| @@ -1140,7 +1156,7 @@ namespace gcc | ||||
|  | ||||
|     void generic_visitor::visit(boot::primitive_type_expression *type) | ||||
|     { | ||||
|         tree symbol = lookup(type->name); | ||||
|         tree symbol = this->symbols->lookup(type->name); | ||||
|  | ||||
|         if (symbol == NULL_TREE || !TYPE_P(symbol)) | ||||
|         { | ||||
| @@ -1181,66 +1197,20 @@ namespace gcc | ||||
|  | ||||
|     void generic_visitor::visit(boot::record_type_expression *type) | ||||
|     { | ||||
|         std::set<std::string> field_names; | ||||
|         tree composite_type_node = this->current_expression == NULL_TREE | ||||
|             ? make_node(RECORD_TYPE) | ||||
|             : this->current_expression; | ||||
|  | ||||
|         for (auto& field : type->fields) | ||||
|         { | ||||
|             if (field_names.find(field.first) != field_names.cend()) | ||||
|             { | ||||
|                 error_at(get_location(&field.second->position()), "repeated field name"); | ||||
|                 this->current_expression = error_mark_node; | ||||
|                 return; | ||||
|             } | ||||
|             field_names.insert(field.first); | ||||
|  | ||||
|             field.second->accept(this); | ||||
|             if (this->current_expression == NULL_TREE || this->current_expression == error_mark_node) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
|             tree field_declaration = build_field(get_location(&field.second->position()), | ||||
|                     composite_type_node, field.first, this->current_expression); | ||||
|             TYPE_FIELDS(composite_type_node) = chainon(TYPE_FIELDS(composite_type_node), field_declaration); | ||||
|             this->current_expression = NULL_TREE; | ||||
|         } | ||||
|         layout_type(composite_type_node); | ||||
|  | ||||
|         this->current_expression = composite_type_node; | ||||
|         build_composite_type(type->fields, composite_type_node); | ||||
|     } | ||||
|  | ||||
|     void generic_visitor::visit(boot::union_type_expression *type) | ||||
|     { | ||||
|         std::set<std::string> field_names; | ||||
|         tree composite_type_node = this->current_expression == NULL_TREE | ||||
|             ? make_node(UNION_TYPE) | ||||
|             : this->current_expression; | ||||
|  | ||||
|         for (auto& field : type->fields) | ||||
|         { | ||||
|             if (field_names.find(field.first) != field_names.cend()) | ||||
|             { | ||||
|                 error_at(get_location(&field.second->position()), "repeated field name"); | ||||
|                 this->current_expression = error_mark_node; | ||||
|                 return; | ||||
|             } | ||||
|             field_names.insert(field.first); | ||||
|  | ||||
|             field.second->accept(this); | ||||
|             if (this->current_expression == NULL_TREE || this->current_expression == error_mark_node) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
|             tree field_declaration = build_field(get_location(&field.second->position()), | ||||
|                     composite_type_node, field.first, this->current_expression); | ||||
|             TYPE_FIELDS(composite_type_node) = chainon(TYPE_FIELDS(composite_type_node), field_declaration); | ||||
|             this->current_expression = NULL_TREE; | ||||
|         } | ||||
|         layout_type(composite_type_node); | ||||
|  | ||||
|         this->current_expression = composite_type_node; | ||||
|         build_composite_type(type->fields, composite_type_node); | ||||
|     } | ||||
|  | ||||
|     void generic_visitor::visit(boot::procedure_type_expression *type) | ||||
|   | ||||
							
								
								
									
										13
									
								
								gcc/elna1.cc
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								gcc/elna1.cc
									
									
									
									
									
								
							| @@ -83,17 +83,10 @@ static void elna_parse_file(const char *filename) | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         std::shared_ptr<elna::gcc::symbol_table> symbol_table = std::make_shared<elna::gcc::symbol_table>(); | ||||
|         std::shared_ptr<elna::boot::symbol_table> info_table = elna::boot::builtin_symbol_table(); | ||||
|         std::shared_ptr<elna::gcc::symbol_table> symbol_table = elna::gcc::builtin_symbol_table(); | ||||
|  | ||||
|         symbol_table->enter("Int", elna_int_type_node); | ||||
|         symbol_table->enter("Word", elna_word_type_node); | ||||
|         symbol_table->enter("Char", elna_char_type_node); | ||||
|         symbol_table->enter("Bool", elna_bool_type_node); | ||||
|         symbol_table->enter("Byte", elna_byte_type_node); | ||||
|         symbol_table->enter("Float", elna_float_type_node); | ||||
|         symbol_table->enter("String", elna_string_type_node); | ||||
|  | ||||
|         auto semantic_errors = elna::gcc::do_semantic_analysis(filename, driver.tree, symbol_table); | ||||
|         auto semantic_errors = elna::gcc::do_semantic_analysis(filename, driver.tree, info_table, symbol_table); | ||||
|  | ||||
|         if (semantic_errors.empty()) | ||||
|         { | ||||
|   | ||||
| @@ -52,12 +52,10 @@ namespace boot | ||||
|     { | ||||
|         type current_type; | ||||
|         std::shared_ptr<symbol_table> symbols; | ||||
|         std::unordered_map<std::string, std::shared_ptr<alias_type>> unresolved; | ||||
|  | ||||
|         bool build_composite_type(const std::vector<field_declaration>& declarations, | ||||
|                 std::vector<type_field>& fields); | ||||
|  | ||||
|     public: | ||||
|         std::unordered_map<std::string, std::shared_ptr<alias_type>> unresolved; | ||||
|  | ||||
|         explicit declaration_visitor(const char *path, std::shared_ptr<symbol_table> symbols); | ||||
|  | ||||
|         void visit(primitive_type_expression *type_expression) override; | ||||
| @@ -65,9 +63,9 @@ namespace boot | ||||
|         void visit(pointer_type_expression *type_expression) override; | ||||
|         void visit(program *program) override; | ||||
|         void visit(type_definition *definition) override; | ||||
|         void visit(record_type_expression *type_expression) override; | ||||
|         void visit(union_type_expression *type_expression) override; | ||||
|         void visit(procedure_type_expression *type_expression) override; | ||||
|         void visit(record_type_expression *) override; | ||||
|         void visit(union_type_expression *) override; | ||||
|         void visit(procedure_type_expression *) override; | ||||
|     }; | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -113,16 +113,12 @@ namespace boot | ||||
|         explicit primitive_type(const std::string& identifier); | ||||
|     }; | ||||
|  | ||||
|     using type_field = typename std::pair<std::string, type>; | ||||
|  | ||||
|     struct record_type | ||||
|     { | ||||
|         std::vector<type_field> fields; | ||||
|     }; | ||||
|  | ||||
|     struct union_type | ||||
|     { | ||||
|         std::vector<type_field> fields; | ||||
|     }; | ||||
|  | ||||
|     class type_info; | ||||
|   | ||||
| @@ -15,16 +15,21 @@ You should have received a copy of the GNU General Public License | ||||
| along with GCC; see the file COPYING3.  If not see | ||||
| <http://www.gnu.org/licenses/>.  */ | ||||
|  | ||||
| #include <memory> | ||||
|  | ||||
| #include "config.h" | ||||
| #include "system.h" | ||||
| #include "coretypes.h" | ||||
| #include "tree.h" | ||||
| #include "tree-iterator.h" | ||||
|  | ||||
| #include "elna/gcc/elna-tree.h" | ||||
|  | ||||
| namespace elna | ||||
| { | ||||
| namespace gcc | ||||
| { | ||||
|     void init_ttree(); | ||||
|     std::shared_ptr<symbol_table> builtin_symbol_table(); | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -35,7 +35,9 @@ namespace elna | ||||
| namespace gcc | ||||
| { | ||||
|     std::deque<std::unique_ptr<boot::error>> do_semantic_analysis(const char *path, | ||||
|             std::unique_ptr<boot::program>& ast, std::shared_ptr<symbol_table> symbols); | ||||
|             std::unique_ptr<boot::program>& ast, std::shared_ptr<boot::symbol_table> info_table, | ||||
|             std::shared_ptr<symbol_table> symbols); | ||||
|     tree handle_symbol(const std::string& symbol_name, const boot::type& type, std::shared_ptr<symbol_table> symbols); | ||||
|  | ||||
|     class generic_visitor final : public boot::empty_visitor | ||||
|     { | ||||
| @@ -44,12 +46,12 @@ namespace gcc | ||||
|  | ||||
|         tree build_label_decl(const char *name, location_t loc); | ||||
|         tree build_procedure_type(boot::procedure_type_expression& type); | ||||
|         void build_composite_type(const std::vector<boot::field_declaration>& fields, | ||||
|                 tree composite_type_node); | ||||
|  | ||||
|         void enter_scope(); | ||||
|         tree leave_scope(); | ||||
|  | ||||
|         tree lookup(const std::string& name); | ||||
|  | ||||
|         void make_if_branch(boot::conditional_statements& branch, tree goto_endif); | ||||
|  | ||||
|         tree build_arithmetic_operation(boot::binary_expression *expression, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user