elna/include/elna/source/parser.hpp

333 lines
9.8 KiB
C++

#pragma once
#include <boost/core/noncopyable.hpp>
#include <memory>
#include <elna/source/lexer.hpp>
namespace elna::source
{
enum class binary_operator
{
sum,
subtraction,
multiplication,
division,
equals,
not_equals,
less,
greater,
less_equal,
greater_equal
};
class declaration;
class constant_definition;
class procedure_definition;
class call_statement;
class compound_statement;
class assign_statement;
class if_statement;
class while_statement;
class block;
class program;
class binary_expression;
class variable_expression;
class integer_literal;
class boolean_literal;
struct parser_visitor
{
virtual void visit(declaration *) = 0;
virtual void visit(constant_definition *) = 0;
virtual void visit(procedure_definition *) = 0;
virtual void visit(call_statement *) = 0;
virtual void visit(compound_statement *) = 0;
virtual void visit(assign_statement *) = 0;
virtual void visit(if_statement *) = 0;
virtual void visit(while_statement *) = 0;
virtual void visit(block *) = 0;
virtual void visit(program *) = 0;
virtual void visit(binary_expression *) = 0;
virtual void visit(variable_expression *) = 0;
virtual void visit(integer_literal *) = 0;
virtual void visit(boolean_literal *) = 0;
};
struct empty_visitor : parser_visitor
{
virtual void visit(declaration *declaration) override;
virtual void visit(constant_definition *definition) override;
virtual void visit(procedure_definition *definition) override;
virtual void visit(call_statement *statement) override;
virtual void visit(compound_statement *statement) override;
virtual void visit(assign_statement *statement) override;
virtual void visit(if_statement *) override;
virtual void visit(while_statement *) override;
virtual void visit(block *block) override;
virtual void visit(program *program) override;
virtual void visit(binary_expression *expression) override;
virtual void visit(variable_expression *variable) override;
virtual void visit(integer_literal *number) override;
virtual void visit(boolean_literal *boolean) override;
};
/**
* AST node.
*/
class node
{
public:
virtual void accept(parser_visitor *) = 0;
};
class statement : public node
{
};
class expression : public node
{
};
/**
* Symbol definition.
*/
class definition : public node
{
std::string m_identifier;
protected:
/**
* Constructs a definition identified by some name.
*
* \param identifier Definition name.
*/
definition(const std::string& identifier);
public:
/**
* \return Definition name.
*/
std::string& identifier() noexcept;
};
/**
* Variable declaration.
*/
class declaration : public definition
{
std::string m_type;
public:
declaration(const std::string& identifier, const std::string& type);
virtual void accept(parser_visitor *visitor) override;
std::string& type() noexcept;
};
/**
* Constant definition.
*/
class constant_definition : public definition
{
std::unique_ptr<integer_literal> m_body;
public:
constant_definition(const std::string& identifier, std::unique_ptr<integer_literal>&& body);
virtual void accept(parser_visitor *visitor) override;
integer_literal& body();
};
class procedure_definition : public definition
{
std::unique_ptr<block> m_body;
std::vector<std::unique_ptr<declaration>> m_parameters;
public:
procedure_definition(const std::string& identifier, std::unique_ptr<block>&& body);
virtual void accept(parser_visitor *visitor) override;
block& body();
std::vector<std::unique_ptr<declaration>>& parameters() noexcept;
};
class call_statement : public statement
{
std::string m_name;
std::vector<std::unique_ptr<expression>> m_arguments;
public:
call_statement(const std::string& name);
virtual void accept(parser_visitor *visitor) override;
std::string& name() noexcept;
std::vector<std::unique_ptr<expression>>& arguments() noexcept;
};
class compound_statement : public statement
{
std::vector<std::unique_ptr<statement>> m_statements;
public:
compound_statement() = default;
compound_statement(std::vector<std::unique_ptr<statement>>&& statements);
virtual void accept(parser_visitor *visitor) override;
std::vector<std::unique_ptr<statement>>& statements();
};
class assign_statement : public statement
{
std::string m_lvalue;
std::unique_ptr<expression> m_rvalue;
public:
assign_statement(const std::string& lvalue, std::unique_ptr<expression>&& rvalue);
virtual void accept(parser_visitor *visitor) override;
std::string& lvalue() noexcept;
expression& rvalue();
};
class if_statement : public statement
{
std::unique_ptr<expression> m_prerequisite;
std::unique_ptr<statement> m_body;
public:
if_statement(std::unique_ptr<expression>&& prerequisite, std::unique_ptr<statement>&& body);
virtual void accept(parser_visitor *visitor) override;
expression& prerequisite();
statement& body();
};
class while_statement : public statement
{
std::unique_ptr<expression> m_prerequisite;
std::unique_ptr<statement> m_body;
public:
while_statement(std::unique_ptr<expression>&& prerequisite, std::unique_ptr<statement>&& body);
virtual void accept(parser_visitor *visitor) override;
expression& prerequisite();
statement& body();
};
class block : public node
{
std::unique_ptr<statement> m_body;
std::vector<std::unique_ptr<definition>> m_definitions;
std::vector<std::unique_ptr<declaration>> m_declarations;
public:
block(std::vector<std::unique_ptr<definition>>&& definitions,
std::vector<std::unique_ptr<declaration>>&& declarations,
std::unique_ptr<statement>&& body);
virtual void accept(parser_visitor *visitor) override;
statement& body();
std::vector<std::unique_ptr<definition>>& definitions() noexcept;
std::vector<std::unique_ptr<declaration>>& declarations() noexcept;
};
class program : public block
{
public:
program(std::vector<std::unique_ptr<definition>>&& definitions,
std::vector<std::unique_ptr<declaration>>&& declarations,
std::unique_ptr<statement>&& body);
virtual void accept(parser_visitor *visitor) override;
};
class integer_literal : public expression
{
std::int32_t m_number;
public:
integer_literal(const std::int32_t value);
virtual void accept(parser_visitor *visitor) override;
std::int32_t number() const noexcept;
};
class boolean_literal : public expression
{
bool m_boolean;
public:
boolean_literal(const bool value);
virtual void accept(parser_visitor *visitor) override;
bool boolean() const noexcept;
};
class variable_expression : public expression
{
std::string m_name;
public:
variable_expression(const std::string& name);
virtual void accept(parser_visitor *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(parser_visitor *visitor) override;
expression& lhs();
expression& rhs();
binary_operator operation() const noexcept;
};
class parser : boost::noncopyable
{
std::unique_ptr<expression> parse_factor();
std::unique_ptr<expression> parse_term();
std::unique_ptr<expression> parse_expression();
std::unique_ptr<expression> parse_condition();
std::unique_ptr<constant_definition> parse_constant_definition();
std::unique_ptr<procedure_definition> parse_procedure_definition();
std::unique_ptr<declaration> parse_declaration();
std::unique_ptr<statement> parse_statement();
std::unique_ptr<call_statement> parse_call_statement();
std::unique_ptr<compound_statement> parse_compound_statement();
std::unique_ptr<assign_statement> parse_assign_statement();
std::unique_ptr<if_statement> parse_if_statement();
std::unique_ptr<while_statement> parse_while_statement();
std::vector<std::unique_ptr<constant_definition>> parse_constant_definitions();
std::vector<std::unique_ptr<procedure_definition>> parse_procedure_definitions();
std::vector<std::unique_ptr<declaration>> parse_declarations();
std::unique_ptr<block> parse_block();
lexer iterator;
public:
parser(lexer&& tokens);
/**
* Parses a source text.
*
* \return Parsed program or nothing if an error occurred.
*/
std::unique_ptr<program> parse();
/**
* Gets produced errors.
*
* \return Produced error list.
*/
const std::list<std::unique_ptr<error>>& errors() const noexcept;
};
}