Implement division
This commit is contained in:
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
@ -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.
|
||||
*
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
54
include/elna/source/symboltable.hpp
Normal file
54
include/elna/source/symboltable.hpp
Normal 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;
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user