Get rid of the raw pointers in the parser
This commit is contained in:
parent
632dc53b53
commit
f84fd91426
@ -19,10 +19,10 @@ add_executable(elnsh shell/main.cpp
|
|||||||
target_include_directories(elnsh PRIVATE include)
|
target_include_directories(elnsh PRIVATE include)
|
||||||
|
|
||||||
add_executable(elna source/main.cpp
|
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/result.cpp include/elna/result.hpp
|
||||||
source/riscv.cpp include/elna/riscv.hpp
|
source/riscv.cpp include/elna/riscv.hpp
|
||||||
source/parser.cpp include/elna/parser.hpp
|
|
||||||
source/ir.cpp include/elna/ir.hpp
|
source/ir.cpp include/elna/ir.hpp
|
||||||
source/cl.cpp include/elna/cl.hpp
|
source/cl.cpp include/elna/cl.hpp
|
||||||
)
|
)
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "elna/parser.hpp"
|
#include "elna/source/parser.hpp"
|
||||||
|
|
||||||
namespace elna
|
namespace elna
|
||||||
{
|
{
|
||||||
class TransformVisitor final : public ParserVisitor
|
class TransformVisitor final : public source::ParserVisitor
|
||||||
{
|
{
|
||||||
void visit(Node *node) override;
|
void visit(source::definition *definition) override;
|
||||||
void visit(Definition *definition) override;
|
void visit(source::bang_statement *statement) override;
|
||||||
void visit(BangStatement *statement) override;
|
void visit(source::block *block) override;
|
||||||
void visit(Block *block) override;
|
void visit(source::integer_literal *number) override;
|
||||||
void visit(Expression *expression) override;
|
void visit(source::variable *variable) override;
|
||||||
void visit(Number *number) override;
|
void visit(source::binary_expression *binaryExpression) override;
|
||||||
void visit(Variable *variable) override;
|
|
||||||
void visit(BinaryExpression *binaryExpression) override;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
@ -1,7 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "elna/parser.hpp"
|
#include <unordered_map>
|
||||||
|
#include "elna/source/parser.hpp"
|
||||||
#include "elna/result.hpp"
|
#include "elna/result.hpp"
|
||||||
|
|
||||||
namespace elna
|
namespace elna
|
||||||
@ -141,7 +142,7 @@ namespace elna
|
|||||||
std::uint32_t instruction{ 0 };
|
std::uint32_t instruction{ 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
class RiscVVisitor : public ParserVisitor
|
class RiscVVisitor : public source::ParserVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Instruction *instructions;
|
Instruction *instructions;
|
||||||
@ -149,19 +150,15 @@ namespace elna
|
|||||||
bool registerInUse{ true };
|
bool registerInUse{ true };
|
||||||
std::uint32_t variableCounter = 1;
|
std::uint32_t variableCounter = 1;
|
||||||
Reference references[3];
|
Reference references[3];
|
||||||
std::int32_t *constValues{ nullptr };
|
std::unordered_map<std::string, std::int32_t> constants;
|
||||||
const char **constNames{ nullptr };
|
|
||||||
std::size_t constCount{ 0 };
|
|
||||||
|
|
||||||
virtual void visit(Node *) override;
|
virtual void visit(source::definition *definition) override;
|
||||||
virtual void visit(Definition *definition) override;
|
virtual void visit(source::bang_statement *statement) override;
|
||||||
virtual void visit(BangStatement *statement) override;
|
virtual void visit(source::block *block) override;
|
||||||
virtual void visit(Block *block) override;
|
virtual void visit(source::variable *variable) override;
|
||||||
virtual void visit(Expression *operand) override;
|
virtual void visit(source::integer_literal *number) override;
|
||||||
virtual void visit(Variable *variable) override;
|
virtual void visit(source::binary_expression *expression) override;
|
||||||
virtual void visit(Number *number) override;
|
|
||||||
virtual void visit(BinaryExpression *expression) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Symbol writeNext(Block *ast);
|
Symbol writeNext(source::block *ast);
|
||||||
}
|
}
|
||||||
|
116
include/elna/source/lexer.hpp
Normal file
116
include/elna/source/lexer.hpp
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
153
include/elna/source/parser.hpp
Normal file
153
include/elna/source/parser.hpp
Normal 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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -41,7 +41,7 @@ namespace elna
|
|||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
size_t tokensCount{ 0 };
|
size_t tokensCount{ 0 };
|
||||||
auto lex_result = lex::lex(sourceText);
|
auto lex_result = source::lex(sourceText);
|
||||||
free(sourceText);
|
free(sourceText);
|
||||||
if (lex_result.has_errors())
|
if (lex_result.has_errors())
|
||||||
{
|
{
|
||||||
@ -51,12 +51,12 @@ namespace elna
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
auto ast = parse(lex_result.success().data(), tokensCount);
|
auto ast = source::parser(lex_result.success()).parse();
|
||||||
if (ast == nullptr)
|
if (ast == nullptr)
|
||||||
{
|
{
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
auto program = writeNext(ast);
|
auto program = writeNext(ast.get());
|
||||||
|
|
||||||
// Create code section
|
// Create code section
|
||||||
ELFIO::section* text_sec = writer.sections.add(".text");
|
ELFIO::section* text_sec = writer.sections.add(".text");
|
||||||
|
@ -4,42 +4,32 @@
|
|||||||
|
|
||||||
namespace elna
|
namespace elna
|
||||||
{
|
{
|
||||||
void TransformVisitor::visit(Node *node)
|
void TransformVisitor::visit(source::definition *definition)
|
||||||
{
|
{
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransformVisitor::visit(Definition *definition)
|
void TransformVisitor::visit(source::bang_statement *statement)
|
||||||
{
|
{
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransformVisitor::visit(BangStatement *statement)
|
void TransformVisitor::visit(source::block *block)
|
||||||
{
|
{
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransformVisitor::visit(Block *block)
|
void TransformVisitor::visit(source::integer_literal *number)
|
||||||
{
|
{
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransformVisitor::visit(Expression *expression)
|
void TransformVisitor::visit(source::variable *variable)
|
||||||
{
|
{
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransformVisitor::visit(Number *number)
|
void TransformVisitor::visit(source::binary_expression *binaryExpression)
|
||||||
{
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TransformVisitor::visit(Variable *variable)
|
|
||||||
{
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TransformVisitor::visit(BinaryExpression *binaryExpression)
|
|
||||||
{
|
{
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
195
source/lexer.cpp
195
source/lexer.cpp
@ -1,54 +1,42 @@
|
|||||||
#include "elna/lexer.hpp"
|
#include "elna/source/lexer.hpp"
|
||||||
|
#include <variant>
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
namespace elna
|
namespace elna
|
||||||
{
|
{
|
||||||
namespace lex
|
namespace source
|
||||||
{
|
{
|
||||||
using source_position = elna::source::position;
|
using source_position = elna::source::position;
|
||||||
using source_error = elna::source::error;
|
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)
|
std::pair<text_iterator, text_iterator> text_iterators(const std::string &buffer)
|
||||||
: m_buffer(buffer)
|
|
||||||
{
|
{
|
||||||
|
return std::make_pair<>(text_iterator(std::cbegin(buffer)),
|
||||||
|
text_iterator(std::cend(buffer), position{0, 0}));
|
||||||
}
|
}
|
||||||
|
|
||||||
source::const_iterator source::begin() const
|
text_iterator::text_iterator(std::string::const_iterator buffer,
|
||||||
{
|
|
||||||
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,
|
|
||||||
const source_position start_position)
|
const source_position start_position)
|
||||||
: m_buffer(buffer), m_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;
|
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;
|
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();
|
return m_buffer.base();
|
||||||
}
|
}
|
||||||
|
|
||||||
source::const_iterator& source::const_iterator::operator++()
|
text_iterator& text_iterator::operator++()
|
||||||
{
|
{
|
||||||
if (*this->m_buffer == '\n')
|
if (*this->m_buffer == '\n')
|
||||||
{
|
{
|
||||||
@ -64,129 +52,156 @@ namespace lex
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
source::const_iterator& source::const_iterator::operator++(int)
|
text_iterator& text_iterator::operator++(int)
|
||||||
{
|
{
|
||||||
auto tmp = *this;
|
auto tmp = *this;
|
||||||
++(*this);
|
++(*this);
|
||||||
return *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;
|
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);
|
return !(*this == that);
|
||||||
}
|
}
|
||||||
|
|
||||||
Token::Token(const type of, const char *value, source_position position)
|
token::value::value()
|
||||||
: m_type(of), m_position(position)
|
: 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)
|
token::value::value(std::int32_t value)
|
||||||
: m_type(of), m_position(position)
|
: 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)
|
: m_type(of), m_position(position)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Token::Token(const Token& that)
|
token::token(const token& that)
|
||||||
: m_type(that.of()), m_position(that.position())
|
: m_type(that.of()), m_position(that.position())
|
||||||
{
|
{
|
||||||
*this = that;
|
*this = that;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token::Token(Token&& that)
|
token::token(token&& that)
|
||||||
: m_type(that.of()), m_position(that.position())
|
: m_type(that.of()), m_position(that.position())
|
||||||
{
|
{
|
||||||
*this = std::move(that);
|
*this = std::move(that);
|
||||||
}
|
}
|
||||||
|
|
||||||
Token::~Token()
|
token::~token()
|
||||||
{
|
{
|
||||||
if (m_type == type::identifier || m_type == type::term_operator || m_type == type::factor_operator)
|
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_type = that.of();
|
||||||
m_position = that.position();
|
m_position = that.position();
|
||||||
if (that.of() == type::identifier || that.of() == type::term_operator || m_type == type::factor_operator)
|
if (that.has_identifier())
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
m_value.identifier = that.identifier();
|
m_value.identifier = that.identifier();
|
||||||
that.m_value.identifier = nullptr;
|
|
||||||
}
|
}
|
||||||
else if (that.of() == type::number)
|
else if (that.of() == type::number)
|
||||||
{
|
{
|
||||||
m_value.number = that.number();
|
m_value.number = that.number();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_value.nil = nullptr;
|
||||||
|
}
|
||||||
return *this;
|
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;
|
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;
|
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;
|
return m_value.number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const source_position& Token::position() const noexcept
|
const source_position& token::position() const noexcept
|
||||||
{
|
{
|
||||||
return m_position;
|
return m_position;
|
||||||
}
|
}
|
||||||
|
|
||||||
source_result lex(const char *buffer)
|
bool token::has_identifier() const noexcept
|
||||||
{
|
{
|
||||||
std::vector<Token> tokens;
|
return of() == type::identifier
|
||||||
source input{ buffer };
|
|| 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')
|
if (*iterator == ' ' || *iterator == '\n')
|
||||||
{
|
{
|
||||||
@ -194,59 +209,59 @@ namespace lex
|
|||||||
else if (std::isdigit(*iterator))
|
else if (std::isdigit(*iterator))
|
||||||
{
|
{
|
||||||
tokens.emplace_back(
|
tokens.emplace_back(
|
||||||
Token::type::number,
|
token::type::number,
|
||||||
static_cast<std::int32_t>(*iterator - '0'),
|
static_cast<std::int32_t>(*iterator - '0'),
|
||||||
iterator.position()
|
iterator.position()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if (*iterator == '=')
|
else if (*iterator == '=')
|
||||||
{
|
{
|
||||||
tokens.emplace_back(Token::type::equals, iterator.position());
|
tokens.emplace_back(token::type::equals, iterator.position());
|
||||||
}
|
}
|
||||||
else if (*iterator == '(')
|
else if (*iterator == '(')
|
||||||
{
|
{
|
||||||
tokens.emplace_back(Token::type::left_paren, iterator.position());
|
tokens.emplace_back(token::type::left_paren, iterator.position());
|
||||||
}
|
}
|
||||||
else if (*iterator == ')')
|
else if (*iterator == ')')
|
||||||
{
|
{
|
||||||
tokens.emplace_back(Token::type::right_paren, iterator.position());
|
tokens.emplace_back(token::type::right_paren, iterator.position());
|
||||||
}
|
}
|
||||||
else if (*iterator == ';')
|
else if (*iterator == ';')
|
||||||
{
|
{
|
||||||
tokens.emplace_back(Token::type::semicolon, iterator.position());
|
tokens.emplace_back(token::type::semicolon, iterator.position());
|
||||||
}
|
}
|
||||||
else if (*iterator == ',')
|
else if (*iterator == ',')
|
||||||
{
|
{
|
||||||
tokens.emplace_back(Token::type::comma, iterator.position());
|
tokens.emplace_back(token::type::comma, iterator.position());
|
||||||
}
|
}
|
||||||
else if (*iterator == '!')
|
else if (*iterator == '!')
|
||||||
{
|
{
|
||||||
tokens.emplace_back(Token::type::bang, iterator.position());
|
tokens.emplace_back(token::type::bang, iterator.position());
|
||||||
}
|
}
|
||||||
else if (*iterator == '.')
|
else if (*iterator == '.')
|
||||||
{
|
{
|
||||||
tokens.emplace_back(Token::type::dot, iterator.position());
|
tokens.emplace_back(token::type::dot, iterator.position());
|
||||||
}
|
}
|
||||||
else if (std::isalpha(*iterator))
|
else if (std::isalpha(*iterator))
|
||||||
{
|
{
|
||||||
std::string word;
|
std::string word;
|
||||||
auto i = iterator;
|
auto i = iterator;
|
||||||
while (i != input.end() && std::isalpha(*i))
|
while (i != text_end && std::isalpha(*i))
|
||||||
{
|
{
|
||||||
word.push_back(*i);
|
word.push_back(*i);
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
if (word == "const")
|
if (word == "const")
|
||||||
{
|
{
|
||||||
tokens.emplace_back(Token::type::let, iterator.position());
|
tokens.emplace_back(token::type::let, iterator.position());
|
||||||
}
|
}
|
||||||
else if (word == "var")
|
else if (word == "var")
|
||||||
{
|
{
|
||||||
tokens.emplace_back(Token::type::var, iterator.position());
|
tokens.emplace_back(token::type::var, iterator.position());
|
||||||
}
|
}
|
||||||
else
|
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;
|
iterator = i;
|
||||||
continue;
|
continue;
|
||||||
@ -255,13 +270,13 @@ namespace lex
|
|||||||
{
|
{
|
||||||
std::string _operator{ *iterator };
|
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 == '/')
|
else if (*iterator == '*' || *iterator == '/')
|
||||||
{
|
{
|
||||||
std::string _operator{ *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
|
else
|
||||||
{
|
{
|
||||||
|
@ -1,254 +1,294 @@
|
|||||||
#include "elna/parser.hpp"
|
#include "elna/source/parser.hpp"
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace elna
|
namespace elna
|
||||||
|
{
|
||||||
|
namespace source
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* AST node.
|
* 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);
|
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);
|
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);
|
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);
|
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;
|
switch (operation)
|
||||||
this->rhs = rhs;
|
|
||||||
|
|
||||||
switch (_operator)
|
|
||||||
{
|
{
|
||||||
case '+':
|
case '+':
|
||||||
this->_operator = BinaryOperator::sum;
|
this->m_operator = binary_operator::sum;
|
||||||
break;
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
this->_operator = BinaryOperator::subtraction;
|
this->m_operator = binary_operator::subtraction;
|
||||||
break;
|
break;
|
||||||
case '*':
|
case '*':
|
||||||
this->_operator = BinaryOperator::multiplication;
|
this->m_operator = binary_operator::multiplication;
|
||||||
break;
|
break;
|
||||||
case '/':
|
case '/':
|
||||||
this->_operator = BinaryOperator::division;
|
this->m_operator = binary_operator::division;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw std::logic_error("Invalid binary operator");
|
throw std::logic_error("Invalid binary operator");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BinaryExpression::accept(ParserVisitor *visitor)
|
void binary_expression::accept(ParserVisitor *visitor)
|
||||||
{
|
{
|
||||||
visitor->visit(this);
|
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);
|
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)
|
|
||||||
{
|
|
||||||
auto number = new Number();
|
|
||||||
number->value = (*tokens)[0].number();
|
|
||||||
++(*tokens);
|
|
||||||
--(*length);
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
else if ((*tokens)[0].of() == lex::Token::type::left_paren)
|
|
||||||
{
|
|
||||||
++(*tokens);
|
|
||||||
--(*length);
|
|
||||||
|
|
||||||
auto expression = parseExpression(tokens, length);
|
std::unique_ptr<block> parser::parse()
|
||||||
|
{
|
||||||
|
return parse_block();
|
||||||
|
}
|
||||||
|
|
||||||
++(*tokens);
|
std::unique_ptr<expression> parser::parse_factor()
|
||||||
--(*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 = parse_expression();
|
||||||
|
|
||||||
|
++tokens;
|
||||||
|
|
||||||
return expression;
|
return expression;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression *parseTerm(lex::Token **tokens, size_t *length)
|
std::unique_ptr<expression> parser::parse_term()
|
||||||
{
|
{
|
||||||
auto lhs = parseFactor(tokens, length);
|
auto lhs = parse_factor();
|
||||||
if (lhs == nullptr || *length == 0 || (*tokens)[0].of() != lex::Token::type::factor_operator)
|
if (lhs == nullptr || tokens == end || tokens->of() != source::token::type::factor_operator)
|
||||||
{
|
{
|
||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
auto _operator = (*tokens)[0].identifier()[0];
|
auto _operator = tokens->identifier()[0];
|
||||||
++(*tokens);
|
++tokens;
|
||||||
--(*length);
|
|
||||||
|
|
||||||
auto rhs = parseFactor(tokens, length);
|
auto rhs = parse_factor();
|
||||||
if (rhs != nullptr)
|
if (rhs != nullptr)
|
||||||
{
|
{
|
||||||
return new BinaryExpression(lhs, rhs, _operator);
|
return std::make_unique<binary_expression>(std::move(lhs),
|
||||||
|
std::move(rhs), _operator);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression *parseExpression(lex::Token **tokens, size_t *length)
|
std::unique_ptr<expression> parser::parse_expression()
|
||||||
{
|
{
|
||||||
auto term = parseTerm(tokens, length);
|
auto term = parse_term();
|
||||||
if (term == nullptr || *length == 0 || (*tokens)[0].of() != lex::Token::type::term_operator)
|
if (term == nullptr || tokens == end || tokens->of() != source::token::type::term_operator)
|
||||||
{
|
{
|
||||||
return term;
|
return term;
|
||||||
}
|
}
|
||||||
auto _operator = (*tokens)[0].identifier()[0];
|
auto _operator = tokens->identifier()[0];
|
||||||
++(*tokens);
|
++tokens;
|
||||||
--(*length);
|
|
||||||
|
|
||||||
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Definition *parseDefinition(lex::Token **tokens, size_t *length)
|
std::unique_ptr<definition> parser::parse_definition()
|
||||||
{
|
{
|
||||||
auto definition = new Definition();
|
std::string definition_identifier = tokens->identifier(); // Copy.
|
||||||
definition->identifier = (*tokens)[0].identifier(); // Copy.
|
|
||||||
|
|
||||||
++(*tokens);
|
++tokens;
|
||||||
++(*tokens); // Skip the equals sign.
|
++tokens; // Skip the equals sign.
|
||||||
*length -= 2;
|
|
||||||
|
|
||||||
if ((*tokens)[0].of() == lex::Token::type::number)
|
if (tokens->of() == source::token::type::number)
|
||||||
{
|
{
|
||||||
auto number = new Number();
|
auto result = std::make_unique<definition>(std::move(definition_identifier),
|
||||||
number->value = (*tokens)[0].number();
|
std::make_unique<integer_literal>(tokens->number()));
|
||||||
definition->number = number;
|
++tokens;
|
||||||
++(*tokens);
|
return result;
|
||||||
--(*length);
|
|
||||||
return definition;
|
|
||||||
}
|
}
|
||||||
return nullptr;
|
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);
|
++tokens;
|
||||||
--(*length);
|
auto bang_body = parse_expression();
|
||||||
auto statement = new BangStatement();
|
if (bang_body != nullptr)
|
||||||
auto expression = parseExpression(tokens, length);
|
|
||||||
if (expression != nullptr)
|
|
||||||
{
|
{
|
||||||
statement->expression = expression;
|
return std::make_unique<bang_statement>(std::move(bang_body));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return statement;
|
|
||||||
}
|
}
|
||||||
return nullptr;
|
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.
|
++tokens; // Skip const.
|
||||||
--(*length);
|
|
||||||
|
|
||||||
Definition **definitions;
|
std::vector<std::unique_ptr<definition>> definitions;
|
||||||
*resultLength = 0;
|
|
||||||
|
|
||||||
while (*length != 0)
|
while (tokens != end)
|
||||||
{
|
{
|
||||||
auto definition = parseDefinition(tokens, length);
|
auto parsed_definition = parse_definition();
|
||||||
if (definition == nullptr)
|
if (parsed_definition == nullptr)
|
||||||
{
|
{
|
||||||
return nullptr;
|
return definitions;
|
||||||
}
|
}
|
||||||
definitions = reinterpret_cast<Definition **>(
|
definitions.push_back(std::move(parsed_definition));
|
||||||
realloc(definitions, (*resultLength + 1) * sizeof(Definition*)));
|
|
||||||
definitions[(*resultLength)++] = definition;
|
|
||||||
|
|
||||||
if ((*tokens)[0].of() == lex::Token::type::semicolon)
|
if (tokens->of() == source::token::type::semicolon)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ((*tokens)[0].of() == lex::Token::type::comma)
|
if (tokens->of() == source::token::type::comma)
|
||||||
{
|
{
|
||||||
++(*tokens);
|
++tokens;
|
||||||
--(*length);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return definitions;
|
return definitions;
|
||||||
}
|
}
|
||||||
|
|
||||||
Block *parseBlock(lex::Token **tokens, std::size_t *length)
|
std::unique_ptr<block> parser::parse_block()
|
||||||
{
|
{
|
||||||
auto block = new Block();
|
std::vector<std::unique_ptr<definition>> definitions;
|
||||||
if ((*tokens)[0].of() == lex::Token::type::let)
|
if (tokens->of() == source::token::type::let)
|
||||||
{
|
{
|
||||||
size_t length_ = 0;
|
definitions = parse_definitions();
|
||||||
auto constDefinitions = parseDefinitions(tokens, length, &length_);
|
++tokens;
|
||||||
if (constDefinitions != nullptr)
|
|
||||||
{
|
|
||||||
block->definitionsLength = length_;
|
|
||||||
block->definitions = constDefinitions;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
++(*tokens);
|
|
||||||
--(*length);
|
|
||||||
}
|
}
|
||||||
auto statement = parseStatement(tokens, length);
|
auto parsed_statement = parse_bang_statement();
|
||||||
if (statement != nullptr)
|
if (parsed_statement == nullptr)
|
||||||
{
|
|
||||||
block->statement = statement;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return block;
|
return std::make_unique<block>(std::move(definitions), std::move(parsed_statement));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#include "elna/parser.hpp"
|
|
||||||
#include "elna/riscv.hpp"
|
#include "elna/riscv.hpp"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@ -59,31 +58,22 @@ namespace elna
|
|||||||
return reinterpret_cast<std::byte *>(&this->instruction) + sizeof(this->instruction);
|
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;
|
for (const auto& block_definition : block->definitions())
|
||||||
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 (std::size_t i = 0; i < block->definitionsLength; ++i)
|
|
||||||
{
|
{
|
||||||
block->definitions[i]->accept(this);
|
block_definition->accept(this);
|
||||||
}
|
}
|
||||||
this->instructionsLength += 4;
|
this->instructionsLength += 4;
|
||||||
this->instructions = reinterpret_cast<Instruction *>(
|
this->instructions = reinterpret_cast<Instruction *>(
|
||||||
realloc(this->instructions, this->instructionsLength * sizeof(Instruction)));
|
realloc(this->instructions, this->instructionsLength * sizeof(Instruction)));
|
||||||
|
|
||||||
block->statement->accept(this);
|
block->body().accept(this);
|
||||||
|
|
||||||
// Prologue.
|
// Prologue.
|
||||||
const uint stackSize = static_cast<std::uint32_t>(variableCounter * 4 + 12);
|
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);
|
.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)
|
void RiscVVisitor::visit(source::variable *variable)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
const auto freeRegister = this->registerInUse ? XRegister::a0 : XRegister::t0;
|
const auto freeRegister = this->registerInUse ? XRegister::a0 : XRegister::t0;
|
||||||
|
|
||||||
@ -183,15 +141,27 @@ namespace elna
|
|||||||
realloc(this->instructions, this->instructionsLength * sizeof(Instruction)));
|
realloc(this->instructions, this->instructionsLength * sizeof(Instruction)));
|
||||||
this->instructions[this->instructionsLength - 1] =
|
this->instructions[this->instructionsLength - 1] =
|
||||||
Instruction(BaseOpcode::opImm) // movl $x, %eax; where $x is a number.
|
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;
|
const auto lhs_register = this->registerInUse ? XRegister::a0 : XRegister::t0;
|
||||||
|
|
||||||
this->registerInUse = true;
|
this->registerInUse = true;
|
||||||
expression->lhs->accept(this);
|
expression->lhs().accept(this);
|
||||||
|
|
||||||
++this->instructionsLength;
|
++this->instructionsLength;
|
||||||
this->instructions = reinterpret_cast<Instruction *>(
|
this->instructions = reinterpret_cast<Instruction *>(
|
||||||
@ -202,7 +172,7 @@ namespace elna
|
|||||||
auto lhs_stack_position = ++this->variableCounter;
|
auto lhs_stack_position = ++this->variableCounter;
|
||||||
|
|
||||||
this->registerInUse = false;
|
this->registerInUse = false;
|
||||||
expression->rhs->accept(this);
|
expression->rhs().accept(this);
|
||||||
|
|
||||||
this->instructionsLength += 2;
|
this->instructionsLength += 2;
|
||||||
this->instructions = reinterpret_cast<Instruction *>(
|
this->instructions = reinterpret_cast<Instruction *>(
|
||||||
@ -213,24 +183,24 @@ namespace elna
|
|||||||
static_cast<std::int8_t>((lhs_stack_position - 1) * 4));
|
static_cast<std::int8_t>((lhs_stack_position - 1) * 4));
|
||||||
|
|
||||||
// Calculate the result and assign it to a variable on the stack.
|
// 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)
|
this->instructions[instructionsLength - 1] = Instruction(BaseOpcode::op)
|
||||||
.r(lhs_register, Funct3::add, XRegister::a0, XRegister::t0);
|
.r(lhs_register, Funct3::add, XRegister::a0, XRegister::t0);
|
||||||
break;
|
break;
|
||||||
case BinaryOperator::subtraction:
|
case source::binary_operator::subtraction:
|
||||||
this->instructions[instructionsLength - 1] = Instruction(BaseOpcode::op)
|
this->instructions[instructionsLength - 1] = Instruction(BaseOpcode::op)
|
||||||
.r(lhs_register, Funct3::sub, XRegister::a0, XRegister::t0, Funct7::sub);
|
.r(lhs_register, Funct3::sub, XRegister::a0, XRegister::t0, Funct7::sub);
|
||||||
break;
|
break;
|
||||||
case BinaryOperator::multiplication:
|
case source::binary_operator::multiplication:
|
||||||
this->instructions[instructionsLength - 1] = Instruction(BaseOpcode::op)
|
this->instructions[instructionsLength - 1] = Instruction(BaseOpcode::op)
|
||||||
.r(lhs_register, Funct3::mul, XRegister::a0, XRegister::t0, Funct7::muldiv);
|
.r(lhs_register, Funct3::mul, XRegister::a0, XRegister::t0, Funct7::muldiv);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol writeNext(Block *ast)
|
Symbol writeNext(source::block *ast)
|
||||||
{
|
{
|
||||||
auto visitor = std::make_unique<RiscVVisitor>();
|
auto visitor = std::make_unique<RiscVVisitor>();
|
||||||
visitor->visit(ast);
|
visitor->visit(ast);
|
||||||
|
Loading…
Reference in New Issue
Block a user