Implement division

This commit is contained in:
2024-03-09 08:36:07 +01:00
parent fe805ca893
commit a3e3be5ec7
25 changed files with 357 additions and 245 deletions

View File

@ -4,23 +4,23 @@
#include <unordered_map>
#include "elna/source/parser.hpp"
namespace elna::backend
namespace elna::riscv
{
enum class Target
enum class address_t
{
text,
high20,
lower12i
};
struct Reference
struct reference
{
const char* name;
std::size_t offset;
Target target;
address_t target;
};
enum class XRegister : std::uint8_t
enum class x_register : std::uint8_t
{
zero = 0,
ra = 1,
@ -56,7 +56,7 @@ namespace elna::backend
t6 = 31,
};
enum class Funct3 : std::uint8_t
enum class funct3_t : std::uint8_t
{
addi = 0b000,
slti = 0b001,
@ -101,30 +101,30 @@ namespace elna::backend
lbu = 0b100,
lhu = 0b101,
jalr = 0b000,
mul = 000,
mulh = 001,
mulhsu = 010,
mulhu = 011,
div = 100,
divu = 101,
rem = 110,
remu = 111
mul = 0b000,
mulh = 0b001,
mulhsu = 0b010,
mulhu = 0b011,
div = 0b100,
divu = 0b101,
rem = 0b110,
remu = 0b111
};
enum class Funct12 : std::uint8_t
enum class funct12_t : std::uint8_t
{
ecall = 0b000000000000,
ebreak = 0b000000000001,
};
enum class Funct7 : std::uint8_t
enum class funct7_t : std::uint8_t
{
none = 0,
sub = 0b0100000,
muldiv = 0b0000001
};
enum class BaseOpcode : std::uint8_t
enum class base_opcode : std::uint8_t
{
opImm = 0b0010011,
lui = 0b0110111,
@ -139,29 +139,29 @@ namespace elna::backend
system = 0b1110011,
};
struct Instruction
struct instruction
{
Instruction(BaseOpcode opcode);
instruction(base_opcode opcode);
Instruction& i(XRegister rd, Funct3 funct3, XRegister rs1, std::uint32_t immediate);
Instruction& s(std::uint32_t imm1, Funct3 funct3, XRegister rs1, XRegister rs2);
Instruction& r(XRegister rd, Funct3 funct3, XRegister rs1, XRegister rs2, Funct7 funct7 = Funct7::none);
Instruction& u(XRegister rd, std::uint32_t imm);
instruction& i(x_register rd, funct3_t funct3, x_register rs1, std::uint32_t immediate);
instruction& s(std::uint32_t imm1, funct3_t funct3, x_register rs1, x_register rs2);
instruction& r(x_register rd, funct3_t funct3, x_register rs1, x_register rs2, funct7_t funct7 = funct7_t::none);
instruction& u(x_register rd, std::uint32_t imm);
const std::byte *cbegin() const;
const std::byte *cend() const;
private:
std::uint32_t instruction{ 0 };
std::uint32_t representation{ 0 };
};
class RiscVVisitor : public source::ParserVisitor
class visitor : public source::parser_visitor
{
public:
std::vector<Instruction> instructions;
bool registerInUse{ true };
std::uint32_t variableCounter = 1;
Reference references[3];
std::vector<instruction> instructions;
bool register_in_use{ true };
std::uint32_t variable_counter = 1;
reference references[3];
std::unordered_map<std::string, std::int32_t> constants;
virtual void visit(source::definition *definition) override;

View File

@ -1,7 +1,7 @@
#include "elna/source/parser.hpp"
#include <filesystem>
namespace elna::backend
namespace elna::riscv
{
void riscv32_elf(source::block *ast, const std::filesystem::path& out_file);
}

View File

@ -1,16 +0,0 @@
#pragma once
#include "elna/source/parser.hpp"
namespace elna::source
{
class TransformVisitor final : public source::ParserVisitor
{
void visit(source::definition *definition) override;
void visit(source::bang_statement *statement) override;
void visit(source::block *block) override;
void visit(source::integer_literal *number) override;
void visit(source::variable_expression *variable) override;
void visit(source::binary_expression *binaryExpression) override;
};
}

View File

@ -103,6 +103,16 @@ namespace elna::source
bool has_identifier() const noexcept;
};
class unexpected_character final : public error
{
std::string character;
public:
unexpected_character(const std::string& character, const source::position position);
std::string what() const override;
};
/**
* Split the source into tokens.
*

View File

@ -21,7 +21,7 @@ namespace elna::source
class variable_expression;
class integer_literal;
struct ParserVisitor
struct parser_visitor
{
virtual void visit(definition *) = 0;
virtual void visit(bang_statement *) = 0;
@ -37,7 +37,7 @@ namespace elna::source
class node
{
public:
virtual void accept(ParserVisitor *) = 0;
virtual void accept(parser_visitor *) = 0;
};
class statement : public node
@ -58,7 +58,7 @@ namespace elna::source
public:
definition(std::string&& identifier, std::unique_ptr<integer_literal>&& body);
virtual void accept(ParserVisitor *visitor) override;
virtual void accept(parser_visitor *visitor) override;
std::string& identifier() noexcept;
integer_literal& body();
@ -70,7 +70,7 @@ namespace elna::source
public:
bang_statement(std::unique_ptr<expression>&& body);
virtual void accept(ParserVisitor *visitor) override;
virtual void accept(parser_visitor *visitor) override;
expression& body();
};
@ -85,7 +85,7 @@ namespace elna::source
public:
block(std::vector<std::unique_ptr<definition>>&& definitions, std::unique_ptr<statement>&& body);
virtual void accept(ParserVisitor *visitor) override;
virtual void accept(parser_visitor *visitor) override;
statement& body();
std::vector<std::unique_ptr<definition>>& definitions() noexcept;
@ -97,7 +97,7 @@ namespace elna::source
public:
integer_literal(const std::int32_t value);
virtual void accept(ParserVisitor *visitor) override;
virtual void accept(parser_visitor *visitor) override;
std::int32_t number() const noexcept;
};
@ -108,7 +108,7 @@ namespace elna::source
public:
variable_expression(const std::string& name);
virtual void accept(ParserVisitor *visitor) override;
virtual void accept(parser_visitor *visitor) override;
const std::string& name() const noexcept;
};
@ -123,7 +123,7 @@ namespace elna::source
binary_expression(std::unique_ptr<expression>&& lhs,
std::unique_ptr<expression>&& rhs, const unsigned char operation);
virtual void accept(ParserVisitor *visitor) override;
virtual void accept(parser_visitor *visitor) override;
expression& lhs();
expression& rhs();
binary_operator operation() const noexcept;

View File

@ -2,7 +2,9 @@
#include <cstddef>
#include <variant>
#include <forward_list>
#include <list>
#include <memory>
#include <type_traits>
namespace elna::source
{
@ -21,21 +23,19 @@ namespace elna::source
/**
* A compilation error consists of an error message and position.
*/
struct error
class error
{
private:
char const *message;
source::position position;
position m_position;
public:
protected:
/**
* \param message Error text.
* \param position Error position in the source text.
*/
error(char const *message, const source::position position) noexcept;
error(const position position);
public:
/// Error text.
const char *what() const noexcept;
virtual std::string what() const = 0;
/// Error line in the source text.
std::size_t line() const noexcept;
@ -47,19 +47,25 @@ namespace elna::source
template<typename T>
struct result
{
using E = std::forward_list<source::error>;
using E = std::list<std::unique_ptr<source::error>>;
template<typename... Args>
template<typename... Args, typename = std::enable_if<std::is_constructible_v<T, Args...>>>
explicit result(Args&&... arguments)
: payload(std::forward<Args>(arguments)...)
{
}
explicit result(const char *message, const source::position position)
: payload(E{ source::error(message, position) })
explicit result(T&& result)
: payload(std::move(result))
{
}
template<typename U, typename = std::enable_if<std::is_base_of_v<error, U>>>
explicit result(U&& first)
{
errors().emplace_back(std::make_unique<U>(first));
}
bool has_errors() const noexcept
{
return std::holds_alternative<E>(payload);

View File

@ -0,0 +1,54 @@
#pragma once
#include "elna/source/parser.hpp"
#include <unordered_map>
#include <memory>
namespace elna::source
{
class info
{
public:
virtual ~info() = 0;
protected:
info();
};
class constant_info final : public info
{
std::int32_t m_value;
public:
constant_info(const std::int32_t value);
~constant_info() override;
std::int32_t value() const noexcept;
};
class variable_info final : public info
{
public:
~variable_info() override;
};
class symbol_table
{
std::unordered_map<std::string, std::shared_ptr<info>> entries;
public:
symbol_table() = default;
std::shared_ptr<info> lookup(const std::string& name);
void enter(const std::string& name, std::shared_ptr<info> entry);
};
class name_analysis_visitor final : public source::parser_visitor
{
void visit(definition *definition) override;
void visit(bang_statement *statement) override;
void visit(block *block) override;
void visit(integer_literal *number) override;
void visit(variable_expression *variable) override;
void visit(binary_expression *expression) override;
};
}