#include "elna/source/semantic.hpp" #include "elna/source/result.hpp" #include namespace elna::source { name_analysis_visitor::name_analysis_visitor(std::shared_ptr table, const std::filesystem::path& filename) : table(table), filename(filename) { } void name_analysis_visitor::visit(constant_definition *definition) { this->table->enter(definition->identifier(), std::make_shared(constant_info(definition->body().number()))); } std::shared_ptr name_analysis_visitor::convert_declaration_type(const type_expression& ast_type) const { auto variable_type = std::dynamic_pointer_cast(table->lookup(ast_type.base())) ->type(); std::shared_ptr declaration_type; if (ast_type.is_pointer()) { return std::make_shared(variable_type, 4); } else { return variable_type; } } void name_analysis_visitor::visit(declaration *declaration) { std::shared_ptr declaration_type = convert_declaration_type(declaration->type()); this->table->enter(declaration->identifier(), std::make_shared(declaration_type)); } void name_analysis_visitor::visit(program *program) { this->table->enter("main", std::make_shared(this->table)); empty_visitor::visit(program); } void name_analysis_visitor::visit(procedure_definition *procedure) { auto info = std::make_shared(this->table); this->table->enter(procedure->identifier(), info); this->table = info->scope(); for (auto& parameter : procedure->parameters()) { auto declaration_type = convert_declaration_type(parameter->type()); this->table->enter(parameter->identifier(), std::make_shared(declaration_type)); } procedure->body().accept(this); this->table = info->scope()->scope(); } const std::list>& name_analysis_visitor::errors() const noexcept { return m_errors; } allocator_visitor::allocator_visitor(std::shared_ptr table) : table(table) { } void allocator_visitor::visit(declaration *declaration) { auto declaration_info = this->table->lookup(declaration->identifier()); if (auto variable = std::dynamic_pointer_cast(declaration_info)) { this->local_offset -= sizeof(std::int32_t); variable->offset = this->local_offset; } else if (auto parameter = std::dynamic_pointer_cast(declaration_info)) { parameter->offset = this->argument_offset; this->argument_offset += sizeof(std::int32_t); } } void allocator_visitor::visit(program *program) { this->local_offset = 0; this->argument_offset = 0; empty_visitor::visit(program); std::dynamic_pointer_cast(table->lookup("main"))->local_stack_size = std::abs(this->local_offset); } void allocator_visitor::visit(procedure_definition *procedure) { this->local_offset = 0; this->argument_offset = 0; auto info = std::dynamic_pointer_cast(this->table->lookup(procedure->identifier())); this->table = info->scope(); empty_visitor::visit(procedure); this->table = info->scope()->scope(); info->local_stack_size = std::abs(this->local_offset); info->argument_stack_size = this->argument_offset; } void allocator_visitor::visit(call_statement *statement) { auto call_info = std::dynamic_pointer_cast(this->table->lookup(statement->name())); this->argument_offset = std::max(static_cast(this->argument_offset), call_info->parameter_stack_size()); } type_analysis_visitor::type_analysis_visitor(std::shared_ptr table, const std::filesystem::path& filename, std::size_t target_pointer_size) : table(table), filename(filename), pointer_size(target_pointer_size) { } void type_analysis_visitor::visit(program *program) { for (auto& definition : program->definitions()) { if (dynamic_cast(definition.get()) != nullptr) { definition->accept(this); } } program->body().accept(this); } void type_analysis_visitor::visit(procedure_definition *definition) { definition->body().accept(this); } void type_analysis_visitor::visit(integer_literal *literal) { literal->data_type = std::dynamic_pointer_cast(table->lookup("Int"))->type(); } void type_analysis_visitor::visit(boolean_literal *literal) { literal->data_type = std::dynamic_pointer_cast(table->lookup("Boolean"))->type(); } void type_analysis_visitor::visit(unary_expression *expression) { empty_visitor::visit(expression); switch (expression->operation()) { case unary_operator::reference: expression->data_type = std::make_shared(expression->operand().data_type, this->pointer_size); break; case unary_operator::dereference: auto operand_type = expression->operand().data_type; if (auto referenced_type = std::dynamic_pointer_cast(operand_type)) { expression->data_type = referenced_type; } else if (operand_type != nullptr) { auto new_error = std::make_unique(operand_type, type_mismatch::operation::dereference, this->filename, expression->position()); m_errors.push_back(std::move(new_error)); } break; } } const std::list>& type_analysis_visitor::errors() const noexcept { return m_errors; } }