From 35c32fcf3fe5870b6eaa46a96ab452e82c2a8642 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Fri, 10 Jan 2025 23:17:18 +0100 Subject: [PATCH] Implement pointers --- CMakeLists.txt | 2 - cli/main.cc | 7 - gcc/Make-lang.in | 1 - gcc/elna-diagnostic.cc | 4 + gcc/elna-generic.cc | 83 +++++++- gcc/elna-tree.cc | 9 +- include/elna/gcc/elna-generic.h | 3 + include/elna/gcc/elna-tree.h | 1 + include/elna/source/ast.h | 22 +- include/elna/source/semantic.h | 100 --------- include/elna/source/symbol_table.h | 198 ------------------ source/ast.cc | 21 +- source/parser.yy | 37 ++-- source/semantic.cc | 325 ----------------------------- source/symbol_table.cc | 233 --------------------- 15 files changed, 131 insertions(+), 915 deletions(-) delete mode 100644 include/elna/source/semantic.h delete mode 100644 include/elna/source/symbol_table.h delete mode 100644 source/semantic.cc delete mode 100644 source/symbol_table.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index c463309..9ee0227 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,9 +17,7 @@ add_library(elna-frontend source/ast.cc include/elna/source/ast.h source/types.cc include/elna/source/types.h source/driver.cc include/elna/source/driver.h - source/symbol_table.cc include/elna/source/symbol_table.h source/result.cc include/elna/source/result.h - source/semantic.cc include/elna/source/semantic.h ${BISON_parser_OUTPUTS} ${FLEX_lexer_OUTPUTS} ) target_include_directories(elna-frontend PRIVATE ${CMAKE_CURRENT_BINARY_DIR} include) diff --git a/cli/main.cc b/cli/main.cc index 5331997..cea8790 100644 --- a/cli/main.cc +++ b/cli/main.cc @@ -1,5 +1,4 @@ #include -#include "elna/source/semantic.h" #include "parser.hh" #include @@ -34,12 +33,6 @@ int main() } return result; } - auto symbol_table = elna::source::add_builtin_symbols(); - elna::source::name_analysis_visitor name_analysis_visitor{ symbol_table, "-", pointer_size }; - elna::source::type_analysis_visitor type_analysis_visitor{ symbol_table, "-", pointer_size }; - - name_analysis_visitor.visit(driver.tree.get()); - for (auto& definition : driver.tree->definitions()) { std::cout << "Definition identifier: " << definition->identifier() << std::endl; diff --git a/gcc/Make-lang.in b/gcc/Make-lang.in index 56e2c02..ad8aad2 100644 --- a/gcc/Make-lang.in +++ b/gcc/Make-lang.in @@ -30,7 +30,6 @@ elna_OBJS = \ elna/lexer.o \ elna/parser.o \ elna/result.o \ - elna/symbol_table.o \ elna/types.o \ $(END) diff --git a/gcc/elna-diagnostic.cc b/gcc/elna-diagnostic.cc index 27f60bb..ec1b8b5 100644 --- a/gcc/elna-diagnostic.cc +++ b/gcc/elna-diagnostic.cc @@ -36,6 +36,10 @@ namespace gcc { return "String"; } + else if (is_pointer_type(type)) + { + return "pointer"; + } else if (is_array_type(type)) { return "array"; diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index c6ba2df..83a41b4 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -51,6 +51,10 @@ namespace gcc { format_number = "%s\n"; } + else if (is_pointer_type(argument_type)) + { + format_number = "%p\n"; + } else { error_at(get_location(&argument->position()), @@ -256,6 +260,20 @@ namespace gcc operator_code, target_type, left, right); } + void generic_visitor::visit(source::unary_expression *expression) + { + switch (expression->operation()) + { + case source::unary_operator::reference: + expression->operand().accept(this); + + this->current_expression = build1_loc(get_location(&expression->position()), ADDR_EXPR, + build_pointer_type_for_mode(TREE_TYPE(this->current_expression), VOIDmode, true), + this->current_expression); + break; + } + } + void generic_visitor::visit(source::constant_definition *definition) { location_t definition_location = get_location(&definition->position()); @@ -344,6 +362,10 @@ namespace gcc { return TREE_TYPE(symbol->second); } + error_at(get_location(&basic_type->position()), + "type '%s' not declared", basic_type->base_name().c_str()); + + return error_mark_node; } else if (source::array_type_expression *array_type = type.is_array()) { @@ -351,14 +373,24 @@ namespace gcc tree upper_bound = build_int_cst_type(integer_type_node, array_type->size); tree base_type = build_type(array_type->base()); - if (base_type == NULL_TREE) + if (base_type == NULL_TREE || base_type == error_mark_node) { - return NULL_TREE; + return base_type; } tree range_type = build_range_type(integer_type_node, lower_bound, upper_bound); return build_array_type(base_type, range_type); } + else if (source::pointer_type_expression *pointer_type = type.is_pointer()) + { + tree base_type = build_type(pointer_type->base()); + + if (base_type == NULL_TREE || base_type == error_mark_node) + { + return base_type; + } + return build_pointer_type_for_mode(base_type, VOIDmode, true); + } else if (source::record_type_expression *record_type = type.is_record()) { std::set field_names; @@ -397,13 +429,8 @@ namespace gcc void generic_visitor::visit(source::declaration *declaration) { tree declaration_type = build_type(declaration->type()); + gcc_assert(declaration_type != NULL_TREE); - if (declaration_type == NULL_TREE) - { - error_at(get_location(&declaration->type().position()), - "type '%s' not declared", declaration->type().base_name().c_str()); - return; - } auto declaration_location = get_location(&declaration->position()); tree declaration_tree = build_decl(declaration_location, VAR_DECL, get_identifier(declaration->identifier().c_str()), declaration_type); @@ -455,6 +482,46 @@ namespace gcc ARRAY_REF, element_type, designator, index, NULL_TREE, NULL_TREE); } + void generic_visitor::visit(source::field_access_expression *expression) + { + expression->base().accept(this); + tree field_declaration = TYPE_FIELDS(TREE_TYPE(this->current_expression)); + + while (field_declaration != NULL_TREE) + { + tree declaration_name = DECL_NAME(field_declaration); + const char *identifier_pointer = IDENTIFIER_POINTER(declaration_name); + + if (expression->field() == identifier_pointer) + { + break; + } + field_declaration = TREE_CHAIN(field_declaration); + } + location_t expression_location = get_location(&expression->position()); + if (field_declaration == NULL_TREE) + { + error_at(expression_location, + "record type does not have a field named '%s'", + expression->field().c_str()); + this->current_expression = error_mark_node; + } + else + { + this->current_expression = build3_loc(expression_location, COMPONENT_REF, + TREE_TYPE(field_declaration), this->current_expression, + field_declaration, NULL_TREE); + } + } + + void generic_visitor::visit(source::dereference_expression *expression) + { + expression->base().accept(this); + + this->current_expression = build1_loc(get_location(&expression->position()), INDIRECT_REF, + TREE_TYPE(TREE_TYPE(this->current_expression)), this->current_expression); + } + void generic_visitor::visit(source::assign_statement *statement) { statement->lvalue().accept(this); diff --git a/gcc/elna-tree.cc b/gcc/elna-tree.cc index ffb8a69..3e91f74 100644 --- a/gcc/elna-tree.cc +++ b/gcc/elna-tree.cc @@ -16,10 +16,15 @@ namespace gcc TYPE_STRING_FLAG(elna_char_type_node) = 1; } - bool is_string_type(tree type) + bool is_pointer_type(tree type) { gcc_assert(TYPE_P(type)); - return TREE_CODE(type) == POINTER_TYPE + return TREE_CODE(type) == POINTER_TYPE; + } + + bool is_string_type(tree type) + { + return is_pointer_type(type) && TYPE_MAIN_VARIANT(TREE_TYPE(type)) == char_type_node; } diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index 83e6aa3..2639474 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -39,11 +39,14 @@ namespace gcc void visit(source::char_literal *character) override; void visit(source::string_literal *string) override; void visit(source::binary_expression *expression) override; + void visit(source::unary_expression *expression) override; void visit(source::constant_definition *definition) override; void visit(source::type_definition *definition) override; void visit(source::declaration *declaration) override; void visit(source::variable_expression *expression) override; void visit(source::array_access_expression *expression) override; + void visit(source::field_access_expression *expression) override; + void visit(source::dereference_expression *expression) override; void visit(source::assign_statement *statement) override; void visit(source::if_statement *statement) override; void visit(source::while_statement *statement) override; diff --git a/include/elna/gcc/elna-tree.h b/include/elna/gcc/elna-tree.h index 017777f..a4ecdd5 100644 --- a/include/elna/gcc/elna-tree.h +++ b/include/elna/gcc/elna-tree.h @@ -23,6 +23,7 @@ namespace elna namespace gcc { void init_ttree(); + bool is_pointer_type(tree type); bool is_string_type(tree type); bool is_array_type(tree type); bool is_record_type(tree type); diff --git a/include/elna/source/ast.h b/include/elna/source/ast.h index 8ecc548..07ed8fe 100644 --- a/include/elna/source/ast.h +++ b/include/elna/source/ast.h @@ -30,8 +30,7 @@ namespace source enum class unary_operator { - reference, - dereference + reference }; class declaration; @@ -117,8 +116,8 @@ namespace source virtual void visit(record_type_expression *expression) override; virtual void visit(variable_expression *) override; virtual void visit(array_access_expression *expression) override; - virtual void visit(field_access_expression *is_field_access) override; - virtual void visit(dereference_expression *is_dereference) override; + virtual void visit(field_access_expression *expression) override; + virtual void visit(dereference_expression *expression) override; virtual void visit(number_literal *) override; virtual void visit(number_literal *) override; virtual void visit(number_literal *) override; @@ -249,7 +248,6 @@ namespace source class type_expression : public node { public: - virtual const std::string& base_name() = 0; virtual basic_type_expression *is_basic(); virtual array_type_expression *is_array(); virtual pointer_type_expression *is_pointer(); @@ -262,7 +260,7 @@ namespace source /** * Expression defining a basic type. */ - class basic_type_expression : public type_expression + class basic_type_expression final : public type_expression { const std::string m_name; @@ -274,12 +272,12 @@ namespace source basic_type_expression(const struct position position, const std::string& name); virtual void accept(parser_visitor *visitor) override; - const std::string& base_name() override; + const std::string& base_name(); basic_type_expression *is_basic() override; }; - class array_type_expression : public type_expression + class array_type_expression final : public type_expression { type_expression *m_base; @@ -290,14 +288,13 @@ namespace source virtual void accept(parser_visitor *visitor) override; type_expression& base(); - const std::string& base_name() override; array_type_expression *is_array() override; virtual ~array_type_expression() override; }; - class pointer_type_expression : public type_expression + class pointer_type_expression final : public type_expression { type_expression *m_base; @@ -306,14 +303,13 @@ namespace source virtual void accept(parser_visitor *visitor) override; type_expression& base(); - const std::string& base_name() override; pointer_type_expression *is_pointer() override; virtual ~pointer_type_expression() override; }; - class record_type_expression : public type_expression + class record_type_expression final : public type_expression { public: using field_t = std::pair; @@ -326,6 +322,8 @@ namespace source record_type_expression *is_record() override; + virtual ~record_type_expression() override; + private: fields_t m_fields; }; diff --git a/include/elna/source/semantic.h b/include/elna/source/semantic.h deleted file mode 100644 index 0c1e223..0000000 --- a/include/elna/source/semantic.h +++ /dev/null @@ -1,100 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public License -// v. 2.0. If a copy of the MPL was not distributed with this file, You can -// obtain one at http://mozilla.org/MPL/2.0/. -#pragma once - -#include -#include "elna/source/ast.h" -#include "elna/source/symbol_table.h" - -namespace elna -{ -namespace source -{ - class name_analysis_visitor final : public empty_visitor - { - std::shared_ptr table; - const char *filename; - std::list> m_errors; - const std::size_t pointer_size; - - std::shared_ptr convert_declaration_type(const type_expression& ast_type) const; - - public: - /** - * \param table Symbol table. - * \param path Source filename. - * \param target_pointer_size Pointer size on the target platform. - */ - name_analysis_visitor(std::shared_ptr table, const char *filename, - const std::size_t target_pointer_size); - - /** - * \return Collected errors. - */ - const std::list>& errors() const noexcept; - - void visit(constant_definition *definition) override; - void visit(declaration *declaration) override; - void visit(program *program) override; - void visit(procedure_definition *procedure) override; - }; - - /** - * Visitor which allocates registers and stack space for variables and - * parameters. - */ - class allocator_visitor final : public empty_visitor - { - std::ptrdiff_t local_offset; - std::ptrdiff_t argument_offset; - std::shared_ptr table; - - public: - allocator_visitor(std::shared_ptr table); - - void visit(declaration *declaration) override; - void visit(program *program) override; - void visit(procedure_definition *procedure) override; - void visit(call_statement *statement) override; - }; - - /** - * This visitor performs the type checking. - */ - class type_analysis_visitor final : public empty_visitor - { - std::shared_ptr table; - const char *filename; - const std::size_t pointer_size; - std::list> m_errors; - - public: - /** - * \param table Symbol table. - * \param path Source filename. - * \param target_pointer_size Pointer size on the target platform. - */ - type_analysis_visitor(std::shared_ptr table, const char *filename, - const std::size_t target_pointer_size); - - /** - * \return Collected errors. - */ - const std::list>& errors() const noexcept; - - void visit(program *program) override; - void visit(procedure_definition *procedure) override; - void visit(integer_literal *literal) override; - void visit(boolean_literal *literal) override; - void visit(variable_expression *expression) override; - void visit(unary_expression *expression) override; - void visit(binary_expression *expression) override; - void visit(call_statement *statement) override; - void visit(constant_definition *definition) override; - void visit(while_statement *statement) override; - void visit(if_statement *statement) override; - void visit(assign_statement *statement) override; - }; -} -} diff --git a/include/elna/source/symbol_table.h b/include/elna/source/symbol_table.h deleted file mode 100644 index b240781..0000000 --- a/include/elna/source/symbol_table.h +++ /dev/null @@ -1,198 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public License -// v. 2.0. If a copy of the MPL was not distributed with this file, You can -// obtain one at http://mozilla.org/MPL/2.0/. -#pragma once - -#include -#include -#include -#include - -namespace elna -{ -namespace source -{ - class symbol_table; - class type_info; - class typed_info; - class constant_info; - class variable_info; - class parameter_info; - class intrinsic_info; - class procedure_info; - - /** - * Generic language entity information. - */ - class info - { - public: - virtual ~info() = 0; - - virtual type_info *is_type_info() noexcept; - virtual typed_info *is_typed_info() noexcept; - virtual constant_info *is_constant_info() noexcept; - virtual variable_info *is_variable_info() noexcept; - virtual parameter_info *is_parameter_info() noexcept; - virtual intrinsic_info *is_intrinsic_info() noexcept; - virtual procedure_info *is_procedure_info() noexcept; - - protected: - info(); - }; - - /** - * Type information. - */ - class type_info final : public info - { - std::shared_ptr m_type; - - public: - explicit type_info(std::shared_ptr type); - ~type_info() override; - - virtual type_info *is_type_info() noexcept override; - std::shared_ptr type() const noexcept; - }; - - /** - * Information for a typed symbol. - */ - class typed_info : public info - { - std::shared_ptr m_type; - - protected: - typed_info(std::shared_ptr type); - - public: - ~typed_info() override; - - virtual typed_info *is_typed_info() noexcept override; - std::shared_ptr type() const noexcept; - }; - - /** - * Constant information. - */ - class constant_info final : public typed_info - { - std::int32_t m_value; - - public: - constant_info(std::shared_ptr type, const std::int32_t value); - - virtual constant_info *is_constant_info() noexcept override; - std::int32_t value() const noexcept; - }; - - /** - * Variable information. - */ - class variable_info final : public typed_info - { - public: - std::ptrdiff_t offset{ 0 }; - - explicit variable_info(std::shared_ptr type); - - virtual variable_info *is_variable_info() noexcept override; - }; - - /** - * Procedure parameter information. - */ - class parameter_info final : public typed_info - { - public: - std::ptrdiff_t offset{ 0 }; - - explicit parameter_info(std::shared_ptr type); - - virtual parameter_info *is_parameter_info() noexcept override; - }; - - /** - * Intrinsic and external procedure information. - */ - class intrinsic_info : public info - { - std::shared_ptr m_type; - - public: - explicit intrinsic_info(const class procedure_type& type); - ~intrinsic_info() override; - - std::shared_ptr type() const noexcept; - std::size_t parameter_stack_size() const noexcept; - virtual intrinsic_info *is_intrinsic_info() noexcept override; - }; - - /** - * Procedure information. - */ - class procedure_info final : public intrinsic_info - { - std::shared_ptr local_table; - - public: - std::size_t local_stack_size{ 0 }; - std::size_t argument_stack_size{ 0 }; - - procedure_info(const class procedure_type& type, std::shared_ptr outer_scope); - ~procedure_info() override; - - std::shared_ptr scope(); - std::size_t stack_size() const noexcept; - virtual procedure_info *is_procedure_info() noexcept override; - }; - - /** - * Symbol table. - */ - class symbol_table - { - std::unordered_map> entries; - std::shared_ptr outer_scope; - - public: - /** - * Constructs a new symbol with an optional outer scope. - * - * \param scope Outer scope. - */ - explicit symbol_table(std::shared_ptr scope = nullptr); - - /** - * Looks for symbol in the table by name. Returns nullptr if the symbol - * can not be found. - * - * \param name Symbol name. - * \return Symbol from the table if found. - */ - std::shared_ptr lookup(const std::string& name); - - /** - * Registers new symbol. - * - * \param name Symbol name. - * \param entry Symbol information. - */ - void enter(const std::string& name, std::shared_ptr entry); - - /** - * Returns the outer scope or nullptr if the this is the global scope. - * - * \return Outer scope. - */ - std::shared_ptr scope(); - }; - - /** - * Creates a symbol table with predefined symbols. - * - * \return A symbol table with predefined symbols. - */ - std::shared_ptr add_builtin_symbols();} -} diff --git a/source/ast.cc b/source/ast.cc index e323fc6..ad36dc0 100644 --- a/source/ast.cc +++ b/source/ast.cc @@ -280,11 +280,6 @@ namespace source return *m_base; } - const std::string& array_type_expression::base_name() - { - return base().base_name(); - } - array_type_expression *array_type_expression::is_array() { return this; @@ -310,11 +305,6 @@ namespace source return *m_base; } - const std::string& pointer_type_expression::base_name() - { - return base().base_name(); - } - pointer_type_expression *pointer_type_expression::is_pointer() { return this; @@ -346,6 +336,14 @@ namespace source return this; } + record_type_expression::~record_type_expression() + { + for (auto& field_declaration : fields()) + { + delete field_declaration.second; + } + } + declaration::declaration(const struct position position, const std::string& identifier, type_expression *type) : definition(position, identifier), m_type(type) @@ -721,9 +719,6 @@ namespace source case '@': this->m_operator = unary_operator::reference; break; - case '^': - this->m_operator = unary_operator::dereference; - break; default: __builtin_unreachable(); } diff --git a/source/parser.yy b/source/parser.yy index 25f8899..6f0d7cc 100644 --- a/source/parser.yy +++ b/source/parser.yy @@ -99,6 +99,8 @@ %type type_definition; %type > type_definitions type_part; %type block; +%type > field_declaration; +%type >> field_list; %% program: type_part constant_part procedure_part variable_part compound_statement DOT @@ -223,37 +225,31 @@ summand: factor: AT pointer { - $$ = new elna::source::unary_expression(elna::source::make_position(@1), - $2, '@'); + $$ = new elna::source::unary_expression(elna::source::make_position(@1), $2, '@'); } | pointer { $$ = $1; } comparand: summand PLUS summand { - $$ = new elna::source::binary_expression(elna::source::make_position(@1), - $1, $3, '+'); + $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '+'); } | summand MINUS summand { - $$ = new elna::source::binary_expression(elna::source::make_position(@1), - $1, $3, '-'); + $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '-'); } | summand { $$ = std::move($1); } expression: comparand EQUALS comparand { - $$ = new elna::source::binary_expression(elna::source::make_position(@1), - $1, $3, '='); + $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '='); } | comparand NOT_EQUAL comparand { - $$ = new elna::source::binary_expression(elna::source::make_position(@1), - $1, $3, 'n'); + $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, 'n'); } | comparand LESS_THAN comparand { - $$ = new elna::source::binary_expression(elna::source::make_position(@1), - $1, $3, '<'); + $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '<'); } | comparand GREATER_THAN comparand { @@ -305,12 +301,21 @@ statements: statement SEMICOLON statements { std::swap($$, $3); - $$.emplace($$.cbegin(), std::move($1)); + $$.emplace($$.cbegin(), $1); } - | statement { $$.emplace_back($1); } + | statement { $$.push_back($1); } optional_statements: statements { std::swap($$, $1); } | /* no statements */ {} +field_declaration: + IDENTIFIER COLON type_expression { $$ = std::make_pair($1, $3); } +field_list: + field_declaration SEMICOLON field_list + { + std::swap($$, $3); + $$.emplace($$.cbegin(), $1); + } + | field_declaration { $$.emplace_back($1); } type_expression: ARRAY INTEGER OF type_expression { @@ -320,6 +325,10 @@ type_expression: { $$ = new elna::source::pointer_type_expression(elna::source::make_position(@1), $2); } + | RECORD field_list END_BLOCK + { + $$ = new elna::source::record_type_expression(elna::source::make_position(@1), std::move($2)); + } | IDENTIFIER { $$ = new elna::source::basic_type_expression(elna::source::make_position(@1), $1); diff --git a/source/semantic.cc b/source/semantic.cc deleted file mode 100644 index 1086ba4..0000000 --- a/source/semantic.cc +++ /dev/null @@ -1,325 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public License -// v. 2.0. If a copy of the MPL was not distributed with this file, You can -// obtain one at http://mozilla.org/MPL/2.0/. -#include "elna/source/semantic.h" -#include "elna/source/result.h" -#include - -namespace elna -{ -namespace source -{ - name_analysis_visitor::name_analysis_visitor(std::shared_ptr table, - const char *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(int_type); - this->table->enter(definition->identifier(), - std::make_shared(constant_type, definition->body().number())); - } - - std::shared_ptr name_analysis_visitor::convert_declaration_type(const type_expression& ast_type) const - { - auto variable_type = table->lookup(ast_type.base())->is_type_info()->type(); - std::shared_ptr declaration_type; - - if (ast_type.is_pointer()) - { - return std::make_shared(variable_type, 4); - } - else - { - return variable_type; - } - } - - void name_analysis_visitor::visit(declaration *declarationx) - { - std::shared_ptr declaration_type = convert_declaration_type(declarationx->type()); - - this->table->enter(declarationx->identifier(), - std::make_shared(declaration_type)); - } - - void name_analysis_visitor::visit(program *program) - { - class procedure_type main_type{ std::vector>(), this->pointer_size }; - this->table->enter("_start", std::make_shared(main_type, this->table)); - empty_visitor::visit(program); - } - - void name_analysis_visitor::visit(procedure_definition *procedure) - { - std::vector> 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(definition_type, this->table); - - 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(definition_type.arguments.at(i))); - } - procedure->body().accept(this); - - this->table = info->scope()->scope(); - } - - const std::list>& name_analysis_visitor::errors() const noexcept - { - return m_errors; - } - - allocator_visitor::allocator_visitor(std::shared_ptr table) - : table(table) - { - } - - void allocator_visitor::visit(declaration *declaration) - { - auto declaration_info = this->table->lookup(declaration->identifier()); - - if (auto variable = declaration_info->is_variable_info()) - { - this->local_offset -= sizeof(std::int32_t); - variable->offset = this->local_offset; - } - else if (auto parameter = declaration_info->is_parameter_info()) - { - parameter->offset = this->argument_offset; - this->argument_offset += sizeof(std::int32_t); - } - } - - void allocator_visitor::visit(program *program) - { - this->local_offset = 0; - this->argument_offset = 0; - - empty_visitor::visit(program); - table->lookup("_start")->is_procedure_info()->local_stack_size = - std::abs(this->local_offset); - } - - void allocator_visitor::visit(procedure_definition *procedure) - { - this->local_offset = 0; - this->argument_offset = 0; - auto info = this->table->lookup(procedure->identifier())->is_procedure_info(); - this->table = info->scope(); - - empty_visitor::visit(procedure); - - this->table = info->scope()->scope(); - info->local_stack_size = std::abs(this->local_offset); - info->argument_stack_size = this->argument_offset; - } - - void allocator_visitor::visit(call_statement *statement) - { - auto call_info = this->table->lookup(statement->name())->is_intrinsic_info(); - - this->argument_offset = std::max(static_cast(this->argument_offset), - call_info->parameter_stack_size()); - } - - type_analysis_visitor::type_analysis_visitor(std::shared_ptr table, - const char *filename, const std::size_t target_pointer_size) - : table(table), filename(filename), pointer_size(target_pointer_size) - { - } - - void type_analysis_visitor::visit(program *program) - { - for (auto& definition : program->definitions()) - { - definition->accept(this); - } - program->body().accept(this); - } - - void type_analysis_visitor::visit(procedure_definition *procedure) - { - auto info = this->table->lookup(procedure->identifier())->is_procedure_info(); - this->table = info->scope(); - - procedure->body().accept(this); - - this->table = info->scope()->scope(); - } - - void type_analysis_visitor::visit(integer_literal *literal) - { - literal->data_type = table->lookup("Int")->is_type_info()->type(); - } - - void type_analysis_visitor::visit(boolean_literal *literal) - { - literal->data_type = table->lookup("Boolean")->is_type_info()->type(); - } - - void type_analysis_visitor::visit(variable_expression *expression) - { - expression->data_type = table->lookup(expression->name())->is_typed_info()->type(); - } - - void type_analysis_visitor::visit(unary_expression *expression) - { - empty_visitor::visit(expression); - - switch (expression->operation()) - { - case unary_operator::reference: - expression->data_type = std::make_shared(expression->operand().data_type, - this->pointer_size); - break; - case unary_operator::dereference: - auto operand_type = expression->operand().data_type; - - if (operand_type->is_pointer_type() != nullptr) - { - expression->data_type = operand_type; - } - else if (operand_type != nullptr) - { - auto new_error = std::make_unique(operand_type, - type_mismatch::operation::dereference, this->filename, expression->position()); - m_errors.push_back(std::move(new_error)); - } - break; - } - } - - void type_analysis_visitor::visit(binary_expression *expression) - { - empty_visitor::visit(expression); - - switch (expression->operation()) - { - case binary_operator::sum: - case binary_operator::subtraction: - case binary_operator::multiplication: - case binary_operator::division: - case binary_operator::less: - case binary_operator::greater: - case binary_operator::less_equal: - case binary_operator::greater_equal: - if (expression->lhs().data_type != nullptr && expression->rhs().data_type != nullptr) - { - std::unique_ptr new_error; - - if (*expression->lhs().data_type != int_type) - { - new_error = std::make_unique(expression->lhs().data_type, - type_mismatch::operation::arithmetic, this->filename, expression->lhs().position()); - } - if (*expression->rhs().data_type != int_type) - { - new_error = std::make_unique(expression->rhs().data_type, - type_mismatch::operation::arithmetic, this->filename, expression->rhs().position()); - } - if (new_error != nullptr) - { - m_errors.push_back(std::move(new_error)); - } - } - break; - case binary_operator::equals: - case binary_operator::not_equals: - if (expression->lhs().data_type != nullptr && expression->rhs().data_type != nullptr) - { - if (expression->lhs().data_type != expression->rhs().data_type) - { - auto new_error = std::make_unique(expression->rhs().data_type, - type_mismatch::operation::comparison, this->filename, expression->rhs().position()); - } - } - break; - } - } - - void type_analysis_visitor::visit(call_statement *statement) - { - auto call_info = this->table->lookup(statement->name())->is_intrinsic_info(); - - 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(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); - } - - void type_analysis_visitor::visit(while_statement *statement) - { - statement->prerequisite().accept(this); - auto condition_type = statement->prerequisite().data_type; - - if (condition_type != nullptr && *condition_type != boolean_type) - { - auto new_error = std::make_unique(condition_type, - type_mismatch::operation::condition, this->filename, statement->prerequisite().position()); - m_errors.push_back(std::move(new_error)); - } - statement->body().accept(this); - } - - void type_analysis_visitor::visit(if_statement *statement) - { - statement->prerequisite().accept(this); - auto condition_type = statement->prerequisite().data_type; - - if (condition_type != nullptr && *condition_type != boolean_type) - { - auto new_error = std::make_unique(condition_type, - type_mismatch::operation::condition, this->filename, statement->prerequisite().position()); - m_errors.push_back(std::move(new_error)); - } - statement->body().accept(this); - } - - void type_analysis_visitor::visit(assign_statement *statement) - { - statement->rvalue().accept(this); - auto lvalue_info = this->table->lookup(statement->lvalue())->is_typed_info(); - - if (statement->rvalue().data_type != nullptr && lvalue_info->type() == statement->rvalue().data_type) - { - auto new_error = std::make_unique(statement->rvalue().data_type, - type_mismatch::operation::assignment, this->filename, statement->position()); - m_errors.push_back(std::move(new_error)); - } - } - - const std::list>& type_analysis_visitor::errors() const noexcept - { - return m_errors; - } -} -} diff --git a/source/symbol_table.cc b/source/symbol_table.cc deleted file mode 100644 index 327781d..0000000 --- a/source/symbol_table.cc +++ /dev/null @@ -1,233 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public License -// v. 2.0. If a copy of the MPL was not distributed with this file, You can -// obtain one at http://mozilla.org/MPL/2.0/. -#include "elna/source/types.h" -#include "elna/source/symbol_table.h" - -namespace elna -{ -namespace source -{ - symbol_table::symbol_table(std::shared_ptr scope) - : outer_scope(scope) - { - } - - std::shared_ptr symbol_table::lookup(const std::string& name) - { - auto entry = entries.find(name); - - if (entry != entries.cend()) - { - return entry->second; - } - if (this->outer_scope != nullptr) - { - return this->outer_scope->lookup(name); - } - return nullptr; - } - - void symbol_table::enter(const std::string& name, std::shared_ptr entry) - { - entries.insert({ name, entry }); - } - - std::shared_ptr symbol_table::scope() - { - return this->outer_scope; - } - - info::~info() - { - } - - type_info *info::is_type_info() noexcept - { - return nullptr; - } - - typed_info *info::is_typed_info() noexcept - { - return nullptr; - } - - constant_info *info::is_constant_info() noexcept - { - return nullptr; - } - - variable_info *info::is_variable_info() noexcept - { - return nullptr; - } - - parameter_info *info::is_parameter_info() noexcept - { - return nullptr; - } - - intrinsic_info *info::is_intrinsic_info() noexcept - { - return nullptr; - } - - procedure_info *info::is_procedure_info() noexcept - { - return nullptr; - } - - info::info() - { - } - - type_info::type_info(std::shared_ptr type) - : info(), m_type(type) - { - } - - type_info::~type_info() - { - } - - std::shared_ptr type_info::type() const noexcept - { - return m_type; - } - - type_info *type_info::is_type_info() noexcept - { - return this; - } - - typed_info::typed_info(std::shared_ptr type) - : m_type(type) - { - } - - typed_info::~typed_info() - { - } - - typed_info *typed_info::is_typed_info() noexcept - { - return this; - } - - std::shared_ptr typed_info::type() const noexcept - { - return m_type; - } - - constant_info::constant_info(const std::shared_ptr type, const std::int32_t value) - : typed_info(type), m_value(value) - { - } - - constant_info *constant_info::is_constant_info() noexcept - { - return this; - } - - std::int32_t constant_info::value() const noexcept - { - return m_value; - } - - variable_info::variable_info(std::shared_ptr type) - : typed_info(type) - { - } - - variable_info *variable_info::is_variable_info() noexcept - { - return this; - } - - parameter_info::parameter_info(std::shared_ptr type) - : typed_info(type) - { - } - - parameter_info *parameter_info::is_parameter_info() noexcept - { - return this; - } - - intrinsic_info::intrinsic_info(const class procedure_type& type) - : m_type(std::make_shared(type)) - { - } - - intrinsic_info::~intrinsic_info() - { - } - - std::shared_ptr intrinsic_info::type() const noexcept - { - return m_type; - } - - std::size_t intrinsic_info::parameter_stack_size() const noexcept - { - return type()->arguments.size() * sizeof(std::int32_t); - } - - intrinsic_info *intrinsic_info::is_intrinsic_info() noexcept - { - return this; - } - - procedure_info::procedure_info(const class procedure_type& type, std::shared_ptr outer_scope) - : intrinsic_info(type), local_table(std::make_shared(outer_scope)) - { - } - - procedure_info::~procedure_info() - { - } - - std::shared_ptr procedure_info::scope() - { - return local_table; - } - - std::size_t procedure_info::stack_size() const noexcept - { - return local_stack_size + argument_stack_size; - } - - procedure_info *procedure_info::is_procedure_info() noexcept - { - return this; - } - - constexpr std::size_t pointer_size = 4; - - std::shared_ptr add_builtin_symbols() - { - source::symbol_table result; - std::vector> intrinsic_arguments; - - auto prim = boolean_type; - auto boolean_info = std::make_shared(std::make_shared(boolean_type)); - auto int_info = std::make_shared(std::make_shared(int_type)); - result.enter("Boolean", boolean_info); - result.enter("Int", int_info); - - intrinsic_arguments.push_back(int_info->type()); - auto writei = std::make_shared( - source::procedure_type{ intrinsic_arguments, pointer_size }); - result.enter("writei", writei); - intrinsic_arguments.clear(); - - intrinsic_arguments.push_back(boolean_info->type()); - auto writeb = std::make_shared( - source::procedure_type{ intrinsic_arguments, pointer_size }); - result.enter("writeb", writeb); - intrinsic_arguments.clear(); - - return std::make_shared(std::move(result)); - } -} -}