2024-03-01 10:13:55 +01:00
|
|
|
#include "elna/parser.hpp"
|
|
|
|
#include <stdexcept>
|
|
|
|
|
|
|
|
namespace elna
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* AST node.
|
|
|
|
*/
|
|
|
|
void Node::accept(ParserVisitor *)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void Definition::accept(ParserVisitor *visitor)
|
|
|
|
{
|
|
|
|
visitor->visit(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Block::accept(ParserVisitor *visitor)
|
|
|
|
{
|
|
|
|
visitor->visit(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Expression::accept(ParserVisitor *visitor)
|
|
|
|
{
|
|
|
|
visitor->visit(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Number::accept(ParserVisitor *visitor)
|
|
|
|
{
|
|
|
|
visitor->visit(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Variable::accept(ParserVisitor *visitor)
|
|
|
|
{
|
|
|
|
visitor->visit(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
BinaryExpression::BinaryExpression(Expression *lhs, Expression *rhs, unsigned char _operator)
|
|
|
|
{
|
|
|
|
this->lhs = lhs;
|
|
|
|
this->rhs = rhs;
|
|
|
|
|
2024-03-03 13:11:39 +01:00
|
|
|
switch (_operator)
|
2024-03-01 10:13:55 +01:00
|
|
|
{
|
2024-03-03 13:11:39 +01:00
|
|
|
case '+':
|
|
|
|
this->_operator = BinaryOperator::sum;
|
|
|
|
break;
|
|
|
|
case '-':
|
|
|
|
this->_operator = BinaryOperator::subtraction;
|
|
|
|
break;
|
|
|
|
case '*':
|
|
|
|
this->_operator = BinaryOperator::multiplication;
|
|
|
|
break;
|
|
|
|
case '/':
|
|
|
|
this->_operator = BinaryOperator::division;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw std::logic_error("Invalid binary operator");
|
2024-03-01 10:13:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BinaryExpression::accept(ParserVisitor *visitor)
|
|
|
|
{
|
|
|
|
visitor->visit(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BangStatement::accept(ParserVisitor *visitor)
|
|
|
|
{
|
|
|
|
visitor->visit(this);
|
|
|
|
}
|
|
|
|
|
2024-03-03 13:11:39 +01:00
|
|
|
Block *parse(lex::Token *tokenStream, std::size_t length)
|
2024-03-01 10:13:55 +01:00
|
|
|
{
|
|
|
|
return parseBlock(&tokenStream, &length);
|
|
|
|
}
|
|
|
|
|
2024-03-03 13:11:39 +01:00
|
|
|
Expression *parseFactor(lex::Token **tokens, size_t *length)
|
2024-03-01 10:13:55 +01:00
|
|
|
{
|
2024-03-03 13:11:39 +01:00
|
|
|
if ((*tokens)[0].of() == lex::Token::type::identifier)
|
2024-03-01 10:13:55 +01:00
|
|
|
{
|
|
|
|
auto variable = new Variable();
|
|
|
|
variable->identifier = (*tokens)[0].identifier();
|
|
|
|
++(*tokens);
|
|
|
|
--(*length);
|
|
|
|
return variable;
|
|
|
|
}
|
2024-03-03 13:11:39 +01:00
|
|
|
else if ((*tokens)[0].of() == lex::Token::Token::type::number)
|
2024-03-01 10:13:55 +01:00
|
|
|
{
|
|
|
|
auto number = new Number();
|
|
|
|
number->value = (*tokens)[0].number();
|
|
|
|
++(*tokens);
|
|
|
|
--(*length);
|
|
|
|
return number;
|
|
|
|
}
|
2024-03-03 13:11:39 +01:00
|
|
|
else if ((*tokens)[0].of() == lex::Token::type::left_paren)
|
2024-03-01 10:13:55 +01:00
|
|
|
{
|
|
|
|
++(*tokens);
|
|
|
|
--(*length);
|
|
|
|
|
|
|
|
auto expression = parseExpression(tokens, length);
|
|
|
|
|
|
|
|
++(*tokens);
|
|
|
|
--(*length);
|
|
|
|
|
|
|
|
return expression;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2024-03-03 13:11:39 +01:00
|
|
|
Expression *parseTerm(lex::Token **tokens, size_t *length)
|
2024-03-01 10:13:55 +01:00
|
|
|
{
|
2024-03-03 13:11:39 +01:00
|
|
|
auto lhs = parseFactor(tokens, length);
|
|
|
|
if (lhs == nullptr || *length == 0 || (*tokens)[0].of() != lex::Token::type::factor_operator)
|
|
|
|
{
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
auto _operator = (*tokens)[0].identifier()[0];
|
|
|
|
++(*tokens);
|
|
|
|
--(*length);
|
|
|
|
|
|
|
|
auto rhs = parseFactor(tokens, length);
|
|
|
|
if (rhs != nullptr)
|
|
|
|
{
|
|
|
|
return new BinaryExpression(lhs, rhs, _operator);
|
|
|
|
}
|
|
|
|
return nullptr;
|
2024-03-01 10:13:55 +01:00
|
|
|
}
|
|
|
|
|
2024-03-03 13:11:39 +01:00
|
|
|
Expression *parseExpression(lex::Token **tokens, size_t *length)
|
2024-03-01 10:13:55 +01:00
|
|
|
{
|
|
|
|
auto term = parseTerm(tokens, length);
|
2024-03-03 13:11:39 +01:00
|
|
|
if (term == nullptr || *length == 0 || (*tokens)[0].of() != lex::Token::type::term_operator)
|
2024-03-01 10:13:55 +01:00
|
|
|
{
|
|
|
|
return term;
|
|
|
|
}
|
|
|
|
auto _operator = (*tokens)[0].identifier()[0];
|
|
|
|
++(*tokens);
|
|
|
|
--(*length);
|
|
|
|
|
|
|
|
auto expression = parseExpression(tokens, length);
|
|
|
|
|
|
|
|
if (expression != nullptr)
|
|
|
|
{
|
2024-03-03 13:11:39 +01:00
|
|
|
return new BinaryExpression(term, expression, _operator);
|
2024-03-01 10:13:55 +01:00
|
|
|
}
|
2024-03-03 13:11:39 +01:00
|
|
|
return nullptr;
|
2024-03-01 10:13:55 +01:00
|
|
|
}
|
|
|
|
|
2024-03-03 13:11:39 +01:00
|
|
|
Definition *parseDefinition(lex::Token **tokens, size_t *length)
|
2024-03-01 10:13:55 +01:00
|
|
|
{
|
|
|
|
auto definition = new Definition();
|
|
|
|
definition->identifier = (*tokens)[0].identifier(); // Copy.
|
|
|
|
|
|
|
|
++(*tokens);
|
|
|
|
++(*tokens); // Skip the equals sign.
|
|
|
|
*length -= 2;
|
|
|
|
|
2024-03-03 13:11:39 +01:00
|
|
|
if ((*tokens)[0].of() == lex::Token::type::number)
|
2024-03-01 10:13:55 +01:00
|
|
|
{
|
|
|
|
auto number = new Number();
|
|
|
|
number->value = (*tokens)[0].number();
|
|
|
|
definition->number = number;
|
|
|
|
++(*tokens);
|
|
|
|
--(*length);
|
|
|
|
return definition;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2024-03-03 13:11:39 +01:00
|
|
|
Statement *parseStatement(lex::Token **tokens, std::size_t *length)
|
2024-03-01 10:13:55 +01:00
|
|
|
{
|
2024-03-03 13:11:39 +01:00
|
|
|
if ((*tokens)[0].of() == lex::Token::type::bang)
|
2024-03-01 10:13:55 +01:00
|
|
|
{
|
|
|
|
++(*tokens);
|
|
|
|
--(*length);
|
|
|
|
auto statement = new BangStatement();
|
|
|
|
auto expression = parseExpression(tokens, length);
|
|
|
|
if (expression != nullptr)
|
|
|
|
{
|
|
|
|
statement->expression = expression;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return statement;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2024-03-03 13:11:39 +01:00
|
|
|
Definition **parseDefinitions(lex::Token **tokens, size_t *length, size_t *resultLength)
|
2024-03-01 10:13:55 +01:00
|
|
|
{
|
|
|
|
++(*tokens); // Skip const.
|
|
|
|
--(*length);
|
|
|
|
|
|
|
|
Definition **definitions;
|
|
|
|
*resultLength = 0;
|
|
|
|
|
|
|
|
while (*length != 0)
|
|
|
|
{
|
|
|
|
auto definition = parseDefinition(tokens, length);
|
|
|
|
if (definition == nullptr)
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
definitions = reinterpret_cast<Definition **>(
|
|
|
|
realloc(definitions, (*resultLength + 1) * sizeof(Definition*)));
|
|
|
|
definitions[(*resultLength)++] = definition;
|
|
|
|
|
2024-03-03 13:11:39 +01:00
|
|
|
if ((*tokens)[0].of() == lex::Token::type::semicolon)
|
2024-03-01 10:13:55 +01:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2024-03-03 13:11:39 +01:00
|
|
|
if ((*tokens)[0].of() == lex::Token::type::comma)
|
2024-03-01 10:13:55 +01:00
|
|
|
{
|
|
|
|
++(*tokens);
|
|
|
|
--(*length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return definitions;
|
|
|
|
}
|
|
|
|
|
2024-03-03 13:11:39 +01:00
|
|
|
Block *parseBlock(lex::Token **tokens, std::size_t *length)
|
2024-03-01 10:13:55 +01:00
|
|
|
{
|
|
|
|
auto block = new Block();
|
2024-03-03 13:11:39 +01:00
|
|
|
if ((*tokens)[0].of() == lex::Token::type::let)
|
2024-03-01 10:13:55 +01:00
|
|
|
{
|
|
|
|
size_t length_ = 0;
|
|
|
|
auto constDefinitions = parseDefinitions(tokens, length, &length_);
|
|
|
|
if (constDefinitions != nullptr)
|
|
|
|
{
|
|
|
|
block->definitionsLength = length_;
|
|
|
|
block->definitions = constDefinitions;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
++(*tokens);
|
|
|
|
--(*length);
|
|
|
|
}
|
|
|
|
auto statement = parseStatement(tokens, length);
|
|
|
|
if (statement != nullptr)
|
|
|
|
{
|
|
|
|
block->statement = statement;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return block;
|
|
|
|
}
|
|
|
|
}
|