/* Generated by re2c 4.1 on Wed Apr 16 21:13:47 2025 */
#line 1 "lexer.re"
/**
 * re2c lexer for Netdata's expression evaluator
 *
 * This implementation uses re2c for lexical analysis and lemon for parsing.
 * It is fully integrated with Netdata's existing EVAL_NODE structure.
 */

#include "../eval-internal.h"
#include "parser_internal.h"

// Scanner functions implementation
void scanner_init(Scanner *s, const char *input) {
    if (!input) {
        // Handle NULL input safely
        s->cursor = "";
        s->marker = s->cursor;
        s->token = s->cursor;
        s->limit = s->cursor;
        s->line = 1;
        s->error = 1;  // Set error flag for NULL input
        return;
    }
    
    s->cursor = input;
    s->marker = s->cursor;
    s->token = s->cursor;
    s->limit = s->cursor + strlen(s->cursor);
    s->line = 1;
    s->error = 0;  // Initialize error flag
}

int scan(Scanner *s, YYSTYPE *lval) {
    const char *YYMARKER;
    const char *YYCURSOR = s->cursor;
    char variable_buffer[EVAL_MAX_VARIABLE_NAME_LENGTH + 1] = {0};
    
    // Skip whitespace
    while (1) {
        s->token = YYCURSOR;
        

#line 45 "lexer.c"
{
	char yych;
	unsigned int yyaccept = 0;
	yych = *YYCURSOR;
	switch (yych) {
		case 0x00: goto yy1;
		case '\t':
		case '\n':
		case '\r':
		case ' ': goto yy4;
		case '!': goto yy6;
		case '$': goto yy8;
		case '%': goto yy9;
		case '&': goto yy10;
		case '(': goto yy11;
		case ')': goto yy12;
		case '*': goto yy13;
		case '+': goto yy14;
		case '-': goto yy15;
		case '.': goto yy16;
		case '/': goto yy17;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy18;
		case ':': goto yy20;
		case '<': goto yy21;
		case '=': goto yy23;
		case '>': goto yy25;
		case '?': goto yy27;
		case 'A':
		case 'a': goto yy28;
		case 'I':
		case 'i': goto yy29;
		case 'N':
		case 'n': goto yy30;
		case 'O':
		case 'o': goto yy31;
		case '|': goto yy32;
		default: goto yy2;
	}
yy1:
	++YYCURSOR;
#line 158 "lexer.re"
	{ s->cursor = YYCURSOR; return 0; }
#line 97 "lexer.c"
yy2:
	++YYCURSOR;
yy3:
#line 161 "lexer.re"
	{ 
        s->cursor = YYCURSOR; 
        s->error = 1;  // Set error flag
        return 0;      // Return 0 to stop parsing
    }
#line 107 "lexer.c"
yy4:
	yych = *++YYCURSOR;
	switch (yych) {
		case '\t':
		case '\n':
		case '\r':
		case ' ': goto yy4;
		default: goto yy5;
	}
yy5:
#line 46 "lexer.re"
	{ continue; }
#line 120 "lexer.c"
yy6:
	yych = *++YYCURSOR;
	switch (yych) {
		case '=': goto yy33;
		default: goto yy7;
	}
yy7:
#line 129 "lexer.re"
	{ 
        s->cursor = YYCURSOR; 
        return TOK_NOT; 
    }
#line 133 "lexer.c"
yy8:
	yych = *++YYCURSOR;
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\r':
		case ' ':
		case '!':
		case '%':
		case '&':
		case '(':
		case ')':
		case '*':
		case '+':
		case '-':
		case '/':
		case '<':
		case '=':
		case '>':
		case '?':
		case '|':
		case '}': goto yy3;
		case '{': goto yy36;
		default: goto yy34;
	}
yy9:
	++YYCURSOR;
#line 115 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_MODULO; }
#line 164 "lexer.c"
yy10:
	yych = *++YYCURSOR;
	switch (yych) {
		case '&': goto yy38;
		default: goto yy3;
	}
yy11:
	++YYCURSOR;
#line 147 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_LPAREN; }
#line 175 "lexer.c"
yy12:
	++YYCURSOR;
#line 148 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_RPAREN; }
#line 180 "lexer.c"
yy13:
	++YYCURSOR;
#line 113 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_MULTIPLY; }
#line 185 "lexer.c"
yy14:
	++YYCURSOR;
#line 111 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_PLUS; }
#line 190 "lexer.c"
yy15:
	++YYCURSOR;
#line 112 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_MINUS; }
#line 195 "lexer.c"
yy16:
	yych = *++YYCURSOR;
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy39;
		default: goto yy3;
	}
yy17:
	++YYCURSOR;
#line 114 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_DIVIDE; }
#line 215 "lexer.c"
yy18:
	yyaccept = 0;
	yych = *(YYMARKER = ++YYCURSOR);
	switch (yych) {
		case '.': goto yy39;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy18;
		case 'E':
		case 'e': goto yy40;
		default: goto yy19;
	}
yy19:
#line 71 "lexer.re"
	{
        char *endptr;
        lval->dval = str2ndd(s->token, &endptr);
        s->cursor = YYCURSOR;
        return TOK_NUMBER;
    }
#line 243 "lexer.c"
yy20:
	++YYCURSOR;
#line 144 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_COLON; }
#line 248 "lexer.c"
yy21:
	yych = *++YYCURSOR;
	switch (yych) {
		case '=': goto yy42;
		case '>': goto yy33;
		default: goto yy22;
	}
yy22:
#line 137 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_LT; }
#line 259 "lexer.c"
yy23:
	yych = *++YYCURSOR;
	switch (yych) {
		case '=': goto yy43;
		default: goto yy24;
	}
yy24:
#line 135 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_EQ; }
#line 269 "lexer.c"
yy25:
	yych = *++YYCURSOR;
	switch (yych) {
		case '=': goto yy44;
		default: goto yy26;
	}
yy26:
#line 139 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_GT; }
#line 279 "lexer.c"
yy27:
	++YYCURSOR;
#line 143 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_QMARK; }
#line 284 "lexer.c"
yy28:
	yyaccept = 1;
	yych = *(YYMARKER = ++YYCURSOR);
	switch (yych) {
		case 'B':
		case 'b': goto yy45;
		case 'N':
		case 'n': goto yy46;
		default: goto yy3;
	}
yy29:
	yyaccept = 1;
	yych = *(YYMARKER = ++YYCURSOR);
	switch (yych) {
		case 'N':
		case 'n': goto yy47;
		default: goto yy3;
	}
yy30:
	yyaccept = 1;
	yych = *(YYMARKER = ++YYCURSOR);
	switch (yych) {
		case 'A':
		case 'a': goto yy48;
		case 'O':
		case 'o': goto yy49;
		case 'U':
		case 'u': goto yy50;
		default: goto yy3;
	}
yy31:
	yych = *++YYCURSOR;
	switch (yych) {
		case 'R':
		case 'r': goto yy51;
		default: goto yy3;
	}
yy32:
	yych = *++YYCURSOR;
	switch (yych) {
		case '|': goto yy51;
		default: goto yy3;
	}
yy33:
	++YYCURSOR;
#line 136 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_NE; }
#line 332 "lexer.c"
yy34:
	yych = *++YYCURSOR;
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\r':
		case ' ':
		case '!':
		case '%':
		case '&':
		case '(':
		case ')':
		case '*':
		case '+':
		case '-':
		case '/':
		case '<':
		case '=':
		case '>':
		case '?':
		case '{':
		case '|':
		case '}': goto yy35;
		default: goto yy34;
	}
yy35:
#line 81 "lexer.re"
	{
        size_t len = YYCURSOR - s->token - 1; // -1 to skip the $
        if (len >= EVAL_MAX_VARIABLE_NAME_LENGTH) {
            len = EVAL_MAX_VARIABLE_NAME_LENGTH - 1;
        }
        memcpy(variable_buffer, s->token + 1, len);
        variable_buffer[len] = '\0';
        lval->strval = strdupz(variable_buffer);
        s->cursor = YYCURSOR;
        return TOK_VARIABLE;
    }
#line 372 "lexer.c"
yy36:
	yyaccept = 2;
	yych = *(YYMARKER = ++YYCURSOR);
	switch (yych) {
		case 0x00: goto yy37;
		case '}': goto yy53;
		default: goto yy52;
	}
yy37:
#line 155 "lexer.re"
	{ s->cursor = YYCURSOR; s->error = 1; return 0; }
#line 384 "lexer.c"
yy38:
	++YYCURSOR;
#line 119 "lexer.re"
	{ 
        s->cursor = YYCURSOR; 
        return TOK_AND; 
    }
#line 392 "lexer.c"
yy39:
	yyaccept = 0;
	yych = *(YYMARKER = ++YYCURSOR);
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy39;
		case 'E':
		case 'e': goto yy40;
		default: goto yy19;
	}
yy40:
	yych = *++YYCURSOR;
	switch (yych) {
		case '+':
		case '-': goto yy54;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy55;
		default: goto yy41;
	}
yy41:
	YYCURSOR = YYMARKER;
	switch (yyaccept) {
		case 0: goto yy19;
		case 1: goto yy3;
		case 2: goto yy37;
		default: goto yy58;
	}
yy42:
	++YYCURSOR;
#line 138 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_LE; }
#line 440 "lexer.c"
yy43:
	++YYCURSOR;
	goto yy24;
yy44:
	++YYCURSOR;
#line 140 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_GE; }
#line 448 "lexer.c"
yy45:
	yych = *++YYCURSOR;
	switch (yych) {
		case 'S':
		case 's': goto yy56;
		default: goto yy41;
	}
yy46:
	yych = *++YYCURSOR;
	switch (yych) {
		case 'D':
		case 'd': goto yy38;
		default: goto yy41;
	}
yy47:
	yych = *++YYCURSOR;
	switch (yych) {
		case 'F':
		case 'f': goto yy57;
		default: goto yy41;
	}
yy48:
	yych = *++YYCURSOR;
	switch (yych) {
		case 'N':
		case 'n': goto yy59;
		default: goto yy41;
	}
yy49:
	yych = *++YYCURSOR;
	switch (yych) {
		case 'T':
		case 't': goto yy60;
		default: goto yy41;
	}
yy50:
	yych = *++YYCURSOR;
	switch (yych) {
		case 'L':
		case 'l': goto yy61;
		default: goto yy41;
	}
yy51:
	++YYCURSOR;
#line 124 "lexer.re"
	{ 
        s->cursor = YYCURSOR; 
        return TOK_OR; 
    }
#line 498 "lexer.c"
yy52:
	yych = *++YYCURSOR;
	switch (yych) {
		case 0x00: goto yy41;
		case '}': goto yy62;
		default: goto yy52;
	}
yy53:
	++YYCURSOR;
#line 94 "lexer.re"
	{ s->cursor = YYCURSOR; s->error = 1; return 0; }
#line 510 "lexer.c"
yy54:
	yych = *++YYCURSOR;
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy55;
		default: goto yy41;
	}
yy55:
	yych = *++YYCURSOR;
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy55;
		default: goto yy19;
	}
yy56:
	++YYCURSOR;
#line 152 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_FUNCTION_ABS; }
#line 545 "lexer.c"
yy57:
	yyaccept = 3;
	yych = *(YYMARKER = ++YYCURSOR);
	switch (yych) {
		case 'I':
		case 'i': goto yy63;
		default: goto yy58;
	}
yy58:
#line 59 "lexer.re"
	{
        lval->dval = INFINITY;
        s->cursor = YYCURSOR;
        return TOK_NUMBER;
    }
#line 561 "lexer.c"
yy59:
	++YYCURSOR;
#line 51 "lexer.re"
	{
        lval->dval = NAN;
        s->cursor = YYCURSOR;
        return TOK_NUMBER;
    }
#line 570 "lexer.c"
yy60:
	++YYCURSOR;
	goto yy7;
yy61:
	yych = *++YYCURSOR;
	switch (yych) {
		case 'L':
		case 'l': goto yy59;
		default: goto yy41;
	}
yy62:
	++YYCURSOR;
#line 97 "lexer.re"
	{
        // Calculate length, excluding the ${ prefix and the } suffix
        size_t len = YYCURSOR - s->token - 3; // -3 to skip ${ and }
        if (len >= EVAL_MAX_VARIABLE_NAME_LENGTH) {
            len = EVAL_MAX_VARIABLE_NAME_LENGTH - 1;
        }
        memcpy(variable_buffer, s->token + 2, len);
        variable_buffer[len] = '\0';
        lval->strval = strdupz(variable_buffer);
        s->cursor = YYCURSOR;
        return TOK_VARIABLE;
    }
#line 596 "lexer.c"
yy63:
	yych = *++YYCURSOR;
	switch (yych) {
		case 'N':
		case 'n': goto yy64;
		default: goto yy41;
	}
yy64:
	yych = *++YYCURSOR;
	switch (yych) {
		case 'I':
		case 'i': goto yy65;
		default: goto yy41;
	}
yy65:
	yych = *++YYCURSOR;
	switch (yych) {
		case 'T':
		case 't': goto yy66;
		default: goto yy41;
	}
yy66:
	yych = *++YYCURSOR;
	switch (yych) {
		case 'Y':
		case 'y': goto yy67;
		default: goto yy41;
	}
yy67:
	++YYCURSOR;
	goto yy58;
}
#line 166 "lexer.re"

    }
}

// Function to parse an expression with re2c/lemon
EVAL_NODE *parse_expression_with_re2c_lemon(const char *string, const char **failed_at, int *error) {
    Scanner scanner;
    scanner_init(&scanner, string);

    if(failed_at)
        *failed_at = NULL;
    
    // Use ParseAlloc with mallocz instead of malloc - mallocz will handle allocation failures
    void *parser = ParseAlloc(mallocz);
    
    EVAL_NODE *result = NULL;
    
    YYSTYPE token_value;
    int token_type;
    
    // Initialize error code
    if (error) *error = EVAL_ERROR_OK;
    
    // Save the token start position for error reporting
    const char *error_pos = scanner.cursor;
    
    // Variable to track if we need to free token_value.strval
    int free_strval = 0;
    
    while ((token_type = scan(&scanner, &token_value)) > 0) {
        // If the token is a variable, remember to free it if there's an error
        free_strval = (token_type == TOK_VARIABLE);
        
        Parse(parser, token_type, token_value, &result);
        
        // Save position before potential error
        error_pos = scanner.token;
        
        // Check for syntax errors after each token
        if (result && result->operator == EVAL_OPERATOR_NOP && result->count == 0) {
            // This is an error marker
            if (error) *error = EVAL_ERROR_SYNTAX;
            if (failed_at) {
                *failed_at = error_pos;
            }
            
            // Clean up
            eval_node_free(result);
            ParseFree(parser, freez);
            
            // If we just scanned a variable, free its strval
            if (free_strval && token_value.strval) {
                freez(token_value.strval);
            }
            
            return NULL;
        }
        
        // Reset free_strval since the parser has taken ownership of the string
        free_strval = 0;
    }
    
    // If the last token was a variable and scanning stopped due to an error,
    // we need to free the token_value.strval
    if (free_strval && token_value.strval) {
        freez(token_value.strval);
        token_value.strval = NULL;
    }
    
    // Finish parsing
    Parse(parser, 0, token_value, &result);
    
    // Clean up the parser
    ParseFree(parser, freez);
    
    // Check for lexer errors
    if (scanner.error) {
        if (error) *error = EVAL_ERROR_UNKNOWN_OPERAND;
        if (failed_at) {
            *failed_at = error_pos;
        }
        
        // Clean up result if it was created
        if (result) {
            eval_node_free(result);
        }
        
        return NULL;
    }
    
    if (!result) {
        if (error) *error = EVAL_ERROR_SYNTAX;
        if (failed_at) {
            *failed_at = error_pos;
        }
        return NULL;
    }
    
    if (failed_at)
        *failed_at = NULL;
    
    return result;
}