<?php

declare(strict_types=1);

namespace Oktagon\WooCommerce\XConnect;

class Parser
{
    const ACTION_ACCEPT = 0;
    const ACTION_REDUCE = 1;
    const ACTION_SHIFT = 2;

    const ACTION_TABLES = [
        0 => 0,
        1 => 1,
        2 => 2,
        3 => 3,
        4 => 4,
        5 => 5,
        6 => 5,
        7 => 7,
        8 => 8,
        9 => 9,
        10 => 10,
        11 => 11,
        12 => 12,
        13 => 13,
        14 => 14,
        15 => 15,
        16 => 5,
        17 => 17,
        18 => 18,
        19 => 19,
        20 => 20,
        21 => 21,
        22 => 22,
        23 => 23,
        24 => 24,
        25 => 25,
        26 => 26,
        27 => 5,
        28 => 28,
        29 => 29,
        30 => 30,
        31 => 3,
        32 => 32,
        33 => 5,
        34 => 5,
        35 => 35,
        36 => 36,
        37 => 37,
        38 => 38,
        39 => 39,
        40 => 40,
        41 => 41,
        42 => 5,
        43 => 43,
        44 => 37,
        45 => 45,
        46 => 46,
        47 => 47,
        48 => 48,
        49 => 49,
        50 => 3,
        51 => 51,
        52 => 5,
        53 => 5,
        54 => 54,
        55 => 55,
        56 => 56,
        57 => 57,
        58 => 58,
        59 => 59,
        60 => 60,
        61 => 61,
        62 => 62,
        63 => 5,
        64 => 64,
        65 => 65,
        66 => 5,
        67 => 67,
        68 => 37,
        69 => 69,
        70 => 70,
        71 => 47,
        72 => 58,
        73 => 73,
        74 => 74,
        75 => 47,
        76 => 58,
        77 => 77,
    ];

    const DISTINCT_ACTION_TABLES = [
        0 => [
            Lexer::EOF_IDENTIFIER => [Parser::ACTION_REDUCE, 2],
            Lexer::T_BOOLEAN => [Parser::ACTION_SHIFT],
            Lexer::T_FLOAT => [Parser::ACTION_SHIFT],
            Lexer::T_FUNCTION_NAME => [Parser::ACTION_SHIFT],
            Lexer::T_INTEGER => [Parser::ACTION_SHIFT],
            Lexer::T_NEGATION => [Parser::ACTION_SHIFT],
            Lexer::T_OPENING_PARENTHESIS => [Parser::ACTION_SHIFT],
            Lexer::T_STRING => [Parser::ACTION_SHIFT],
            Lexer::T_VARIABLE => [Parser::ACTION_SHIFT],
        ],
        1 => [
            Lexer::EOF_IDENTIFIER => [Parser::ACTION_REDUCE, 27],
            Lexer::T_AND => [Parser::ACTION_REDUCE, 27],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 27],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 27],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 27],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 27],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 27],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 27],
            Lexer::T_NEWLINE => [Parser::ACTION_REDUCE, 27],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 27],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 27],
        ],
        2 => [
            Lexer::EOF_IDENTIFIER => [Parser::ACTION_REDUCE, 28],
            Lexer::T_AND => [Parser::ACTION_REDUCE, 28],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 28],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 28],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 28],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 28],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 28],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 28],
            Lexer::T_NEWLINE => [Parser::ACTION_REDUCE, 28],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 28],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 28],
        ],
        3 => [
            Lexer::T_OPENING_PARENTHESIS => [Parser::ACTION_SHIFT],
        ],
        4 => [
            Lexer::EOF_IDENTIFIER => [Parser::ACTION_REDUCE, 29],
            Lexer::T_AND => [Parser::ACTION_REDUCE, 29],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 29],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 29],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 29],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 29],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 29],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 29],
            Lexer::T_NEWLINE => [Parser::ACTION_REDUCE, 29],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 29],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 29],
        ],
        5 => [
            Lexer::T_BOOLEAN => [Parser::ACTION_SHIFT],
            Lexer::T_FLOAT => [Parser::ACTION_SHIFT],
            Lexer::T_FUNCTION_NAME => [Parser::ACTION_SHIFT],
            Lexer::T_INTEGER => [Parser::ACTION_SHIFT],
            Lexer::T_NEGATION => [Parser::ACTION_SHIFT],
            Lexer::T_OPENING_PARENTHESIS => [Parser::ACTION_SHIFT],
            Lexer::T_STRING => [Parser::ACTION_SHIFT],
            Lexer::T_VARIABLE => [Parser::ACTION_SHIFT],
        ],
        7 => [
            Lexer::EOF_IDENTIFIER => [Parser::ACTION_REDUCE, 30],
            Lexer::T_AND => [Parser::ACTION_REDUCE, 30],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 30],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 30],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 30],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 30],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 30],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 30],
            Lexer::T_NEWLINE => [Parser::ACTION_REDUCE, 30],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 30],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 30],
        ],
        8 => [
            Lexer::EOF_IDENTIFIER => [Parser::ACTION_REDUCE, 31],
            Lexer::T_AND => [Parser::ACTION_REDUCE, 31],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 31],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 31],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 31],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 31],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 31],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 31],
            Lexer::T_NEWLINE => [Parser::ACTION_REDUCE, 31],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 31],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 31],
        ],
        9 => [
            Lexer::EOF_IDENTIFIER => [Parser::ACTION_REDUCE, 5],
            Lexer::T_AND => [Parser::ACTION_SHIFT],
            Lexer::T_DIFFERS => [Parser::ACTION_SHIFT],
            Lexer::T_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_GREATER => [Parser::ACTION_SHIFT],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_LESSER => [Parser::ACTION_SHIFT],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_NEWLINE => [Parser::ACTION_REDUCE, 5],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_OR => [Parser::ACTION_SHIFT],
        ],
        10 => [
            Lexer::EOF_IDENTIFIER => [Parser::ACTION_REDUCE, 6],
            Lexer::T_AND => [Parser::ACTION_REDUCE, 6],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 6],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 6],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 6],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 6],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 6],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 6],
            Lexer::T_NEWLINE => [Parser::ACTION_REDUCE, 6],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 6],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 6],
        ],
        11 => [
            Lexer::EOF_IDENTIFIER => [Parser::ACTION_REDUCE, 3],
            Lexer::T_NEWLINE => [Parser::ACTION_REDUCE, 3],
        ],
        12 => [
            Lexer::EOF_IDENTIFIER => [Parser::ACTION_REDUCE, 1],
            Lexer::T_NEWLINE => [Parser::ACTION_SHIFT],
        ],
        13 => [
            Lexer::EOF_IDENTIFIER => [Parser::ACTION_ACCEPT],
        ],
        14 => [
            Lexer::EOF_IDENTIFIER => [Parser::ACTION_REDUCE, 7],
            Lexer::T_AND => [Parser::ACTION_REDUCE, 7],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 7],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 7],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 7],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 7],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 7],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 7],
            Lexer::T_NEWLINE => [Parser::ACTION_REDUCE, 7],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 7],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 7],
        ],
        15 => [
            Lexer::EOF_IDENTIFIER => [Parser::ACTION_REDUCE, 8],
            Lexer::T_AND => [Parser::ACTION_REDUCE, 8],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 8],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 8],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 8],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 8],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 8],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 8],
            Lexer::T_NEWLINE => [Parser::ACTION_REDUCE, 8],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 8],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 8],
        ],
        17 => [
            Lexer::EOF_IDENTIFIER => [Parser::ACTION_REDUCE, 4],
            Lexer::T_NEWLINE => [Parser::ACTION_REDUCE, 4],
        ],
        18 => [
            Lexer::T_BOOLEAN => [Parser::ACTION_REDUCE, 13],
            Lexer::T_FLOAT => [Parser::ACTION_REDUCE, 13],
            Lexer::T_FUNCTION_NAME => [Parser::ACTION_REDUCE, 13],
            Lexer::T_INTEGER => [Parser::ACTION_REDUCE, 13],
            Lexer::T_NEGATION => [Parser::ACTION_REDUCE, 13],
            Lexer::T_OPENING_PARENTHESIS => [Parser::ACTION_REDUCE, 13],
            Lexer::T_STRING => [Parser::ACTION_REDUCE, 13],
            Lexer::T_VARIABLE => [Parser::ACTION_REDUCE, 13],
        ],
        19 => [
            Lexer::T_BOOLEAN => [Parser::ACTION_REDUCE, 14],
            Lexer::T_FLOAT => [Parser::ACTION_REDUCE, 14],
            Lexer::T_FUNCTION_NAME => [Parser::ACTION_REDUCE, 14],
            Lexer::T_INTEGER => [Parser::ACTION_REDUCE, 14],
            Lexer::T_NEGATION => [Parser::ACTION_REDUCE, 14],
            Lexer::T_OPENING_PARENTHESIS => [Parser::ACTION_REDUCE, 14],
            Lexer::T_STRING => [Parser::ACTION_REDUCE, 14],
            Lexer::T_VARIABLE => [Parser::ACTION_REDUCE, 14],
        ],
        20 => [
            Lexer::T_BOOLEAN => [Parser::ACTION_REDUCE, 15],
            Lexer::T_FLOAT => [Parser::ACTION_REDUCE, 15],
            Lexer::T_FUNCTION_NAME => [Parser::ACTION_REDUCE, 15],
            Lexer::T_INTEGER => [Parser::ACTION_REDUCE, 15],
            Lexer::T_NEGATION => [Parser::ACTION_REDUCE, 15],
            Lexer::T_OPENING_PARENTHESIS => [Parser::ACTION_REDUCE, 15],
            Lexer::T_STRING => [Parser::ACTION_REDUCE, 15],
            Lexer::T_VARIABLE => [Parser::ACTION_REDUCE, 15],
        ],
        21 => [
            Lexer::T_BOOLEAN => [Parser::ACTION_REDUCE, 16],
            Lexer::T_FLOAT => [Parser::ACTION_REDUCE, 16],
            Lexer::T_FUNCTION_NAME => [Parser::ACTION_REDUCE, 16],
            Lexer::T_INTEGER => [Parser::ACTION_REDUCE, 16],
            Lexer::T_NEGATION => [Parser::ACTION_REDUCE, 16],
            Lexer::T_OPENING_PARENTHESIS => [Parser::ACTION_REDUCE, 16],
            Lexer::T_STRING => [Parser::ACTION_REDUCE, 16],
            Lexer::T_VARIABLE => [Parser::ACTION_REDUCE, 16],
        ],
        22 => [
            Lexer::T_BOOLEAN => [Parser::ACTION_REDUCE, 17],
            Lexer::T_FLOAT => [Parser::ACTION_REDUCE, 17],
            Lexer::T_FUNCTION_NAME => [Parser::ACTION_REDUCE, 17],
            Lexer::T_INTEGER => [Parser::ACTION_REDUCE, 17],
            Lexer::T_NEGATION => [Parser::ACTION_REDUCE, 17],
            Lexer::T_OPENING_PARENTHESIS => [Parser::ACTION_REDUCE, 17],
            Lexer::T_STRING => [Parser::ACTION_REDUCE, 17],
            Lexer::T_VARIABLE => [Parser::ACTION_REDUCE, 17],
        ],
        23 => [
            Lexer::T_BOOLEAN => [Parser::ACTION_REDUCE, 18],
            Lexer::T_FLOAT => [Parser::ACTION_REDUCE, 18],
            Lexer::T_FUNCTION_NAME => [Parser::ACTION_REDUCE, 18],
            Lexer::T_INTEGER => [Parser::ACTION_REDUCE, 18],
            Lexer::T_NEGATION => [Parser::ACTION_REDUCE, 18],
            Lexer::T_OPENING_PARENTHESIS => [Parser::ACTION_REDUCE, 18],
            Lexer::T_STRING => [Parser::ACTION_REDUCE, 18],
            Lexer::T_VARIABLE => [Parser::ACTION_REDUCE, 18],
        ],
        24 => [
            Lexer::T_BOOLEAN => [Parser::ACTION_REDUCE, 19],
            Lexer::T_FLOAT => [Parser::ACTION_REDUCE, 19],
            Lexer::T_FUNCTION_NAME => [Parser::ACTION_REDUCE, 19],
            Lexer::T_INTEGER => [Parser::ACTION_REDUCE, 19],
            Lexer::T_NEGATION => [Parser::ACTION_REDUCE, 19],
            Lexer::T_OPENING_PARENTHESIS => [Parser::ACTION_REDUCE, 19],
            Lexer::T_STRING => [Parser::ACTION_REDUCE, 19],
            Lexer::T_VARIABLE => [Parser::ACTION_REDUCE, 19],
        ],
        25 => [
            Lexer::T_BOOLEAN => [Parser::ACTION_REDUCE, 21],
            Lexer::T_FLOAT => [Parser::ACTION_REDUCE, 21],
            Lexer::T_FUNCTION_NAME => [Parser::ACTION_REDUCE, 21],
            Lexer::T_INTEGER => [Parser::ACTION_REDUCE, 21],
            Lexer::T_NEGATION => [Parser::ACTION_REDUCE, 21],
            Lexer::T_OPENING_PARENTHESIS => [Parser::ACTION_REDUCE, 21],
            Lexer::T_STRING => [Parser::ACTION_REDUCE, 21],
            Lexer::T_VARIABLE => [Parser::ACTION_REDUCE, 21],
        ],
        26 => [
            Lexer::T_BOOLEAN => [Parser::ACTION_REDUCE, 20],
            Lexer::T_FLOAT => [Parser::ACTION_REDUCE, 20],
            Lexer::T_FUNCTION_NAME => [Parser::ACTION_REDUCE, 20],
            Lexer::T_INTEGER => [Parser::ACTION_REDUCE, 20],
            Lexer::T_NEGATION => [Parser::ACTION_REDUCE, 20],
            Lexer::T_OPENING_PARENTHESIS => [Parser::ACTION_REDUCE, 20],
            Lexer::T_STRING => [Parser::ACTION_REDUCE, 20],
            Lexer::T_VARIABLE => [Parser::ACTION_REDUCE, 20],
        ],
        28 => [
            Lexer::EOF_IDENTIFIER => [Parser::ACTION_REDUCE, 11],
            Lexer::T_AND => [Parser::ACTION_REDUCE, 11],
            Lexer::T_DIFFERS => [Parser::ACTION_SHIFT],
            Lexer::T_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_GREATER => [Parser::ACTION_SHIFT],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_LESSER => [Parser::ACTION_SHIFT],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_NEWLINE => [Parser::ACTION_REDUCE, 11],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 11],
        ],
        29 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 27],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 27],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 27],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 27],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 27],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 27],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 27],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 27],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 27],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 27],
        ],
        30 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 28],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 28],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 28],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 28],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 28],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 28],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 28],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 28],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 28],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 28],
        ],
        32 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 29],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 29],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 29],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 29],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 29],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 29],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 29],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 29],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 29],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 29],
        ],
        35 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 30],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 30],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 30],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 30],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 30],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 30],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 30],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 30],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 30],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 30],
        ],
        36 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 31],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 31],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 31],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 31],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 31],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 31],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 31],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 31],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 31],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 31],
        ],
        37 => [
            Lexer::T_AND => [Parser::ACTION_SHIFT],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_SHIFT],
            Lexer::T_DIFFERS => [Parser::ACTION_SHIFT],
            Lexer::T_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_GREATER => [Parser::ACTION_SHIFT],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_LESSER => [Parser::ACTION_SHIFT],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_OR => [Parser::ACTION_SHIFT],
        ],
        38 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 6],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 6],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 6],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 6],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 6],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 6],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 6],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 6],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 6],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 6],
        ],
        39 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 7],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 7],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 7],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 7],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 7],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 7],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 7],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 7],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 7],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 7],
        ],
        40 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 8],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 8],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 8],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 8],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 8],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 8],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 8],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 8],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 8],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 8],
        ],
        41 => [
            Lexer::EOF_IDENTIFIER => [Parser::ACTION_REDUCE, 9],
            Lexer::T_AND => [Parser::ACTION_REDUCE, 9],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 9],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 9],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 9],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 9],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 9],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 9],
            Lexer::T_NEWLINE => [Parser::ACTION_REDUCE, 9],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 9],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 9],
        ],
        43 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 11],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 11],
            Lexer::T_DIFFERS => [Parser::ACTION_SHIFT],
            Lexer::T_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_GREATER => [Parser::ACTION_SHIFT],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_LESSER => [Parser::ACTION_SHIFT],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 11],
        ],
        45 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 9],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 9],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 9],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 9],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 9],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 9],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 9],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 9],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 9],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 9],
        ],
        46 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 10],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 10],
            Lexer::T_DIFFERS => [Parser::ACTION_SHIFT],
            Lexer::T_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_GREATER => [Parser::ACTION_SHIFT],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_LESSER => [Parser::ACTION_SHIFT],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 10],
        ],
        47 => [
            Lexer::T_BOOLEAN => [Parser::ACTION_SHIFT],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 22],
            Lexer::T_FLOAT => [Parser::ACTION_SHIFT],
            Lexer::T_FUNCTION_NAME => [Parser::ACTION_SHIFT],
            Lexer::T_INTEGER => [Parser::ACTION_SHIFT],
            Lexer::T_NEGATION => [Parser::ACTION_SHIFT],
            Lexer::T_OPENING_PARENTHESIS => [Parser::ACTION_SHIFT],
            Lexer::T_STRING => [Parser::ACTION_SHIFT],
            Lexer::T_VARIABLE => [Parser::ACTION_SHIFT],
        ],
        48 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 27],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 27],
            Lexer::T_COMMA => [Parser::ACTION_REDUCE, 27],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 27],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 27],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 27],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 27],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 27],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 27],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 27],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 27],
        ],
        49 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 28],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 28],
            Lexer::T_COMMA => [Parser::ACTION_REDUCE, 28],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 28],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 28],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 28],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 28],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 28],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 28],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 28],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 28],
        ],
        51 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 29],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 29],
            Lexer::T_COMMA => [Parser::ACTION_REDUCE, 29],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 29],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 29],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 29],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 29],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 29],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 29],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 29],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 29],
        ],
        54 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 30],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 30],
            Lexer::T_COMMA => [Parser::ACTION_REDUCE, 30],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 30],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 30],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 30],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 30],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 30],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 30],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 30],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 30],
        ],
        55 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 31],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 31],
            Lexer::T_COMMA => [Parser::ACTION_REDUCE, 31],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 31],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 31],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 31],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 31],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 31],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 31],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 31],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 31],
        ],
        56 => [
            Lexer::T_AND => [Parser::ACTION_SHIFT],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 26],
            Lexer::T_COMMA => [Parser::ACTION_REDUCE, 26],
            Lexer::T_DIFFERS => [Parser::ACTION_SHIFT],
            Lexer::T_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_GREATER => [Parser::ACTION_SHIFT],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_LESSER => [Parser::ACTION_SHIFT],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_OR => [Parser::ACTION_SHIFT],
        ],
        57 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 6],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 6],
            Lexer::T_COMMA => [Parser::ACTION_REDUCE, 6],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 6],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 6],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 6],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 6],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 6],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 6],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 6],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 6],
        ],
        58 => [
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_SHIFT],
        ],
        59 => [
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 24],
            Lexer::T_COMMA => [Parser::ACTION_SHIFT],
        ],
        60 => [
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 23],
        ],
        61 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 7],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 7],
            Lexer::T_COMMA => [Parser::ACTION_REDUCE, 7],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 7],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 7],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 7],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 7],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 7],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 7],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 7],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 7],
        ],
        62 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 8],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 8],
            Lexer::T_COMMA => [Parser::ACTION_REDUCE, 8],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 8],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 8],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 8],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 8],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 8],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 8],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 8],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 8],
        ],
        64 => [
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 25],
        ],
        65 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 12],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 12],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 12],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 12],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 12],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 12],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 12],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 12],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 12],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 12],
        ],
        67 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 11],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 11],
            Lexer::T_COMMA => [Parser::ACTION_REDUCE, 11],
            Lexer::T_DIFFERS => [Parser::ACTION_SHIFT],
            Lexer::T_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_GREATER => [Parser::ACTION_SHIFT],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_LESSER => [Parser::ACTION_SHIFT],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 11],
        ],
        69 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 9],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 9],
            Lexer::T_COMMA => [Parser::ACTION_REDUCE, 9],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 9],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 9],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 9],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 9],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 9],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 9],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 9],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 9],
        ],
        70 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 10],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 10],
            Lexer::T_COMMA => [Parser::ACTION_REDUCE, 10],
            Lexer::T_DIFFERS => [Parser::ACTION_SHIFT],
            Lexer::T_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_GREATER => [Parser::ACTION_SHIFT],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_LESSER => [Parser::ACTION_SHIFT],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 10],
        ],
        73 => [
            Lexer::T_AND => [Parser::ACTION_REDUCE, 12],
            Lexer::T_CLOSING_PARENTHESIS => [Parser::ACTION_REDUCE, 12],
            Lexer::T_COMMA => [Parser::ACTION_REDUCE, 12],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 12],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 12],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 12],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 12],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 12],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 12],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 12],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 12],
        ],
        74 => [
            Lexer::EOF_IDENTIFIER => [Parser::ACTION_REDUCE, 10],
            Lexer::T_AND => [Parser::ACTION_REDUCE, 10],
            Lexer::T_DIFFERS => [Parser::ACTION_SHIFT],
            Lexer::T_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_GREATER => [Parser::ACTION_SHIFT],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_LESSER => [Parser::ACTION_SHIFT],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_NEWLINE => [Parser::ACTION_REDUCE, 10],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_SHIFT],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 10],
        ],
        77 => [
            Lexer::EOF_IDENTIFIER => [Parser::ACTION_REDUCE, 12],
            Lexer::T_AND => [Parser::ACTION_REDUCE, 12],
            Lexer::T_DIFFERS => [Parser::ACTION_REDUCE, 12],
            Lexer::T_EQUALS => [Parser::ACTION_REDUCE, 12],
            Lexer::T_GREATER => [Parser::ACTION_REDUCE, 12],
            Lexer::T_GREATER_OR_EQUALS => [Parser::ACTION_REDUCE, 12],
            Lexer::T_LESSER => [Parser::ACTION_REDUCE, 12],
            Lexer::T_LESSER_OR_EQUALS => [Parser::ACTION_REDUCE, 12],
            Lexer::T_NEWLINE => [Parser::ACTION_REDUCE, 12],
            Lexer::T_NOT_EQUALS => [Parser::ACTION_REDUCE, 12],
            Lexer::T_OR => [Parser::ACTION_REDUCE, 12],
        ],
    ];

    const GOTO_TABLES = [
        0 => 0,
        1 => 1,
        2 => 1,
        3 => 2,
        4 => 1,
        5 => 3,
        6 => 4,
        7 => 1,
        8 => 1,
        9 => 5,
        10 => 1,
        11 => 1,
        12 => 6,
        13 => 1,
        14 => 1,
        15 => 1,
        16 => 7,
        17 => 1,
        18 => 1,
        19 => 1,
        20 => 1,
        21 => 1,
        22 => 1,
        23 => 1,
        24 => 1,
        25 => 1,
        26 => 1,
        27 => 8,
        28 => 5,
        29 => 1,
        30 => 1,
        31 => 9,
        32 => 1,
        33 => 10,
        34 => 11,
        35 => 1,
        36 => 1,
        37 => 12,
        38 => 1,
        39 => 1,
        40 => 1,
        41 => 1,
        42 => 13,
        43 => 14,
        44 => 15,
        45 => 1,
        46 => 14,
        47 => 16,
        48 => 1,
        49 => 1,
        50 => 17,
        51 => 1,
        52 => 18,
        53 => 19,
        54 => 1,
        55 => 1,
        56 => 20,
        57 => 1,
        58 => 21,
        59 => 22,
        60 => 1,
        61 => 1,
        62 => 1,
        63 => 23,
        64 => 1,
        65 => 1,
        66 => 24,
        67 => 20,
        68 => 25,
        69 => 1,
        70 => 20,
        71 => 26,
        72 => 27,
        73 => 1,
        74 => 5,
        75 => 28,
        76 => 29,
        77 => 1,
    ];

    const DISTINCT_GOTO_TABLES = [
        0 => [
            Lexer::T_BOOLEAN => 1,
            Lexer::T_FLOAT => 2,
            Lexer::T_FUNCTION_NAME => 3,
            Lexer::T_INTEGER => 4,
            Lexer::T_NEGATION => 5,
            Lexer::T_OPENING_PARENTHESIS => 6,
            Lexer::T_STRING => 7,
            Lexer::T_VARIABLE => 8,
            Lexer::N_EXPRESSION => 9,
            Lexer::N_FUNCTION_CALL => 10,
            Lexer::N_LOGICAL_EXPRESSION => 11,
            Lexer::N_LOGICAL_EXPRESSIONS => 12,
            Lexer::N_OPTIONAL_LOGICAL_EXPRESSIONS => 13,
            Lexer::N_SCALAR => 14,
            Lexer::N_VARIABLE => 15,
        ],
        1 => [],
        2 => [
            Lexer::T_OPENING_PARENTHESIS => 75,
        ],
        3 => [
            Lexer::T_BOOLEAN => 1,
            Lexer::T_FLOAT => 2,
            Lexer::T_FUNCTION_NAME => 3,
            Lexer::T_INTEGER => 4,
            Lexer::T_NEGATION => 5,
            Lexer::T_OPENING_PARENTHESIS => 6,
            Lexer::T_STRING => 7,
            Lexer::T_VARIABLE => 8,
            Lexer::N_EXPRESSION => 74,
            Lexer::N_FUNCTION_CALL => 10,
            Lexer::N_SCALAR => 14,
            Lexer::N_VARIABLE => 15,
        ],
        4 => [
            Lexer::T_BOOLEAN => 29,
            Lexer::T_FLOAT => 30,
            Lexer::T_FUNCTION_NAME => 31,
            Lexer::T_INTEGER => 32,
            Lexer::T_NEGATION => 33,
            Lexer::T_OPENING_PARENTHESIS => 34,
            Lexer::T_STRING => 35,
            Lexer::T_VARIABLE => 36,
            Lexer::N_EXPRESSION => 37,
            Lexer::N_FUNCTION_CALL => 38,
            Lexer::N_SCALAR => 39,
            Lexer::N_VARIABLE => 40,
        ],
        5 => [
            Lexer::T_AND => 18,
            Lexer::T_DIFFERS => 19,
            Lexer::T_EQUALS => 20,
            Lexer::T_GREATER => 21,
            Lexer::T_GREATER_OR_EQUALS => 22,
            Lexer::T_LESSER => 23,
            Lexer::T_LESSER_OR_EQUALS => 24,
            Lexer::T_NOT_EQUALS => 25,
            Lexer::T_OR => 26,
            Lexer::N_OPERATOR => 27,
        ],
        6 => [
            Lexer::T_NEWLINE => 16,
        ],
        7 => [
            Lexer::T_BOOLEAN => 1,
            Lexer::T_FLOAT => 2,
            Lexer::T_FUNCTION_NAME => 3,
            Lexer::T_INTEGER => 4,
            Lexer::T_NEGATION => 5,
            Lexer::T_OPENING_PARENTHESIS => 6,
            Lexer::T_STRING => 7,
            Lexer::T_VARIABLE => 8,
            Lexer::N_EXPRESSION => 9,
            Lexer::N_FUNCTION_CALL => 10,
            Lexer::N_LOGICAL_EXPRESSION => 17,
            Lexer::N_SCALAR => 14,
            Lexer::N_VARIABLE => 15,
        ],
        8 => [
            Lexer::T_BOOLEAN => 1,
            Lexer::T_FLOAT => 2,
            Lexer::T_FUNCTION_NAME => 3,
            Lexer::T_INTEGER => 4,
            Lexer::T_NEGATION => 5,
            Lexer::T_OPENING_PARENTHESIS => 6,
            Lexer::T_STRING => 7,
            Lexer::T_VARIABLE => 8,
            Lexer::N_EXPRESSION => 28,
            Lexer::N_FUNCTION_CALL => 10,
            Lexer::N_SCALAR => 14,
            Lexer::N_VARIABLE => 15,
        ],
        9 => [
            Lexer::T_OPENING_PARENTHESIS => 47,
        ],
        10 => [
            Lexer::T_BOOLEAN => 29,
            Lexer::T_FLOAT => 30,
            Lexer::T_FUNCTION_NAME => 31,
            Lexer::T_INTEGER => 32,
            Lexer::T_NEGATION => 33,
            Lexer::T_OPENING_PARENTHESIS => 34,
            Lexer::T_STRING => 35,
            Lexer::T_VARIABLE => 36,
            Lexer::N_EXPRESSION => 46,
            Lexer::N_FUNCTION_CALL => 38,
            Lexer::N_SCALAR => 39,
            Lexer::N_VARIABLE => 40,
        ],
        11 => [
            Lexer::T_BOOLEAN => 29,
            Lexer::T_FLOAT => 30,
            Lexer::T_FUNCTION_NAME => 31,
            Lexer::T_INTEGER => 32,
            Lexer::T_NEGATION => 33,
            Lexer::T_OPENING_PARENTHESIS => 34,
            Lexer::T_STRING => 35,
            Lexer::T_VARIABLE => 36,
            Lexer::N_EXPRESSION => 44,
            Lexer::N_FUNCTION_CALL => 38,
            Lexer::N_SCALAR => 39,
            Lexer::N_VARIABLE => 40,
        ],
        12 => [
            Lexer::T_AND => 18,
            Lexer::T_CLOSING_PARENTHESIS => 41,
            Lexer::T_DIFFERS => 19,
            Lexer::T_EQUALS => 20,
            Lexer::T_GREATER => 21,
            Lexer::T_GREATER_OR_EQUALS => 22,
            Lexer::T_LESSER => 23,
            Lexer::T_LESSER_OR_EQUALS => 24,
            Lexer::T_NOT_EQUALS => 25,
            Lexer::T_OR => 26,
            Lexer::N_OPERATOR => 42,
        ],
        13 => [
            Lexer::T_BOOLEAN => 29,
            Lexer::T_FLOAT => 30,
            Lexer::T_FUNCTION_NAME => 31,
            Lexer::T_INTEGER => 32,
            Lexer::T_NEGATION => 33,
            Lexer::T_OPENING_PARENTHESIS => 34,
            Lexer::T_STRING => 35,
            Lexer::T_VARIABLE => 36,
            Lexer::N_EXPRESSION => 43,
            Lexer::N_FUNCTION_CALL => 38,
            Lexer::N_SCALAR => 39,
            Lexer::N_VARIABLE => 40,
        ],
        14 => [
            Lexer::T_AND => 18,
            Lexer::T_DIFFERS => 19,
            Lexer::T_EQUALS => 20,
            Lexer::T_GREATER => 21,
            Lexer::T_GREATER_OR_EQUALS => 22,
            Lexer::T_LESSER => 23,
            Lexer::T_LESSER_OR_EQUALS => 24,
            Lexer::T_NOT_EQUALS => 25,
            Lexer::T_OR => 26,
            Lexer::N_OPERATOR => 42,
        ],
        15 => [
            Lexer::T_AND => 18,
            Lexer::T_CLOSING_PARENTHESIS => 45,
            Lexer::T_DIFFERS => 19,
            Lexer::T_EQUALS => 20,
            Lexer::T_GREATER => 21,
            Lexer::T_GREATER_OR_EQUALS => 22,
            Lexer::T_LESSER => 23,
            Lexer::T_LESSER_OR_EQUALS => 24,
            Lexer::T_NOT_EQUALS => 25,
            Lexer::T_OR => 26,
            Lexer::N_OPERATOR => 42,
        ],
        16 => [
            Lexer::T_BOOLEAN => 48,
            Lexer::T_FLOAT => 49,
            Lexer::T_FUNCTION_NAME => 50,
            Lexer::T_INTEGER => 51,
            Lexer::T_NEGATION => 52,
            Lexer::T_OPENING_PARENTHESIS => 53,
            Lexer::T_STRING => 54,
            Lexer::T_VARIABLE => 55,
            Lexer::N_EXPRESSION => 56,
            Lexer::N_FUNCTION_CALL => 57,
            Lexer::N_OPTIONAL_PARAMETERS => 58,
            Lexer::N_PARAMETER => 59,
            Lexer::N_PARAMETERS => 60,
            Lexer::N_SCALAR => 61,
            Lexer::N_VARIABLE => 62,
        ],
        17 => [
            Lexer::T_OPENING_PARENTHESIS => 71,
        ],
        18 => [
            Lexer::T_BOOLEAN => 48,
            Lexer::T_FLOAT => 49,
            Lexer::T_FUNCTION_NAME => 50,
            Lexer::T_INTEGER => 51,
            Lexer::T_NEGATION => 52,
            Lexer::T_OPENING_PARENTHESIS => 53,
            Lexer::T_STRING => 54,
            Lexer::T_VARIABLE => 55,
            Lexer::N_EXPRESSION => 70,
            Lexer::N_FUNCTION_CALL => 57,
            Lexer::N_SCALAR => 61,
            Lexer::N_VARIABLE => 62,
        ],
        19 => [
            Lexer::T_BOOLEAN => 29,
            Lexer::T_FLOAT => 30,
            Lexer::T_FUNCTION_NAME => 31,
            Lexer::T_INTEGER => 32,
            Lexer::T_NEGATION => 33,
            Lexer::T_OPENING_PARENTHESIS => 34,
            Lexer::T_STRING => 35,
            Lexer::T_VARIABLE => 36,
            Lexer::N_EXPRESSION => 68,
            Lexer::N_FUNCTION_CALL => 38,
            Lexer::N_SCALAR => 39,
            Lexer::N_VARIABLE => 40,
        ],
        20 => [
            Lexer::T_AND => 18,
            Lexer::T_DIFFERS => 19,
            Lexer::T_EQUALS => 20,
            Lexer::T_GREATER => 21,
            Lexer::T_GREATER_OR_EQUALS => 22,
            Lexer::T_LESSER => 23,
            Lexer::T_LESSER_OR_EQUALS => 24,
            Lexer::T_NOT_EQUALS => 25,
            Lexer::T_OR => 26,
            Lexer::N_OPERATOR => 66,
        ],
        21 => [
            Lexer::T_CLOSING_PARENTHESIS => 65,
        ],
        22 => [
            Lexer::T_COMMA => 63,
        ],
        23 => [
            Lexer::T_BOOLEAN => 48,
            Lexer::T_FLOAT => 49,
            Lexer::T_FUNCTION_NAME => 50,
            Lexer::T_INTEGER => 51,
            Lexer::T_NEGATION => 52,
            Lexer::T_OPENING_PARENTHESIS => 53,
            Lexer::T_STRING => 54,
            Lexer::T_VARIABLE => 55,
            Lexer::N_EXPRESSION => 56,
            Lexer::N_FUNCTION_CALL => 57,
            Lexer::N_PARAMETER => 59,
            Lexer::N_PARAMETERS => 64,
            Lexer::N_SCALAR => 61,
            Lexer::N_VARIABLE => 62,
        ],
        24 => [
            Lexer::T_BOOLEAN => 48,
            Lexer::T_FLOAT => 49,
            Lexer::T_FUNCTION_NAME => 50,
            Lexer::T_INTEGER => 51,
            Lexer::T_NEGATION => 52,
            Lexer::T_OPENING_PARENTHESIS => 53,
            Lexer::T_STRING => 54,
            Lexer::T_VARIABLE => 55,
            Lexer::N_EXPRESSION => 67,
            Lexer::N_FUNCTION_CALL => 57,
            Lexer::N_SCALAR => 61,
            Lexer::N_VARIABLE => 62,
        ],
        25 => [
            Lexer::T_AND => 18,
            Lexer::T_CLOSING_PARENTHESIS => 69,
            Lexer::T_DIFFERS => 19,
            Lexer::T_EQUALS => 20,
            Lexer::T_GREATER => 21,
            Lexer::T_GREATER_OR_EQUALS => 22,
            Lexer::T_LESSER => 23,
            Lexer::T_LESSER_OR_EQUALS => 24,
            Lexer::T_NOT_EQUALS => 25,
            Lexer::T_OR => 26,
            Lexer::N_OPERATOR => 42,
        ],
        26 => [
            Lexer::T_BOOLEAN => 48,
            Lexer::T_FLOAT => 49,
            Lexer::T_FUNCTION_NAME => 50,
            Lexer::T_INTEGER => 51,
            Lexer::T_NEGATION => 52,
            Lexer::T_OPENING_PARENTHESIS => 53,
            Lexer::T_STRING => 54,
            Lexer::T_VARIABLE => 55,
            Lexer::N_EXPRESSION => 56,
            Lexer::N_FUNCTION_CALL => 57,
            Lexer::N_OPTIONAL_PARAMETERS => 72,
            Lexer::N_PARAMETER => 59,
            Lexer::N_PARAMETERS => 60,
            Lexer::N_SCALAR => 61,
            Lexer::N_VARIABLE => 62,
        ],
        27 => [
            Lexer::T_CLOSING_PARENTHESIS => 73,
        ],
        28 => [
            Lexer::T_BOOLEAN => 48,
            Lexer::T_FLOAT => 49,
            Lexer::T_FUNCTION_NAME => 50,
            Lexer::T_INTEGER => 51,
            Lexer::T_NEGATION => 52,
            Lexer::T_OPENING_PARENTHESIS => 53,
            Lexer::T_STRING => 54,
            Lexer::T_VARIABLE => 55,
            Lexer::N_EXPRESSION => 56,
            Lexer::N_FUNCTION_CALL => 57,
            Lexer::N_OPTIONAL_PARAMETERS => 76,
            Lexer::N_PARAMETER => 59,
            Lexer::N_PARAMETERS => 60,
            Lexer::N_SCALAR => 61,
            Lexer::N_VARIABLE => 62,
        ],
        29 => [
            Lexer::T_CLOSING_PARENTHESIS => 77,
        ],
    ];

    const PRODUCTIONS_BY_NUMBER = [
        0 => [
            [
                Lexer::N_START,
            ],
            [
                Lexer::N_OPTIONAL_LOGICAL_EXPRESSIONS,
            ],
        ],
        1 => [
            [
                Lexer::N_OPTIONAL_LOGICAL_EXPRESSIONS,
            ],
            [
                Lexer::N_LOGICAL_EXPRESSIONS,
            ],
        ],
        2 => [
            [
                Lexer::N_OPTIONAL_LOGICAL_EXPRESSIONS,
            ],
            [
                Lexer::E_IDENTIFIER,
            ],
        ],
        3 => [
            [
                Lexer::N_LOGICAL_EXPRESSIONS,
            ],
            [
                Lexer::N_LOGICAL_EXPRESSION,
            ],
        ],
        4 => [
            [
                Lexer::N_LOGICAL_EXPRESSIONS,
            ],
            [
                Lexer::N_LOGICAL_EXPRESSIONS,
                Lexer::T_NEWLINE,
                Lexer::N_LOGICAL_EXPRESSION,
            ],
        ],
        5 => [
            [
                Lexer::N_LOGICAL_EXPRESSION,
            ],
            [
                Lexer::N_EXPRESSION,
            ],
        ],
        6 => [
            [
                Lexer::N_EXPRESSION,
            ],
            [
                Lexer::N_FUNCTION_CALL,
            ],
        ],
        7 => [
            [
                Lexer::N_EXPRESSION,
            ],
            [
                Lexer::N_SCALAR,
            ],
        ],
        8 => [
            [
                Lexer::N_EXPRESSION,
            ],
            [
                Lexer::N_VARIABLE,
            ],
        ],
        9 => [
            [
                Lexer::N_EXPRESSION,
            ],
            [
                Lexer::T_OPENING_PARENTHESIS,
                Lexer::N_EXPRESSION,
                Lexer::T_CLOSING_PARENTHESIS,
            ],
        ],
        10 => [
            [
                Lexer::N_EXPRESSION,
            ],
            [
                Lexer::T_NEGATION,
                Lexer::N_EXPRESSION,
            ],
        ],
        11 => [
            [
                Lexer::N_EXPRESSION,
            ],
            [
                Lexer::N_EXPRESSION,
                Lexer::N_OPERATOR,
                Lexer::N_EXPRESSION,
            ],
        ],
        12 => [
            [
                Lexer::N_FUNCTION_CALL,
            ],
            [
                Lexer::T_FUNCTION_NAME,
                Lexer::T_OPENING_PARENTHESIS,
                Lexer::N_OPTIONAL_PARAMETERS,
                Lexer::T_CLOSING_PARENTHESIS,
            ],
        ],
        13 => [
            [
                Lexer::N_OPERATOR,
            ],
            [
                Lexer::T_AND,
            ],
        ],
        14 => [
            [
                Lexer::N_OPERATOR,
            ],
            [
                Lexer::T_DIFFERS,
            ],
        ],
        15 => [
            [
                Lexer::N_OPERATOR,
            ],
            [
                Lexer::T_EQUALS,
            ],
        ],
        16 => [
            [
                Lexer::N_OPERATOR,
            ],
            [
                Lexer::T_GREATER,
            ],
        ],
        17 => [
            [
                Lexer::N_OPERATOR,
            ],
            [
                Lexer::T_GREATER_OR_EQUALS,
            ],
        ],
        18 => [
            [
                Lexer::N_OPERATOR,
            ],
            [
                Lexer::T_LESSER,
            ],
        ],
        19 => [
            [
                Lexer::N_OPERATOR,
            ],
            [
                Lexer::T_LESSER_OR_EQUALS,
            ],
        ],
        20 => [
            [
                Lexer::N_OPERATOR,
            ],
            [
                Lexer::T_OR,
            ],
        ],
        21 => [
            [
                Lexer::N_OPERATOR,
            ],
            [
                Lexer::T_NOT_EQUALS,
            ],
        ],
        22 => [
            [
                Lexer::N_OPTIONAL_PARAMETERS,
            ],
            [
                Lexer::E_IDENTIFIER,
            ],
        ],
        23 => [
            [
                Lexer::N_OPTIONAL_PARAMETERS,
            ],
            [
                Lexer::N_PARAMETERS,
            ],
        ],
        24 => [
            [
                Lexer::N_PARAMETERS,
            ],
            [
                Lexer::N_PARAMETER,
            ],
        ],
        25 => [
            [
                Lexer::N_PARAMETERS,
            ],
            [
                Lexer::N_PARAMETER,
                Lexer::T_COMMA,
                Lexer::N_PARAMETERS,
            ],
        ],
        26 => [
            [
                Lexer::N_PARAMETER,
            ],
            [
                Lexer::N_EXPRESSION,
            ],
        ],
        27 => [
            [
                Lexer::N_SCALAR,
            ],
            [
                Lexer::T_BOOLEAN,
            ],
        ],
        28 => [
            [
                Lexer::N_SCALAR,
            ],
            [
                Lexer::T_FLOAT,
            ],
        ],
        29 => [
            [
                Lexer::N_SCALAR,
            ],
            [
                Lexer::T_INTEGER,
            ],
        ],
        30 => [
            [
                Lexer::N_SCALAR,
            ],
            [
                Lexer::T_STRING,
            ],
        ],
        31 => [
            [
                Lexer::N_VARIABLE,
            ],
            [
                Lexer::T_VARIABLE,
            ],
        ],
    ];

    const LOOK_AHEADS = [
        Lexer::EOF_IDENTIFIER => true,
        Lexer::T_AND => true,
        Lexer::T_BOOLEAN => true,
        Lexer::T_CLOSING_PARENTHESIS => true,
        Lexer::T_COMMA => true,
        Lexer::T_DIFFERS => true,
        Lexer::T_EQUALS => true,
        Lexer::T_FLOAT => true,
        Lexer::T_FUNCTION_NAME => true,
        Lexer::T_GREATER => true,
        Lexer::T_GREATER_OR_EQUALS => true,
        Lexer::T_INTEGER => true,
        Lexer::T_LESSER => true,
        Lexer::T_LESSER_OR_EQUALS => true,
        Lexer::T_NEGATION => true,
        Lexer::T_NEWLINE => true,
        Lexer::T_NOT_EQUALS => true,
        Lexer::T_OPENING_PARENTHESIS => true,
        Lexer::T_OR => true,
        Lexer::T_STRING => true,
        Lexer::T_VARIABLE => true,
    ];

    const TERMINALS = [
        Lexer::T_AND => true,
        Lexer::T_BOOLEAN => true,
        Lexer::T_CLOSING_PARENTHESIS => true,
        Lexer::T_COMMA => true,
        Lexer::T_DIFFERS => true,
        Lexer::T_EQUALS => true,
        Lexer::T_FLOAT => true,
        Lexer::T_FUNCTION_NAME => true,
        Lexer::T_GREATER => true,
        Lexer::T_GREATER_OR_EQUALS => true,
        Lexer::T_INTEGER => true,
        Lexer::T_LESSER => true,
        Lexer::T_LESSER_OR_EQUALS => true,
        Lexer::T_NEGATION => true,
        Lexer::T_NEWLINE => true,
        Lexer::T_NOT_EQUALS => true,
        Lexer::T_OPENING_PARENTHESIS => true,
        Lexer::T_OR => true,
        Lexer::T_STRING => true,
        Lexer::T_VARIABLE => true,
    ];

    const NON_TERMINALS = [
        Lexer::N_EXPRESSION => true,
        Lexer::N_FUNCTION_CALL => true,
        Lexer::N_LOGICAL_EXPRESSION => true,
        Lexer::N_LOGICAL_EXPRESSIONS => true,
        Lexer::N_OPERATOR => true,
        Lexer::N_OPTIONAL_LOGICAL_EXPRESSIONS => true,
        Lexer::N_OPTIONAL_PARAMETERS => true,
        Lexer::N_PARAMETERS => true,
        Lexer::N_PARAMETER => true,
        Lexer::N_SCALAR => true,
        Lexer::N_START => true,
        Lexer::N_VARIABLE => true,
    ];

    private int $index = 0;
    private static array $translations = [];

    private array $variables = [];
    private array $functions = [];
    private array $functionParameters = [];

    private Lexer $lexerHelper;

    /**
     * phpcs:disable Generic.Files.LineLength.TooLong
     * phpcs:disable PSR2.Files.EndFileNewline.TooMany
     */
    public function __construct(
        Lexer $lexerHelper
    ) {
        $this->lexerHelper = $lexerHelper;
        self::$translations = [

            /**
             * Lexer::N_OPTIONAL_LOGICAL_EXPRESSIONS -> Lexer::E_IDENTIFIER
             */
            2 => function ($nonTerminals, $terminals) {
                return $nonTerminals[0] ?? true;
            },

            /**
             * Lexer::N_LOGICAL_EXPRESSIONS -> Lexer::N_LOGICAL_EXPRESSIONS Lexer::T_NEWLINE Lexer::N_LOGICAL_EXPRESSION
             *
             * @SuppressWarnings(PHPMD.UnusedParameter)
             */
            4 => function ($nonTerminals, $terminals) {
                return $nonTerminals[0] || $nonTerminals[2];
            },

            /**
             * Lexer::N_LOGICAL_EXPRESSION -> Lexer::N_EXPRESSION
             *
             * @SuppressWarnings(PHPMD.UnusedParameter)
             */
            5 => function ($expressionValue, $terminals) {
                return $expressionValue == true;
            },

            /**
             * Lexer::N_EXPRESSION -> Lexer::T_OPENING_PARENTHESIS Lexer::N_EXPRESSION Lexer::T_CLOSING_PARENTHESIS
             *
             * @SuppressWarnings(PHPMD.UnusedParameter)
             */
            9 => function ($nonTerminals, $terminals) {
                return $nonTerminals[1];
            },

            /**
             * Lexer::N_EXPRESSION -> Lexer::T_NEGATION Lexer::N_EXPRESSION
             *
             * @SuppressWarnings(PHPMD.UnusedParameter)
             */
            10 => function ($nonTerminals, $terminals) {
                $aValue = $nonTerminals[0];
                $aLogicalValue = $aValue == true;
                return !$aLogicalValue;
            },

            /**
             * Lexer::N_EXPRESSION -> Lexer::N_EXPRESSION Lexer::N_OPERATOR Lexer::N_EXPRESSION
             *
             * @SuppressWarnings(PHPMD.UnusedParameter)
             */
            11 => function ($nonTerminals, $terminals) {
                $aValue = $nonTerminals[0];
                $aLogicalValue = $aValue == true;
                $bValue = $nonTerminals[2];
                $bLogicalValue = $bValue == true;
                $operator = $terminals[1][0];
                switch ($operator) {
                    case Lexer::T_AND:
                        return $aLogicalValue && $bLogicalValue;
                    case Lexer::T_DIFFERS:
                    case Lexer::T_NOT_EQUALS:
                        return $aValue != $bValue;
                    case Lexer::T_EQUALS:
                        return $aValue == $bValue;
                    case Lexer::T_GREATER:
                        return $aValue > $bValue;
                    case Lexer::T_GREATER_OR_EQUALS:
                        return $aValue >= $bValue;
                    case Lexer::T_LESSER:
                        return $aValue < $bValue;
                    case Lexer::T_LESSER_OR_EQUALS:
                        return $aValue <= $bValue;
                    case Lexer::T_OR:
                        return $aLogicalValue || $bLogicalValue;
                    default:
                        throw new \Exception(
                            sprintf(
                                'Invalid operator %s!',
                                $operator
                            )
                        );
                }
            },

            /**
             * Lexer::N_FUNCTION_CALL -> Lexer::T_FUNCTION_NAME Lexer::T_OPENING_PARENTHESIS Lexer::N_OPTIONAL_PARAMETERS Lexer::T_CLOSING_PARENTHESIS
             *
             * @SuppressWarnings(PHPMD.UnusedParameter)
             */
            12 => function ($nonTerminals, $terminals) {
                $functionName = $nonTerminals[0];
                $functionParameters = $nonTerminals[2];
                if (
                    !isset($this->functions[$functionName])
                    || !isset($this->functionParameters[$functionName])
                    || !is_callable($this->functions[$functionName])
                    || !is_int($this->functionParameters[$functionName])
                ) {
                    throw new \Exception(
                        sprintf(
                            'Undefined function %s!',
                            $functionName
                        )
                    );
                }
                if (count($functionParameters) !== $this->functionParameters[$functionName]) {
                    throw new \Exception(
                        sprintf(
                            'Wrong number of function %s parameter count, got %d expected %d!',
                            $functionName,
                            count($functionParameters),
                            $this->functionParameters[$functionName]
                        )
                    );
                }
                return call_user_func_array(
                    $this->functions[$functionName],
                    $functionParameters
                );
            },

            /**
             * Lexer::N_PARAMETERS -> Lexer::N_PARAMETER
             *
             * @SuppressWarnings(PHPMD.UnusedParameter)
             */
            24 => function ($nonTerminals, $terminals) {
                return [$nonTerminals];
            },

            /**
             * Lexer::N_PARAMETERS -> Lexer::N_PARAMETER Lexer::T_COMMA Lexer::N_PARAMETERS
             *
             * @SuppressWarnings(PHPMD.UnusedParameter)
             */
            25 => function ($nonTerminals, $terminals) {
                $parameter = $nonTerminals[0];
                $parameters = $nonTerminals[2];
                return array_merge([$parameter], $parameters);
            },

            /**
             * Lexer::N_VARIABLE -> Lexer::T_VARIABLE
             *
             * @SuppressWarnings(PHPMD.UnusedParameter)
             */
            31 => function ($variableName, $terminals) {
                if (!isset($this->variables[$variableName])) {
                    throw new \Exception(
                        sprintf(
                            'Undefined variable %s!',
                            $variableName
                        )
                    );
                }
                return $this->variables[$variableName];
            },

        ];
    }


    // Functions for Lex-Analyzer:


    private function lexAnalyzerGetToken(array $token)
    {
        $fetch = $this->lexerHelper->getToken($token);
        return $fetch;
    }

    private function lexAnalyzerReset(): void
    {
        $this->index = 0;
    }

    private function lexAnalyzerPeekNextLookAhead(): array
    {
        if ($token = $this->lexerHelper->fetchTokenWithForward($this->index)) {
            return $token;
        }
        return [Lexer::EOF_IDENTIFIER];
    }

    private function lexAnalyzerPopToken(): array
    {
        $token = $this->lexAnalyzerPeekNextLookAhead();
        $this->index = $token[2];
        return $token;
    }


    // Functions for Syntax-Analyzer / Parser:


    private function getGrammarProductionByNumber(int $number): ?array
    {
        if (isset(self::PRODUCTIONS_BY_NUMBER[$number])) {
            return self::PRODUCTIONS_BY_NUMBER[$number];
        }
        return null;
    }

    private function isValidSymbol($symbol): bool
    {
        if (
            $this->isValidE($symbol)
            || $this->isValidEof($symbol)
            || $this->isValidNonTerminal($symbol)
            || $this->isValidTerminal($symbol)
        ) {
            return true;
        }
        return false;
    }

    private function isValidE($symbol): bool
    {
        return $symbol === Lexer::E_IDENTIFIER;
    }

    private function isValidEof($symbol): bool
    {
        return $symbol === Lexer::EOF_IDENTIFIER;
    }

    private function isValidNonTerminal($symbol): bool
    {
        return isset(self::NON_TERMINALS[$symbol]);
    }

    private function isValidTerminal($symbol): bool
    {
        return isset(self::TERMINALS[$symbol]);
    }

    private function getGrammarTranslationByNumber(int $number): ?callable
    {
        if (isset(self::$translations[$number])) {
            return self::$translations[$number];
        }
        return null;
    }

    /**
     * @throws \Exception
     */
    public function evaluate(
        string $input,
        array $variables = [],
        array $functions = [],
        array $functionParameters = []
    ) {
        $parse = $this->parse(
            $input,
            $variables,
            $functions,
            $functionParameters
        );
        return $parse[0];
    }

    /**
     * @throws \Exception
     */
    private function parse(
        string $input,
        array $variables = [],
        array $functions = [],
        array $functionParameters = []
    ): array {
        $this->lexerHelper->setInput($input);
        $this->lexAnalyzerReset();
        $accept = false;
        $pushdownList = [0];
        $output = [];
        $translation = null;
        $translationSymbolTable = [];
        $this->variables = $variables;
        $this->functions = $functions;
        $this->functionParameters = $functionParameters;

        while (!$accept) {
            $lookaheadFull = $this->lexAnalyzerPeekNextLookAhead();
            $lookahead = $lookaheadFull[0];
            $tableIndex = end($pushdownList);

            if (!isset(self::ACTION_TABLES[$tableIndex])) {
                throw new \Exception(
                    sprintf(
                        'Missing action table %d!',
                        $tableIndex
                    )
                );
            }
            $actionTableDistinctIndex = self::ACTION_TABLES[$tableIndex];
            if (!isset(self::DISTINCT_ACTION_TABLES[$actionTableDistinctIndex])) {
                throw new \Exception(
                    sprintf(
                        'Missing distinct action table %d!',
                        $actionTableDistinctIndex
                    )
                );
            }
            $actionTable = self::DISTINCT_ACTION_TABLES[$actionTableDistinctIndex];
            if (!isset($actionTable[$lookahead])) {
                $actionLookAheads = array_keys($actionTable);
                if (count($actionLookAheads) > 1) {
                    throw new \Exception(
                        sprintf(
                            'Invalid syntax! Expected one of %s found %s at %d!',
                            var_export(implode(', ', $actionLookAheads), true),
                            var_export($lookahead, true),
                            $this->index
                        )
                    );
                } else {
                    throw new \Exception(
                        sprintf(
                            'Invalid syntax! Expected %s found %s at %d!',
                            var_export($actionLookAheads[0], true),
                            var_export($lookahead, true),
                            $this->index
                        )
                    );
                }
            }

            $actionMatch = $actionTable[$lookahead];
            $actionMatchType = $actionMatch[0];

            switch ($actionMatchType) {
                case Parser::ACTION_SHIFT:
                    if (!isset(self::GOTO_TABLES[$tableIndex])) {
                        throw new \Exception(
                            sprintf(
                                'Missing GOTO-table %d!',
                                $tableIndex
                            )
                        );
                    }
                    $distinctGotoTableIndex = self::GOTO_TABLES[$tableIndex];

                    if (!isset(self::DISTINCT_GOTO_TABLES[$distinctGotoTableIndex])) {
                        throw new \Exception(
                            sprintf(
                                'Missing distinct GOTO-table %d!',
                                $distinctGotoTableIndex
                            )
                        );
                    }
                    $gotoTable = self::DISTINCT_GOTO_TABLES[$distinctGotoTableIndex];

                    if (!isset($gotoTable[$lookahead])) {
                        throw new \Exception(
                            sprintf(
                                'In shift, found no GOTO-item for %s at %d, expected one of %s!',
                                $lookahead,
                                $this->index,
                                var_export(array_keys($gotoTable), true)
                            )
                        );
                    }

                    $nextIndex = $gotoTable[$lookahead];
                    $pushdownList[] = $lookaheadFull;
                    $pushdownList[] = $nextIndex;

                    $this->lexAnalyzerPopToken();
                    break;

                case Parser::ACTION_REDUCE:
                    if (!isset($actionMatch[1])) {
                        throw new \Exception(
                            sprintf(
                                'Invalid reduce action: %s!',
                                var_export($actionMatch, true)
                            )
                        );
                    }
                    $productionNumber = $actionMatch[1];
                    $production = $this->getGrammarProductionByNumber($productionNumber);
                    if (!$production) {
                        throw new \Exception(
                            sprintf(
                                'Failed to find production by number: %s!',
                                var_export($productionNumber, true)
                            )
                        );
                    }
                    $productionLhs = $production[0];
                    $productionRhs = $production[1];
                    $poppedItemContents = [];
                    if ($productionRhs !== [Lexer::E_IDENTIFIER]) {
                        $popItemCount = 2 * count($productionRhs);
                        for ($popItemIndex = 0; $popItemIndex < $popItemCount; $popItemIndex++) {
                            $poppedItem = array_pop($pushdownList);
                            if (
                                is_array($poppedItem)
                                && $this->isValidSymbol($poppedItem[0])
                            ) {
                                $poppedItemContents[] = $poppedItem;
                            }
                        }
                    }

                    $output[] = $productionNumber;
                    $poppedItemsMetaContents = [];
                    $poppedItemsTerminals = [];

                    foreach ($poppedItemContents as $poppedItem) {
                        if (
                            is_array($poppedItem)
                            && isset($poppedItem[1])
                        ) {
                            // If item is a terminal, use it's literal value
                            $poppedItemsMetaContents[] = $this->lexAnalyzerGetToken(
                                $poppedItem
                            );
                            $poppedItemsTerminals[] =
                                $poppedItem;
                        } else {
                            // If item is a non-terminal
                            $tempHashKey = var_export($poppedItem, true);
                            if (isset($translationSymbolTable[$tempHashKey])) {
                                $symbolTranslation =
                                    array_pop($translationSymbolTable[$tempHashKey]);
                                if (
                                    is_array($symbolTranslation)
                                    && isset($symbolTranslation[0])
                                    && isset($symbolTranslation[1])
                                ) {
                                    $poppedItemsMetaContents[] =
                                        $symbolTranslation[0];
                                    $poppedItemsTerminals[] =
                                        $symbolTranslation[1];
                                }
                            } else {
                                $poppedItemsMetaContents[] = null;
                                $poppedItemsTerminals[] = null;
                            }
                        }
                    }

                    $poppedItemsMetaContents = array_reverse($poppedItemsMetaContents);
                    $poppedItemsTerminals = array_reverse($poppedItemsTerminals);

                    // If we just have one argument, pass it as a instead of a list
                    if (count($poppedItemsMetaContents) === 1) {
                        $poppedItemsMetaContents = $poppedItemsMetaContents[0];
                        $poppedItemsTerminals = $poppedItemsTerminals[0];
                    }

                    // Perform translation at reduction if specified
                    if ($function = $this->getGrammarTranslationByNumber($productionNumber)) {
                        $partialTranslation = call_user_func(
                            $function,
                            $poppedItemsMetaContents,
                            $poppedItemsTerminals
                        );
                        $tempHashKey = var_export($productionLhs, true);
                        if (!isset($translationSymbolTable[$tempHashKey])) {
                            $translationSymbolTable[$tempHashKey] = [];
                        }
                        $translationSymbolTable[$tempHashKey][] = [
                            $partialTranslation,
                            $poppedItemsTerminals
                        ];
                        $translation = $partialTranslation;
                    } else {
                        // When no translation is specified just use popped contents as translation
                        $tempHashKey = var_export($productionLhs, true);
                        if (!isset($translationSymbolTable[$tempHashKey])) {
                            $translationSymbolTable[$tempHashKey] = [];
                        }
                        $translationSymbolTable[$tempHashKey][] = [
                            $poppedItemsMetaContents,
                            $poppedItemsTerminals,
                        ];
                        $translation = $poppedItemsMetaContents;
                    }

                    $newTableIndex = end($pushdownList);
                    if (!isset(self::GOTO_TABLES[$newTableIndex])) {
                        throw new \Exception(
                            sprintf(
                                'Failed to find GOTO-table %d!',
                                $newTableIndex
                            )
                        );
                    }

                    $gotoTableDistinctIndex = self::GOTO_TABLES[$newTableIndex];

                    if (!isset(self::DISTINCT_GOTO_TABLES[$gotoTableDistinctIndex])) {
                        throw new \Exception(
                            'Failed to find distinct GOTO-table %s!',
                            $gotoTableDistinctIndex
                        );
                    }
                    $gotoTable = self::DISTINCT_GOTO_TABLES[$gotoTableDistinctIndex];

                    $gotoKey = $productionLhs[0];
                    if (isset($gotoTable[$gotoKey])) {
                        $nextIndex = $gotoTable[$gotoKey];
                        $pushdownList[] = $productionLhs;
                        $pushdownList[] = $nextIndex;
                    }

                    break;
                case Parser::ACTION_ACCEPT:
                    $accept = true;
                    break;
            }
        }

        return [$translation, $output];
    }
}
