Get rid of the raw pointers in the parser

This commit is contained in:
Eugen Wissner 2024-03-06 07:51:56 +01:00
parent 632dc53b53
commit f84fd91426
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
12 changed files with 601 additions and 562 deletions

View File

@ -19,10 +19,10 @@ add_executable(elnsh shell/main.cpp
target_include_directories(elnsh PRIVATE include)
add_executable(elna source/main.cpp
source/lexer.cpp include/elna/lexer.hpp
source/lexer.cpp include/elna/source/lexer.hpp
source/parser.cpp include/elna/source/parser.hpp
source/result.cpp include/elna/result.hpp
source/riscv.cpp include/elna/riscv.hpp
source/parser.cpp include/elna/parser.hpp
source/ir.cpp include/elna/ir.hpp
source/cl.cpp include/elna/cl.hpp
)

View File

@ -1,18 +1,16 @@
#pragma once
#include "elna/parser.hpp"
#include "elna/source/parser.hpp"
namespace elna
{
class TransformVisitor final : public ParserVisitor
class TransformVisitor final : public source::ParserVisitor
{
void visit(Node *node) override;
void visit(Definition *definition) override;
void visit(BangStatement *statement) override;
void visit(Block *block) override;
void visit(Expression *expression) override;
void visit(Number *number) override;
void visit(Variable *variable) override;
void visit(BinaryExpression *binaryExpression) override;
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 *variable) override;
void visit(source::binary_expression *binaryExpression) override;
};
}

View File

@ -1,115 +0,0 @@
#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.
*/
struct source
{
class const_iterator
{
std::string::const_iterator m_buffer;
elna::source::position m_position;
const_iterator(std::string::const_iterator buffer,
const elna::source::position start_position = elna::source::position());
public:
using iterator_category = std::forward_iterator_tag;
using difference_type = ptrdiff_t;
using value_type = char;
using pointer = const value_type *;
using reference = const value_type&;
const elna::source::position& position() const noexcept;
reference operator*() const noexcept;
pointer operator->() const noexcept;
const_iterator& operator++();
const_iterator& operator++(int);
bool operator==(const const_iterator& that) const noexcept;
bool operator!=(const const_iterator& that) const noexcept;
friend source;
};
source(const std::string& buffer);
const_iterator begin() const;
const_iterator end() const;
private:
const std::string m_buffer;
};
/**
* Union type representing a single token.
*/
struct Token
{
/**
* Token type.
*/
enum class type : std::uint16_t
{
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,
};
/**
* Type of the token value.
*/
union Value
{
std::int32_t number;
const char *identifier;
};
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();
Token& operator=(const Token& that);
Token& operator=(Token&& that);
type of() const noexcept;
const char *identifier() const noexcept;
std::int32_t number() const noexcept;
const elna::source::position& position() const noexcept;
private:
type m_type;
Value m_value;
elna::source::position m_position;
};
/**
* Split the source into tokens.
*
* \param buffer Source text.
* \return Tokens or error.
*/
elna::source::result<std::vector<Token>> lex(const char *buffer);
}
}

View File

@ -1,125 +0,0 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <elna/lexer.hpp>
namespace elna
{
enum class BinaryOperator
{
sum,
subtraction,
multiplication,
division
};
class Node;
class Definition;
class BangStatement;
class Block;
class Expression;
class BinaryExpression;
class Variable;
class Number;
struct ParserVisitor
{
virtual void visit(Node *) = 0;
virtual void visit(Definition *) = 0;
virtual void visit(BangStatement *) = 0;
virtual void visit(Block *) = 0;
virtual void visit(Expression *) = 0;
virtual void visit(BinaryExpression *) = 0;
virtual void visit(Variable *) = 0;
virtual void visit(Number *) = 0;
};
/**
* AST node.
*/
class Node
{
public:
virtual void accept(ParserVisitor *) = 0;
};
class Statement : public Node
{
};
/**
* Constant definition.
*/
class Definition : public Node
{
public:
Number *number;
const char *identifier;
virtual void accept(ParserVisitor *visitor) override;
};
class BangStatement : public Statement
{
public:
Expression *expression;
virtual void accept(ParserVisitor *visitor) override;
};
/**
* Block.
*/
class Block : public Node
{
public:
Definition** definitions{ nullptr };
size_t definitionsLength{ 0 };
Statement *statement{ nullptr };
virtual void accept(ParserVisitor *visitor) override;
};
class Expression : public Node
{
public:
virtual void accept(ParserVisitor *visitor) override;
};
class Number : public Expression
{
public:
std::int32_t value;
virtual void accept(ParserVisitor *visitor) override;
};
class Variable : public Expression
{
public:
const char *identifier;
virtual void accept(ParserVisitor *visitor) override;
};
class BinaryExpression : public Expression
{
public:
Expression *lhs, *rhs;
BinaryOperator _operator;
BinaryExpression(Expression *lhs, Expression *rhs, unsigned char);
virtual void accept(ParserVisitor *visitor) override;
};
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,7 +1,8 @@
#pragma once
#include <cstdint>
#include "elna/parser.hpp"
#include <unordered_map>
#include "elna/source/parser.hpp"
#include "elna/result.hpp"
namespace elna
@ -141,7 +142,7 @@ namespace elna
std::uint32_t instruction{ 0 };
};
class RiscVVisitor : public ParserVisitor
class RiscVVisitor : public source::ParserVisitor
{
public:
Instruction *instructions;
@ -149,19 +150,15 @@ namespace elna
bool registerInUse{ true };
std::uint32_t variableCounter = 1;
Reference references[3];
std::int32_t *constValues{ nullptr };
const char **constNames{ nullptr };
std::size_t constCount{ 0 };
std::unordered_map<std::string, std::int32_t> constants;
virtual void visit(Node *) override;
virtual void visit(Definition *definition) override;
virtual void visit(BangStatement *statement) override;
virtual void visit(Block *block) override;
virtual void visit(Expression *operand) override;
virtual void visit(Variable *variable) override;
virtual void visit(Number *number) override;
virtual void visit(BinaryExpression *expression) override;
virtual void visit(source::definition *definition) override;
virtual void visit(source::bang_statement *statement) override;
virtual void visit(source::block *block) override;
virtual void visit(source::variable *variable) override;
virtual void visit(source::integer_literal *number) override;
virtual void visit(source::binary_expression *expression) override;
};
Symbol writeNext(Block *ast);
Symbol writeNext(source::block *ast);
}

View File

@ -0,0 +1,116 @@
#pragma once
#include <cstdint>
#include <string>
#include "elna/result.hpp"
namespace elna
{
namespace source
{
/**
* Range over the source text that keeps track of the current position.
*/
class text_iterator
{
std::string::const_iterator m_buffer;
elna::source::position m_position;
text_iterator(std::string::const_iterator buffer,
const elna::source::position start_position = elna::source::position());
public:
using iterator_category = std::forward_iterator_tag;
using difference_type = ptrdiff_t;
using value_type = char;
using pointer = const value_type *;
using reference = const value_type&;
const elna::source::position& position() const noexcept;
reference operator*() const noexcept;
pointer operator->() const noexcept;
text_iterator& operator++();
text_iterator& operator++(int);
bool operator==(const text_iterator& that) const noexcept;
bool operator!=(const text_iterator& that) const noexcept;
friend std::pair<text_iterator, text_iterator> text_iterators(const std::string& buffer);
};
std::pair<text_iterator, text_iterator>
text_iterators(const std::string &buffer);
/**
* Union type representing a single token.
*/
struct token
{
/**
* Token type.
*/
enum class type : std::uint16_t
{
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,
};
/**
* Type of the token value.
*/
union value
{
value();
value(std::int32_t value);
value(const std::string& value);
~value();
std::nullptr_t nil;
std::int32_t number;
std::string identifier;
};
token(type of, elna::source::position position);
token(type of, std::int32_t value, const elna::source::position position);
token(type of, const std::string& value, const elna::source::position position);
token(const token& that);
token(token&& that);
~token();
token& operator=(const token& that);
token& operator=(token&& that);
type of() const noexcept;
const std::string& identifier() const;
std::int32_t number() const;
const elna::source::position& position() const noexcept;
private:
type m_type;
value m_value;
elna::source::position m_position;
bool has_identifier() const noexcept;
};
/**
* Split the source into tokens.
*
* \param buffer Source text.
* \return Tokens or error.
*/
elna::source::result<std::vector<token>> lex(const std::string& buffer);
}
}

View File

@ -0,0 +1,153 @@
#pragma once
#include <cstdint>
#include <memory>
#include <elna/source/lexer.hpp>
namespace elna
{
namespace source
{
enum class binary_operator
{
sum,
subtraction,
multiplication,
division
};
class definition;
class bang_statement;
class block;
class binary_expression;
class variable;
class integer_literal;
struct ParserVisitor
{
virtual void visit(definition *) = 0;
virtual void visit(bang_statement *) = 0;
virtual void visit(block *) = 0;
virtual void visit(binary_expression *) = 0;
virtual void visit(variable *) = 0;
virtual void visit(integer_literal *) = 0;
};
/**
* AST node.
*/
class node
{
public:
virtual void accept(ParserVisitor *) = 0;
};
class statement : public node
{
};
class expression : public node
{
};
/**
* Constant definition.
*/
class definition : public node
{
std::string m_identifier;
std::unique_ptr<integer_literal> m_body;
public:
definition(std::string&& identifier, std::unique_ptr<integer_literal>&& body);
virtual void accept(ParserVisitor *visitor) override;
std::string& identifier() noexcept;
integer_literal& body();
};
class bang_statement : public statement
{
std::unique_ptr<expression> m_body;
public:
bang_statement(std::unique_ptr<expression>&& body);
virtual void accept(ParserVisitor *visitor) override;
expression& body();
};
/**
* Block.
*/
class block : public node
{
std::unique_ptr<statement> m_body;
std::vector<std::unique_ptr<definition>> m_definitions;
public:
block(std::vector<std::unique_ptr<definition>>&& definitions, std::unique_ptr<statement>&& body);
virtual void accept(ParserVisitor *visitor) override;
statement& body();
std::vector<std::unique_ptr<definition>>& definitions() noexcept;
};
class integer_literal : public expression
{
std::int32_t m_number;
public:
integer_literal(const std::int32_t value);
virtual void accept(ParserVisitor *visitor) override;
std::int32_t number() const noexcept;
};
class variable : public expression
{
std::string m_name;
public:
variable(const std::string& name);
virtual void accept(ParserVisitor *visitor) override;
const std::string& name() const noexcept;
};
class binary_expression : public expression
{
std::unique_ptr<expression> m_lhs;
std::unique_ptr<expression> m_rhs;
binary_operator m_operator;
public:
binary_expression(std::unique_ptr<expression>&& lhs,
std::unique_ptr<expression>&& rhs, const unsigned char operation);
virtual void accept(ParserVisitor *visitor) override;
expression& lhs();
expression& rhs();
binary_operator operation() const noexcept;
};
struct parser
{
parser(const std::vector<token>& tokens);
std::unique_ptr<block> parse();
private:
std::unique_ptr<expression> parse_factor();
std::unique_ptr<expression> parse_term();
std::unique_ptr<expression> parse_expression();
std::unique_ptr<definition> parse_definition();
std::unique_ptr<statement> parse_bang_statement();
std::vector<std::unique_ptr<definition>> parse_definitions();
std::unique_ptr<block> parse_block();
std::vector<token>::const_iterator tokens;
std::vector<token>::const_iterator end;
};
}
}

View File

@ -41,7 +41,7 @@ namespace elna
return 3;
}
size_t tokensCount{ 0 };
auto lex_result = lex::lex(sourceText);
auto lex_result = source::lex(sourceText);
free(sourceText);
if (lex_result.has_errors())
{
@ -51,12 +51,12 @@ namespace elna
}
return 1;
}
auto ast = parse(lex_result.success().data(), tokensCount);
auto ast = source::parser(lex_result.success()).parse();
if (ast == nullptr)
{
return 2;
}
auto program = writeNext(ast);
auto program = writeNext(ast.get());
// Create code section
ELFIO::section* text_sec = writer.sections.add(".text");

View File

@ -4,42 +4,32 @@
namespace elna
{
void TransformVisitor::visit(Node *node)
void TransformVisitor::visit(source::definition *definition)
{
assert(false);
}
void TransformVisitor::visit(Definition *definition)
void TransformVisitor::visit(source::bang_statement *statement)
{
assert(false);
}
void TransformVisitor::visit(BangStatement *statement)
void TransformVisitor::visit(source::block *block)
{
assert(false);
}
void TransformVisitor::visit(Block *block)
void TransformVisitor::visit(source::integer_literal *number)
{
assert(false);
}
void TransformVisitor::visit(Expression *expression)
void TransformVisitor::visit(source::variable *variable)
{
assert(false);
}
void TransformVisitor::visit(Number *number)
{
assert(false);
}
void TransformVisitor::visit(Variable *variable)
{
assert(false);
}
void TransformVisitor::visit(BinaryExpression *binaryExpression)
void TransformVisitor::visit(source::binary_expression *binaryExpression)
{
assert(false);
}

View File

@ -1,54 +1,42 @@
#include "elna/lexer.hpp"
#include <cstring>
#include "elna/source/lexer.hpp"
#include <variant>
namespace elna
{
namespace lex
namespace source
{
using source_position = elna::source::position;
using source_error = elna::source::error;
using source_result = elna::source::result<std::vector<Token>>;
using source_result = elna::source::result<std::vector<token>>;
source::source(const std::string& buffer)
: m_buffer(buffer)
std::pair<text_iterator, text_iterator> text_iterators(const std::string &buffer)
{
return std::make_pair<>(text_iterator(std::cbegin(buffer)),
text_iterator(std::cend(buffer), position{0, 0}));
}
source::const_iterator source::begin() const
{
return source::const_iterator(std::cbegin(m_buffer));
}
source::const_iterator source::end() const
{
source_position end_position{ 0, 0 };
return source::const_iterator(std::cend(m_buffer), end_position);
}
source::const_iterator::const_iterator(std::string::const_iterator buffer,
text_iterator::text_iterator(std::string::const_iterator buffer,
const source_position start_position)
: m_buffer(buffer), m_position(start_position)
{
}
const source_position& source::const_iterator::position() const noexcept
const source_position& text_iterator::position() const noexcept
{
return this->m_position;
}
source::const_iterator::reference source::const_iterator::operator*() const noexcept
text_iterator::reference text_iterator::operator*() const noexcept
{
return *m_buffer;
}
source::const_iterator::pointer source::const_iterator::operator->() const noexcept
text_iterator::pointer text_iterator::operator->() const noexcept
{
return m_buffer.base();
}
source::const_iterator& source::const_iterator::operator++()
text_iterator& text_iterator::operator++()
{
if (*this->m_buffer == '\n')
{
@ -64,129 +52,156 @@ namespace lex
return *this;
}
source::const_iterator& source::const_iterator::operator++(int)
text_iterator& text_iterator::operator++(int)
{
auto tmp = *this;
++(*this);
return *this;
}
bool source::const_iterator::operator==(const source::const_iterator& that) const noexcept
bool text_iterator::operator==(const text_iterator& that) const noexcept
{
return this->m_buffer == that.m_buffer;
}
bool source::const_iterator::operator!=(const source::const_iterator& that) const noexcept
bool text_iterator::operator!=(const text_iterator& that) const noexcept
{
return !(*this == that);
}
Token::Token(const type of, const char *value, source_position position)
: m_type(of), m_position(position)
token::value::value()
: nil(nullptr)
{
std::size_t value_length = strlen(value);
char *buffer = reinterpret_cast<char *>(malloc(value_length + 1));
std::memcpy(buffer, value, value_length);
buffer[value_length] = 0;
m_value.identifier = buffer;
}
Token::Token(const type of, std::int32_t number, source_position position)
: m_type(of), m_position(position)
token::value::value(std::int32_t value)
: number(value)
{
m_value.number = number;
}
Token::Token(const type of, source_position position)
token::value::value(const std::string& value)
: identifier(value)
{
}
token::value::~value()
{
}
token::token(const type of, const std::string& value, const source_position position)
: m_type(of), m_value(value), m_position(position)
{
}
token::token(const type of, std::int32_t number, const source_position position)
: m_type(of), m_value(number), m_position(position)
{
}
token::token(const type of, source_position position)
: m_type(of), m_position(position)
{
}
Token::Token(const Token& that)
token::token(const token& that)
: m_type(that.of()), m_position(that.position())
{
*this = that;
}
Token::Token(Token&& that)
token::token(token&& that)
: m_type(that.of()), m_position(that.position())
{
*this = std::move(that);
}
Token::~Token()
token::~token()
{
if (m_type == type::identifier || m_type == type::term_operator || m_type == type::factor_operator)
{
std::free(const_cast<char*>(m_value.identifier));
m_value.identifier.~basic_string();
}
}
Token& Token::operator=(const Token& that)
token& token::operator=(const token& that)
{
m_type = that.of();
m_position = that.position();
if (that.of() == type::identifier || that.of() == type::term_operator || m_type == type::factor_operator)
{
std::size_t value_length = strlen(that.identifier());
char *buffer = reinterpret_cast<char *>(malloc(value_length + 1));
std::memcpy(buffer, that.identifier(), value_length);
buffer[value_length] = 0;
m_value.identifier = buffer;
}
else if (that.of() == type::number)
{
m_value.number = that.number();
}
return *this;
}
Token& Token::operator=(Token&& that)
{
m_type = that.of();
m_position = that.position();
if (that.of() == type::identifier || that.of() == type::term_operator || that.of() == type::factor_operator)
if (that.has_identifier())
{
m_value.identifier = that.identifier();
that.m_value.identifier = nullptr;
}
else if (that.of() == type::number)
{
m_value.number = that.number();
}
else
{
m_value.nil = nullptr;
}
return *this;
}
Token::type Token::of() const noexcept
token& token::operator=(token&& that)
{
m_type = that.of();
m_position = that.position();
if (that.has_identifier())
{
m_value.identifier = std::move(that.identifier());
}
else if (that.of() == type::number)
{
m_value.number = that.number();
}
else
{
m_value.nil = nullptr;
}
return *this;
}
token::type token::of() const noexcept
{
return m_type;
}
const char *Token::identifier() const noexcept
const std::string& token::identifier() const
{
if (!has_identifier())
{
throw std::bad_variant_access();
}
return m_value.identifier;
}
std::int32_t Token::number() const noexcept
std::int32_t token::number() const
{
if (of() != type::number)
{
throw std::bad_variant_access();
}
return m_value.number;
}
const source_position& Token::position() const noexcept
const source_position& token::position() const noexcept
{
return m_position;
}
source_result lex(const char *buffer)
bool token::has_identifier() const noexcept
{
std::vector<Token> tokens;
source input{ buffer };
return of() == type::identifier
|| of() == type::term_operator
|| of() == type::factor_operator;
}
for (auto iterator = input.begin(); iterator != input.end();)
source_result lex(const std::string& buffer)
{
std::vector<token> tokens;
auto [iterator, text_end] = text_iterators(buffer);
while (iterator != text_end)
{
if (*iterator == ' ' || *iterator == '\n')
{
@ -194,59 +209,59 @@ namespace lex
else if (std::isdigit(*iterator))
{
tokens.emplace_back(
Token::type::number,
token::type::number,
static_cast<std::int32_t>(*iterator - '0'),
iterator.position()
);
}
else if (*iterator == '=')
{
tokens.emplace_back(Token::type::equals, iterator.position());
tokens.emplace_back(token::type::equals, iterator.position());
}
else if (*iterator == '(')
{
tokens.emplace_back(Token::type::left_paren, iterator.position());
tokens.emplace_back(token::type::left_paren, iterator.position());
}
else if (*iterator == ')')
{
tokens.emplace_back(Token::type::right_paren, iterator.position());
tokens.emplace_back(token::type::right_paren, iterator.position());
}
else if (*iterator == ';')
{
tokens.emplace_back(Token::type::semicolon, iterator.position());
tokens.emplace_back(token::type::semicolon, iterator.position());
}
else if (*iterator == ',')
{
tokens.emplace_back(Token::type::comma, iterator.position());
tokens.emplace_back(token::type::comma, iterator.position());
}
else if (*iterator == '!')
{
tokens.emplace_back(Token::type::bang, iterator.position());
tokens.emplace_back(token::type::bang, iterator.position());
}
else if (*iterator == '.')
{
tokens.emplace_back(Token::type::dot, iterator.position());
tokens.emplace_back(token::type::dot, iterator.position());
}
else if (std::isalpha(*iterator))
{
std::string word;
auto i = iterator;
while (i != input.end() && std::isalpha(*i))
while (i != text_end && std::isalpha(*i))
{
word.push_back(*i);
++i;
}
if (word == "const")
{
tokens.emplace_back(Token::type::let, iterator.position());
tokens.emplace_back(token::type::let, iterator.position());
}
else if (word == "var")
{
tokens.emplace_back(Token::type::var, iterator.position());
tokens.emplace_back(token::type::var, iterator.position());
}
else
{
tokens.emplace_back(Token::type::identifier, word.c_str(), iterator.position());
tokens.emplace_back(token::type::identifier, word.c_str(), iterator.position());
}
iterator = i;
continue;
@ -255,13 +270,13 @@ namespace lex
{
std::string _operator{ *iterator };
tokens.emplace_back(Token::type::term_operator, _operator.c_str(), iterator.position());
tokens.emplace_back(token::type::term_operator, _operator.c_str(), iterator.position());
}
else if (*iterator == '*' || *iterator == '/')
{
std::string _operator{ *iterator };
tokens.emplace_back(Token::type::factor_operator, _operator.c_str(), iterator.position());
tokens.emplace_back(token::type::factor_operator, _operator.c_str(), iterator.position());
}
else
{

View File

@ -1,254 +1,294 @@
#include "elna/parser.hpp"
#include "elna/source/parser.hpp"
#include <stdexcept>
namespace elna
{
namespace source
{
/**
* AST node.
*/
void Node::accept(ParserVisitor *)
void node::accept(ParserVisitor *)
{
}
void Definition::accept(ParserVisitor *visitor)
definition::definition(std::string&& identifier, std::unique_ptr<integer_literal>&& body)
: m_identifier(std::move(identifier)), m_body(std::move(body))
{
}
void definition::accept(ParserVisitor *visitor)
{
visitor->visit(this);
}
void Block::accept(ParserVisitor *visitor)
std::string& definition::identifier() noexcept
{
return m_identifier;
}
integer_literal& definition::body()
{
return *m_body;
}
block::block(std::vector<std::unique_ptr<definition>>&& definitions, std::unique_ptr<statement>&& body)
: m_definitions(std::move(definitions)), m_body(std::move(body))
{
}
void block::accept(ParserVisitor *visitor)
{
visitor->visit(this);
}
void Expression::accept(ParserVisitor *visitor)
statement& block::body()
{
return *m_body;
}
std::vector<std::unique_ptr<definition>>& block::definitions() noexcept
{
return m_definitions;
}
integer_literal::integer_literal(const std::int32_t value)
: m_number(value)
{
}
void integer_literal::accept(ParserVisitor *visitor)
{
visitor->visit(this);
}
void Number::accept(ParserVisitor *visitor)
std::int32_t integer_literal::number() const noexcept
{
return m_number;
}
variable::variable(const std::string& name)
: m_name(name)
{
}
void variable::accept(ParserVisitor *visitor)
{
visitor->visit(this);
}
void Variable::accept(ParserVisitor *visitor)
const std::string& variable::name() const noexcept
{
visitor->visit(this);
return m_name;
}
BinaryExpression::BinaryExpression(Expression *lhs, Expression *rhs, unsigned char _operator)
binary_expression::binary_expression(std::unique_ptr<expression>&& lhs,
std::unique_ptr<expression>&& rhs, const unsigned char operation)
: m_lhs(std::move(lhs)), m_rhs(std::move(rhs))
{
this->lhs = lhs;
this->rhs = rhs;
switch (_operator)
switch (operation)
{
case '+':
this->_operator = BinaryOperator::sum;
this->m_operator = binary_operator::sum;
break;
case '-':
this->_operator = BinaryOperator::subtraction;
this->m_operator = binary_operator::subtraction;
break;
case '*':
this->_operator = BinaryOperator::multiplication;
this->m_operator = binary_operator::multiplication;
break;
case '/':
this->_operator = BinaryOperator::division;
this->m_operator = binary_operator::division;
break;
default:
throw std::logic_error("Invalid binary operator");
}
}
void BinaryExpression::accept(ParserVisitor *visitor)
void binary_expression::accept(ParserVisitor *visitor)
{
visitor->visit(this);
}
void BangStatement::accept(ParserVisitor *visitor)
expression& binary_expression::lhs()
{
return *m_lhs;
}
expression& binary_expression::rhs()
{
return *m_rhs;
}
binary_operator binary_expression::operation() const noexcept
{
return m_operator;
}
bang_statement::bang_statement(std::unique_ptr<expression>&& body)
: m_body(std::move(body))
{
}
void bang_statement::accept(ParserVisitor *visitor)
{
visitor->visit(this);
}
Block *parse(lex::Token *tokenStream, std::size_t length)
expression& bang_statement::body()
{
return parseBlock(&tokenStream, &length);
return *m_body;
}
Expression *parseFactor(lex::Token **tokens, size_t *length)
parser::parser(const std::vector<token>& tokens)
: tokens(tokens.cbegin()), end(tokens.cend())
{
if ((*tokens)[0].of() == lex::Token::type::identifier)
{
auto variable = new Variable();
variable->identifier = (*tokens)[0].identifier();
++(*tokens);
--(*length);
return variable;
}
else if ((*tokens)[0].of() == lex::Token::Token::type::number)
std::unique_ptr<block> parser::parse()
{
auto number = new Number();
number->value = (*tokens)[0].number();
++(*tokens);
--(*length);
return number;
return parse_block();
}
else if ((*tokens)[0].of() == lex::Token::type::left_paren)
std::unique_ptr<expression> parser::parse_factor()
{
++(*tokens);
--(*length);
if (tokens->of() == source::token::type::identifier)
{
auto result = std::make_unique<variable>(tokens->identifier());
++tokens;
return result;
}
else if (tokens->of() == source::token::token::type::number)
{
auto result = std::make_unique<integer_literal>(tokens->number());
++tokens;
return result;
}
else if (tokens->of() == source::token::type::left_paren)
{
++tokens;
auto expression = parseExpression(tokens, length);
auto expression = parse_expression();
++(*tokens);
--(*length);
++tokens;
return expression;
}
return nullptr;
}
Expression *parseTerm(lex::Token **tokens, size_t *length)
std::unique_ptr<expression> parser::parse_term()
{
auto lhs = parseFactor(tokens, length);
if (lhs == nullptr || *length == 0 || (*tokens)[0].of() != lex::Token::type::factor_operator)
auto lhs = parse_factor();
if (lhs == nullptr || tokens == end || tokens->of() != source::token::type::factor_operator)
{
return lhs;
}
auto _operator = (*tokens)[0].identifier()[0];
++(*tokens);
--(*length);
auto _operator = tokens->identifier()[0];
++tokens;
auto rhs = parseFactor(tokens, length);
auto rhs = parse_factor();
if (rhs != nullptr)
{
return new BinaryExpression(lhs, rhs, _operator);
return std::make_unique<binary_expression>(std::move(lhs),
std::move(rhs), _operator);
}
return nullptr;
}
Expression *parseExpression(lex::Token **tokens, size_t *length)
std::unique_ptr<expression> parser::parse_expression()
{
auto term = parseTerm(tokens, length);
if (term == nullptr || *length == 0 || (*tokens)[0].of() != lex::Token::type::term_operator)
auto term = parse_term();
if (term == nullptr || tokens == end || tokens->of() != source::token::type::term_operator)
{
return term;
}
auto _operator = (*tokens)[0].identifier()[0];
++(*tokens);
--(*length);
auto _operator = tokens->identifier()[0];
++tokens;
auto expression = parseExpression(tokens, length);
auto rhs = parse_expression();
if (expression != nullptr)
if (rhs != nullptr)
{
return new BinaryExpression(term, expression, _operator);
return std::make_unique<binary_expression>(std::move(term),
std::move(rhs), _operator);
}
return nullptr;
}
Definition *parseDefinition(lex::Token **tokens, size_t *length)
std::unique_ptr<definition> parser::parse_definition()
{
auto definition = new Definition();
definition->identifier = (*tokens)[0].identifier(); // Copy.
std::string definition_identifier = tokens->identifier(); // Copy.
++(*tokens);
++(*tokens); // Skip the equals sign.
*length -= 2;
++tokens;
++tokens; // Skip the equals sign.
if ((*tokens)[0].of() == lex::Token::type::number)
if (tokens->of() == source::token::type::number)
{
auto number = new Number();
number->value = (*tokens)[0].number();
definition->number = number;
++(*tokens);
--(*length);
return definition;
auto result = std::make_unique<definition>(std::move(definition_identifier),
std::make_unique<integer_literal>(tokens->number()));
++tokens;
return result;
}
return nullptr;
}
Statement *parseStatement(lex::Token **tokens, std::size_t *length)
std::unique_ptr<statement> parser::parse_bang_statement()
{
if ((*tokens)[0].of() == lex::Token::type::bang)
if (tokens->of() == source::token::type::bang)
{
++(*tokens);
--(*length);
auto statement = new BangStatement();
auto expression = parseExpression(tokens, length);
if (expression != nullptr)
++tokens;
auto bang_body = parse_expression();
if (bang_body != nullptr)
{
statement->expression = expression;
return std::make_unique<bang_statement>(std::move(bang_body));
}
else
{
return nullptr;
}
return statement;
}
return nullptr;
}
Definition **parseDefinitions(lex::Token **tokens, size_t *length, size_t *resultLength)
std::vector<std::unique_ptr<definition>> parser::parse_definitions()
{
++(*tokens); // Skip const.
--(*length);
++tokens; // Skip const.
Definition **definitions;
*resultLength = 0;
std::vector<std::unique_ptr<definition>> definitions;
while (*length != 0)
while (tokens != end)
{
auto definition = parseDefinition(tokens, length);
if (definition == nullptr)
auto parsed_definition = parse_definition();
if (parsed_definition == nullptr)
{
return nullptr;
return definitions;
}
definitions = reinterpret_cast<Definition **>(
realloc(definitions, (*resultLength + 1) * sizeof(Definition*)));
definitions[(*resultLength)++] = definition;
definitions.push_back(std::move(parsed_definition));
if ((*tokens)[0].of() == lex::Token::type::semicolon)
if (tokens->of() == source::token::type::semicolon)
{
break;
}
if ((*tokens)[0].of() == lex::Token::type::comma)
if (tokens->of() == source::token::type::comma)
{
++(*tokens);
--(*length);
++tokens;
}
}
return definitions;
}
Block *parseBlock(lex::Token **tokens, std::size_t *length)
std::unique_ptr<block> parser::parse_block()
{
auto block = new Block();
if ((*tokens)[0].of() == lex::Token::type::let)
std::vector<std::unique_ptr<definition>> definitions;
if (tokens->of() == source::token::type::let)
{
size_t length_ = 0;
auto constDefinitions = parseDefinitions(tokens, length, &length_);
if (constDefinitions != nullptr)
{
block->definitionsLength = length_;
block->definitions = constDefinitions;
definitions = parse_definitions();
++tokens;
}
else
auto parsed_statement = parse_bang_statement();
if (parsed_statement == nullptr)
{
return nullptr;
}
++(*tokens);
--(*length);
}
auto statement = parseStatement(tokens, length);
if (statement != nullptr)
{
block->statement = statement;
}
else
{
return nullptr;
}
return block;
return std::make_unique<block>(std::move(definitions), std::move(parsed_statement));
}
}
}

View File

@ -1,4 +1,3 @@
#include "elna/parser.hpp"
#include "elna/riscv.hpp"
#include <memory>
#include <cstring>
@ -59,31 +58,22 @@ namespace elna
return reinterpret_cast<std::byte *>(&this->instruction) + sizeof(this->instruction);
}
void RiscVVisitor::visit(Node *)
void RiscVVisitor::visit(source::definition *definition)
{
constants[definition->identifier()] = definition->body().number();
}
void RiscVVisitor::visit(Definition *definition)
void RiscVVisitor::visit(source::block *block)
{
++constCount;
constNames = reinterpret_cast<const char **>(realloc(constNames, sizeof(const char *) * constCount));
constValues = reinterpret_cast<std::int32_t *>(realloc(constValues, sizeof(std::int32_t) * constCount));
constNames[constCount - 1] = definition->identifier;
constValues[constCount - 1] = definition->number->value;
}
void RiscVVisitor::visit(Block *block)
for (const auto& block_definition : block->definitions())
{
for (std::size_t i = 0; i < block->definitionsLength; ++i)
{
block->definitions[i]->accept(this);
block_definition->accept(this);
}
this->instructionsLength += 4;
this->instructions = reinterpret_cast<Instruction *>(
realloc(this->instructions, this->instructionsLength * sizeof(Instruction)));
block->statement->accept(this);
block->body().accept(this);
// Prologue.
const uint stackSize = static_cast<std::uint32_t>(variableCounter * 4 + 12);
@ -137,44 +127,12 @@ namespace elna
.i(XRegister::zero, Funct3::jalr, XRegister::ra, 0);
}
void RiscVVisitor::visit(BangStatement *statement)
void RiscVVisitor::visit(source::bang_statement *statement)
{
statement->expression->accept(this);
statement->body().accept(this);
}
void RiscVVisitor::visit(Expression *operand)
{
if (dynamic_cast<Variable *>(operand) != nullptr)
{
return dynamic_cast<Variable *>(operand)->accept(this);
}
if (dynamic_cast<Number *>(operand) != nullptr)
{
return dynamic_cast<Number *>(operand)->accept(this);
}
}
void RiscVVisitor::visit(Variable *variable)
{
std::size_t i = 0;
for (; i < constCount; ++i)
{
if (std::strcmp(variable->identifier, constNames[i]) == 0)
{
break;
}
}
const auto freeRegister = this->registerInUse ? XRegister::a0 : XRegister::t0;
++this->instructionsLength;
this->instructions = reinterpret_cast<Instruction *>(
realloc(this->instructions, this->instructionsLength * sizeof(Instruction)));
this->instructions[this->instructionsLength - 1] =
Instruction(BaseOpcode::opImm) // movl $x, %eax; where $x is a number.
.i(freeRegister, Funct3::addi, XRegister::zero, constValues[i]);
}
void RiscVVisitor::visit(Number *number)
void RiscVVisitor::visit(source::variable *variable)
{
const auto freeRegister = this->registerInUse ? XRegister::a0 : XRegister::t0;
@ -183,15 +141,27 @@ namespace elna
realloc(this->instructions, this->instructionsLength * sizeof(Instruction)));
this->instructions[this->instructionsLength - 1] =
Instruction(BaseOpcode::opImm) // movl $x, %eax; where $x is a number.
.i(freeRegister, Funct3::addi, XRegister::zero, number->value);
.i(freeRegister, Funct3::addi, XRegister::zero, constants[variable->name()]);
}
void RiscVVisitor::visit(BinaryExpression *expression)
void RiscVVisitor::visit(source::integer_literal *number)
{
const auto freeRegister = this->registerInUse ? XRegister::a0 : XRegister::t0;
++this->instructionsLength;
this->instructions = reinterpret_cast<Instruction *>(
realloc(this->instructions, this->instructionsLength * sizeof(Instruction)));
this->instructions[this->instructionsLength - 1] =
Instruction(BaseOpcode::opImm) // movl $x, %eax; where $x is a number.
.i(freeRegister, Funct3::addi, XRegister::zero, number->number());
}
void RiscVVisitor::visit(source::binary_expression *expression)
{
const auto lhs_register = this->registerInUse ? XRegister::a0 : XRegister::t0;
this->registerInUse = true;
expression->lhs->accept(this);
expression->lhs().accept(this);
++this->instructionsLength;
this->instructions = reinterpret_cast<Instruction *>(
@ -202,7 +172,7 @@ namespace elna
auto lhs_stack_position = ++this->variableCounter;
this->registerInUse = false;
expression->rhs->accept(this);
expression->rhs().accept(this);
this->instructionsLength += 2;
this->instructions = reinterpret_cast<Instruction *>(
@ -213,24 +183,24 @@ namespace elna
static_cast<std::int8_t>((lhs_stack_position - 1) * 4));
// Calculate the result and assign it to a variable on the stack.
switch (expression->_operator)
switch (expression->operation())
{
case BinaryOperator::sum:
case source::binary_operator::sum:
this->instructions[instructionsLength - 1] = Instruction(BaseOpcode::op)
.r(lhs_register, Funct3::add, XRegister::a0, XRegister::t0);
break;
case BinaryOperator::subtraction:
case source::binary_operator::subtraction:
this->instructions[instructionsLength - 1] = Instruction(BaseOpcode::op)
.r(lhs_register, Funct3::sub, XRegister::a0, XRegister::t0, Funct7::sub);
break;
case BinaryOperator::multiplication:
case source::binary_operator::multiplication:
this->instructions[instructionsLength - 1] = Instruction(BaseOpcode::op)
.r(lhs_register, Funct3::mul, XRegister::a0, XRegister::t0, Funct7::muldiv);
break;
}
}
Symbol writeNext(Block *ast)
Symbol writeNext(source::block *ast)
{
auto visitor = std::make_unique<RiscVVisitor>();
visitor->visit(ast);