241 lines
5.8 KiB
C++
241 lines
5.8 KiB
C++
|
#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;
|
||
|
|
||
|
if (_operator == '+')
|
||
|
{
|
||
|
this->_operator = BinaryOperator::sum;
|
||
|
}
|
||
|
else if (_operator == '-')
|
||
|
{
|
||
|
this->_operator = BinaryOperator::subtraction;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
throw std::logic_error("Invalid binary operator");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void BinaryExpression::accept(ParserVisitor *visitor)
|
||
|
{
|
||
|
visitor->visit(this);
|
||
|
}
|
||
|
|
||
|
void BangStatement::accept(ParserVisitor *visitor)
|
||
|
{
|
||
|
visitor->visit(this);
|
||
|
}
|
||
|
|
||
|
Block *parse(Token *tokenStream, std::size_t length)
|
||
|
{
|
||
|
return parseBlock(&tokenStream, &length);
|
||
|
}
|
||
|
|
||
|
Expression *parseFactor(Token **tokens, size_t *length)
|
||
|
{
|
||
|
if ((*tokens)[0].of() == Token::TOKEN_IDENTIFIER)
|
||
|
{
|
||
|
auto variable = new Variable();
|
||
|
variable->identifier = (*tokens)[0].identifier();
|
||
|
++(*tokens);
|
||
|
--(*length);
|
||
|
return variable;
|
||
|
}
|
||
|
else if ((*tokens)[0].of() == Token::TOKEN_NUMBER)
|
||
|
{
|
||
|
auto number = new Number();
|
||
|
number->value = (*tokens)[0].number();
|
||
|
++(*tokens);
|
||
|
--(*length);
|
||
|
return number;
|
||
|
}
|
||
|
else if ((*tokens)[0].of() == Token::TOKEN_LEFT_PAREN)
|
||
|
{
|
||
|
++(*tokens);
|
||
|
--(*length);
|
||
|
|
||
|
auto expression = parseExpression(tokens, length);
|
||
|
|
||
|
++(*tokens);
|
||
|
--(*length);
|
||
|
|
||
|
return expression;
|
||
|
}
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
Expression *parseTerm(Token **tokens, size_t *length)
|
||
|
{
|
||
|
return parseFactor(tokens, length);
|
||
|
}
|
||
|
|
||
|
Expression *parseExpression(Token **tokens, size_t *length)
|
||
|
{
|
||
|
auto term = parseTerm(tokens, length);
|
||
|
if (term == nullptr || *length == 0 || (*tokens)[0].of() != Token::TOKEN_OPERATOR)
|
||
|
{
|
||
|
return term;
|
||
|
}
|
||
|
auto _operator = (*tokens)[0].identifier()[0];
|
||
|
++(*tokens);
|
||
|
--(*length);
|
||
|
|
||
|
auto expression = parseExpression(tokens, length);
|
||
|
|
||
|
if (expression != nullptr)
|
||
|
{
|
||
|
auto binaryExpression = new BinaryExpression(term, expression, _operator);
|
||
|
|
||
|
return binaryExpression;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return nullptr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Definition *parseDefinition(Token **tokens, size_t *length)
|
||
|
{
|
||
|
auto definition = new Definition();
|
||
|
definition->identifier = (*tokens)[0].identifier(); // Copy.
|
||
|
|
||
|
++(*tokens);
|
||
|
++(*tokens); // Skip the equals sign.
|
||
|
*length -= 2;
|
||
|
|
||
|
if ((*tokens)[0].of() == Token::TOKEN_NUMBER)
|
||
|
{
|
||
|
auto number = new Number();
|
||
|
number->value = (*tokens)[0].number();
|
||
|
definition->number = number;
|
||
|
++(*tokens);
|
||
|
--(*length);
|
||
|
return definition;
|
||
|
}
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
Statement *parseStatement(Token **tokens, std::size_t *length)
|
||
|
{
|
||
|
if ((*tokens)[0].of() == Token::TOKEN_BANG)
|
||
|
{
|
||
|
++(*tokens);
|
||
|
--(*length);
|
||
|
auto statement = new BangStatement();
|
||
|
auto expression = parseExpression(tokens, length);
|
||
|
if (expression != nullptr)
|
||
|
{
|
||
|
statement->expression = expression;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return nullptr;
|
||
|
}
|
||
|
return statement;
|
||
|
}
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
Definition **parseDefinitions(Token **tokens, size_t *length, size_t *resultLength)
|
||
|
{
|
||
|
++(*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;
|
||
|
|
||
|
if ((*tokens)[0].of() == Token::TOKEN_SEMICOLON)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
if ((*tokens)[0].of() == Token::TOKEN_COMMA)
|
||
|
{
|
||
|
++(*tokens);
|
||
|
--(*length);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return definitions;
|
||
|
}
|
||
|
|
||
|
Block *parseBlock(Token **tokens, std::size_t *length)
|
||
|
{
|
||
|
auto block = new Block();
|
||
|
if ((*tokens)[0].of() == Token::TOKEN_LET)
|
||
|
{
|
||
|
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;
|
||
|
}
|
||
|
}
|