elna/source/parser.cpp

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