Initial commit

This commit is contained in:
2024-12-21 00:08:48 +01:00
commit 72681e349a
11 changed files with 1599 additions and 0 deletions

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);
}
}