0
\$\begingroup\$

#include <iostream>
#include <optional>
#include <string>
#include <vector>

#include "syntaxtoken.hpp"
#include "token.hpp"

#include "astnode.hpp"
#include "binaryexpression.hpp"
#include "boolnode.hpp"
#include "identifiernode.hpp"
#include "numbernode.hpp"
#include "stringnode.hpp"
#include "ifstmtnode.hpp"
#include "unarynode.hpp"
#include "varassignmentstmtnode.hpp"
#include "vardeclarationnode.hpp"
#include "functioncallexpr.hpp"
#include "blockstmtnode.hpp"

#include "printstmtnode.hpp"

#include "parser.hpp"

Parser::Parser(std::string program, EnvStack env_stack, FunctionMemory& function_memory)
    : function_memory(function_memory)
{
    this->env_stack = std::move(env_stack);

    Lexer lexer(program);

    std::vector<SyntaxToken> tokens;
    //temp 'token' will be overwritten.
    SyntaxToken token = SyntaxToken::SyntaxToken(NO_OPERATOR_TOKEN, "", 0, 0, 0);
    while (token.get_token_t() != BAD_TOKEN)
    {
        token = lexer.lex();
        if (token.get_token_t() == END_OF_FILE_TOKEN)
        {
            break;
        }
        tokens.push_back(token);
    }
    this->tokens = tokens;
    this->index = 0;
}

SyntaxToken Parser::next_token()
{
    size_t size = this->tokens.size();
    if (this->index < size)
    {
        return this->tokens[this->index++];
    }
    return SyntaxToken::SyntaxToken(END_OF_FILE_TOKEN, "", this->index - 1, 0, -1);
}

bool Parser::is_at_end()
{
    if (this->index >= this->tokens.size()                      ||
        this->tokens[this->index].get_token_t() == BAD_TOKEN    ||
        this->tokens[this->index].get_token_t() == END_OF_FILE_TOKEN)
    {
        return true;
    }
    return false;
}

void Parser::advance()
{
    size_t size = this->tokens.size();
    if (this->index < size)
    {
        this->index++;
    }
}

SyntaxToken Parser::peek_next_next()
{
    return look_ahead(2);
}

SyntaxToken Parser::peek_next()
{
    return look_ahead(1);
}

SyntaxToken Parser::peek()
{
    return look_ahead(0);
}

SyntaxToken Parser::previous()
{
    return look_ahead(-1);
}

SyntaxToken Parser::previous_previous()
{
    return look_ahead(-2);
}

void Parser::back()
{
    if (this->index - 1 >= 0)
    {
        --this->index;
    }
}

SyntaxToken Parser::look_ahead(int offset) {
    int index = offset + this->index;
    if (index < this->tokens.size()) {
        return this->tokens[index];
    }
    return this->tokens[this->tokens.size() - 1];
}

SyntaxToken Parser::expect(Token_t expect)
{
    if (peek().get_token_t() == expect)
    {
        return next_token();
    }
    SyntaxToken curr = peek();
    report("Expected " + token_name(expect));
    return SyntaxToken::SyntaxToken(BAD_TOKEN, "", -1, 0, 0);
}

std::optional<SyntaxToken> Parser::expect_optional(Token_t expect)
{
    if (peek().get_token_t() == expect)
    {
        return next_token();
    }
    return std::nullopt;
}

std::optional<SyntaxToken> Parser::find_var_type()
{
    std::optional<SyntaxToken> dt_op = std::nullopt;
    if (expect_optional(BOOL_TYPE))
    {
        dt_op = previous();
    }
    if (expect_optional(SHORT_TYPE))
    {
        dt_op = previous();
    }
    if (expect_optional(INT_TYPE))
    {
        dt_op = previous();
    }
    if (expect_optional(LONG_TYPE))
    {
        dt_op = previous();
    }
    if (expect_optional(FLOAT_TYPE))
    {
        dt_op = previous();
    }
    if (expect_optional(DOUBLE_TYPE))
    {
        dt_op = previous();
    }
    return dt_op;
}

bool Parser::match(Token_t match) {
    if (peek().get_token_t() == match) {
        return true;
    }
    return false;
}

bool Parser::matchany(std::vector<Token_t> tokens)
{
    for (Token_t token : tokens)
    {
        if (match(token))
        {
            return true;
        }
    }
    return false;
}

std::vector<std::unique_ptr<AstNode>> Parser::parse()
{
    std::vector<std::unique_ptr<AstNode>> statements;
    while (!is_at_end() && this->get_error_reports().empty())
    {
        try
        {
            std::unique_ptr<AstNode> statement = parseStatement();
            if (statement == nullptr)
            {
                break;
            }
            statements.push_back(std::move(statement));
        }
        catch (std::invalid_argument e)
        {
            report(e.what());
        }
    }

    return statements;
}

void Parser::report(std::string error)
{
    this->error_reports.push_back(error);
}

std::vector<std::string> Parser::get_error_reports()
{
    return this->error_reports;
}

std::unique_ptr<AstNode> Parser::parseStatement()
{
    if (match(PRINT_STMT))
    {
        return parsePrintStatement();
    }
    if (matchany({ BOOL_TYPE, SHORT_TYPE, INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE }))
    {
        return declarationStatement();
    }

    if (match(IF_KW))
    {
        return parseIfStatement();
    }

    if (match(OPEN_CURLY_BRACKET))
    {
        return parseBlockStatement({}, "main");
    }
    return parseExpression();
}

std::unique_ptr<AstNode> Parser::parseIfStatement()
{
    expect(IF_KW);
    expect(OPEN_PAREN);
    std::unique_ptr<AstNode> expression = parseExpression();
    expect(CLOSE_PAREN);

    std::unique_ptr<AstNode> blockstmt = parseBlockStatement();
    return std::make_unique<IfStmtNode>(std::move(expression), std::move(blockstmt));
}

std::unique_ptr<AstNode> Parser::parsePrintStatement()
{
    advance();
    std::unique_ptr<AstNode> expression = parseExpression();
    if (expression != nullptr)
    {
        expect(SEMICOLON_TOKEN);
    }
    return std::make_unique<PrintStmtNode>(std::move(expression));
}

std::unique_ptr<AstNode> Parser::declarationStatement()
{
    if (matchany({
        BOOL_TYPE,
        SHORT_TYPE,
        INT_TYPE,
        LONG_TYPE,
        FLOAT_TYPE,
        DOUBLE_TYPE}) && peek_next().get_token_t() == IDENTIFIER_TOKEN)
    {
        if (peek_next_next().get_token_t() == OPEN_PAREN)
        {
            return functionDeclarationStatement();
        }
        return varDeclarationStatement();
    }
    
    return nullptr;
}

std::unique_ptr<AstNode> Parser::functionDeclarationStatement()
{
    std::optional<SyntaxToken> dt_op = find_var_type();

    SyntaxToken identifier = expect(IDENTIFIER_TOKEN);
    if (not dt_op.has_value())
    {
        throw std::invalid_argument("Data type for identifier: " + identifier.get_value() + " not found.");
    }
    SyntaxToken dt = dt_op.value();
    FuncVariable func_var;
    func_var.return_type = from_TokenT_to_DataType(dt.get_token_t());
    func_var.identifier = identifier.get_value();
    
    expect(OPEN_PAREN);
    std::vector<Variable> formal_parameters;
    if (not match(CLOSE_PAREN))
    {
        formal_parameters = parameters();
    }
    expect(CLOSE_PAREN);
    
    std::unique_ptr<AstNode> blockstmt = parseBlockStatement(formal_parameters, func_var.identifier);
    func_var.block_stmt = std::move(blockstmt);
    func_var.parameters = std::move(formal_parameters);
    this->function_memory.add(std::move(func_var));
    return {}; // nullptr for std::unique_ptr
}

std::unique_ptr<AstNode> Parser::functionCall()
{
    SyntaxToken identifier = expect(IDENTIFIER_TOKEN);
    std::vector<std::unique_ptr<AstNode>> args = arguments();
    expect(CLOSE_PAREN); 
    return std::make_unique<FunctionCallExpr>(identifier.get_value(), std::move(args));;
}

std::vector<Variable> Parser::parameters()
{
    std::vector<Variable> formal_parameters;

    std::optional<SyntaxToken> var_dt = find_var_type();
    SyntaxToken identifier = expect(IDENTIFIER_TOKEN);
    if (not var_dt.has_value())
    {
        throw std::invalid_argument("Data type for identifier: " + identifier.get_value() + " not found.");
    }
    Variable var1;
    var1.dtType = from_TokenT_to_DataType(var_dt.value().get_token_t());
    var1.identifier = identifier.get_value();
    
    formal_parameters.push_back(var1);

    while (match(COMMA_TOKEN))
    {
        advance();
        std::optional<SyntaxToken> var_dt = find_var_type();
        SyntaxToken identifier = expect(IDENTIFIER_TOKEN);
        if (not var_dt.has_value())
        {
            throw std::invalid_argument("Data type for identifier: " + identifier.get_value() + " not found.");
        }
        Variable var2;
        var2.dtType = from_TokenT_to_DataType(var_dt.value().get_token_t());
        var2.identifier = identifier.get_value();
        formal_parameters.push_back(var2);
    }
    return formal_parameters;
}

std::vector<std::unique_ptr<AstNode>> Parser::arguments()
{
    expect(OPEN_PAREN);
    std::vector<std::unique_ptr<AstNode>> args;
    while (not match(CLOSE_PAREN))
    {
        args.push_back(parseExpression());
        if (match(CLOSE_PAREN))
        {
            break;
        }
        expect(COMMA_TOKEN);
    }
    expect(CLOSE_PAREN);
    return args;
}

std::unique_ptr<AstNode> Parser::parseBlockStatement(std::vector<Variable> pre_vars, std::string func_id)
{
    expect(OPEN_CURLY_BRACKET);

    Environment block_env;
    for (auto pre_var : pre_vars)
    {
        block_env.env_var.set(pre_var);
    }
    this->env_stack.push(std::move(block_env));

    std::vector<std::unique_ptr<AstNode>> stmts;
    while (not match(CLOSE_CURLY_BRACKET))
    {
        stmts.push_back(std::move(parseStatement()));
    }
    expect(CLOSE_CURLY_BRACKET);
    return std::make_unique<BlockStmtNode>(std::move(stmts));
}

std::unique_ptr<AstNode> Parser::varDeclarationStatement()
{
    std::optional<SyntaxToken> dt_op = find_var_type();

    SyntaxToken identifier = expect(IDENTIFIER_TOKEN);

    if (not dt_op.has_value())
    {
        throw std::invalid_argument("Data type for identifier: " + identifier.get_value() + " not found.");
    }
    SyntaxToken dt = dt_op.value();
    Variable var;
    var.dtType = from_TokenT_to_DataType(dt.get_token_t());
    var.identifier = identifier.get_value();
    this->env_stack.add(var);
    std::unique_ptr<AstNode> expression;
    if (expect_optional(EQUAL_TOKEN))
    {
        expression = std::move(parseExpression());
    }
    expect(SEMICOLON_TOKEN);

    return std::make_unique<VarDeclarationNode>(dt.get_token_t(), identifier.get_value(), std::move(expression));
}

std::unique_ptr<AstNode> Parser::varAssignmentStatement()
{
    SyntaxToken identifier = expect(IDENTIFIER_TOKEN);

    if (expect_optional(PLUS_PLUS_TOKEN))
    {
        std::unique_ptr<AstNode> ppt = std::make_unique<BinaryExpression>(std::make_unique<IdentifierNode>(identifier.get_value()), PLUS_TOKEN, std::make_unique<NumberNode>(1));
        expect(SEMICOLON_TOKEN);
        return std::make_unique<VarAssignmentStmtNode>(identifier.get_value(), std::move(ppt));
    }
    if (expect_optional(TRIPLE_PLUS_TOKEN))
    {
        std::unique_ptr<AstNode> ppt = std::make_unique<BinaryExpression>(std::make_unique<IdentifierNode>(identifier.get_value()), PLUS_TOKEN, std::make_unique<NumberNode>(2));
        expect(SEMICOLON_TOKEN);
        return std::make_unique<VarAssignmentStmtNode>(identifier.get_value(), std::move(ppt));
    }
    if (expect_optional(MINUS_MINUS_TOKEN))
    {
        std::unique_ptr<AstNode> ppt = std::make_unique<BinaryExpression>(std::make_unique<IdentifierNode>(identifier.get_value()), MINUS_TOKEN, std::make_unique<NumberNode>(1));
        expect(SEMICOLON_TOKEN);
        return std::make_unique<VarAssignmentStmtNode>(identifier.get_value(), std::move(ppt));
    }
    if (expect_optional(PLUS_EQUAL_TOKEN))
    {
        std::unique_ptr<AstNode> ppt = std::make_unique<BinaryExpression>(std::make_unique<IdentifierNode>(identifier.get_value()), PLUS_TOKEN, std::move(parseExpression()));
        expect(SEMICOLON_TOKEN);
        return std::make_unique<VarAssignmentStmtNode>(identifier.get_value(), std::move(ppt));
    }
    if (expect_optional(MINUS_EQUAL_TOKEN))
    {
        std::unique_ptr<AstNode> ppt = std::make_unique<BinaryExpression>(std::make_unique<IdentifierNode>(identifier.get_value()), MINUS_TOKEN, std::move(parseExpression()));
        expect(SEMICOLON_TOKEN);
        return std::make_unique<VarAssignmentStmtNode>(identifier.get_value(), std::move(ppt));
    }
    if (expect_optional(STAR_EQUAL_TOKEN))
    {
        std::unique_ptr<AstNode> ppt = std::make_unique<BinaryExpression>(std::make_unique<IdentifierNode>(identifier.get_value()), STAR_TOKEN, std::move(parseExpression()));
        expect(SEMICOLON_TOKEN);
        return std::make_unique<VarAssignmentStmtNode>(identifier.get_value(), std::move(ppt));
    }
    if (expect_optional(SLASH_EQUAL_TOKEN))
    {
        std::unique_ptr<AstNode> ppt = std::make_unique<BinaryExpression>(std::make_unique<IdentifierNode>(identifier.get_value()), SLASH_TOKEN, std::move(parseExpression()));
        expect(SEMICOLON_TOKEN);
        return std::make_unique<VarAssignmentStmtNode>(identifier.get_value(), std::move(ppt));
    }

    if (expect_optional(EQUAL_TOKEN))
    {
        std::unique_ptr<AstNode> expression = parseExpression();
        expect(SEMICOLON_TOKEN);
        return std::make_unique<VarAssignmentStmtNode>(identifier.get_value(), std::move(expression));
    }
    back();
    return parseTerm();
}

std::unique_ptr<AstNode> Parser::parseExpression()
{
    if (match(IDENTIFIER_TOKEN))
    {
        if (peek_next().get_token_t() == OPEN_PAREN)
        {
            return functionCall();
        }
        return varAssignmentStatement();
    }
    return parseTerm();
}

std::unique_ptr<AstNode> Parser::parseTerm()
{
    std::unique_ptr<AstNode> left = parseFactor();
    while (matchany({
        PLUS_TOKEN,
        MINUS_TOKEN
                    }))
    {
        SyntaxToken op = next_token();
        std::unique_ptr<AstNode> right = parseFactor();
        left = std::make_unique<BinaryExpression>(std::move(left), op.get_token_t(), std::move(right));
    }
    return left;
}

std::unique_ptr<AstNode> Parser::parseFactor()
{
    std::unique_ptr<AstNode> left = parseUnary();

    while (matchany({ STAR_TOKEN, SLASH_TOKEN }))
    {
        SyntaxToken op = next_token();
        std::unique_ptr<AstNode> right = parseUnary();
        left = std::make_unique<BinaryExpression>(std::move(left), op.get_token_t(), std::move(right));
    }

    return left;
}

std::unique_ptr<AstNode> Parser::parseUnary()
{
    if (match(MINUS_TOKEN))
    {
        SyntaxToken token = next_token();
        std::unique_ptr<AstNode> unary = parseUnary();
        return std::make_unique<UnaryNode>(token.get_token_t(), std::move(unary));
    }
    return parsePrimary();
}

std::unique_ptr<AstNode> Parser::parsePrimary()
{
    std::unique_ptr<AstNode> primary = {};
    SyntaxToken token = SyntaxToken::SyntaxToken(BAD_TOKEN, "", -1, 0, 0);

    SyntaxToken prev = previous();
    SyntaxToken prev_prev = previous_previous();
    if (match(NUMBER_TOKEN) &&
        prev.get_token_t() == EQUAL_TOKEN &&
        prev_prev.get_token_t() == IDENTIFIER_TOKEN)
    {
        token = next_token();
        std::pair<Variable, Environment> var = std::move(this->env_stack.get(prev_prev.get_value()));
        switch (var.first.dtType)
        {
        case DT_SHORT:
            return std::make_unique<NumberNode>((short)stoi(token.get_value()));
        case DT_INT:
            return std::make_unique<NumberNode>(stoi(token.get_value()));
        case DT_LONG:
            return std::make_unique<NumberNode>(stol(token.get_value()));
        case DT_FLOAT:
            return std::make_unique<NumberNode>(stof(token.get_value()));
        case DT_DOUBLE:
            return std::make_unique<NumberNode>(stod(token.get_value()));
        default:
            return std::make_unique<NumberNode>(stoi(token.get_value()));
        }
    }
    else if (match(NUMBER_TOKEN))
    {
        token = next_token();
        if (token.get_value().find('.') != std::string::npos)
        {
            return std::make_unique<NumberNode>(stod(token.get_value()));
        }
        return std::make_unique<NumberNode>(stoi(token.get_value()));
    }
    else if (match(STRING_LITERAL_TOKEN))
    {
        token = next_token();
        return std::make_unique<StringNode>(token.get_value());
    }
    else if (match(IDENTIFIER_TOKEN))
    {
        token = next_token();
        return std::make_unique<IdentifierNode>(token.get_value());
    }
    else if (match(FALSE_TOKEN)) {
        advance();
        return std::make_unique<BoolNode>(false);
    }
    else if (match(TRUE_TOKEN)) {
        advance();
        return std::make_unique<BoolNode>(true);
    }
    return primary;
}

This is all the code for the parser. The grammar is this:


program => statement* EOF

statement => ifStatement                    |
             printStatement                 |
             declearationStatement          |    
             varAssignmentStatement         |
             functionDeclarationStatement   |
             functionCall                   |
             blockStatement

declearationStatement => varDeclearationStatement    | 
                         functionDeclarationStatement

ifStatement => "if" "(" expression ")" blockStatement

printStatement => "print " expression ";"
varDeclearationStatement => varType IDENTIFIER ("=" expression)? ";"
varAssignmentStatement => IDENTIFIER "=" expression ";"

functionDeclarationStatement => varType IDENTIFIER "(" (parameters)? ")" blockStatement
functionCall => IDENTIFIER "(" (arguments)? ")" ";"
blockStatement => "{" statement* "}"

parameters => varType IDENTIFIER ("," varType IDENTIFIER)*
arguments => primary ("," primary)*

varType => "short"  |
           "int"    |
           "long"   |
           "float"  |
           "double"

expression => binary | unary | literal

binary  => expression operator expression
unary   => "-" unary | primary
primary => NUMBER | STRING | IDENTIFIER | "true" | "false"

operator => "+" | "-" | "*" | "/" | "==" | "!=" | "&&" | "||" 

I believe my varAssignmentStatement method in the parser is implemented correctly. Does anyone share my same thought?

New contributor
Sohryuu is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
\$\endgroup\$
2
  • 1
    \$\begingroup\$ You should know that your code is working correctly because you have tested it and it does work correctly. To do a proper code review we need to see parser.hpp as well as parser.cpp. \$\endgroup\$
    – pacmaninbw
    Commented 2 days ago
  • \$\begingroup\$ varAssignmentStatement has code for += etc. which currently isn’t included in the provided grammar. \$\endgroup\$
    – Ryan1729
    Commented yesterday

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.