Translate position to a GCC location
This commit is contained in:
		| @@ -21,7 +21,9 @@ gccelna$(exeext): $(GCCELNA_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBDEPS | |||||||
|  |  | ||||||
| elna_OBJS = \ | elna_OBJS = \ | ||||||
| 	elna/elna1.o \ | 	elna/elna1.o \ | ||||||
| 	elna/generic-visitor.o \ | 	elna/elna-generic.o \ | ||||||
|  | 	elna/elna-convert.o \ | ||||||
|  | 	elna/elna-diagnostic.o \ | ||||||
| 	elna/ast.o \ | 	elna/ast.o \ | ||||||
| 	elna/driver.o \ | 	elna/driver.o \ | ||||||
| 	elna/lexer.o \ | 	elna/lexer.o \ | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								gcc/elna-convert.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								gcc/elna-convert.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | #include "config.h" | ||||||
|  | #include "system.h" | ||||||
|  | #include "coretypes.h" | ||||||
|  | #include "tree.h" | ||||||
|  | #include "fold-const.h" | ||||||
|  | #include "convert.h" | ||||||
|  |  | ||||||
|  | /* Creates an expression whose value is that of EXPR, converted to type TYPE. | ||||||
|  |    This function implements all reasonable scalar conversions.  */ | ||||||
|  |  | ||||||
|  | tree convert(tree type, tree expr) | ||||||
|  | { | ||||||
|  |   return expr; | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								gcc/elna-diagnostic.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								gcc/elna-diagnostic.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | #include "elna/gcc/elna-diagnostic.h" | ||||||
|  |  | ||||||
|  | location_t elna_gcc_location(const elna::source::position *position) | ||||||
|  | { | ||||||
|  |     linemap_line_start(line_table, position->line, 0); | ||||||
|  |  | ||||||
|  |     return linemap_position_for_column(line_table, position->column); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const char *elna_gcc_print_type(tree type) | ||||||
|  | { | ||||||
|  |     gcc_assert(TYPE_P(type)); | ||||||
|  |  | ||||||
|  |     if (type == integer_type_node) | ||||||
|  |     { | ||||||
|  |         return "Int"; | ||||||
|  |     } | ||||||
|  |     else if (type == boolean_type_node) | ||||||
|  |     { | ||||||
|  |         return "Boolean"; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         return "<<unknown-type>>"; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,8 +1,11 @@ | |||||||
| #include "elna/gcc/generic-visitor.h" | #include "elna/gcc/elna-generic.h" | ||||||
|  | #include "elna/gcc/elna-diagnostic.h" | ||||||
| 
 | 
 | ||||||
| #include "input.h" | #include "input.h" | ||||||
| #include "cgraph.h" | #include "cgraph.h" | ||||||
| #include "gimplify.h" | #include "gimplify.h" | ||||||
|  | #include "stringpool.h" | ||||||
|  | #include "diagnostic.h" | ||||||
| 
 | 
 | ||||||
| namespace elna | namespace elna | ||||||
| { | { | ||||||
| @@ -72,6 +75,11 @@ namespace gcc | |||||||
|         current_expression = build_int_cst_type(integer_type_node, literal->number()); |         current_expression = build_int_cst_type(integer_type_node, literal->number()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     void generic_visitor::visit(source::boolean_literal *literal) | ||||||
|  |     { | ||||||
|  |         current_expression = build_int_cst_type(boolean_type_node, literal->boolean()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     void generic_visitor::visit(source::binary_expression *expression) |     void generic_visitor::visit(source::binary_expression *expression) | ||||||
|     { |     { | ||||||
|         expression->lhs().accept(this); |         expression->lhs().accept(this); | ||||||
| @@ -102,5 +110,79 @@ namespace gcc | |||||||
| 
 | 
 | ||||||
|         this->current_expression = build2(operator_code, integer_type_node, left, right); |         this->current_expression = build2(operator_code, integer_type_node, left, right); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     void generic_visitor::visit(source::declaration *declaration) | ||||||
|  |     { | ||||||
|  |         if (declaration->type().base() != "Int" && declaration->type().base() != "Bool") | ||||||
|  |         { | ||||||
|  |             error_at(elna_gcc_location(&declaration->type().position()), | ||||||
|  |                     "type '%s' not declared", | ||||||
|  |                     declaration->type().base().c_str()); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         auto declaration_location = elna_gcc_location(&declaration->position()); | ||||||
|  |         tree declaration_tree = build_decl(declaration_location, VAR_DECL, | ||||||
|  |                 get_identifier(declaration->identifier().c_str()), integer_type_node); | ||||||
|  |         auto result = this->symbol_map.insert({ declaration->identifier(), declaration_tree }); | ||||||
|  | 
 | ||||||
|  |         if (result.second) | ||||||
|  |         { | ||||||
|  |             auto declaration_statement = build1_loc(declaration_location, DECL_EXPR, | ||||||
|  |                     void_type_node, declaration_tree); | ||||||
|  |             append_to_statement_list(declaration_statement, &this->current_statements); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             error_at(declaration_location, | ||||||
|  |                     "variable '%s' already declared in this scope", | ||||||
|  |                     declaration->identifier().c_str()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void generic_visitor::visit(source::variable_expression *expression) | ||||||
|  |     { | ||||||
|  |         auto symbol = this->symbol_map.find(expression->name()); | ||||||
|  | 
 | ||||||
|  |         if (symbol == this->symbol_map.end()) | ||||||
|  |         { | ||||||
|  |             error_at(elna_gcc_location(&expression->position()), | ||||||
|  |                     "variable '%s' not declared in the current scope", | ||||||
|  |                     expression->name().c_str()); | ||||||
|  |             this->current_expression = error_mark_node; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         this->current_expression = symbol->second; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void generic_visitor::visit(source::assign_statement *statement) | ||||||
|  |     { | ||||||
|  |         auto lvalue = this->symbol_map.find(statement->lvalue()); | ||||||
|  |         auto statement_location = elna_gcc_location(&statement->position()); | ||||||
|  | 
 | ||||||
|  |         if (lvalue == this->symbol_map.end()) | ||||||
|  |         { | ||||||
|  |             error_at(statement_location, | ||||||
|  |                     "variable '%s' not declared in the current scope", | ||||||
|  |                     statement->lvalue().c_str()); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         statement->rvalue().accept(this); | ||||||
|  | 
 | ||||||
|  |         if (TREE_TYPE(this->current_expression) != TREE_TYPE(lvalue->second)) | ||||||
|  |         { | ||||||
|  |             error_at(elna_gcc_location(&statement->position()), | ||||||
|  |                     "cannot assign value of type %s to variable '%s' of type %s", | ||||||
|  |                     elna_gcc_print_type(TREE_TYPE(this->current_expression)), | ||||||
|  |                     statement->lvalue().c_str(), | ||||||
|  |                     elna_gcc_print_type(TREE_TYPE(lvalue->second))); | ||||||
|  |             this->current_expression = error_mark_node; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         auto assignment = build2_loc(statement_location, MODIFY_EXPR, | ||||||
|  |                 void_type_node, lvalue->second, this->current_expression); | ||||||
|  | 
 | ||||||
|  |         append_to_statement_list(assignment, &this->current_statements); | ||||||
|  |         this->current_expression = NULL_TREE; | ||||||
|  |     } | ||||||
| } | } | ||||||
| } | } | ||||||
							
								
								
									
										43
									
								
								gcc/elna1.cc
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								gcc/elna1.cc
									
									
									
									
									
								
							| @@ -10,15 +10,14 @@ | |||||||
| #include "fold-const.h" | #include "fold-const.h" | ||||||
| #include "stor-layout.h" | #include "stor-layout.h" | ||||||
| #include "debug.h" | #include "debug.h" | ||||||
| #include "convert.h" |  | ||||||
| #include "langhooks.h" | #include "langhooks.h" | ||||||
| #include "langhooks-def.h" | #include "langhooks-def.h" | ||||||
| #include "common/common-target.h" | #include "common/common-target.h" | ||||||
|  |  | ||||||
| #include <fstream> | #include <fstream> | ||||||
| #include <elna/source/driver.h> | #include <elna/source/driver.h> | ||||||
| #include "elna/source/semantic.h" | #include "elna/gcc/elna-generic.h" | ||||||
| #include "elna/gcc/generic-visitor.h" | #include "elna/gcc/elna-diagnostic.h" | ||||||
| #include "parser.hh" | #include "parser.hh" | ||||||
|  |  | ||||||
| /* Language-dependent contents of a type.  */ | /* Language-dependent contents of a type.  */ | ||||||
| @@ -61,23 +60,10 @@ struct GTY (()) language_function | |||||||
|   int dummy; |   int dummy; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /* Creates an expression whose value is that of EXPR, converted to type TYPE. |  | ||||||
|    This function implements all reasonable scalar conversions.  */ |  | ||||||
|  |  | ||||||
| tree |  | ||||||
| convert (tree type, tree expr) |  | ||||||
| { |  | ||||||
|   return expr; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* Language hooks.  */ | /* Language hooks.  */ | ||||||
|  |  | ||||||
| static bool | static bool elna_langhook_init(void) | ||||||
| elna_langhook_init (void) |  | ||||||
| { | { | ||||||
|   /* NOTE: Newer versions of GCC use only: |  | ||||||
|            build_common_tree_nodes (false); |  | ||||||
|      See Eugene's comment in the comments section. */ |  | ||||||
|     build_common_tree_nodes (false); |     build_common_tree_nodes (false); | ||||||
|  |  | ||||||
|     /* I don't know why this has to be done explicitly.  */ |     /* I don't know why this has to be done explicitly.  */ | ||||||
| @@ -88,10 +74,7 @@ elna_langhook_init (void) | |||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| constexpr std::size_t pointer_size = 4; | static void elna_parse_file (const char *filename) | ||||||
|  |  | ||||||
| static void |  | ||||||
| elna_parse_file (const char *filename) |  | ||||||
| { | { | ||||||
|     std::ifstream file{ filename, std::ios::in }; |     std::ifstream file{ filename, std::ios::in }; | ||||||
|  |  | ||||||
| @@ -104,30 +87,24 @@ elna_parse_file (const char *filename) | |||||||
|     elna::source::lexer lexer(file); |     elna::source::lexer lexer(file); | ||||||
|     yy::parser parser(lexer, driver); |     yy::parser parser(lexer, driver); | ||||||
|  |  | ||||||
|  |     linemap_add(line_table, LC_ENTER, 0, filename, 1); | ||||||
|     if (auto result = parser()) |     if (auto result = parser()) | ||||||
|     { |     { | ||||||
|         for (const auto& error : driver.errors()) |         for (const auto& error : driver.errors()) | ||||||
|         { |         { | ||||||
|           linemap_add (line_table, LC_ENTER, 0, filename, 1); |             auto gcc_location = elna_gcc_location(&error->position); | ||||||
|  |  | ||||||
|             linemap_line_start (line_table, error->line (), 0); |  | ||||||
|             auto gcc_location = linemap_position_for_column (line_table, error->column ()); |  | ||||||
|       linemap_add (line_table, LC_LEAVE, 0, NULL, 0); |  | ||||||
|  |  | ||||||
|             error_at(gcc_location, error->what().c_str()); |             error_at(gcc_location, error->what().c_str()); | ||||||
|         } |         } | ||||||
|       return; |  | ||||||
|     } |     } | ||||||
|    |     else | ||||||
|     auto symbol_table = elna::source::add_builtin_symbols(); |     { | ||||||
|     elna::source::name_analysis_visitor name_analysis_visitor{ symbol_table, filename, pointer_size }; |  | ||||||
|     elna::source::type_analysis_visitor type_analysis_visitor{ symbol_table, filename, pointer_size }; |  | ||||||
|         elna::gcc::generic_visitor generic_visitor; |         elna::gcc::generic_visitor generic_visitor; | ||||||
|  |  | ||||||
|     name_analysis_visitor.visit(driver.tree.get()); |  | ||||||
|     type_analysis_visitor.visit(driver.tree.get()); |  | ||||||
|         generic_visitor.visit(driver.tree.get()); |         generic_visitor.visit(driver.tree.get()); | ||||||
|     } |     } | ||||||
|  |     linemap_add(line_table, LC_LEAVE, 0, NULL, 0); | ||||||
|  | } | ||||||
|  |  | ||||||
| static void | static void | ||||||
| elna_langhook_parse_file (void) | elna_langhook_parse_file (void) | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								include/elna/gcc/elna-diagnostic.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								include/elna/gcc/elna-diagnostic.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "config.h" | ||||||
|  | #include "system.h" | ||||||
|  | #include "coretypes.h" | ||||||
|  | #include "input.h" | ||||||
|  | #include "tree.h" | ||||||
|  |  | ||||||
|  | #include "elna/source/result.h" | ||||||
|  |  | ||||||
|  | location_t elna_gcc_location(const elna::source::position *position); | ||||||
|  |  | ||||||
|  | const char *elna_gcc_print_type(tree type); | ||||||
| @@ -8,6 +8,9 @@ | |||||||
| #include "tree.h" | #include "tree.h" | ||||||
| #include "tree-iterator.h" | #include "tree-iterator.h" | ||||||
| 
 | 
 | ||||||
|  | #include <unordered_map> | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
| namespace elna | namespace elna | ||||||
| { | { | ||||||
| namespace gcc | namespace gcc | ||||||
| @@ -16,12 +19,17 @@ namespace gcc | |||||||
|     { |     { | ||||||
|         tree current_statements{ NULL_TREE }; |         tree current_statements{ NULL_TREE }; | ||||||
|         tree current_expression{ NULL_TREE }; |         tree current_expression{ NULL_TREE }; | ||||||
|  |         std::unordered_map<std::string, tree> symbol_map; | ||||||
| 
 | 
 | ||||||
|     public: |     public: | ||||||
|         void visit(source::program *program) override; |         void visit(source::program *program) override; | ||||||
|         void visit(source::call_statement *statement) override; |         void visit(source::call_statement *statement) override; | ||||||
|         void visit(source::integer_literal *literal) override; |         void visit(source::integer_literal *literal) override; | ||||||
|  |         void visit(source::boolean_literal *literal) override; | ||||||
|         void visit(source::binary_expression *expression) override; |         void visit(source::binary_expression *expression) override; | ||||||
|  |         void visit(source::declaration *declaration) override; | ||||||
|  |         void visit(source::variable_expression *expression) override; | ||||||
|  |         void visit(source::assign_statement *statement) override; | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| } | } | ||||||
| @@ -27,8 +27,6 @@ namespace source | |||||||
|      */ |      */ | ||||||
|     class error |     class error | ||||||
|     { |     { | ||||||
|         position m_position; |  | ||||||
|  |  | ||||||
|     protected: |     protected: | ||||||
|         /** |         /** | ||||||
|          * Constructs an error. |          * Constructs an error. | ||||||
| @@ -36,9 +34,10 @@ namespace source | |||||||
|          * \param path Source file name. |          * \param path Source file name. | ||||||
|          * \param position Error position in the source text. |          * \param position Error position in the source text. | ||||||
|          */ |          */ | ||||||
|         error(const char *path, const position position); |         error(const char *path, const struct position position); | ||||||
|  |  | ||||||
|     public: |     public: | ||||||
|  |         const struct position position; | ||||||
|         const char *path; |         const char *path; | ||||||
|  |  | ||||||
|         virtual ~error() noexcept = default; |         virtual ~error() noexcept = default; | ||||||
| @@ -55,7 +54,7 @@ namespace source | |||||||
|  |  | ||||||
|     class name_collision final : public error |     class name_collision final : public error | ||||||
|     { |     { | ||||||
|         position previous; |         const struct position previous; | ||||||
|         std::string name; |         std::string name; | ||||||
|  |  | ||||||
|     public: |     public: | ||||||
| @@ -66,7 +65,7 @@ namespace source | |||||||
|          * \param previous Position of the previously defined symbol. |          * \param previous Position of the previously defined symbol. | ||||||
|          */ |          */ | ||||||
|         name_collision(const std::string& name, const char *path, |         name_collision(const std::string& name, const char *path, | ||||||
|                 const position current, const position previous); |                 const struct position current, const struct position previous); | ||||||
|  |  | ||||||
|         std::string what() const override; |         std::string what() const override; | ||||||
|     }; |     }; | ||||||
|   | |||||||
| @@ -7,23 +7,23 @@ namespace elna | |||||||
| { | { | ||||||
| namespace source | namespace source | ||||||
| { | { | ||||||
|     error::error(const char *path, const position position) |     error::error(const char *path, const struct position position) | ||||||
|         : m_position(position), path(path) |         : position(position), path(path) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     std::size_t error::line() const noexcept |     std::size_t error::line() const noexcept | ||||||
|     { |     { | ||||||
|         return this->m_position.line; |         return this->position.line; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     std::size_t error::column() const noexcept |     std::size_t error::column() const noexcept | ||||||
|     { |     { | ||||||
|         return this->m_position.column; |         return this->position.column; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     name_collision::name_collision(const std::string& name, const char *path, |     name_collision::name_collision(const std::string& name, const char *path, | ||||||
|             const position current, const position previous) |             const struct position current, const struct position previous) | ||||||
|         : error(path, current), name(name), previous(previous) |         : error(path, current), name(name), previous(previous) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user