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