Initial commit

This commit is contained in:
Eugen Wissner 2024-12-21 00:08:48 +01:00
commit 72681e349a
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
11 changed files with 1599 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/build/
.cache/

25
CMakeLists.txt Normal file
View File

@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.21)
project(Elna)
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_CXX_STANDARD 17)
find_package(Boost CONFIG COMPONENTS process program_options REQUIRED)
find_package(FLEX REQUIRED)
find_package(BISON REQUIRED)
include_directories(${Boost_INCLUDE_DIR})
FLEX_TARGET(lexer source/lexer.ll ${CMAKE_CURRENT_BINARY_DIR}/lexer.cpp)
BISON_TARGET(parser source/parser.yy ${CMAKE_CURRENT_BINARY_DIR}/parser.cpp)
add_flex_bison_dependency(lexer parser)
add_executable(elna cli/main.cpp
source/ast.cpp include/elna/source/ast.hpp
source/types.cpp include/elna/source/types.hpp
source/result.cpp include/elna/source/result.hpp
${BISON_parser_OUTPUTS} ${FLEX_lexer_OUTPUTS}
)
target_include_directories(elna PRIVATE ${CMAKE_CURRENT_BINARY_DIR} include)
target_link_libraries(elna LINK_PUBLIC ${Boost_LIBRARIES})

22
cli/main.cpp Normal file
View File

@ -0,0 +1,22 @@
#include "parser.hpp"
#include <sstream>
int main()
{
std::istringstream inp("const world = 5, hello = 7;");
std::unique_ptr<elna::source::program> program;
elna::syntax::FooLexer lexer(inp);
yy::parser parser(lexer, program);
auto result = parser();
for (auto& definition : program->definitions())
{
auto const_definition = dynamic_cast<elna::source::constant_definition *>(definition.get());
std::cout << "const " << const_definition->identifier() << " = "
<< const_definition->body().number() << std::endl;
}
return result;
}

483
include/elna/source/ast.hpp Normal file
View File

@ -0,0 +1,483 @@
#pragma once
#include <memory>
#include "elna/source/result.hpp"
#include "elna/source/types.hpp"
namespace elna::source
{
enum class binary_operator
{
sum,
subtraction,
multiplication,
division,
equals,
not_equals,
less,
greater,
less_equal,
greater_equal
};
enum class unary_operator
{
reference,
dereference
};
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 unary_expression;
class type_expression;
class variable_expression;
class integer_literal;
class boolean_literal;
/**
* Interface for AST visitors.
*/
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(unary_expression *) = 0;
virtual void visit(type_expression *) = 0;
virtual void visit(variable_expression *) = 0;
virtual void visit(integer_literal *) = 0;
virtual void visit(boolean_literal *) = 0;
};
/**
* A visitor which visits all nodes but does nothing.
*/
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(unary_expression *expression) override;
virtual void visit(type_expression *variable) override;
virtual void visit(variable_expression *variable) override;
virtual void visit(integer_literal *number) override;
virtual void visit(boolean_literal *boolean) override;
};
/**
* Operand representing a subexpression in the 3 address code.
*/
struct operand
{
public:
virtual ~operand() noexcept = 0;
};
struct integer_operand final : public operand
{
std::int32_t m_value;
public:
explicit integer_operand(const std::int32_t value);
std::int32_t value() const noexcept;
};
class variable_operand final : public operand
{
std::string m_name;
public:
explicit variable_operand(const std::string& name);
const std::string& name() const noexcept;
};
struct temporary_variable final : public operand
{
std::size_t m_counter;
public:
explicit temporary_variable(const std::size_t counter);
std::size_t counter() const noexcept;
};
struct label_operand final : public operand
{
std::size_t m_counter;
public:
explicit label_operand(const std::size_t counter);
std::size_t counter() const noexcept;
};
/**
* AST node.
*/
class node
{
const struct position source_position;
protected:
/**
* \param position Source code position.
*/
explicit node(const position position);
public:
virtual ~node() noexcept = default;
virtual void accept(parser_visitor *) = 0;
/**
* \return Node position in the source code.
*/
const struct position& position() const noexcept;
};
class statement : public node
{
protected:
/**
* \param position Source code position.
*/
explicit statement(const struct position position);
};
class expression : public node
{
public:
std::shared_ptr<operand> place;
std::shared_ptr<const type> data_type;
protected:
/**
* \param position Source code position.
*/
explicit expression(const struct position position);
};
/**
* Symbol definition.
*/
class definition : public node
{
std::string m_identifier;
protected:
/**
* Constructs a definition identified by some name.
*
* \param position Source code position.
* \param identifier Definition name.
*/
definition(const struct position position, const std::string& identifier);
public:
/**
* \return Definition name.
*/
std::string& identifier() noexcept;
};
/**
* Expression defining a composed type like pointer or an array.
*/
class type_expression : public node
{
std::string m_base;
bool m_pointer{ false };
public:
/**
* \param position Source code position.
* \param name Type name.
* \param is_pointer Whether it is a pointer type.
*/
type_expression(const struct position position, const std::string& name, const bool is_pointer = false);
virtual void accept(parser_visitor *visitor) override;
/**
* \return Name of the base type.
*/
const std::string& base() const noexcept;
/**
* \return Whether the type is a pointer.
*/
bool is_pointer() const noexcept;
};
/**
* Variable declaration.
*/
class declaration : public definition
{
std::unique_ptr<type_expression> m_type;
public:
/**
* Constructs a declaration with a name and a type.
*
* \param position Source code position.
* \param identifier Definition name.
* \param type Declared type.
*/
declaration(const struct position position, const std::string& identifier,
std::unique_ptr<type_expression>&& type);
virtual void accept(parser_visitor *visitor) override;
type_expression& type() noexcept;
};
/**
* Constant definition.
*/
class constant_definition : public definition
{
std::unique_ptr<integer_literal> m_body;
public:
/**
* \param position Source code position.
* \param identifier Constant name.
* \param body Constant value.
*/
constant_definition(const struct position position, const std::string& identifier,
std::unique_ptr<integer_literal>&& body);
virtual void accept(parser_visitor *visitor) override;
integer_literal& body();
};
/**
* Procedure definition.
*/
class procedure_definition : public definition
{
std::unique_ptr<block> m_body;
std::vector<std::unique_ptr<declaration>> m_parameters;
public:
/**
* \param position Source code position.
* \param identifier Procedure name.
* \param body Procedure body.
*/
procedure_definition(const struct position position, 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;
};
/**
* Call statement.
*/
class call_statement : public statement
{
std::string m_name;
std::vector<std::unique_ptr<expression>> m_arguments;
public:
/**
* \param position Source code position.
* \param name Callable's name.
*/
call_statement(const struct position position, 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:
explicit compound_statement(const struct position position);
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:
/**
* \param position Source code position.
* \param lvalue Left-hand side.
* \param rvalue Assigned expression.
*/
assign_statement(const struct position position, const std::string& lvalue,
std::unique_ptr<expression>&& rvalue);
virtual void accept(parser_visitor *visitor) override;
std::string& lvalue() noexcept;
expression& rvalue();
};
/**
* If-statement.
*/
class if_statement : public statement
{
std::unique_ptr<expression> m_prerequisite;
std::unique_ptr<statement> m_body;
public:
/**
* \param position Source code position.
* \param prerequisite Condition.
* \param body Statement executed if the condition is met.
*/
if_statement(const struct position position, std::unique_ptr<expression>&& prerequisite,
std::unique_ptr<statement>&& body);
virtual void accept(parser_visitor *visitor) override;
expression& prerequisite();
statement& body();
};
/**
* While-statement.
*/
class while_statement : public statement
{
std::unique_ptr<expression> m_prerequisite;
std::unique_ptr<statement> m_body;
public:
/**
* \param position Source code position.
* \param prerequisite Condition.
* \param body Statement executed while the condition is met.
*/
while_statement(const struct position position, 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(const struct position position, 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(const struct position position, 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 struct position position, 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 struct position position, 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 struct position position, 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(const struct position position, 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 unary_expression : public expression
{
std::unique_ptr<expression> m_operand;
unary_operator m_operator;
public:
unary_expression(const struct position position, std::unique_ptr<expression>&& operand,
const unsigned char operation);
virtual void accept(parser_visitor *visitor) override;
expression& operand();
unary_operator operation() const noexcept;
};
}

View File

@ -0,0 +1,52 @@
#pragma once
#include <cstddef>
#include <filesystem>
namespace elna::source
{
/**
* Position in the source text.
*/
struct position
{
/// Line.
std::size_t line = 1;
/// Column.
std::size_t column = 1;
};
/**
* A compilation error consists of an error message and position.
*/
class error
{
position m_position;
std::filesystem::path m_path;
protected:
/**
* Constructs an error.
*
* \param path Source file name.
* \param position Error position in the source text.
*/
error(const std::filesystem::path& path, const position position);
public:
virtual ~error() noexcept = default;
/// Error text.
virtual std::string what() const = 0;
/// Error line in the source text.
std::size_t line() const noexcept;
/// Error column in the source text.
std::size_t column() const noexcept;
/// Source file name.
const std::filesystem::path& path() const noexcept;
};
}

View File

@ -0,0 +1,99 @@
#pragma once
#include <memory>
#include <string>
#include <vector>
namespace elna::source
{
/**
* Type representation.
*/
class type
{
const std::size_t byte_size;
protected:
/**
* Constructor.
*
* \param byte_size The type size in bytes.
*/
explicit type(const std::size_t byte_size);
public:
/**
* \return The type size in bytes.
*/
virtual std::size_t size() const noexcept;
friend bool operator==(const type& lhs, const type& rhs) noexcept;
friend bool operator!=(const type& lhs, const type& rhs) noexcept;
};
/**
* Built-in type representation.
*/
struct primitive_type : public type
{
/// Type name.
const std::string type_name;
/**
* Constructor.
*
* \param type_name Type name.
* \param byte_size The type size in bytes.
*/
primitive_type(const std::string& type_name, const std::size_t byte_size);
bool operator==(const primitive_type& that) const noexcept;
bool operator!=(const primitive_type& that) const noexcept;
};
/**
* Typed pointer.
*/
struct pointer_type : public type
{
/// Pointer target type.
std::shared_ptr<const type> base_type;
/**
* Constructor.
*
* \param base_type Pointer target type.
* \param byte_size The type size in bytes.
*/
pointer_type(std::shared_ptr<const type> base_type, const std::size_t byte_size);
bool operator==(const pointer_type& that) const noexcept;
bool operator!=(const pointer_type& that) const noexcept;
};
/**
* Type of a procedure.
*/
struct procedure_type : public type
{
/// Argument types.
std::vector<std::shared_ptr<const type>> arguments;
/**
* Constructor.
*
* \param arguments Argument types.
* \param byte_size Function pointer size.
*/
procedure_type(std::vector<std::shared_ptr<const type>> arguments, const std::size_t byte_size);
bool operator==(const procedure_type& that) const noexcept;
bool operator!=(const procedure_type& that) const noexcept;
};
bool operator==(const type& lhs, const type& rhs) noexcept;
bool operator!=(const type& lhs, const type& rhs) noexcept;
inline const primitive_type boolean_type{ "Boolean", 1 };
inline const primitive_type int_type{ "Int", 4 };
}

524
source/ast.cpp Normal file
View File

@ -0,0 +1,524 @@
#include "elna/source/ast.hpp"
#include <stdexcept>
namespace elna::source
{
void empty_visitor::visit(declaration *declaration)
{
}
void empty_visitor::visit(constant_definition *definition)
{
definition->body().accept(this);
}
void empty_visitor::visit(procedure_definition *definition)
{
for (auto& parameter : definition->parameters())
{
parameter->accept(this);
}
definition->body().accept(this);
}
void empty_visitor::visit(call_statement *statement)
{
for (auto& argument : statement->arguments())
{
argument->accept(this);
}
}
void empty_visitor::visit(compound_statement *statement)
{
for (auto& nested_statement : statement->statements())
{
nested_statement->accept(this);
}
}
void empty_visitor::visit(assign_statement *statement)
{
statement->rvalue().accept(this);
}
void empty_visitor::visit(if_statement *statement)
{
statement->prerequisite().accept(this);
statement->body().accept(this);
}
void empty_visitor::visit(while_statement *statement)
{
statement->prerequisite().accept(this);
statement->body().accept(this);
}
void empty_visitor::visit(block *block)
{
for (const auto& constant : block->definitions())
{
constant->accept(this);
}
for (const auto& block_declaration : block->declarations())
{
block_declaration->accept(this);
}
block->body().accept(this);
}
void empty_visitor::visit(program *program)
{
visit(dynamic_cast<block *>(program));
}
void empty_visitor::visit(binary_expression *expression)
{
expression->lhs().accept(this);
expression->rhs().accept(this);
}
void empty_visitor::visit(unary_expression *expression)
{
expression->operand().accept(this);
}
void empty_visitor::visit(type_expression *variable)
{
}
void empty_visitor::visit(variable_expression *variable)
{
}
void empty_visitor::visit(integer_literal *number)
{
}
void empty_visitor::visit(boolean_literal *boolean)
{
}
operand::~operand() noexcept
{
}
integer_operand::integer_operand(const std::int32_t value)
: m_value(value)
{
}
std::int32_t integer_operand::value() const noexcept
{
return m_value;
}
variable_operand::variable_operand(const std::string& name)
: m_name(name)
{
}
const std::string& variable_operand::name() const noexcept
{
return m_name;
}
temporary_variable::temporary_variable(const std::size_t counter)
: m_counter(counter)
{
}
std::size_t temporary_variable::counter() const noexcept
{
return m_counter;
}
label_operand::label_operand(const std::size_t counter)
: m_counter(counter)
{
}
std::size_t label_operand::counter() const noexcept
{
return m_counter;
}
node::node(const struct position position)
: source_position(position)
{
}
const struct position& node::position() const noexcept
{
return this->source_position;
}
statement::statement(const struct position position)
: node(position)
{
}
expression::expression(const struct position position)
: node(position)
{
}
type_expression::type_expression(const struct position position, const std::string& name, const bool is_pointer)
: node(position), m_base(name), m_pointer(is_pointer)
{
}
void type_expression::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
const std::string& type_expression::base() const noexcept
{
return m_base;
}
bool type_expression::is_pointer() const noexcept
{
return m_pointer;
}
declaration::declaration(const struct position position, const std::string& identifier,
std::unique_ptr<type_expression>&& type)
: definition(position, identifier), m_type(std::move(type))
{
}
void declaration::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
type_expression& declaration::type() noexcept
{
return *m_type;
}
definition::definition(const struct position position, const std::string& identifier)
: node(position), m_identifier(identifier)
{
}
std::string& definition::identifier() noexcept
{
return m_identifier;
}
constant_definition::constant_definition(const struct position position, const std::string& identifier,
std::unique_ptr<integer_literal>&& body)
: definition(position, identifier), m_body(std::move(body))
{
}
void constant_definition::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
integer_literal& constant_definition::body()
{
return *m_body;
}
procedure_definition::procedure_definition(const struct position position, const std::string& identifier,
std::unique_ptr<block>&& body)
: definition(position, identifier), m_body(std::move(body))
{
}
void procedure_definition::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
block& procedure_definition::body()
{
return *m_body;
}
std::vector<std::unique_ptr<declaration>>& procedure_definition::parameters() noexcept
{
return m_parameters;
}
block::block(const struct position position, std::vector<std::unique_ptr<definition>>&& definitions,
std::vector<std::unique_ptr<declaration>>&& declarations,
std::unique_ptr<statement>&& body)
: node(position), m_definitions(std::move(definitions)),
m_declarations(std::move(declarations)), m_body(std::move(body))
{
}
void block::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
statement& block::body()
{
return *m_body;
}
std::vector<std::unique_ptr<definition>>& block::definitions() noexcept
{
return m_definitions;
}
std::vector<std::unique_ptr<declaration>>& block::declarations() noexcept
{
return m_declarations;
}
program::program(const struct position position, std::vector<std::unique_ptr<definition>>&& definitions,
std::vector<std::unique_ptr<declaration>>&& declarations,
std::unique_ptr<statement>&& body)
: block(position, std::move(definitions), std::move(declarations), std::move(body))
{
}
void program::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
integer_literal::integer_literal(const struct position position, const std::int32_t value)
: expression(position), m_number(value)
{
}
void integer_literal::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
std::int32_t integer_literal::number() const noexcept
{
return m_number;
}
boolean_literal::boolean_literal(const struct position position, const bool value)
: expression(position), m_boolean(value)
{
}
void boolean_literal::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
bool boolean_literal::boolean() const noexcept
{
return m_boolean;
}
variable_expression::variable_expression(const struct position position, const std::string& name)
: expression(position), m_name(name)
{
}
void variable_expression::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
const std::string& variable_expression::name() const noexcept
{
return m_name;
}
binary_expression::binary_expression(const struct position position, std::unique_ptr<expression>&& lhs,
std::unique_ptr<expression>&& rhs, const unsigned char operation)
: expression(position), m_lhs(std::move(lhs)), m_rhs(std::move(rhs))
{
switch (operation)
{
case '+':
this->m_operator = binary_operator::sum;
break;
case '-':
this->m_operator = binary_operator::subtraction;
break;
case '*':
this->m_operator = binary_operator::multiplication;
break;
case '/':
this->m_operator = binary_operator::division;
break;
case '=':
this->m_operator = binary_operator::equals;
break;
case 'n':
this->m_operator = binary_operator::not_equals;
break;
case '<':
this->m_operator = binary_operator::less;
break;
case 'l':
this->m_operator = binary_operator::less_equal;
break;
case '>':
this->m_operator = binary_operator::greater;
break;
case 'g':
this->m_operator = binary_operator::greater_equal;
break;
default:
throw std::logic_error("Invalid binary operator");
}
}
void binary_expression::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
expression& binary_expression::lhs()
{
return *m_lhs;
}
expression& binary_expression::rhs()
{
return *m_rhs;
}
binary_operator binary_expression::operation() const noexcept
{
return m_operator;
}
unary_expression::unary_expression(const struct position position, std::unique_ptr<expression>&& operand,
const unsigned char operation)
: expression(position), m_operand(std::move(operand))
{
switch (operation)
{
case '@':
this->m_operator = unary_operator::reference;
break;
case '^':
this->m_operator = unary_operator::dereference;
break;
default:
throw std::logic_error("Invalid unary operator");
}
}
void unary_expression::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
expression& unary_expression::operand()
{
return *m_operand;
}
unary_operator unary_expression::operation() const noexcept
{
return this->m_operator;
}
call_statement::call_statement(const struct position position, const std::string& name)
: statement(position), m_name(name)
{
}
void call_statement::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
std::string& call_statement::name() noexcept
{
return m_name;
}
std::vector<std::unique_ptr<expression>>& call_statement::arguments() noexcept
{
return m_arguments;
}
compound_statement::compound_statement(const struct position position)
: statement(position)
{
}
void compound_statement::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
std::vector<std::unique_ptr<statement>>& compound_statement::statements()
{
return m_statements;
}
void assign_statement::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
assign_statement::assign_statement(const struct position position, const std::string& lvalue,
std::unique_ptr<expression>&& rvalue)
: statement(position), m_lvalue(lvalue), m_rvalue(std::move(rvalue))
{
}
std::string& assign_statement::lvalue() noexcept
{
return m_lvalue;
}
expression& assign_statement::rvalue()
{
return *m_rvalue;
}
if_statement::if_statement(const struct position position, std::unique_ptr<expression>&& prerequisite,
std::unique_ptr<statement>&& body)
: statement(position), m_prerequisite(std::move(prerequisite)), m_body(std::move(body))
{
}
void if_statement::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
expression& if_statement::prerequisite()
{
return *m_prerequisite;
}
statement& if_statement::body()
{
return *m_body;
}
while_statement::while_statement(const struct position position, std::unique_ptr<expression>&& prerequisite,
std::unique_ptr<statement>&& body)
: statement(position), m_prerequisite(std::move(prerequisite)), m_body(std::move(body))
{
}
void while_statement::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
expression& while_statement::prerequisite()
{
return *m_prerequisite;
}
statement& while_statement::body()
{
return *m_body;
}
}

131
source/lexer.ll Normal file
View File

@ -0,0 +1,131 @@
%{
#define YY_NO_UNISTD_H
#define YY_USER_ACTION this->location.columns(yyleng);
#include <sstream>
#include "parser.hpp"
#undef YY_DECL
#define YY_DECL yy::parser::symbol_type elna::syntax::FooLexer::lex()
#define yyterminate() return yy::parser::make_YYEOF(this->location)
%}
%option c++ noyywrap never-interactive
%option yyclass="elna::syntax::FooLexer"
%%
%{
this->location.step();
%}
\-\-.* {
/* Skip the comment */
}
[\ \t\r] ; /* Skip the whitespaces */
\n+ {
this->location.lines(yyleng);
this->location.step();
}
if {
return yy::parser::make_IF(this->location);
}
then {
return yy::parser::make_THEN(this->location);
}
while {
return yy::parser::make_WHILE(this->location);
}
do {
return yy::parser::make_DO(this->location);
}
proc {
return yy::parser::make_PROCEDURE(this->location);
}
begin {
return yy::parser::make_BEGIN_BLOCK(this->location);
}
end {
return yy::parser::make_END_BLOCK(this->location);
}
const {
return yy::parser::make_CONST(this->location);
}
var {
return yy::parser::make_VAR(this->location);
}
True {
return yy::parser::make_BOOLEAN(true, this->location);
}
False {
return yy::parser::make_BOOLEAN(false, this->location);
}
[A-Za-z_][A-Za-z0-9_]* {
return yy::parser::make_IDENTIFIER(yytext, this->location);
}
[0-9]+ {
return yy::parser::make_NUMBER(strtol(yytext, NULL, 10), this->location);
}
\( {
return yy::parser::make_LEFT_PAREN(this->location);
}
\) {
return yy::parser::make_RIGHT_PAREN(this->location);
}
\>= {
return yy::parser::make_GREATER_EQUAL(this->location);
}
\<= {
return yy::parser::make_LESS_EQUAL(this->location);
}
\> {
return yy::parser::make_GREATER_THAN(this->location);
}
\< {
return yy::parser::make_LESS_THAN(this->location);
}
\/= {
return yy::parser::make_NOT_EQUAL(this->location);
}
= {
return yy::parser::make_EQUALS(this->location);
}
; {
return yy::parser::make_SEMICOLON(this->location);
}
\. {
return yy::parser::make_DOT(this->location);
}
, {
return yy::parser::make_COMMA(this->location);
}
\+ {
return yy::parser::make_PLUS(this->location);
}
\- {
return yy::parser::make_MINUS(this->location);
}
\* {
return yy::parser::make_MULTIPLICATION(this->location);
}
\/ {
return yy::parser::make_DIVISION(this->location);
}
:= {
return yy::parser::make_ASSIGNMENT(this->location);
}
: {
return yy::parser::make_COLON(this->location);
}
\^ {
return yy::parser::make_HAT(this->location);
}
@ {
return yy::parser::make_AT(this->location);
}
. {
std::stringstream ss;
ss << "Illegal character 0x" << std::hex << static_cast<unsigned char>(yytext[0]);
throw yy::parser::syntax_error(this->location, ss.str());
}
%%

141
source/parser.yy Normal file
View File

@ -0,0 +1,141 @@
%require "3.2"
%language "c++"
%code requires {
#include <cstdint>
#include <iostream>
#include "elna/source/ast.hpp"
#if ! defined(yyFlexLexerOnce)
#include <FlexLexer.h>
#endif
namespace elna::syntax
{
class FooLexer;
}
}
%code provides {
namespace elna::syntax
{
class FooLexer : public yyFlexLexer
{
public:
yy::location location;
FooLexer(std::istream& arg_yyin)
: yyFlexLexer(&arg_yyin)
{
}
yy::parser::symbol_type lex();
};
}
}
%define api.token.raw
%define api.token.constructor
%define api.value.type variant
%define parse.assert
%parse-param {elna::syntax::FooLexer& lexer}
%parse-param {std::unique_ptr<elna::source::program>& program}
%locations
%header
%code {
#define yylex lexer.lex
}
%start program;
%token <std::string> IDENTIFIER "identifier"
%token <std::int32_t> NUMBER "number"
%token <bool> BOOLEAN
%token IF THEN WHILE DO
%token CONST VAR PROCEDURE
%token BEGIN_BLOCK END_BLOCK
%token TRUE FALSE
%token LEFT_PAREN RIGHT_PAREN SEMICOLON DOT COMMA
%token GREATER_EQUAL LESS_EQUAL LESS_THAN GREATER_THAN NOT_EQUAL EQUALS
%token PLUS MINUS MULTIPLICATION DIVISION
%token ASSIGNMENT COLON HAT AT
%type <std::unique_ptr<elna::source::integer_literal>> integer_literal;
%type <std::unique_ptr<elna::source::constant_definition>> constant_definition;
%type <std::vector<std::unique_ptr<elna::source::constant_definition>>> constant_definition_part constant_definitions;
%type <std::unique_ptr<elna::source::type_expression>> type_expression;
%%
program: constant_definition_part
{
elna::source::position position;
std::vector<std::unique_ptr<elna::source::declaration>> declarations;
std::vector<std::unique_ptr<elna::source::definition>> definitions($1.size());
std::vector<std::unique_ptr<elna::source::definition>>::iterator definition = definitions.begin();
for (auto& constant : $1)
{
*definition++ = std::move(constant);
}
program = std::make_unique<elna::source::program>(position,
std::move(definitions), std::move(declarations),
std::make_unique<elna::source::compound_statement>(position));
}
integer_literal: NUMBER
{
elna::source::position position{
static_cast<std::size_t>(@1.begin.line),
static_cast<std::size_t>(@1.begin.column)
};
$$ = std::make_unique<elna::source::integer_literal>(position, $1);
};
type_expression:
HAT IDENTIFIER
{
elna::source::position position{
static_cast<std::size_t>(@1.begin.line),
static_cast<std::size_t>(@1.begin.column)
};
$$ = std::make_unique<elna::source::type_expression>(position, $2, true);
}
| IDENTIFIER
{
elna::source::position position{
static_cast<std::size_t>(@1.begin.line),
static_cast<std::size_t>(@1.begin.column)
};
$$ = std::make_unique<elna::source::type_expression>(position, $1, false);
}
variable_declaration: IDENTIFIER COLON type_expression
variable_declarations:
variable_declaration COMMA variable_declarations
| variable_declaration
constant_definition: IDENTIFIER EQUALS integer_literal
{
elna::source::position position{
static_cast<std::size_t>(@1.begin.line),
static_cast<std::size_t>(@1.begin.column)
};
$$ = std::make_unique<elna::source::constant_definition>(position,
$1, std::move($3));
};
constant_definitions:
constant_definition COMMA constant_definitions
{
std::swap($$, $3);
$$.emplace($$.cbegin(), std::move($1));
}
| constant_definition { $$.emplace_back(std::move($1)); }
constant_definition_part:
/* no constant definitions */ {}
| CONST constant_definitions SEMICOLON { std::swap($$, $2); };
%%
void yy::parser::error(const location_type& loc, const std::string &message)
{
std::cerr << "Error: " << message << std::endl;
}

24
source/result.cpp Normal file
View File

@ -0,0 +1,24 @@
#include "elna/source/result.hpp"
namespace elna::source
{
error::error(const std::filesystem::path& path, const position position)
: m_position(position), m_path(path)
{
}
std::size_t error::line() const noexcept
{
return this->m_position.line;
}
std::size_t error::column() const noexcept
{
return this->m_position.column;
}
const std::filesystem::path& error::path() const noexcept
{
return this->m_path;
}
}

96
source/types.cpp Normal file
View File

@ -0,0 +1,96 @@
#include <elna/source/types.hpp>
namespace elna::source
{
type::type(const std::size_t byte_size)
: byte_size(byte_size)
{
}
std::size_t type::size() const noexcept
{
return this->byte_size;
}
primitive_type::primitive_type(const std::string& type_name, const std::size_t byte_size)
: type(byte_size), type_name(type_name)
{
}
bool primitive_type::operator==(const primitive_type& that) const noexcept
{
return this->type_name == that.type_name;
}
bool primitive_type::operator!=(const primitive_type& that) const noexcept
{
return this->type_name != that.type_name;
}
pointer_type::pointer_type(std::shared_ptr<const type> base_type, const std::size_t byte_size)
: type(byte_size), base_type(base_type)
{
}
bool pointer_type::operator==(const pointer_type& that) const noexcept
{
return this->base_type == that.base_type;
}
bool pointer_type::operator!=(const pointer_type& that) const noexcept
{
return this->base_type != that.base_type;
}
procedure_type::procedure_type(std::vector<std::shared_ptr<const type>> arguments, const std::size_t byte_size)
: arguments(std::move(arguments)), type(byte_size)
{
}
bool procedure_type::operator==(const procedure_type &that) const noexcept
{
return this->arguments == that.arguments;
}
bool procedure_type::operator!=(const procedure_type &that) const noexcept
{
return this->arguments != that.arguments;
}
bool operator==(const type& lhs, const type& rhs) noexcept
{
{
auto lhs_type = dynamic_cast<const primitive_type *>(&lhs);
auto rhs_type = dynamic_cast<const primitive_type *>(&rhs);
if (lhs_type != nullptr && rhs_type != nullptr)
{
return *lhs_type == *rhs_type;
}
}
{
auto lhs_type = dynamic_cast<const pointer_type *>(&lhs);
auto rhs_type = dynamic_cast<const pointer_type *>(&rhs);
if (lhs_type != nullptr && rhs_type != nullptr)
{
return *lhs_type == *rhs_type;
}
}
{
auto lhs_type = dynamic_cast<const procedure_type *>(&lhs);
auto rhs_type = dynamic_cast<const procedure_type *>(&rhs);
if (lhs_type != nullptr && rhs_type != nullptr)
{
return *lhs_type == *rhs_type;
}
}
return false;
}
bool operator!=(const type& lhs, const type& rhs) noexcept
{
return !(lhs == rhs);
}
}