/* Generated by re2c 4.5.1 on Wed Jul  1 10:42:42 2026 */
#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};

    lval->strval = NULL;
    
    // Skip whitespace
    while (1) {
        s->token = YYCURSOR;
        

#line 47 "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 160 "lexer.re"
	{ s->cursor = YYCURSOR; return 0; }
#line 99 "lexer.c"
yy2:
	++YYCURSOR;
yy3:
#line 163 "lexer.re"
	{ 
        s->cursor = YYCURSOR; 
        s->error = 1;  // Set error flag
        return 0;      // Return 0 to stop parsing
    }
#line 109 "lexer.c"
yy4:
	yych = *++YYCURSOR;
	switch (yych) {
		case '\t':
		case '\n':
		case '\r':
		case ' ': goto yy4;
		default: goto yy5;
	}
yy5:
#line 48 "lexer.re"
	{ continue; }
#line 122 "lexer.c"
yy6:
	yych = *++YYCURSOR;
	switch (yych) {
		case '=': goto yy33;
		default: goto yy7;
	}
yy7:
#line 131 "lexer.re"
	{ 
        s->cursor = YYCURSOR; 
        return TOK_NOT; 
    }
#line 135 "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 117 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_MODULO; }
#line 166 "lexer.c"
yy10:
	yych = *++YYCURSOR;
	switch (yych) {
		case '&': goto yy38;
		default: goto yy3;
	}
yy11:
	++YYCURSOR;
#line 149 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_LPAREN; }
#line 177 "lexer.c"
yy12:
	++YYCURSOR;
#line 150 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_RPAREN; }
#line 182 "lexer.c"
yy13:
	++YYCURSOR;
#line 115 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_MULTIPLY; }
#line 187 "lexer.c"
yy14:
	++YYCURSOR;
#line 113 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_PLUS; }
#line 192 "lexer.c"
yy15:
	++YYCURSOR;
#line 114 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_MINUS; }
#line 197 "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 116 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_DIVIDE; }
#line 217 "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 73 "lexer.re"
	{
        char *endptr;
        lval->dval = str2ndd(s->token, &endptr);
        s->cursor = YYCURSOR;
        return TOK_NUMBER;
    }
#line 245 "lexer.c"
yy20:
	++YYCURSOR;
#line 146 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_COLON; }
#line 250 "lexer.c"
yy21:
	yych = *++YYCURSOR;
	switch (yych) {
		case '=': goto yy42;
		case '>': goto yy33;
		default: goto yy22;
	}
yy22:
#line 139 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_LT; }
#line 261 "lexer.c"
yy23:
	yych = *++YYCURSOR;
	switch (yych) {
		case '=': goto yy43;
		default: goto yy24;
	}
yy24:
#line 137 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_EQ; }
#line 271 "lexer.c"
yy25:
	yych = *++YYCURSOR;
	switch (yych) {
		case '=': goto yy44;
		default: goto yy26;
	}
yy26:
#line 141 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_GT; }
#line 281 "lexer.c"
yy27:
	++YYCURSOR;
#line 145 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_QMARK; }
#line 286 "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 138 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_NE; }
#line 334 "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 83 "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 374 "lexer.c"
yy36:
	yyaccept = 2;
	yych = *(YYMARKER = ++YYCURSOR);
	switch (yych) {
		case 0x00: goto yy37;
		case '}': goto yy53;
		default: goto yy52;
	}
yy37:
#line 157 "lexer.re"
	{ s->cursor = YYCURSOR; s->error = 1; return 0; }
#line 386 "lexer.c"
yy38:
	++YYCURSOR;
#line 121 "lexer.re"
	{ 
        s->cursor = YYCURSOR; 
        return TOK_AND; 
    }
#line 394 "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 140 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_LE; }
#line 442 "lexer.c"
yy43:
	++YYCURSOR;
	goto yy24;
yy44:
	++YYCURSOR;
#line 142 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_GE; }
#line 450 "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 126 "lexer.re"
	{ 
        s->cursor = YYCURSOR; 
        return TOK_OR; 
    }
#line 500 "lexer.c"
yy52:
	yych = *++YYCURSOR;
	switch (yych) {
		case 0x00: goto yy41;
		case '}': goto yy62;
		default: goto yy52;
	}
yy53:
	++YYCURSOR;
#line 96 "lexer.re"
	{ s->cursor = YYCURSOR; s->error = 1; return 0; }
#line 512 "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 154 "lexer.re"
	{ s->cursor = YYCURSOR; return TOK_FUNCTION_ABS; }
#line 547 "lexer.c"
yy57:
	yyaccept = 3;
	yych = *(YYMARKER = ++YYCURSOR);
	switch (yych) {
		case 'I':
		case 'i': goto yy63;
		default: goto yy58;
	}
yy58:
#line 61 "lexer.re"
	{
        lval->dval = INFINITY;
        s->cursor = YYCURSOR;
        return TOK_NUMBER;
    }
#line 563 "lexer.c"
yy59:
	++YYCURSOR;
#line 53 "lexer.re"
	{
        lval->dval = NAN;
        s->cursor = YYCURSOR;
        return TOK_NUMBER;
    }
#line 572 "lexer.c"
yy60:
	++YYCURSOR;
	goto yy7;
yy61:
	yych = *++YYCURSOR;
	switch (yych) {
		case 'L':
		case 'l': goto yy59;
		default: goto yy41;
	}
yy62:
	++YYCURSOR;
#line 99 "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 598 "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 168 "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;
    
    while ((token_type = scan(&scanner, &token_value)) > 0) {
        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);

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