2024-04-18 12:15:26 +02:00
|
|
|
#include "elna/source/optimizer.hpp"
|
|
|
|
#include <cassert>
|
|
|
|
|
|
|
|
namespace elna::source
|
|
|
|
{
|
|
|
|
quadruple::quadruple(const quadruple_operator operation, std::shared_ptr<operand> operand1,
|
|
|
|
std::shared_ptr<operand> operand2, std::shared_ptr<operand> operand3)
|
|
|
|
: m_operation(operation), m_operand1(operand1), m_operand2(operand2), m_operand3(operand3)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
quadruple_operator quadruple::operation() const noexcept
|
|
|
|
{
|
|
|
|
return m_operation;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<operand> quadruple::operand1()
|
|
|
|
{
|
|
|
|
return m_operand1;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<operand> quadruple::operand2()
|
|
|
|
{
|
|
|
|
return m_operand2;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<operand> quadruple::operand3()
|
|
|
|
{
|
|
|
|
return m_operand3;
|
|
|
|
}
|
|
|
|
|
|
|
|
intermediate_code::intermediate_code()
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void intermediate_code::emplace_back(const quadruple_operator operation, std::shared_ptr<operand> operand1,
|
|
|
|
std::shared_ptr<operand> operand2, std::shared_ptr<operand> operand3)
|
|
|
|
{
|
|
|
|
this->instructions.emplace_back(operation, operand1, operand2, operand3);
|
|
|
|
}
|
|
|
|
|
|
|
|
void intermediate_code::clear()
|
|
|
|
{
|
|
|
|
this->instructions.clear();
|
2024-05-27 22:58:54 +02:00
|
|
|
this->m_variable_counter = 1;
|
|
|
|
this->m_label_counter = 0;
|
2024-04-18 12:15:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<quadruple>::iterator intermediate_code::begin()
|
|
|
|
{
|
|
|
|
return this->instructions.begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<quadruple>::iterator intermediate_code::end()
|
|
|
|
{
|
|
|
|
return this->instructions.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::int32_t intermediate_code::variable_counter() const noexcept
|
|
|
|
{
|
|
|
|
return m_variable_counter;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::int32_t intermediate_code::increment_variable() noexcept
|
|
|
|
{
|
|
|
|
return m_variable_counter++;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::int32_t intermediate_code::label_counter() const noexcept
|
|
|
|
{
|
|
|
|
return m_label_counter;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::int32_t intermediate_code::increment_label() noexcept
|
|
|
|
{
|
|
|
|
return m_label_counter++;
|
|
|
|
}
|
|
|
|
|
|
|
|
intermediate_code_generator::intermediate_code_generator(std::shared_ptr<symbol_table> table)
|
|
|
|
: table(table)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
quadruple_operator intermediate_code_generator::convert(const binary_operator operation) const
|
|
|
|
{
|
|
|
|
switch (operation)
|
|
|
|
{
|
|
|
|
case binary_operator::sum:
|
|
|
|
return quadruple_operator::add;
|
|
|
|
case binary_operator::subtraction:
|
|
|
|
return quadruple_operator::sub;
|
|
|
|
case binary_operator::multiplication:
|
|
|
|
return quadruple_operator::mul;
|
|
|
|
case binary_operator::division:
|
|
|
|
return quadruple_operator::div;
|
|
|
|
case binary_operator::equals:
|
|
|
|
return quadruple_operator::eq;
|
|
|
|
case source::binary_operator::not_equals:
|
|
|
|
return quadruple_operator::neq;
|
|
|
|
case source::binary_operator::less:
|
|
|
|
return quadruple_operator::lt;
|
|
|
|
case source::binary_operator::greater_equal:
|
|
|
|
return quadruple_operator::ge;
|
|
|
|
case source::binary_operator::greater:
|
|
|
|
return quadruple_operator::gt;
|
|
|
|
case source::binary_operator::less_equal:
|
|
|
|
return quadruple_operator::le;
|
|
|
|
default:
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
quadruple_operator intermediate_code_generator::convert(const unary_operator operation) const
|
|
|
|
{
|
|
|
|
switch (operation)
|
|
|
|
{
|
|
|
|
case unary_operator::reference:
|
|
|
|
return quadruple_operator::ref;
|
|
|
|
case unary_operator::dereference:
|
|
|
|
return quadruple_operator::load;
|
|
|
|
default:
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void intermediate_code_generator::visit(source::declaration *declaration)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void intermediate_code_generator::visit(source::constant_definition *definition)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void intermediate_code_generator::visit(procedure_definition *definition)
|
|
|
|
{
|
|
|
|
this->current.emplace_back(quadruple_operator::start);
|
|
|
|
definition->body().accept(this);
|
|
|
|
this->current.emplace_back(quadruple_operator::stop);
|
|
|
|
code[definition->identifier()] = std::move(this->current);
|
|
|
|
this->current.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unordered_map<std::string, intermediate_code>::iterator intermediate_code_generator::begin()
|
|
|
|
{
|
|
|
|
return code.begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unordered_map<std::string, intermediate_code>::iterator intermediate_code_generator::end()
|
|
|
|
{
|
|
|
|
return code.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
void intermediate_code_generator::visit(block *block)
|
|
|
|
{
|
|
|
|
block->body().accept(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void intermediate_code_generator::visit(program *program)
|
|
|
|
{
|
|
|
|
for (auto& definition : program->definitions())
|
|
|
|
{
|
|
|
|
definition->accept(this);
|
|
|
|
}
|
|
|
|
this->current.emplace_back(quadruple_operator::start);
|
|
|
|
program->body().accept(this);
|
|
|
|
this->current.emplace_back(quadruple_operator::stop);
|
2024-05-23 01:13:16 +02:00
|
|
|
code["_start"] = std::move(this->current);
|
2024-04-18 12:15:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void intermediate_code_generator::visit(call_statement *statement)
|
|
|
|
{
|
|
|
|
for (auto& argument : statement->arguments())
|
|
|
|
{
|
|
|
|
argument->accept(this);
|
|
|
|
this->current.emplace_back(quadruple_operator::param, argument->place, nullptr, nullptr);
|
|
|
|
}
|
|
|
|
this->current.emplace_back(quadruple_operator::call,
|
|
|
|
std::make_shared<variable_operand>(statement->name()),
|
|
|
|
std::make_shared<integer_operand>(statement->arguments().size()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void intermediate_code_generator::visit(assign_statement *statement)
|
|
|
|
{
|
|
|
|
statement->rvalue().accept(this);
|
|
|
|
|
|
|
|
this->current.emplace_back(quadruple_operator::assign, statement->rvalue().place, nullptr,
|
|
|
|
std::make_shared<variable_operand>(statement->lvalue()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void intermediate_code_generator::visit(if_statement *statement)
|
|
|
|
{
|
|
|
|
statement->prerequisite().accept(this);
|
|
|
|
|
|
|
|
auto end_label = std::make_shared<label_operand>(this->current.increment_label());
|
|
|
|
this->current.emplace_back(quadruple_operator::beqz, statement->prerequisite().place, nullptr, end_label);
|
|
|
|
|
|
|
|
statement->body().accept(this);
|
|
|
|
this->current.emplace_back(quadruple_operator::label, nullptr, nullptr, end_label);
|
|
|
|
}
|
|
|
|
|
|
|
|
void intermediate_code_generator::visit(while_statement *statement)
|
|
|
|
{
|
|
|
|
auto condition_label = std::make_shared<label_operand>(this->current.increment_label());
|
|
|
|
|
|
|
|
this->current.emplace_back(quadruple_operator::label, nullptr, nullptr, condition_label);
|
|
|
|
statement->prerequisite().accept(this);
|
|
|
|
|
|
|
|
auto end_label = std::make_shared<label_operand>(this->current.increment_label());
|
|
|
|
this->current.emplace_back(quadruple_operator::beqz, statement->prerequisite().place, nullptr, end_label);
|
|
|
|
|
|
|
|
statement->body().accept(this);
|
|
|
|
this->current.emplace_back(quadruple_operator::j, nullptr, nullptr, condition_label);
|
|
|
|
this->current.emplace_back(quadruple_operator::label, nullptr, nullptr, end_label);
|
|
|
|
}
|
|
|
|
|
|
|
|
void intermediate_code_generator::visit(type_expression *type)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void intermediate_code_generator::visit(variable_expression *variable)
|
|
|
|
{
|
|
|
|
auto symbol = table->lookup(variable->name());
|
|
|
|
if (auto constant_symbol = std::dynamic_pointer_cast<source::constant_info>(symbol))
|
|
|
|
{
|
|
|
|
variable->place = std::make_shared<integer_operand>(constant_symbol->value());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
variable->place = std::make_shared<variable_operand>(variable->name());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void intermediate_code_generator::visit(binary_expression *expression)
|
|
|
|
{
|
|
|
|
expression->lhs().accept(this);
|
|
|
|
auto left = expression->lhs().place;
|
|
|
|
|
|
|
|
expression->rhs().accept(this);
|
|
|
|
auto right = expression->rhs().place;
|
|
|
|
auto operation = convert(expression->operation());
|
|
|
|
auto new_place = std::make_shared<temporary_variable>(this->current.increment_variable());
|
|
|
|
|
|
|
|
this->current.emplace_back(operation, left, right, new_place);
|
|
|
|
expression->place = new_place;
|
|
|
|
}
|
|
|
|
|
|
|
|
void intermediate_code_generator::visit(unary_expression *expression)
|
|
|
|
{
|
|
|
|
expression->operand().accept(this);
|
|
|
|
auto operation = convert(expression->operation());
|
|
|
|
auto new_place = std::make_shared<temporary_variable>(this->current.increment_variable());
|
|
|
|
|
|
|
|
this->current.emplace_back(operation, expression->operand().place, nullptr, new_place);
|
|
|
|
expression->place = new_place;
|
|
|
|
}
|
|
|
|
|
|
|
|
void intermediate_code_generator::visit(integer_literal *number)
|
|
|
|
{
|
|
|
|
number->place = std::make_shared<integer_operand>(number->number());
|
|
|
|
}
|
|
|
|
|
|
|
|
void intermediate_code_generator::visit(boolean_literal *number)
|
|
|
|
{
|
|
|
|
number->place = std::make_shared<integer_operand>(number->boolean());
|
|
|
|
}
|
|
|
|
}
|