Implement multiplication

This commit is contained in:
2024-03-03 13:11:39 +01:00
parent 3a6d89767b
commit d2516cb76c
25 changed files with 343 additions and 1989 deletions

View File

@ -1,7 +1,9 @@
#pragma once
#include <filesystem>
namespace elna
{
char *readSource(const char *source);
int compile(const char *inFile, const char *outputFilename);
int compile(const std::filesystem::path& in_file, const std::filesystem::path& out_file);
}

View File

@ -1,10 +1,13 @@
#pragma once
#include <cstdint>
#include <string>
#include "elna/result.hpp"
namespace elna
{
namespace lex
{
/**
* Range over the source text that keeps track of the current position.
@ -14,10 +17,10 @@ namespace elna
class const_iterator
{
std::string::const_iterator m_buffer;
Position m_position;
elna::source::position m_position;
const_iterator(std::string::const_iterator buffer,
const Position position = Position());
const elna::source::position start_position = elna::source::position());
public:
using iterator_category = std::forward_iterator_tag;
@ -26,7 +29,7 @@ namespace elna
using pointer = const value_type *;
using reference = const value_type&;
const Position& position() const noexcept;
const elna::source::position& position() const noexcept;
reference operator*() const noexcept;
pointer operator->() const noexcept;
@ -54,20 +57,21 @@ namespace elna
/**
* Token type.
*/
enum Type : std::uint16_t
enum class type : std::uint16_t
{
TOKEN_NUMBER = 0,
TOKEN_OPERATOR = 1,
TOKEN_LET = 2,
TOKEN_IDENTIFIER = 3,
TOKEN_EQUALS = 4,
TOKEN_VAR = 5,
TOKEN_SEMICOLON = 6,
TOKEN_LEFT_PAREN = 7,
TOKEN_RIGHT_PAREN = 8,
TOKEN_BANG = 9,
TOKEN_DOT = 10,
TOKEN_COMMA = 11,
number = 0,
term_operator = 1,
let = 2,
identifier = 3,
equals = 4,
var = 5,
semicolon = 6,
left_paren = 7,
right_paren = 8,
bang = 9,
dot = 10,
comma = 11,
factor_operator = 12,
};
/**
@ -79,9 +83,9 @@ namespace elna
const char *identifier;
};
Token(Type of, Position position);
Token(Type of, std::int32_t value, Position position);
Token(Type of, const char *value, Position position);
Token(type of, elna::source::position position);
Token(type of, std::int32_t value, elna::source::position position);
Token(type of, const char *value, elna::source::position position);
Token(const Token& that);
Token(Token&& that);
~Token();
@ -89,21 +93,23 @@ namespace elna
Token& operator=(const Token& that);
Token& operator=(Token&& that);
Type of() const noexcept;
type of() const noexcept;
const char *identifier() const noexcept;
std::int32_t number() const noexcept;
const Position& position() const noexcept;
const elna::source::position& position() const noexcept;
private:
Type m_type;
type m_type;
Value m_value;
Position m_position;
elna::source::position m_position;
};
/**
* Split the source into tokens.
*
* \param buffer Source text.
* \return Tokens or error.
*/
Token *lex(const char *buffer, CompileError *compile_error, std::size_t *length);
elna::source::result<std::vector<Token>> lex(const char *buffer);
}
}

View File

@ -9,7 +9,9 @@ namespace elna
enum class BinaryOperator
{
sum,
subtraction
subtraction,
multiplication,
division
};
class Node;
@ -112,12 +114,12 @@ namespace elna
virtual void accept(ParserVisitor *visitor) override;
};
Expression *parseFactor(Token **tokens, std::size_t *length);
Expression *parseTerm(Token **tokens, std::size_t *length);
Expression *parseExpression(Token **tokens, std::size_t *length);
Definition *parseDefinition(Token **tokens, std::size_t *length);
Statement *parseStatement(Token **tokens, std::size_t *length);
Definition **parseDefinitions(Token **tokens, std::size_t *length, std::size_t *resultLength);
Block *parseBlock(Token **tokens, std::size_t *length);
Block *parse(Token *tokenStream, std::size_t length);
Expression *parseFactor(lex::Token **tokens, std::size_t *length);
Expression *parseTerm(lex::Token **tokens, std::size_t *length);
Expression *parseExpression(lex::Token **tokens, std::size_t *length);
Definition *parseDefinition(lex::Token **tokens, std::size_t *length);
Statement *parseStatement(lex::Token **tokens, std::size_t *length);
Definition **parseDefinitions(lex::Token **tokens, std::size_t *length, std::size_t *resultLength);
Block *parseBlock(lex::Token **tokens, std::size_t *length);
Block *parse(lex::Token *tokenStream, std::size_t length);
}

View File

@ -1,50 +1,92 @@
#pragma once
#include <cstddef>
#include <boost/outcome.hpp>
#include <variant>
#include <vector>
#include <forward_list>
namespace elna
{
/**
* Position in the source text.
*/
struct Position
namespace source
{
/// Line.
std::size_t line = 1;
/// Column.
std::size_t column = 1;
};
/**
* A compilation error consists of an error message and position.
*/
struct CompileError
{
private:
char const *message;
Position position;
public:
/**
* @param message Error text.
* @param position Error position in the source text.
* Position in the source text.
*/
CompileError(char const *message, const Position position) noexcept;
struct position
{
/// Line.
std::size_t line = 1;
/// Error text.
const char *what() const noexcept;
/// Column.
std::size_t column = 1;
};
/// Error line in the source text.
std::size_t line() const noexcept;
/**
* A compilation error consists of an error message and position.
*/
struct error
{
private:
char const *message;
source::position position;
/// Error column in the source text.
std::size_t column() const noexcept;
};
public:
/**
* \param message Error text.
* \param position Error position in the source text.
*/
error(char const *message, const source::position position) noexcept;
template<typename T>
using result = boost::outcome_v2::result<T, CompileError>;
/// Error text.
const char *what() const noexcept;
/// Error line in the source text.
std::size_t line() const noexcept;
/// Error column in the source text.
std::size_t column() const noexcept;
};
template<typename T>
struct result
{
using E = std::forward_list<source::error>;
template<typename... 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) })
{
}
bool has_errors() const noexcept
{
return std::holds_alternative<E>(payload);
}
bool is_success() const noexcept
{
return std::holds_alternative<T>(payload);
}
T& success()
{
return std::get<T>(payload);
}
E& errors()
{
return std::get<E>(payload);
}
private:
std::variant<T, E> payload;
};
}
enum class Target
{
@ -64,8 +106,7 @@ namespace elna
{
Symbol(const char *name);
const char *name;
unsigned char *text;
std::size_t length;
std::vector<std::byte> text;
Reference symbols[3];
};
}

View File

@ -87,6 +87,14 @@ namespace elna
lbu = 0b100,
lhu = 0b101,
jalr = 0b000,
mul = 000,
mulh = 001,
mulhsu = 010,
mulhu = 011,
div = 100,
divu = 101,
rem = 110,
remu = 111
};
enum class Funct12 : std::uint8_t
@ -98,7 +106,8 @@ namespace elna
enum class Funct7 : std::uint8_t
{
none = 0,
sub = 0b0100000
sub = 0b0100000,
muldiv = 0b0000001
};
enum class BaseOpcode : std::uint8_t
@ -124,7 +133,9 @@ namespace elna
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);
std::uint8_t *encode();
const std::byte *cbegin();
const std::byte *cend();
private:
std::uint32_t instruction{ 0 };