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);
|
||||
}
|
||||
|
||||
visitor::visitor(std::shared_ptr<source::writer> writer)
|
||||
: writer(writer)
|
||||
visitor::visitor(std::shared_ptr<source::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);
|
||||
|
||||
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::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));
|
||||
|
||||
prologue();
|
||||
this->instructions.push_back(instruction(base_opcode::opImm)
|
||||
.i(x_register::a1, funct3_t::addi, x_register::zero, 't'));
|
||||
this->instructions.push_back(instruction(base_opcode::branch)
|
||||
@ -114,32 +107,16 @@ namespace elna::riscv
|
||||
this->instructions.push_back(instruction(base_opcode::jalr)
|
||||
.i(x_register::ra, funct3_t::jalr, x_register::ra, 0));
|
||||
|
||||
this->instructions.push_back(instruction(base_opcode::load)
|
||||
.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));
|
||||
epilogue(8);
|
||||
|
||||
this->writer->sink("writeb", reinterpret_cast<const std::byte *>(this->instructions.data()),
|
||||
this->instructions.size() * sizeof(instruction));
|
||||
|
||||
this->instructions.clear();
|
||||
}
|
||||
{
|
||||
auto format_string = this->writer->sink(reinterpret_cast<const std::byte *>("%d\n\0"), 4);
|
||||
|
||||
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::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));
|
||||
|
||||
prologue();
|
||||
this->instructions.push_back(instruction(base_opcode::opImm)
|
||||
.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)
|
||||
.i(x_register::ra, funct3_t::jalr, x_register::ra, 0));
|
||||
|
||||
this->instructions.push_back(instruction(base_opcode::load)
|
||||
.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));
|
||||
epilogue(8);
|
||||
|
||||
this->writer->sink("writei", reinterpret_cast<const std::byte *>(this->instructions.data()),
|
||||
this->instructions.size() * sizeof(instruction));
|
||||
|
||||
this->instructions.clear();
|
||||
}
|
||||
}
|
||||
@ -186,29 +155,16 @@ namespace elna::riscv
|
||||
{
|
||||
}
|
||||
|
||||
void visitor::visit(source::procedure_definition *definition)
|
||||
{
|
||||
}
|
||||
|
||||
void visitor::visit(source::block *block)
|
||||
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));
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
void visitor::epilogue(const std::size_t 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[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));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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->instructions.size() * sizeof(instruction));
|
||||
}
|
||||
|
||||
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);
|
||||
this->instructions.push_back(instruction(base_opcode::auipc).u(x_register::ra, 0));
|
||||
this->instructions.push_back(instruction(base_opcode::jalr)
|
||||
|
@ -146,7 +146,8 @@ namespace elna::riscv
|
||||
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;
|
||||
|
||||
@ -197,7 +198,7 @@ namespace elna::riscv
|
||||
ELFIO::relocation_section_accessor rela(writer, rel_sec);
|
||||
auto _writer = std::make_shared<elfio_writer>(text_sec, ro_sec, syma, stra);
|
||||
|
||||
visitor _visitor{ _writer };
|
||||
visitor _visitor{ _writer, table };
|
||||
_visitor.visit(ast);
|
||||
|
||||
syma.arrange_local_symbols();
|
||||
|
@ -54,10 +54,11 @@ namespace elna::cli
|
||||
}
|
||||
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::allocator_visitor().visit(ast.get());
|
||||
riscv::riscv32_elf(ast.get(), out_file);
|
||||
source::allocator_visitor(global_scope).visit(ast.get());
|
||||
riscv::riscv32_elf(ast.get(), global_scope, out_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -165,13 +165,16 @@ namespace elna::riscv
|
||||
|
||||
void generate_intrinsics();
|
||||
void relocate(std::string_view name, address_t target);
|
||||
void prologue();
|
||||
void epilogue(const std::size_t stack_size);
|
||||
|
||||
public:
|
||||
std::uint32_t variable_counter = 1;
|
||||
std::vector<reference> references;
|
||||
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::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);
|
||||
|
||||
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
|
||||
{
|
||||
std::string m_identifier;
|
||||
std::string m_type;
|
||||
|
||||
public:
|
||||
declaration(const std::string& identifier);
|
||||
declaration(const std::string& identifier, const std::string& type);
|
||||
virtual void accept(parser_visitor *visitor) override;
|
||||
|
||||
std::string& identifier() noexcept;
|
||||
std::string& type() noexcept;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -124,25 +126,27 @@ namespace elna::source
|
||||
class procedure_definition : public definition
|
||||
{
|
||||
std::unique_ptr<block> m_body;
|
||||
std::vector<std::unique_ptr<declaration>> m_parameters;
|
||||
|
||||
public:
|
||||
procedure_definition(const std::string& identifier, std::unique_ptr<block>&& body);
|
||||
virtual void accept(parser_visitor *visitor) override;
|
||||
|
||||
block& body();
|
||||
std::vector<std::unique_ptr<declaration>>& parameters() noexcept;
|
||||
};
|
||||
|
||||
class call_statement : public statement
|
||||
{
|
||||
std::string m_name;
|
||||
std::unique_ptr<expression> m_body;
|
||||
std::vector<std::unique_ptr<expression>> m_arguments;
|
||||
|
||||
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;
|
||||
|
||||
std::string& name() noexcept;
|
||||
expression& arguments();
|
||||
std::vector<std::unique_ptr<expression>>& arguments() noexcept;
|
||||
};
|
||||
|
||||
class compound_statement : public statement
|
||||
@ -201,7 +205,6 @@ namespace elna::source
|
||||
std::unique_ptr<statement> m_body;
|
||||
std::vector<std::unique_ptr<definition>> m_definitions;
|
||||
std::vector<std::unique_ptr<declaration>> m_declarations;
|
||||
std::shared_ptr<symbol_table> m_table;
|
||||
|
||||
public:
|
||||
block(std::vector<std::unique_ptr<definition>>&& definitions,
|
||||
@ -212,7 +215,6 @@ namespace elna::source
|
||||
statement& body();
|
||||
std::vector<std::unique_ptr<definition>>& definitions() noexcept;
|
||||
std::vector<std::unique_ptr<declaration>>& declarations() noexcept;
|
||||
std::shared_ptr<symbol_table> table();
|
||||
};
|
||||
|
||||
class program : public block
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace elna::source
|
||||
{
|
||||
@ -110,6 +111,32 @@ namespace elna::source
|
||||
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.
|
||||
*/
|
||||
@ -122,6 +149,19 @@ namespace elna::source
|
||||
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.
|
||||
*/
|
||||
@ -145,18 +185,36 @@ namespace elna::source
|
||||
~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.
|
||||
*/
|
||||
class procedure_info final : public info
|
||||
{
|
||||
std::size_t local_stack_size{ 0 };
|
||||
std::shared_ptr<symbol_table> local_table;
|
||||
|
||||
public:
|
||||
std::vector<parameter_info> parameter_infos;
|
||||
|
||||
explicit procedure_info(std::shared_ptr<symbol_table> outer_scope);
|
||||
~procedure_info() override;
|
||||
|
||||
void stack_size(const std::size_t size) noexcept;
|
||||
std::size_t stack_size() const noexcept;
|
||||
std::shared_ptr<symbol_table> scope();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -174,12 +232,39 @@ namespace elna::source
|
||||
class symbol_table
|
||||
{
|
||||
std::unordered_map<std::string, std::shared_ptr<info>> entries;
|
||||
std::shared_ptr<symbol_table> outer_scope;
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* Registers new symbol.
|
||||
*
|
||||
* \param name Symbol name.
|
||||
* \param entry Symbol information.
|
||||
*/
|
||||
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
|
||||
|
@ -6,21 +6,28 @@ namespace elna::source
|
||||
{
|
||||
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:
|
||||
name_analysis_visitor(std::shared_ptr<symbol_table> table);
|
||||
|
||||
void visit(constant_definition *definition) 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
|
||||
{
|
||||
std::ptrdiff_t offset;
|
||||
std::shared_ptr<symbol_table> table;
|
||||
|
||||
public:
|
||||
allocator_visitor(std::shared_ptr<symbol_table> table);
|
||||
|
||||
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
|
||||
|
@ -19,7 +19,10 @@ namespace elna::source
|
||||
|
||||
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)
|
||||
@ -87,8 +90,8 @@ namespace elna::source
|
||||
{
|
||||
}
|
||||
|
||||
declaration::declaration(const std::string& identifier)
|
||||
: m_identifier(identifier)
|
||||
declaration::declaration(const std::string& identifier, const std::string& type)
|
||||
: m_identifier(identifier), m_type(type)
|
||||
{
|
||||
}
|
||||
|
||||
@ -102,6 +105,11 @@ namespace elna::source
|
||||
return m_identifier;
|
||||
}
|
||||
|
||||
std::string& declaration::type() noexcept
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
definition::definition(const std::string& identifier)
|
||||
: m_identifier(identifier)
|
||||
{
|
||||
@ -142,12 +150,16 @@ namespace elna::source
|
||||
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,
|
||||
std::vector<std::unique_ptr<declaration>>&& declarations,
|
||||
std::unique_ptr<statement>&& body)
|
||||
: m_definitions(std::move(definitions)),
|
||||
m_declarations(std::move(declarations)), m_body(std::move(body)),
|
||||
m_table(std::make_shared<symbol_table>())
|
||||
m_declarations(std::move(declarations)), m_body(std::move(body))
|
||||
{
|
||||
}
|
||||
|
||||
@ -171,11 +183,6 @@ namespace elna::source
|
||||
return m_declarations;
|
||||
}
|
||||
|
||||
std::shared_ptr<symbol_table> block::table()
|
||||
{
|
||||
return m_table;
|
||||
}
|
||||
|
||||
program::program(std::vector<std::unique_ptr<definition>>&& definitions,
|
||||
std::vector<std::unique_ptr<declaration>>&& declarations,
|
||||
std::unique_ptr<statement>&& body)
|
||||
@ -276,8 +283,8 @@ namespace elna::source
|
||||
return m_operator;
|
||||
}
|
||||
|
||||
call_statement::call_statement(const std::string& name, std::unique_ptr<expression>&& body)
|
||||
: m_name(name), m_body(std::move(body))
|
||||
call_statement::call_statement(const std::string& name)
|
||||
: m_name(name)
|
||||
{
|
||||
}
|
||||
|
||||
@ -291,9 +298,9 @@ namespace elna::source
|
||||
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)
|
||||
@ -537,7 +544,8 @@ namespace elna::source
|
||||
{
|
||||
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()
|
||||
@ -573,11 +581,27 @@ namespace elna::source
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -27,23 +27,39 @@ namespace elna::source
|
||||
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)
|
||||
{
|
||||
auto entry = entries.find(name);
|
||||
if (entry == entries.cend())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
|
||||
if (entry != entries.cend())
|
||||
{
|
||||
return entry->second;
|
||||
}
|
||||
if (this->outer_scope != nullptr)
|
||||
{
|
||||
return this->outer_scope->lookup(name);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void symbol_table::enter(const std::string& name, std::shared_ptr<info> entry)
|
||||
@ -51,6 +67,11 @@ namespace elna::source
|
||||
entries.insert_or_assign(name, entry);
|
||||
}
|
||||
|
||||
std::shared_ptr<symbol_table> symbol_table::scope()
|
||||
{
|
||||
return this->outer_scope;
|
||||
}
|
||||
|
||||
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)
|
||||
: 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()
|
||||
{
|
||||
}
|
||||
@ -91,6 +145,11 @@ namespace elna::source
|
||||
this->local_stack_size = size;
|
||||
}
|
||||
|
||||
std::shared_ptr<symbol_table> procedure_info::scope()
|
||||
{
|
||||
return local_table;
|
||||
}
|
||||
|
||||
intrinsic_info::~intrinsic_info()
|
||||
{
|
||||
}
|
||||
|
@ -3,6 +3,11 @@
|
||||
|
||||
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)
|
||||
{
|
||||
this->table->enter(definition->identifier(),
|
||||
@ -15,12 +20,24 @@ namespace elna::source
|
||||
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)
|
||||
@ -28,11 +45,19 @@ namespace elna::source
|
||||
this->offset -= sizeof(std::int32_t);
|
||||
}
|
||||
|
||||
void allocator_visitor::visit(block *block)
|
||||
void allocator_visitor::visit(program *program)
|
||||
{
|
||||
this->offset = 0;
|
||||
empty_visitor::visit(block);
|
||||
std::dynamic_pointer_cast<procedure_info>(block->table()->lookup("main"))
|
||||
empty_visitor::visit(program);
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
2
|
||||
5
|
||||
|
@ -1,6 +1,5 @@
|
||||
proc f;
|
||||
writei(5);
|
||||
proc f; writei(5);
|
||||
|
||||
begin
|
||||
writei(2)
|
||||
f()
|
||||
end.
|
||||
|
Loading…
Reference in New Issue
Block a user