Introduce a procedure type
This commit is contained in:
		
							
								
								
									
										19
									
								
								cli/cl.cpp
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								cli/cl.cpp
									
									
									
									
									
								
							| @@ -14,22 +14,29 @@ namespace elna::cli | ||||
|             << ": " << compile_error->what() << std::endl; | ||||
|     } | ||||
|  | ||||
|     constexpr std::size_t pointer_size = 4; | ||||
|  | ||||
|     static std::shared_ptr<source::symbol_table> add_builtin_symbols() | ||||
|     { | ||||
|         source::symbol_table result; | ||||
|         std::vector<std::shared_ptr<const source::type>> intrinsic_arguments; | ||||
|  | ||||
|         auto boolean_info = std::make_shared<source::type_info>(source::boolean_type); | ||||
|         auto int_info = std::make_shared<source::type_info>(source::int_type); | ||||
|         result.enter("Boolean", boolean_info); | ||||
|         result.enter("Int", int_info); | ||||
|  | ||||
|         auto writei = std::make_shared<source::intrinsic_info>(); | ||||
|         writei->parameter_infos.emplace_back(int_info->type()); | ||||
|         intrinsic_arguments.push_back(int_info->type()); | ||||
|         auto writei = std::make_shared<source::intrinsic_info>( | ||||
|                 source::procedure_type{ intrinsic_arguments, pointer_size }); | ||||
|         result.enter("writei", writei); | ||||
|         intrinsic_arguments.clear(); | ||||
|  | ||||
|         auto writeb = std::make_shared<source::intrinsic_info>(); | ||||
|         writeb->parameter_infos.emplace_back(boolean_info->type()); | ||||
|         intrinsic_arguments.push_back(boolean_info->type()); | ||||
|         auto writeb = std::make_shared<source::intrinsic_info>( | ||||
|                 source::procedure_type{ intrinsic_arguments, pointer_size }); | ||||
|         result.enter("writeb", writeb); | ||||
|         intrinsic_arguments.clear(); | ||||
|  | ||||
|         return std::make_shared<source::symbol_table>(std::move(result)); | ||||
|     } | ||||
| @@ -53,8 +60,8 @@ namespace elna::cli | ||||
|                 return 2; | ||||
|             } | ||||
|             auto global_scope = add_builtin_symbols(); | ||||
|             source::name_analysis_visitor(global_scope, in_file).visit(ast.get()); | ||||
|             source::type_analysis_visitor(global_scope, in_file, 4).visit(ast.get()); | ||||
|             source::name_analysis_visitor(global_scope, in_file, pointer_size).visit(ast.get()); | ||||
|             source::type_analysis_visitor(global_scope, in_file, pointer_size).visit(ast.get()); | ||||
|             source::allocator_visitor(global_scope).visit(ast.get()); | ||||
|  | ||||
|             source::intermediate_code_generator intermediate_code_generator{ global_scope }; | ||||
|   | ||||
| @@ -132,6 +132,7 @@ namespace elna::source | ||||
|         enum class operation | ||||
|         { | ||||
|             dereference, | ||||
|             argument | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
|   | ||||
| @@ -10,6 +10,7 @@ namespace elna::source | ||||
|         std::shared_ptr<symbol_table> table; | ||||
|         const std::filesystem::path filename; | ||||
|         std::list<std::unique_ptr<error>> m_errors; | ||||
|         const std::size_t pointer_size; | ||||
|  | ||||
|         std::shared_ptr<const type> convert_declaration_type(const type_expression& ast_type) const; | ||||
|  | ||||
| @@ -17,8 +18,10 @@ namespace elna::source | ||||
|         /** | ||||
|          * \param table Symbol table. | ||||
|          * \param path Source filename. | ||||
|          * \param target_pointer_size Pointer size on the target platform. | ||||
|          */ | ||||
|         name_analysis_visitor(std::shared_ptr<symbol_table> table, const std::filesystem::path& filename); | ||||
|         name_analysis_visitor(std::shared_ptr<symbol_table> table, const std::filesystem::path& filename, | ||||
|                 const std::size_t target_pointer_size); | ||||
|  | ||||
|         /** | ||||
|          * \return Collected errors. | ||||
| @@ -67,7 +70,7 @@ namespace elna::source | ||||
|          * \param target_pointer_size Pointer size on the target platform. | ||||
|          */ | ||||
|         type_analysis_visitor(std::shared_ptr<symbol_table> table, const std::filesystem::path& filename, | ||||
|                 std::size_t target_pointer_size); | ||||
|                 const std::size_t target_pointer_size); | ||||
|  | ||||
|         /** | ||||
|          * \return Collected errors. | ||||
| @@ -75,9 +78,11 @@ namespace elna::source | ||||
|         const std::list<std::unique_ptr<error>>& errors() const noexcept; | ||||
|  | ||||
|         void visit(program *program) override; | ||||
|         void visit(procedure_definition *definition) override; | ||||
|         void visit(procedure_definition *procedure) override; | ||||
|         void visit(integer_literal *literal) override; | ||||
|         void visit(boolean_literal *literal) override; | ||||
|         void visit(unary_expression *expression) override; | ||||
|         void visit(call_statement *statement) override; | ||||
|         void visit(constant_definition *definition) override; | ||||
|     }; | ||||
| } | ||||
|   | ||||
| @@ -4,7 +4,6 @@ | ||||
| #include <unordered_map> | ||||
| #include <string> | ||||
| #include <memory> | ||||
| #include <vector> | ||||
|  | ||||
| namespace elna::source | ||||
| { | ||||
| @@ -40,11 +39,14 @@ namespace elna::source | ||||
|      */ | ||||
|     class constant_info final : public info | ||||
|     { | ||||
|         std::shared_ptr<const class type> m_type; | ||||
|         std::int32_t m_value; | ||||
|  | ||||
|     public: | ||||
|         constant_info(const std::int32_t value); | ||||
|         constant_info(std::shared_ptr<const class type> type, const std::int32_t value); | ||||
|         ~constant_info() override; | ||||
|  | ||||
|         std::shared_ptr<const class type> type() const noexcept; | ||||
|         std::int32_t value() const noexcept; | ||||
|     }; | ||||
|  | ||||
| @@ -83,10 +85,13 @@ namespace elna::source | ||||
|      */ | ||||
|     class intrinsic_info : public info | ||||
|     { | ||||
|     public: | ||||
|         std::vector<parameter_info> parameter_infos; | ||||
|         std::shared_ptr<const class procedure_type> m_type; | ||||
|  | ||||
|     public: | ||||
|         explicit intrinsic_info(const class procedure_type& type); | ||||
|         ~intrinsic_info() override; | ||||
|  | ||||
|         std::shared_ptr<const class procedure_type> type() const noexcept; | ||||
|         std::size_t parameter_stack_size() const noexcept; | ||||
|     }; | ||||
|  | ||||
| @@ -101,7 +106,7 @@ namespace elna::source | ||||
|         std::size_t local_stack_size{ 0 }; | ||||
|         std::size_t argument_stack_size{ 0 }; | ||||
|  | ||||
|         explicit procedure_info(std::shared_ptr<symbol_table> outer_scope); | ||||
|         procedure_info(const class procedure_type& type, std::shared_ptr<symbol_table> outer_scope); | ||||
|         ~procedure_info() override; | ||||
|  | ||||
|         std::shared_ptr<symbol_table> scope(); | ||||
|   | ||||
| @@ -2,6 +2,7 @@ | ||||
|  | ||||
| #include <memory> | ||||
| #include <string> | ||||
| #include <vector> | ||||
|  | ||||
| namespace elna::source | ||||
| { | ||||
| @@ -61,6 +62,23 @@ namespace elna::source | ||||
|         pointer_type(std::shared_ptr<const type> base_type, const std::size_t byte_size); | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Type of a procedure. | ||||
|      */ | ||||
|     struct procedure_type : public type | ||||
|     { | ||||
|         /// Argument types. | ||||
|         std::vector<std::shared_ptr<const type>> arguments; | ||||
|  | ||||
|         /** | ||||
|          * Constructor. | ||||
|          * | ||||
|          * \param arguments Argument types. | ||||
|          * \param byte_size Function pointer size. | ||||
|          */ | ||||
|         procedure_type(std::vector<std::shared_ptr<const type>> arguments, const std::size_t byte_size); | ||||
|     }; | ||||
|  | ||||
|     inline const primitive_type boolean_type{ "Boolean", 1 }; | ||||
|     inline const primitive_type int_type{ "Int", 4 }; | ||||
| } | ||||
|   | ||||
| @@ -5,15 +5,16 @@ | ||||
| namespace elna::source | ||||
| { | ||||
|     name_analysis_visitor::name_analysis_visitor(std::shared_ptr<symbol_table> table, | ||||
|             const std::filesystem::path& filename) | ||||
|         : table(table), filename(filename) | ||||
|             const std::filesystem::path& filename, const std::size_t target_pointer_size) | ||||
|         : table(table), filename(filename), pointer_size(target_pointer_size) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     void name_analysis_visitor::visit(constant_definition *definition) | ||||
|     { | ||||
|         auto constant_type = std::make_shared<const class type>(int_type); | ||||
|         this->table->enter(definition->identifier(), | ||||
|                 std::make_shared<constant_info>(constant_info(definition->body().number()))); | ||||
|                 std::make_shared<constant_info>(constant_type, definition->body().number())); | ||||
|     } | ||||
|  | ||||
|     std::shared_ptr<const type> name_analysis_visitor::convert_declaration_type(const type_expression& ast_type) const | ||||
| @@ -42,22 +43,30 @@ namespace elna::source | ||||
|  | ||||
|     void name_analysis_visitor::visit(program *program) | ||||
|     { | ||||
|         this->table->enter("main", std::make_shared<procedure_info>(this->table)); | ||||
|         class procedure_type main_type{ std::vector<std::shared_ptr<const class type>>(), this->pointer_size }; | ||||
|         this->table->enter("main", std::make_shared<procedure_info>(main_type, this->table)); | ||||
|         empty_visitor::visit(program); | ||||
|     } | ||||
|  | ||||
|     void name_analysis_visitor::visit(procedure_definition *procedure) | ||||
|     { | ||||
|         auto info = std::make_shared<procedure_info>(this->table); | ||||
|         this->table->enter(procedure->identifier(), info); | ||||
|         this->table = info->scope(); | ||||
|         std::vector<std::shared_ptr<const type>> arguments; | ||||
|  | ||||
|         for (auto& parameter : procedure->parameters()) | ||||
|         { | ||||
|             auto declaration_type = convert_declaration_type(parameter->type()); | ||||
|             arguments.push_back(declaration_type); | ||||
|         } | ||||
|         procedure_type definition_type{ std::move(arguments), this->pointer_size }; | ||||
|         auto info = std::make_shared<procedure_info>(definition_type, this->table); | ||||
|  | ||||
|             this->table->enter(parameter->identifier(), | ||||
|                     std::make_shared<parameter_info>(declaration_type)); | ||||
|         this->table->enter(procedure->identifier(), info); | ||||
|         this->table = info->scope(); | ||||
|  | ||||
|         for (std::size_t i = 0; i < procedure->parameters().size(); ++i) | ||||
|         { | ||||
|             this->table->enter(procedure->parameters().at(i)->identifier(), | ||||
|                     std::make_shared<parameter_info>(definition_type.arguments.at(i))); | ||||
|         } | ||||
|         procedure->body().accept(this); | ||||
|  | ||||
| @@ -123,7 +132,7 @@ namespace elna::source | ||||
|     } | ||||
|  | ||||
|     type_analysis_visitor::type_analysis_visitor(std::shared_ptr<symbol_table> table, | ||||
|             const std::filesystem::path& filename, std::size_t target_pointer_size) | ||||
|             const std::filesystem::path& filename, const std::size_t target_pointer_size) | ||||
|         : table(table), filename(filename), pointer_size(target_pointer_size) | ||||
|     { | ||||
|     } | ||||
| @@ -140,9 +149,14 @@ namespace elna::source | ||||
|         program->body().accept(this); | ||||
|     } | ||||
|  | ||||
|     void type_analysis_visitor::visit(procedure_definition *definition) | ||||
|     void type_analysis_visitor::visit(procedure_definition *procedure) | ||||
|     { | ||||
|         definition->body().accept(this); | ||||
|         auto info = std::dynamic_pointer_cast<procedure_info>(this->table->lookup(procedure->identifier())); | ||||
|         this->table = info->scope(); | ||||
|  | ||||
|         procedure->body().accept(this); | ||||
|  | ||||
|         this->table = info->scope()->scope(); | ||||
|     } | ||||
|  | ||||
|     void type_analysis_visitor::visit(integer_literal *literal) | ||||
| @@ -182,6 +196,32 @@ namespace elna::source | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void type_analysis_visitor::visit(call_statement *statement) | ||||
|     { | ||||
|         auto call_info = std::dynamic_pointer_cast<intrinsic_info>(this->table->lookup(statement->name())); | ||||
|  | ||||
|         std::size_t i{ 0 }; | ||||
|         for (const auto& argument : statement->arguments()) | ||||
|         { | ||||
|             argument->accept(this); | ||||
|  | ||||
|             if (argument->data_type != nullptr && i < call_info->type()->arguments.size() | ||||
|                     && call_info->type()->arguments[i] != argument->data_type) | ||||
|             { | ||||
|                 auto new_error = std::make_unique<type_mismatch>(argument->data_type, | ||||
|                         type_mismatch::operation::argument, this->filename, argument->position()); | ||||
|                 m_errors.push_back(std::move(new_error)); | ||||
|             } | ||||
|  | ||||
|             ++i; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void type_analysis_visitor::visit(constant_definition *definition) | ||||
|     { | ||||
|         definition->body().accept(this); | ||||
|     } | ||||
|  | ||||
|     const std::list<std::unique_ptr<error>>& type_analysis_visitor::errors() const noexcept | ||||
|     { | ||||
|         return m_errors; | ||||
|   | ||||
| @@ -55,8 +55,8 @@ namespace elna::source | ||||
|         return m_type; | ||||
|     } | ||||
|  | ||||
|     constant_info::constant_info(const std::int32_t value) | ||||
|         : m_value(value) | ||||
|     constant_info::constant_info(const std::shared_ptr<const class type> type, const std::int32_t value) | ||||
|         : m_type(type), m_value(value) | ||||
|     { | ||||
|     } | ||||
|  | ||||
| @@ -64,6 +64,11 @@ namespace elna::source | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     std::shared_ptr<const class type> constant_info::type() const noexcept | ||||
|     { | ||||
|         return m_type; | ||||
|     } | ||||
|  | ||||
|     std::int32_t constant_info::value() const noexcept | ||||
|     { | ||||
|         return m_value; | ||||
| @@ -97,17 +102,27 @@ namespace elna::source | ||||
|         return m_type; | ||||
|     } | ||||
|  | ||||
|     intrinsic_info::intrinsic_info(const class procedure_type& type) | ||||
|         : m_type(std::make_shared<procedure_type>(type)) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     intrinsic_info::~intrinsic_info() | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     std::size_t intrinsic_info::parameter_stack_size() const noexcept | ||||
|     std::shared_ptr<const class procedure_type> intrinsic_info::type() const noexcept | ||||
|     { | ||||
|         return this->parameter_infos.size() * sizeof(std::int32_t); | ||||
|         return m_type; | ||||
|     } | ||||
|  | ||||
|     procedure_info::procedure_info(std::shared_ptr<symbol_table> outer_scope) | ||||
|         : local_table(std::make_shared<symbol_table>(outer_scope)) | ||||
|     std::size_t intrinsic_info::parameter_stack_size() const noexcept | ||||
|     { | ||||
|         return type()->arguments.size() * sizeof(std::int32_t); | ||||
|     } | ||||
|  | ||||
|     procedure_info::procedure_info(const class procedure_type& type, std::shared_ptr<symbol_table> outer_scope) | ||||
|         : intrinsic_info(type), local_table(std::make_shared<symbol_table>(outer_scope)) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -21,4 +21,9 @@ namespace elna::source | ||||
|         : type(byte_size), base_type(base_type) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     procedure_type::procedure_type(std::vector<std::shared_ptr<const type>> arguments, const std::size_t byte_size) | ||||
|         : arguments(std::move(arguments)), type(byte_size) | ||||
|     { | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user