Support procedure calls without arguments
This commit is contained in:
parent
f2a20c2825
commit
44e32760ca
@ -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()
|
||||||
{
|
{
|
||||||
|
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::opImm));
|
||||||
}
|
}
|
||||||
|
|
||||||
void visitor::visit(source::block *block)
|
void visitor::epilogue(const std::size_t stack_size)
|
||||||
{
|
{
|
||||||
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::opImm));
|
|
||||||
|
|
||||||
table = block->table();
|
|
||||||
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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
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("writei", std::make_shared<intrinsic_info>());
|
||||||
enter("writeb", 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.
|
||||||
|
Loading…
Reference in New Issue
Block a user