1064 lines
29 KiB
C++
1064 lines
29 KiB
C++
#include "elna/source/parser.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;
|
|
}
|
|
|
|
parser::parser(lexer&& tokens)
|
|
: iterator(std::move(tokens))
|
|
{
|
|
}
|
|
|
|
std::unique_ptr<program> parser::parse()
|
|
{
|
|
auto constants = parse_constant_definitions();
|
|
auto declarations = parse_declarations();
|
|
auto procedures = parse_procedure_definitions();
|
|
auto parsed_statement = parse_statement();
|
|
|
|
if (parsed_statement == nullptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
std::vector<std::unique_ptr<definition>> definitions(constants.size() + procedures.size());
|
|
std::vector<std::unique_ptr<definition>>::iterator definition = definitions.begin();
|
|
|
|
for (auto& constant : constants)
|
|
{
|
|
*definition++ = std::move(constant);
|
|
}
|
|
for (auto& procedure : procedures)
|
|
{
|
|
*definition++ = std::move(procedure);
|
|
}
|
|
return std::make_unique<program>(position(), std::move(definitions),
|
|
std::move(declarations), std::move(parsed_statement));
|
|
}
|
|
|
|
const std::list<std::unique_ptr<error>>& parser::errors() const noexcept
|
|
{
|
|
return iterator.errors();
|
|
}
|
|
|
|
std::unique_ptr<expression> parser::parse_unary_expression()
|
|
{
|
|
std::unique_ptr<expression> result;
|
|
|
|
if (iterator.current(token::type::at))
|
|
{
|
|
std::unique_ptr<expression> body_expression;
|
|
|
|
++iterator;
|
|
if ((body_expression = parse_factor()) == nullptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
result = std::make_unique<unary_expression>(iterator->position(), std::move(body_expression), '@');
|
|
}
|
|
else
|
|
{
|
|
if ((result = parse_factor()) == nullptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
}
|
|
if (iterator.current(token::type::hat))
|
|
{
|
|
++iterator;
|
|
result = std::make_unique<unary_expression>(iterator->position(), std::move(result), '^');
|
|
}
|
|
return result;
|
|
}
|
|
|
|
std::unique_ptr<expression> parser::parse_factor()
|
|
{
|
|
if (iterator->of() == token::type::identifier)
|
|
{
|
|
auto result = std::make_unique<variable_expression>(iterator->position(), iterator->identifier());
|
|
++iterator;
|
|
return result;
|
|
}
|
|
else if (iterator->of() == token::token::type::number)
|
|
{
|
|
auto result = std::make_unique<integer_literal>(iterator->position(), iterator->number());
|
|
++iterator;
|
|
return result;
|
|
}
|
|
else if (iterator->of() == token::token::type::boolean)
|
|
{
|
|
auto result = std::make_unique<boolean_literal>(iterator->position(), iterator->number());
|
|
++iterator;
|
|
return result;
|
|
}
|
|
else if (iterator->of() == token::type::left_paren)
|
|
{
|
|
++iterator;
|
|
|
|
auto expression = parse_condition();
|
|
|
|
iterator.advance(token::type::right_paren);
|
|
|
|
return expression;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
std::unique_ptr<expression> parser::parse_term()
|
|
{
|
|
auto lhs = parse_unary_expression();
|
|
if (lhs == nullptr || iterator.current().of() != source::token::type::factor_operator)
|
|
{
|
|
return lhs;
|
|
}
|
|
while (iterator->of() == source::token::type::factor_operator)
|
|
{
|
|
auto _operator = iterator->identifier()[0];
|
|
const auto operator_position = iterator->position();
|
|
++iterator;
|
|
|
|
auto rhs = parse_unary_expression();
|
|
lhs = std::make_unique<binary_expression>(operator_position, std::move(lhs),
|
|
std::move(rhs), _operator);
|
|
}
|
|
return lhs;
|
|
}
|
|
|
|
std::unique_ptr<expression> parser::parse_expression()
|
|
{
|
|
auto term = parse_term();
|
|
if (term == nullptr || iterator.current().of() != source::token::type::term_operator)
|
|
{
|
|
return term;
|
|
}
|
|
while (iterator->of() == source::token::type::term_operator)
|
|
{
|
|
auto _operator = iterator->identifier()[0];
|
|
const auto operator_position = iterator->position();
|
|
++iterator;
|
|
|
|
auto rhs = parse_term();
|
|
term = std::make_unique<binary_expression>(operator_position, std::move(term),
|
|
std::move(rhs), _operator);
|
|
}
|
|
return term;
|
|
}
|
|
|
|
std::unique_ptr<expression> parser::parse_condition()
|
|
{
|
|
std::unique_ptr<expression> lhs;
|
|
|
|
if ((lhs = parse_expression()) == nullptr)
|
|
{
|
|
return lhs;
|
|
}
|
|
unsigned char _operator{ 0 };
|
|
|
|
if (iterator.current().of() == source::token::type::equals)
|
|
{
|
|
_operator = '=';
|
|
}
|
|
else if (iterator.current().of() == source::token::type::comparison_operator)
|
|
{
|
|
_operator = iterator->identifier()[0];
|
|
}
|
|
else
|
|
{
|
|
return lhs;
|
|
}
|
|
const auto operator_position = iterator->position();
|
|
++iterator;
|
|
auto rhs = parse_expression();
|
|
|
|
if (rhs == nullptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
return std::make_unique<binary_expression>(operator_position, std::move(lhs), std::move(rhs), _operator);
|
|
}
|
|
|
|
std::unique_ptr<constant_definition> parser::parse_constant_definition()
|
|
{
|
|
auto definition_identifier = iterator.advance(token::type::identifier);
|
|
const auto identifier_position = iterator->position();
|
|
|
|
if (!definition_identifier.has_value())
|
|
{
|
|
return nullptr;
|
|
}
|
|
if (!iterator.skip(token::type::equals))
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
if (iterator->of() == source::token::type::number)
|
|
{
|
|
auto result = std::make_unique<constant_definition>(identifier_position,
|
|
definition_identifier.value().get().identifier(),
|
|
std::make_unique<integer_literal>(iterator->position(), iterator->number()));
|
|
++iterator;
|
|
return result;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
std::unique_ptr<procedure_definition> parser::parse_procedure_definition()
|
|
{
|
|
const auto proc_position = iterator->position();
|
|
if (!iterator.skip(token::type::procedure))
|
|
{
|
|
return nullptr;
|
|
}
|
|
auto definition_identifier = iterator.advance(token::type::identifier);
|
|
|
|
if (!definition_identifier.has_value() || !iterator.skip(token::type::left_paren))
|
|
{
|
|
return nullptr;
|
|
}
|
|
std::vector<std::unique_ptr<declaration>> declarations;
|
|
while (!iterator.current(token::type::right_paren))
|
|
{
|
|
std::unique_ptr<declaration> parsed_declaration = parse_declaration();
|
|
if (parsed_declaration == nullptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
declarations.push_back(std::move(parsed_declaration));
|
|
|
|
if (iterator->of() == token::type::comma)
|
|
{
|
|
++iterator;
|
|
continue;
|
|
}
|
|
else if (iterator->of() != token::type::right_paren)
|
|
{
|
|
iterator.add_error(*iterator);
|
|
return nullptr;
|
|
}
|
|
}
|
|
iterator.skip(token::type::right_paren);
|
|
auto definition_body = parse_block();
|
|
|
|
if (definition_body == nullptr || !iterator.skip(token::type::semicolon))
|
|
{
|
|
return nullptr;
|
|
}
|
|
auto procedure = std::make_unique<procedure_definition>(proc_position,
|
|
definition_identifier->get().identifier(), std::move(definition_body));
|
|
procedure->parameters() = std::move(declarations);
|
|
|
|
return procedure;
|
|
}
|
|
|
|
std::unique_ptr<type_expression> parser::parse_type_expression()
|
|
{
|
|
const auto type_position = iterator->position();
|
|
bool is_pointer{ false };
|
|
if (iterator.current(token::type::hat))
|
|
{
|
|
is_pointer = true;
|
|
++iterator;
|
|
}
|
|
auto type_identifier = iterator.advance(token::type::identifier);
|
|
|
|
if (!type_identifier.has_value())
|
|
{
|
|
return nullptr;
|
|
}
|
|
return std::make_unique<type_expression>(type_position, type_identifier.value().get().identifier(),
|
|
is_pointer);
|
|
}
|
|
|
|
std::unique_ptr<declaration> parser::parse_declaration()
|
|
{
|
|
auto declaration_identifier = iterator.advance(token::type::identifier);
|
|
|
|
if (!declaration_identifier.has_value() || !iterator.skip(token::type::colon))
|
|
{
|
|
return nullptr;
|
|
}
|
|
auto type_identifier = parse_type_expression();
|
|
|
|
if (type_identifier == nullptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
return std::make_unique<declaration>(declaration_identifier.value().get().position(),
|
|
declaration_identifier.value().get().identifier(), std::move(type_identifier));
|
|
}
|
|
|
|
std::unique_ptr<statement> parser::parse_statement()
|
|
{
|
|
if (iterator.look_ahead(token::type::assignment))
|
|
{
|
|
return parse_assign_statement();
|
|
}
|
|
else if (iterator.current(token::type::identifier) && iterator.look_ahead(token::type::left_paren))
|
|
{
|
|
return parse_call_statement();
|
|
}
|
|
else if (iterator.current(token::type::begin))
|
|
{
|
|
return parse_compound_statement();
|
|
}
|
|
else if (iterator.current(token::type::when))
|
|
{
|
|
return parse_if_statement();
|
|
}
|
|
else if (iterator.current(token::type::loop))
|
|
{
|
|
return parse_while_statement();
|
|
}
|
|
iterator.add_error(*iterator);
|
|
return nullptr;
|
|
}
|
|
|
|
std::unique_ptr<call_statement> parser::parse_call_statement()
|
|
{
|
|
auto function_name = iterator.advance(token::type::identifier);
|
|
if (function_name.has_value() && !iterator.skip(token::type::left_paren))
|
|
{
|
|
return nullptr;
|
|
}
|
|
auto call = std::make_unique<call_statement>(function_name->get().position(),
|
|
function_name->get().identifier());
|
|
std::unique_ptr<expression> argument_expression;
|
|
|
|
if (iterator.current(token::type::right_paren))
|
|
{
|
|
++iterator;
|
|
return call;
|
|
}
|
|
while ((argument_expression = parse_condition()) != nullptr)
|
|
{
|
|
call->arguments().push_back(std::move(argument_expression));
|
|
|
|
if (iterator.current(token::type::right_paren))
|
|
{
|
|
++iterator;
|
|
return call;
|
|
}
|
|
if (!iterator.skip(token::type::comma))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
std::unique_ptr<compound_statement> parser::parse_compound_statement()
|
|
{
|
|
const auto begin_position = iterator->position();
|
|
if (!iterator.advance(token::type::begin))
|
|
{
|
|
return nullptr;
|
|
}
|
|
auto result = std::make_unique<compound_statement>(begin_position);
|
|
std::unique_ptr<statement> next_statement;
|
|
|
|
while ((next_statement = parse_statement()) != nullptr)
|
|
{
|
|
result->statements().push_back(std::move(next_statement));
|
|
|
|
if (iterator->of() == token::type::semicolon)
|
|
{
|
|
++iterator;
|
|
}
|
|
else if (iterator->of() == token::type::end)
|
|
{
|
|
++iterator;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
iterator.add_error(*iterator);
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
std::unique_ptr<assign_statement> parser::parse_assign_statement()
|
|
{
|
|
auto name = iterator.advance(token::type::identifier);
|
|
if (!name.has_value() || !iterator.skip(token::type::assignment))
|
|
{
|
|
return nullptr;
|
|
}
|
|
auto rvalue = parse_condition();
|
|
|
|
if (rvalue == nullptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
return std::make_unique<assign_statement>(name.value().get().position(), name.value().get().identifier(),
|
|
std::move(rvalue));
|
|
}
|
|
|
|
std::unique_ptr<if_statement> parser::parse_if_statement()
|
|
{
|
|
const auto if_position = iterator->position();
|
|
if (!iterator.skip(token::type::when))
|
|
{
|
|
return nullptr;
|
|
}
|
|
auto condition = parse_condition();
|
|
|
|
if (condition == nullptr || !iterator.skip(token::type::then))
|
|
{
|
|
return nullptr;
|
|
}
|
|
auto body = parse_statement();
|
|
|
|
if (body == nullptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
return std::make_unique<if_statement>(if_position, std::move(condition), std::move(body));
|
|
}
|
|
|
|
std::unique_ptr<while_statement> parser::parse_while_statement()
|
|
{
|
|
const auto while_position = iterator->position();
|
|
if (!iterator.skip(token::type::loop))
|
|
{
|
|
return nullptr;
|
|
}
|
|
auto condition = parse_condition();
|
|
|
|
if (condition == nullptr || !iterator.skip(token::type::_do))
|
|
{
|
|
return nullptr;
|
|
}
|
|
auto body = parse_statement();
|
|
|
|
if (body == nullptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
return std::make_unique<while_statement>(while_position, std::move(condition), std::move(body));
|
|
}
|
|
|
|
std::vector<std::unique_ptr<constant_definition>> parser::parse_constant_definitions()
|
|
{
|
|
std::vector<std::unique_ptr<constant_definition>> definitions;
|
|
|
|
if (iterator->of() != token::type::let)
|
|
{
|
|
return definitions;
|
|
}
|
|
++iterator; // Skip const.
|
|
|
|
std::unique_ptr<constant_definition> parsed_definition;
|
|
while ((parsed_definition = parse_constant_definition()) != nullptr)
|
|
{
|
|
definitions.push_back(std::move(parsed_definition));
|
|
|
|
if (iterator->of() == source::token::type::comma)
|
|
{
|
|
++iterator;
|
|
}
|
|
else if (iterator->of() == source::token::type::semicolon)
|
|
{
|
|
++iterator;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
iterator.add_error(*iterator);
|
|
break;
|
|
}
|
|
}
|
|
return definitions;
|
|
}
|
|
|
|
std::vector<std::unique_ptr<procedure_definition>> parser::parse_procedure_definitions()
|
|
{
|
|
std::vector<std::unique_ptr<procedure_definition>> definitions;
|
|
|
|
while (iterator.current(token::type::procedure))
|
|
{
|
|
auto parsed_definition = parse_procedure_definition();
|
|
|
|
if (parsed_definition == nullptr)
|
|
{
|
|
break;
|
|
}
|
|
definitions.push_back(std::move(parsed_definition));
|
|
}
|
|
return definitions;
|
|
}
|
|
|
|
std::vector<std::unique_ptr<declaration>> parser::parse_declarations()
|
|
{
|
|
std::vector<std::unique_ptr<declaration>> declarations;
|
|
|
|
if (iterator->of() != token::type::var)
|
|
{
|
|
return declarations;
|
|
}
|
|
++iterator; // Skip var.
|
|
|
|
std::unique_ptr<declaration> parsed_declaration;
|
|
while ((parsed_declaration = parse_declaration()) != nullptr)
|
|
{
|
|
declarations.push_back(std::move(parsed_declaration));
|
|
|
|
if (iterator->of() == token::type::comma)
|
|
{
|
|
++iterator;
|
|
}
|
|
else if (iterator->of() == token::type::semicolon)
|
|
{
|
|
++iterator;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
iterator.add_error(*iterator);
|
|
break;
|
|
}
|
|
}
|
|
return declarations;
|
|
}
|
|
|
|
std::unique_ptr<block> parser::parse_block()
|
|
{
|
|
auto constants = parse_constant_definitions();
|
|
auto declarations = parse_declarations();
|
|
auto parsed_statement = parse_statement();
|
|
|
|
if (parsed_statement == nullptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
std::vector<std::unique_ptr<definition>> definitions(constants.size());
|
|
std::vector<std::unique_ptr<definition>>::iterator definition = definitions.begin();
|
|
|
|
for (auto& constant : constants)
|
|
{
|
|
*definition++ = std::move(constant);
|
|
}
|
|
return std::make_unique<block>(parsed_statement->position(), std::move(definitions),
|
|
std::move(declarations), std::move(parsed_statement));
|
|
}
|
|
}
|