Support procedure calls without arguments
This commit is contained in:
		@@ -76,8 +76,9 @@ namespace elna::riscv
 | 
				
			|||||||
        return reinterpret_cast<const std::byte *>(&this->representation) + sizeof(this->representation);
 | 
					        return reinterpret_cast<const std::byte *>(&this->representation) + sizeof(this->representation);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    visitor::visitor(std::shared_ptr<source::writer> writer)
 | 
					    visitor::visitor(std::shared_ptr<source::writer> writer,
 | 
				
			||||||
        : writer(writer)
 | 
					            std::shared_ptr<source::symbol_table> table)
 | 
				
			||||||
 | 
					        : writer(writer), table(table)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -87,15 +88,7 @@ namespace elna::riscv
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            auto format_string = this->writer->sink(reinterpret_cast<const std::byte *>("%c\n\0"), 4);
 | 
					            auto format_string = this->writer->sink(reinterpret_cast<const std::byte *>("%c\n\0"), 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this->instructions.push_back(instruction(base_opcode::opImm)
 | 
					            prologue();
 | 
				
			||||||
                    .i(x_register::sp, funct3_t::addi, x_register::sp, -8));
 | 
					 | 
				
			||||||
            this->instructions.push_back(instruction(base_opcode::store)
 | 
					 | 
				
			||||||
                    .s(4, funct3_t::sw, x_register::sp, x_register::s0));
 | 
					 | 
				
			||||||
            this->instructions.push_back(instruction(base_opcode::store)
 | 
					 | 
				
			||||||
                    .s(0, funct3_t::sw, x_register::sp, x_register::ra));
 | 
					 | 
				
			||||||
            this->instructions.push_back(instruction(base_opcode::opImm)
 | 
					 | 
				
			||||||
                    .i(x_register::s0, funct3_t::addi, x_register::sp, -8));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            this->instructions.push_back(instruction(base_opcode::opImm)
 | 
					            this->instructions.push_back(instruction(base_opcode::opImm)
 | 
				
			||||||
                    .i(x_register::a1, funct3_t::addi, x_register::zero, 't'));
 | 
					                    .i(x_register::a1, funct3_t::addi, x_register::zero, 't'));
 | 
				
			||||||
            this->instructions.push_back(instruction(base_opcode::branch)
 | 
					            this->instructions.push_back(instruction(base_opcode::branch)
 | 
				
			||||||
@@ -114,32 +107,16 @@ namespace elna::riscv
 | 
				
			|||||||
            this->instructions.push_back(instruction(base_opcode::jalr)
 | 
					            this->instructions.push_back(instruction(base_opcode::jalr)
 | 
				
			||||||
                    .i(x_register::ra, funct3_t::jalr, x_register::ra, 0));
 | 
					                    .i(x_register::ra, funct3_t::jalr, x_register::ra, 0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this->instructions.push_back(instruction(base_opcode::load)
 | 
					            epilogue(8);
 | 
				
			||||||
                    .i(x_register::s0, funct3_t::lw, x_register::sp, 4));
 | 
					 | 
				
			||||||
            this->instructions.push_back(instruction(base_opcode::load)
 | 
					 | 
				
			||||||
                    .i(x_register::ra, funct3_t::lw, x_register::sp, 0));
 | 
					 | 
				
			||||||
            this->instructions.push_back(instruction(base_opcode::opImm)
 | 
					 | 
				
			||||||
                    .i(x_register::sp, funct3_t::addi, x_register::sp, 8));
 | 
					 | 
				
			||||||
            this->instructions.push_back(instruction(base_opcode::jalr)
 | 
					 | 
				
			||||||
                    .i(x_register::zero, funct3_t::jalr, x_register::ra, 0));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this->writer->sink("writeb", reinterpret_cast<const std::byte *>(this->instructions.data()),
 | 
					            this->writer->sink("writeb", reinterpret_cast<const std::byte *>(this->instructions.data()),
 | 
				
			||||||
                    this->instructions.size() * sizeof(instruction));
 | 
					                    this->instructions.size() * sizeof(instruction));
 | 
				
			||||||
     
 | 
					 | 
				
			||||||
            this->instructions.clear();
 | 
					            this->instructions.clear();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            auto format_string = this->writer->sink(reinterpret_cast<const std::byte *>("%d\n\0"), 4);
 | 
					            auto format_string = this->writer->sink(reinterpret_cast<const std::byte *>("%d\n\0"), 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this->instructions.push_back(instruction(base_opcode::opImm)
 | 
					            prologue();
 | 
				
			||||||
                    .i(x_register::sp, funct3_t::addi, x_register::sp, -8));
 | 
					 | 
				
			||||||
            this->instructions.push_back(instruction(base_opcode::store)
 | 
					 | 
				
			||||||
                    .s(4, funct3_t::sw, x_register::sp, x_register::s0));
 | 
					 | 
				
			||||||
            this->instructions.push_back(instruction(base_opcode::store)
 | 
					 | 
				
			||||||
                    .s(0, funct3_t::sw, x_register::sp, x_register::ra));
 | 
					 | 
				
			||||||
            this->instructions.push_back(instruction(base_opcode::opImm)
 | 
					 | 
				
			||||||
                    .i(x_register::s0, funct3_t::addi, x_register::sp, -8));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            this->instructions.push_back(instruction(base_opcode::opImm)
 | 
					            this->instructions.push_back(instruction(base_opcode::opImm)
 | 
				
			||||||
                    .i(x_register::a1, funct3_t::addi, x_register::a0, 0));
 | 
					                    .i(x_register::a1, funct3_t::addi, x_register::a0, 0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -154,18 +131,10 @@ namespace elna::riscv
 | 
				
			|||||||
            this->instructions.push_back(instruction(base_opcode::jalr)
 | 
					            this->instructions.push_back(instruction(base_opcode::jalr)
 | 
				
			||||||
                    .i(x_register::ra, funct3_t::jalr, x_register::ra, 0));
 | 
					                    .i(x_register::ra, funct3_t::jalr, x_register::ra, 0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this->instructions.push_back(instruction(base_opcode::load)
 | 
					            epilogue(8);
 | 
				
			||||||
                    .i(x_register::s0, funct3_t::lw, x_register::sp, 4));
 | 
					 | 
				
			||||||
            this->instructions.push_back(instruction(base_opcode::load)
 | 
					 | 
				
			||||||
                    .i(x_register::ra, funct3_t::lw, x_register::sp, 0));
 | 
					 | 
				
			||||||
            this->instructions.push_back(instruction(base_opcode::opImm)
 | 
					 | 
				
			||||||
                    .i(x_register::sp, funct3_t::addi, x_register::sp, 8));
 | 
					 | 
				
			||||||
            this->instructions.push_back(instruction(base_opcode::jalr)
 | 
					 | 
				
			||||||
                    .i(x_register::zero, funct3_t::jalr, x_register::ra, 0));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this->writer->sink("writei", reinterpret_cast<const std::byte *>(this->instructions.data()),
 | 
					            this->writer->sink("writei", reinterpret_cast<const std::byte *>(this->instructions.data()),
 | 
				
			||||||
                    this->instructions.size() * sizeof(instruction));
 | 
					                    this->instructions.size() * sizeof(instruction));
 | 
				
			||||||
     
 | 
					 | 
				
			||||||
            this->instructions.clear();
 | 
					            this->instructions.clear();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -186,29 +155,16 @@ namespace elna::riscv
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void visitor::visit(source::procedure_definition *definition)
 | 
					    void visitor::prologue()
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void visitor::visit(source::block *block)
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        this->instructions.push_back(instruction(base_opcode::opImm));
 | 
					        this->instructions.push_back(instruction(base_opcode::opImm));
 | 
				
			||||||
        this->instructions.push_back(instruction(base_opcode::store));
 | 
					        this->instructions.push_back(instruction(base_opcode::store));
 | 
				
			||||||
        this->instructions.push_back(instruction(base_opcode::store));
 | 
					        this->instructions.push_back(instruction(base_opcode::store));
 | 
				
			||||||
        this->instructions.push_back(instruction(base_opcode::opImm));
 | 
					        this->instructions.push_back(instruction(base_opcode::opImm));
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        table = block->table();
 | 
					    void visitor::epilogue(const std::size_t stack_size)
 | 
				
			||||||
        block->body().accept(this);
 | 
					    {
 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Set the return value (0).
 | 
					 | 
				
			||||||
        this->instructions.push_back(instruction(base_opcode::op)
 | 
					 | 
				
			||||||
            .r(x_register::a0, funct3_t::_and, x_register::zero, x_register::zero));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Prologue.
 | 
					 | 
				
			||||||
        auto main_symbol =
 | 
					 | 
				
			||||||
            std::dynamic_pointer_cast<source::procedure_info>(table->lookup("main"));
 | 
					 | 
				
			||||||
        const uint stack_size = static_cast<std::uint32_t>(variable_counter * 4 + 8 + main_symbol->stack_size());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        this->instructions[0].i(x_register::sp, funct3_t::addi, x_register::sp, -stack_size);
 | 
					        this->instructions[0].i(x_register::sp, funct3_t::addi, x_register::sp, -stack_size);
 | 
				
			||||||
        this->instructions[1].s(stack_size - 4, funct3_t::sw, x_register::sp, x_register::s0);
 | 
					        this->instructions[1].s(stack_size - 4, funct3_t::sw, x_register::sp, x_register::s0);
 | 
				
			||||||
        this->instructions[2].s(stack_size - 8, funct3_t::sw, x_register::sp, x_register::ra);
 | 
					        this->instructions[2].s(stack_size - 8, funct3_t::sw, x_register::sp, x_register::ra);
 | 
				
			||||||
@@ -225,19 +181,60 @@ namespace elna::riscv
 | 
				
			|||||||
            .i(x_register::zero, funct3_t::jalr, x_register::ra, 0));
 | 
					            .i(x_register::zero, funct3_t::jalr, x_register::ra, 0));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void visitor::visit(source::procedure_definition *definition)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        prologue();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto main_symbol =
 | 
				
			||||||
 | 
					            std::dynamic_pointer_cast<source::procedure_info>(this->table->lookup(definition->identifier()));
 | 
				
			||||||
 | 
					        this->table = main_symbol->scope();
 | 
				
			||||||
 | 
					        definition->body().accept(this);
 | 
				
			||||||
 | 
					        this->table = main_symbol->scope()->scope();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Set the return value (0).
 | 
				
			||||||
 | 
					        this->instructions.push_back(instruction(base_opcode::op)
 | 
				
			||||||
 | 
					            .r(x_register::a0, funct3_t::_and, x_register::zero, x_register::zero));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        epilogue(static_cast<std::uint32_t>(variable_counter * 4 + 8 + main_symbol->stack_size()));
 | 
				
			||||||
 | 
					        this->writer->sink(definition->identifier(),
 | 
				
			||||||
 | 
					                reinterpret_cast<const std::byte *>(this->instructions.data()),
 | 
				
			||||||
 | 
					                this->instructions.size() * sizeof(instruction));
 | 
				
			||||||
 | 
					        this->instructions.clear();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void visitor::visit(source::block *block)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        block->body().accept(this);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void visitor::visit(source::program *program)
 | 
					    void visitor::visit(source::program *program)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        generate_intrinsics();
 | 
					        generate_intrinsics();
 | 
				
			||||||
 | 
					        for (auto& definition : program->definitions())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            definition->accept(this);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        prologue();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        visit(dynamic_cast<source::block *>(program));
 | 
					        auto main_symbol =
 | 
				
			||||||
 | 
					            std::dynamic_pointer_cast<source::procedure_info>(this->table->lookup("main"));
 | 
				
			||||||
 | 
					        program->body().accept(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Set the return value (0).
 | 
				
			||||||
 | 
					        this->instructions.push_back(instruction(base_opcode::op)
 | 
				
			||||||
 | 
					            .r(x_register::a0, funct3_t::_and, x_register::zero, x_register::zero));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        epilogue(static_cast<std::uint32_t>(variable_counter * 4 + 8 + main_symbol->stack_size()));
 | 
				
			||||||
        this->writer->sink("main", reinterpret_cast<const std::byte *>(this->instructions.data()),
 | 
					        this->writer->sink("main", reinterpret_cast<const std::byte *>(this->instructions.data()),
 | 
				
			||||||
                this->instructions.size() * sizeof(instruction));
 | 
					                this->instructions.size() * sizeof(instruction));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void visitor::visit(source::call_statement *statement)
 | 
					    void visitor::visit(source::call_statement *statement)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        statement->arguments().accept(this);
 | 
					        for (auto& argument : statement->arguments())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            argument->accept(this);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        relocate(statement->name(), address_t::text);
 | 
					        relocate(statement->name(), address_t::text);
 | 
				
			||||||
        this->instructions.push_back(instruction(base_opcode::auipc).u(x_register::ra, 0));
 | 
					        this->instructions.push_back(instruction(base_opcode::auipc).u(x_register::ra, 0));
 | 
				
			||||||
        this->instructions.push_back(instruction(base_opcode::jalr)
 | 
					        this->instructions.push_back(instruction(base_opcode::jalr)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -146,7 +146,8 @@ namespace elna::riscv
 | 
				
			|||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void riscv32_elf(source::program *ast, const std::filesystem::path& out_file)
 | 
					    void riscv32_elf(source::program *ast, std::shared_ptr<source::symbol_table> table,
 | 
				
			||||||
 | 
					            const std::filesystem::path& out_file)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        ELFIO::elfio writer;
 | 
					        ELFIO::elfio writer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -197,7 +198,7 @@ namespace elna::riscv
 | 
				
			|||||||
        ELFIO::relocation_section_accessor rela(writer, rel_sec);
 | 
					        ELFIO::relocation_section_accessor rela(writer, rel_sec);
 | 
				
			||||||
        auto _writer = std::make_shared<elfio_writer>(text_sec, ro_sec, syma, stra);
 | 
					        auto _writer = std::make_shared<elfio_writer>(text_sec, ro_sec, syma, stra);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        visitor _visitor{ _writer };
 | 
					        visitor _visitor{ _writer, table };
 | 
				
			||||||
        _visitor.visit(ast);
 | 
					        _visitor.visit(ast);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        syma.arrange_local_symbols();
 | 
					        syma.arrange_local_symbols();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,10 +54,11 @@ namespace elna::cli
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            return 2;
 | 
					            return 2;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        source::name_analysis_visitor().visit(ast.get());
 | 
					        auto global_scope = std::make_shared<source::symbol_table>();
 | 
				
			||||||
 | 
					        source::name_analysis_visitor(global_scope).visit(ast.get());
 | 
				
			||||||
        source::type_analysis_visitor().visit(ast.get());
 | 
					        source::type_analysis_visitor().visit(ast.get());
 | 
				
			||||||
        source::allocator_visitor().visit(ast.get());
 | 
					        source::allocator_visitor(global_scope).visit(ast.get());
 | 
				
			||||||
        riscv::riscv32_elf(ast.get(), out_file);
 | 
					        riscv::riscv32_elf(ast.get(), global_scope, out_file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -165,13 +165,16 @@ namespace elna::riscv
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        void generate_intrinsics();
 | 
					        void generate_intrinsics();
 | 
				
			||||||
        void relocate(std::string_view name, address_t target);
 | 
					        void relocate(std::string_view name, address_t target);
 | 
				
			||||||
 | 
					        void prologue();
 | 
				
			||||||
 | 
					        void epilogue(const std::size_t stack_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
        std::uint32_t variable_counter = 1;
 | 
					        std::uint32_t variable_counter = 1;
 | 
				
			||||||
        std::vector<reference> references;
 | 
					        std::vector<reference> references;
 | 
				
			||||||
        std::shared_ptr<source::symbol_table> table;
 | 
					        std::shared_ptr<source::symbol_table> table;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        visitor(std::shared_ptr<source::writer> writer);
 | 
					        visitor(std::shared_ptr<source::writer> writer,
 | 
				
			||||||
 | 
					                std::shared_ptr<source::symbol_table> table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        virtual void visit(source::declaration *declaration) override;
 | 
					        virtual void visit(source::declaration *declaration) override;
 | 
				
			||||||
        virtual void visit(source::constant_definition *definition) override;
 | 
					        virtual void visit(source::constant_definition *definition) override;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -99,5 +99,6 @@ namespace elna::riscv
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    std::ptrdiff_t lookup(ELFIO::symbol_section_accessor symbol_accessor, const std::string& label);
 | 
					    std::ptrdiff_t lookup(ELFIO::symbol_section_accessor symbol_accessor, const std::string& label);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void riscv32_elf(source::program *ast, const std::filesystem::path& out_file);
 | 
					    void riscv32_elf(source::program *ast, std::shared_ptr<source::symbol_table> table,
 | 
				
			||||||
 | 
					            const std::filesystem::path& out_file);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -88,12 +88,14 @@ namespace elna::source
 | 
				
			|||||||
    class declaration : public node
 | 
					    class declaration : public node
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::string m_identifier;
 | 
					        std::string m_identifier;
 | 
				
			||||||
 | 
					        std::string m_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
        declaration(const std::string& identifier);
 | 
					        declaration(const std::string& identifier, const std::string& type);
 | 
				
			||||||
        virtual void accept(parser_visitor *visitor) override;
 | 
					        virtual void accept(parser_visitor *visitor) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string& identifier() noexcept;
 | 
					        std::string& identifier() noexcept;
 | 
				
			||||||
 | 
					        std::string& type() noexcept;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -124,25 +126,27 @@ namespace elna::source
 | 
				
			|||||||
    class procedure_definition : public definition
 | 
					    class procedure_definition : public definition
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::unique_ptr<block> m_body;
 | 
					        std::unique_ptr<block> m_body;
 | 
				
			||||||
 | 
					        std::vector<std::unique_ptr<declaration>> m_parameters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
        procedure_definition(const std::string& identifier, std::unique_ptr<block>&& body);
 | 
					        procedure_definition(const std::string& identifier, std::unique_ptr<block>&& body);
 | 
				
			||||||
        virtual void accept(parser_visitor *visitor) override;
 | 
					        virtual void accept(parser_visitor *visitor) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        block& body();
 | 
					        block& body();
 | 
				
			||||||
 | 
					        std::vector<std::unique_ptr<declaration>>& parameters() noexcept;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class call_statement : public statement
 | 
					    class call_statement : public statement
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::string m_name;
 | 
					        std::string m_name;
 | 
				
			||||||
        std::unique_ptr<expression> m_body;
 | 
					        std::vector<std::unique_ptr<expression>> m_arguments;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
        call_statement(const std::string& name, std::unique_ptr<expression>&& body);
 | 
					        call_statement(const std::string& name);
 | 
				
			||||||
        virtual void accept(parser_visitor *visitor) override;
 | 
					        virtual void accept(parser_visitor *visitor) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string& name() noexcept;
 | 
					        std::string& name() noexcept;
 | 
				
			||||||
        expression& arguments();
 | 
					        std::vector<std::unique_ptr<expression>>& arguments() noexcept;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class compound_statement : public statement
 | 
					    class compound_statement : public statement
 | 
				
			||||||
@@ -201,7 +205,6 @@ namespace elna::source
 | 
				
			|||||||
        std::unique_ptr<statement> m_body;
 | 
					        std::unique_ptr<statement> m_body;
 | 
				
			||||||
        std::vector<std::unique_ptr<definition>> m_definitions;
 | 
					        std::vector<std::unique_ptr<definition>> m_definitions;
 | 
				
			||||||
        std::vector<std::unique_ptr<declaration>> m_declarations;
 | 
					        std::vector<std::unique_ptr<declaration>> m_declarations;
 | 
				
			||||||
        std::shared_ptr<symbol_table> m_table;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
        block(std::vector<std::unique_ptr<definition>>&& definitions,
 | 
					        block(std::vector<std::unique_ptr<definition>>&& definitions,
 | 
				
			||||||
@@ -212,7 +215,6 @@ namespace elna::source
 | 
				
			|||||||
        statement& body();
 | 
					        statement& body();
 | 
				
			||||||
        std::vector<std::unique_ptr<definition>>& definitions() noexcept;
 | 
					        std::vector<std::unique_ptr<definition>>& definitions() noexcept;
 | 
				
			||||||
        std::vector<std::unique_ptr<declaration>>& declarations() noexcept;
 | 
					        std::vector<std::unique_ptr<declaration>>& declarations() noexcept;
 | 
				
			||||||
        std::shared_ptr<symbol_table> table();
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class program : public block
 | 
					    class program : public block
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@
 | 
				
			|||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <type_traits>
 | 
					#include <type_traits>
 | 
				
			||||||
#include <unordered_map>
 | 
					#include <unordered_map>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace elna::source
 | 
					namespace elna::source
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -110,6 +111,32 @@ namespace elna::source
 | 
				
			|||||||
        std::string what() const override;
 | 
					        std::string what() const override;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class symbol_table;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Type representation.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    struct type
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const std::size_t byte_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected:
 | 
				
			||||||
 | 
					        explicit type(const std::size_t byte_size);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Built-in type representation.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    struct primitive_type : public type
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const std::string type_name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        primitive_type(const std::string& type_name, const std::size_t byte_size);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline const primitive_type boolean_type{ "Boolean", 1 };
 | 
				
			||||||
 | 
					    inline const primitive_type int_type{ "Int", 4 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Generic language entity information.
 | 
					     * Generic language entity information.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
@@ -122,6 +149,19 @@ namespace elna::source
 | 
				
			|||||||
        info();
 | 
					        info();
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Type information.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    class type_info final : public info
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        class type m_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        explicit type_info(const class type& type);
 | 
				
			||||||
 | 
					        ~type_info() override;
 | 
				
			||||||
 | 
					        const class type& type() const noexcept;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Constant information.
 | 
					     * Constant information.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
@@ -145,18 +185,36 @@ namespace elna::source
 | 
				
			|||||||
        ~variable_info() override;
 | 
					        ~variable_info() override;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Procedure parameter information.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    class parameter_info final : public info
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        class type m_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        explicit parameter_info(const class type& type);
 | 
				
			||||||
 | 
					        ~parameter_info() override;
 | 
				
			||||||
 | 
					        const class type& type() const noexcept;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Procedure information.
 | 
					     * Procedure information.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    class procedure_info final : public info
 | 
					    class procedure_info final : public info
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::size_t local_stack_size{ 0 };
 | 
					        std::size_t local_stack_size{ 0 };
 | 
				
			||||||
 | 
					        std::shared_ptr<symbol_table> local_table;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
 | 
					        std::vector<parameter_info> parameter_infos;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        explicit procedure_info(std::shared_ptr<symbol_table> outer_scope);
 | 
				
			||||||
        ~procedure_info() override;
 | 
					        ~procedure_info() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void stack_size(const std::size_t size) noexcept;
 | 
					        void stack_size(const std::size_t size) noexcept;
 | 
				
			||||||
        std::size_t stack_size() const noexcept;
 | 
					        std::size_t stack_size() const noexcept;
 | 
				
			||||||
 | 
					        std::shared_ptr<symbol_table> scope();
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -174,12 +232,39 @@ namespace elna::source
 | 
				
			|||||||
    class symbol_table
 | 
					    class symbol_table
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::unordered_map<std::string, std::shared_ptr<info>> entries;
 | 
					        std::unordered_map<std::string, std::shared_ptr<info>> entries;
 | 
				
			||||||
 | 
					        std::shared_ptr<symbol_table> outer_scope;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
        symbol_table();
 | 
					        /**
 | 
				
			||||||
 | 
					         * Constructs a new symbol with an optional outer scope.
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * \param scope Outer scope.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        explicit symbol_table(std::shared_ptr<symbol_table> 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<info> lookup(const std::string& name);
 | 
					        std::shared_ptr<info> 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<info> entry);
 | 
					        void enter(const std::string& name, std::shared_ptr<info> entry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * Returns the outer scope or nullptr if the this is the global scope.
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * \return Outer scope.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        std::shared_ptr<symbol_table> scope();
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct writer
 | 
					    struct writer
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,21 +6,28 @@ namespace elna::source
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    class name_analysis_visitor final : public empty_visitor
 | 
					    class name_analysis_visitor final : public empty_visitor
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::shared_ptr<symbol_table> table;
 | 
					        std::shared_ptr<symbol_table> table = std::make_shared<symbol_table>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
 | 
					        name_analysis_visitor(std::shared_ptr<symbol_table> table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void visit(constant_definition *definition) override;
 | 
					        void visit(constant_definition *definition) override;
 | 
				
			||||||
        void visit(declaration *declaration) override;
 | 
					        void visit(declaration *declaration) override;
 | 
				
			||||||
        void visit(block *block) override;
 | 
					        void visit(program *program) override;
 | 
				
			||||||
 | 
					        void visit(procedure_definition *procedure) override;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class allocator_visitor final : public empty_visitor
 | 
					    class allocator_visitor final : public empty_visitor
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::ptrdiff_t offset;
 | 
					        std::ptrdiff_t offset;
 | 
				
			||||||
 | 
					        std::shared_ptr<symbol_table> table;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
 | 
					        allocator_visitor(std::shared_ptr<symbol_table> table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void visit(declaration *declaration) override;
 | 
					        void visit(declaration *declaration) override;
 | 
				
			||||||
        void visit(block *block) override;
 | 
					        void visit(program *program) override;
 | 
				
			||||||
 | 
					        void visit(procedure_definition *procedure) override;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class type_analysis_visitor final : public empty_visitor
 | 
					    class type_analysis_visitor final : public empty_visitor
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,7 +19,10 @@ namespace elna::source
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    void empty_visitor::visit(call_statement *statement)
 | 
					    void empty_visitor::visit(call_statement *statement)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        statement->arguments().accept(this);
 | 
					        for (auto& argument : statement->arguments())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            argument->accept(this);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void empty_visitor::visit(compound_statement *statement)
 | 
					    void empty_visitor::visit(compound_statement *statement)
 | 
				
			||||||
@@ -87,8 +90,8 @@ namespace elna::source
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    declaration::declaration(const std::string& identifier)
 | 
					    declaration::declaration(const std::string& identifier, const std::string& type)
 | 
				
			||||||
        : m_identifier(identifier)
 | 
					        : m_identifier(identifier), m_type(type)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -102,6 +105,11 @@ namespace elna::source
 | 
				
			|||||||
        return m_identifier;
 | 
					        return m_identifier;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::string& declaration::type() noexcept
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return m_type;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    definition::definition(const std::string& identifier)
 | 
					    definition::definition(const std::string& identifier)
 | 
				
			||||||
        : m_identifier(identifier)
 | 
					        : m_identifier(identifier)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -142,12 +150,16 @@ namespace elna::source
 | 
				
			|||||||
        return *m_body;
 | 
					        return *m_body;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::vector<std::unique_ptr<declaration>>& procedure_definition::parameters() noexcept
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return m_parameters;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    block::block(std::vector<std::unique_ptr<definition>>&& definitions,
 | 
					    block::block(std::vector<std::unique_ptr<definition>>&& definitions,
 | 
				
			||||||
            std::vector<std::unique_ptr<declaration>>&& declarations,
 | 
					            std::vector<std::unique_ptr<declaration>>&& declarations,
 | 
				
			||||||
            std::unique_ptr<statement>&& body)
 | 
					            std::unique_ptr<statement>&& body)
 | 
				
			||||||
        : m_definitions(std::move(definitions)),
 | 
					        : m_definitions(std::move(definitions)),
 | 
				
			||||||
        m_declarations(std::move(declarations)), m_body(std::move(body)),
 | 
					        m_declarations(std::move(declarations)), m_body(std::move(body))
 | 
				
			||||||
        m_table(std::make_shared<symbol_table>())
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -171,11 +183,6 @@ namespace elna::source
 | 
				
			|||||||
        return m_declarations;
 | 
					        return m_declarations;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::shared_ptr<symbol_table> block::table()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return m_table;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    program::program(std::vector<std::unique_ptr<definition>>&& definitions,
 | 
					    program::program(std::vector<std::unique_ptr<definition>>&& definitions,
 | 
				
			||||||
            std::vector<std::unique_ptr<declaration>>&& declarations,
 | 
					            std::vector<std::unique_ptr<declaration>>&& declarations,
 | 
				
			||||||
            std::unique_ptr<statement>&& body)
 | 
					            std::unique_ptr<statement>&& body)
 | 
				
			||||||
@@ -276,8 +283,8 @@ namespace elna::source
 | 
				
			|||||||
        return m_operator;
 | 
					        return m_operator;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    call_statement::call_statement(const std::string& name, std::unique_ptr<expression>&& body)
 | 
					    call_statement::call_statement(const std::string& name)
 | 
				
			||||||
        : m_name(name), m_body(std::move(body))
 | 
					        : m_name(name)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -291,9 +298,9 @@ namespace elna::source
 | 
				
			|||||||
        return m_name;
 | 
					        return m_name;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    expression& call_statement::arguments()
 | 
					    std::vector<std::unique_ptr<expression>>& call_statement::arguments() noexcept
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return *m_body;
 | 
					        return m_arguments;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    compound_statement::compound_statement(std::vector<std::unique_ptr<statement>>&& statements)
 | 
					    compound_statement::compound_statement(std::vector<std::unique_ptr<statement>>&& statements)
 | 
				
			||||||
@@ -537,7 +544,8 @@ namespace elna::source
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            return nullptr;
 | 
					            return nullptr;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return std::make_unique<declaration>(declaration_identifier.value().get().identifier());
 | 
					        return std::make_unique<declaration>(declaration_identifier.value().get().identifier(),
 | 
				
			||||||
 | 
					                type_identifier.value().get().identifier());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::unique_ptr<statement> parser::parse_statement()
 | 
					    std::unique_ptr<statement> parser::parse_statement()
 | 
				
			||||||
@@ -573,11 +581,27 @@ namespace elna::source
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            return nullptr;
 | 
					            return nullptr;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        auto bang_body = parse_expression();
 | 
					        auto call = std::make_unique<call_statement>(function_name->get().identifier());
 | 
				
			||||||
 | 
					        std::unique_ptr<expression> argument_expression;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (bang_body != nullptr && iterator.skip(token::type::right_paren))
 | 
					        if (iterator.current(token::type::right_paren))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return std::make_unique<call_statement>(function_name->get().identifier(), std::move(bang_body));
 | 
					            ++iterator;
 | 
				
			||||||
 | 
					            return call;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        while ((argument_expression = parse_expression()) != nullptr)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            call->arguments().push_back(std::move(argument_expression));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (iterator.current(token::type::right_paren))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                ++iterator;
 | 
				
			||||||
 | 
					                return call;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (!iterator.skip(token::type::comma))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return nullptr;
 | 
					        return nullptr;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,23 +27,39 @@ namespace elna::source
 | 
				
			|||||||
        return "Name '" + name + "' was already defined";
 | 
					        return "Name '" + name + "' was already defined";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    symbol_table::symbol_table()
 | 
					    type::type(const std::size_t byte_size)
 | 
				
			||||||
 | 
					        : byte_size(byte_size)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        enter("writei", std::make_shared<intrinsic_info>());
 | 
					    }
 | 
				
			||||||
        enter("writeb", std::make_shared<intrinsic_info>());
 | 
					
 | 
				
			||||||
 | 
					    primitive_type::primitive_type(const std::string& type_name, const std::size_t byte_size)
 | 
				
			||||||
 | 
					        : type(byte_size), type_name(type_name)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    symbol_table::symbol_table(std::shared_ptr<symbol_table> scope)
 | 
				
			||||||
 | 
					        : outer_scope(scope)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (scope == nullptr)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            enter("writei", std::make_shared<intrinsic_info>());
 | 
				
			||||||
 | 
					            enter("writeb", std::make_shared<intrinsic_info>());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::shared_ptr<info> symbol_table::lookup(const std::string& name)
 | 
					    std::shared_ptr<info> symbol_table::lookup(const std::string& name)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        auto entry = entries.find(name);
 | 
					        auto entry = entries.find(name);
 | 
				
			||||||
        if (entry == entries.cend())
 | 
					
 | 
				
			||||||
        {
 | 
					        if (entry != entries.cend())
 | 
				
			||||||
            return nullptr;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return entry->second;
 | 
					            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<info> entry)
 | 
					    void symbol_table::enter(const std::string& name, std::shared_ptr<info> entry)
 | 
				
			||||||
@@ -51,6 +67,11 @@ namespace elna::source
 | 
				
			|||||||
        entries.insert_or_assign(name, entry);
 | 
					        entries.insert_or_assign(name, entry);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::shared_ptr<symbol_table> symbol_table::scope()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return this->outer_scope;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    info::~info()
 | 
					    info::~info()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -59,6 +80,20 @@ namespace elna::source
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    type_info::type_info(const class type& type)
 | 
				
			||||||
 | 
					        : info(), m_type(type)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    type_info::~type_info()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const class type& type_info::type() const noexcept
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return m_type;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constant_info::constant_info(const std::int32_t value)
 | 
					    constant_info::constant_info(const std::int32_t value)
 | 
				
			||||||
        : m_value(value)
 | 
					        : m_value(value)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -77,6 +112,25 @@ namespace elna::source
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    parameter_info::parameter_info(const class type& type)
 | 
				
			||||||
 | 
					        : m_type(type)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    parameter_info::~parameter_info()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const class type& parameter_info::type() const noexcept
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return m_type;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    procedure_info::procedure_info(std::shared_ptr<symbol_table> outer_scope)
 | 
				
			||||||
 | 
					        : local_table(std::make_shared<symbol_table>(outer_scope))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    procedure_info::~procedure_info()
 | 
					    procedure_info::~procedure_info()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -91,6 +145,11 @@ namespace elna::source
 | 
				
			|||||||
        this->local_stack_size = size;
 | 
					        this->local_stack_size = size;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::shared_ptr<symbol_table> procedure_info::scope()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return local_table;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    intrinsic_info::~intrinsic_info()
 | 
					    intrinsic_info::~intrinsic_info()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace elna::source
 | 
					namespace elna::source
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    name_analysis_visitor::name_analysis_visitor(std::shared_ptr<symbol_table> table)
 | 
				
			||||||
 | 
					        : table(table)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void name_analysis_visitor::visit(constant_definition *definition)
 | 
					    void name_analysis_visitor::visit(constant_definition *definition)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        this->table->enter(definition->identifier(),
 | 
					        this->table->enter(definition->identifier(),
 | 
				
			||||||
@@ -15,12 +20,24 @@ namespace elna::source
 | 
				
			|||||||
                std::make_shared<variable_info>(variable_info()));
 | 
					                std::make_shared<variable_info>(variable_info()));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void name_analysis_visitor::visit(block *block)
 | 
					    void name_analysis_visitor::visit(program *program)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this->table->enter("main", std::make_shared<procedure_info>(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();
 | 
				
			||||||
 | 
					        empty_visitor::visit(procedure);
 | 
				
			||||||
 | 
					        this->table = info->scope()->scope();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    allocator_visitor::allocator_visitor(std::shared_ptr<symbol_table> table)
 | 
				
			||||||
 | 
					        : table(table)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        this->table = block->table();
 | 
					 | 
				
			||||||
        empty_visitor::visit(block);
 | 
					 | 
				
			||||||
        this->table->enter("main",
 | 
					 | 
				
			||||||
                std::make_shared<procedure_info>());
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void allocator_visitor::visit(declaration *declaration)
 | 
					    void allocator_visitor::visit(declaration *declaration)
 | 
				
			||||||
@@ -28,11 +45,19 @@ namespace elna::source
 | 
				
			|||||||
        this->offset -= sizeof(std::int32_t);
 | 
					        this->offset -= sizeof(std::int32_t);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void allocator_visitor::visit(block *block)
 | 
					    void allocator_visitor::visit(program *program)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        this->offset = 0;
 | 
					        this->offset = 0;
 | 
				
			||||||
        empty_visitor::visit(block);
 | 
					        empty_visitor::visit(program);
 | 
				
			||||||
        std::dynamic_pointer_cast<procedure_info>(block->table()->lookup("main"))
 | 
					        std::dynamic_pointer_cast<procedure_info>(table->lookup("main"))
 | 
				
			||||||
 | 
					            ->stack_size(std::abs(this->offset));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void allocator_visitor::visit(procedure_definition *procedure)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this->offset = 0;
 | 
				
			||||||
 | 
					        empty_visitor::visit(procedure);
 | 
				
			||||||
 | 
					        std::dynamic_pointer_cast<procedure_info>(table->lookup(procedure->identifier()))
 | 
				
			||||||
            ->stack_size(std::abs(this->offset));
 | 
					            ->stack_size(std::abs(this->offset));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1 +1 @@
 | 
				
			|||||||
2
 | 
					5
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,5 @@
 | 
				
			|||||||
proc f;
 | 
					proc f; writei(5);
 | 
				
			||||||
  writei(5);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
begin
 | 
					begin
 | 
				
			||||||
  writei(2)
 | 
					  f()
 | 
				
			||||||
end.
 | 
					end.
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user