master
c 731 lines 13.7 KB
Raw
1 /* Generated by re2c 4.1 on Wed Apr 16 21:13:47 2025 */
2 #line 1 "lexer.re"
3 /**
4 * re2c lexer for Netdata's expression evaluator
5 *
6 * This implementation uses re2c for lexical analysis and lemon for parsing.
7 * It is fully integrated with Netdata's existing EVAL_NODE structure.
8 */
9
10 #include "../eval-internal.h"
11 #include "parser_internal.h"
12
13 // Scanner functions implementation
14 void scanner_init(Scanner *s, const char *input) {
15 if (!input) {
16 // Handle NULL input safely
17 s->cursor = "";
18 s->marker = s->cursor;
19 s->token = s->cursor;
20 s->limit = s->cursor;
21 s->line = 1;
22 s->error = 1; // Set error flag for NULL input
23 return;
24 }
25
26 s->cursor = input;
27 s->marker = s->cursor;
28 s->token = s->cursor;
29 s->limit = s->cursor + strlen(s->cursor);
30 s->line = 1;
31 s->error = 0; // Initialize error flag
32 }
33
34 int scan(Scanner *s, YYSTYPE *lval) {
35 const char *YYMARKER;
36 const char *YYCURSOR = s->cursor;
37 char variable_buffer[EVAL_MAX_VARIABLE_NAME_LENGTH + 1] = {0};
38
39 // Skip whitespace
40 while (1) {
41 s->token = YYCURSOR;
42
43
44 #line 45 "lexer.c"
45 {
46 char yych;
47 unsigned int yyaccept = 0;
48 yych = *YYCURSOR;
49 switch (yych) {
50 case 0x00: goto yy1;
51 case '\t':
52 case '\n':
53 case '\r':
54 case ' ': goto yy4;
55 case '!': goto yy6;
56 case '$': goto yy8;
57 case '%': goto yy9;
58 case '&': goto yy10;
59 case '(': goto yy11;
60 case ')': goto yy12;
61 case '*': goto yy13;
62 case '+': goto yy14;
63 case '-': goto yy15;
64 case '.': goto yy16;
65 case '/': goto yy17;
66 case '0':
67 case '1':
68 case '2':
69 case '3':
70 case '4':
71 case '5':
72 case '6':
73 case '7':
74 case '8':
75 case '9': goto yy18;
76 case ':': goto yy20;
77 case '<': goto yy21;
78 case '=': goto yy23;
79 case '>': goto yy25;
80 case '?': goto yy27;
81 case 'A':
82 case 'a': goto yy28;
83 case 'I':
84 case 'i': goto yy29;
85 case 'N':
86 case 'n': goto yy30;
87 case 'O':
88 case 'o': goto yy31;
89 case '|': goto yy32;
90 default: goto yy2;
91 }
92 yy1:
93 ++YYCURSOR;
94 #line 158 "lexer.re"
95 { s->cursor = YYCURSOR; return 0; }
96 #line 97 "lexer.c"
97 yy2:
98 ++YYCURSOR;
99 yy3:
100 #line 161 "lexer.re"
101 {
102 s->cursor = YYCURSOR;
103 s->error = 1; // Set error flag
104 return 0; // Return 0 to stop parsing
105 }
106 #line 107 "lexer.c"
107 yy4:
108 yych = *++YYCURSOR;
109 switch (yych) {
110 case '\t':
111 case '\n':
112 case '\r':
113 case ' ': goto yy4;
114 default: goto yy5;
115 }
116 yy5:
117 #line 46 "lexer.re"
118 { continue; }
119 #line 120 "lexer.c"
120 yy6:
121 yych = *++YYCURSOR;
122 switch (yych) {
123 case '=': goto yy33;
124 default: goto yy7;
125 }
126 yy7:
127 #line 129 "lexer.re"
128 {
129 s->cursor = YYCURSOR;
130 return TOK_NOT;
131 }
132 #line 133 "lexer.c"
133 yy8:
134 yych = *++YYCURSOR;
135 switch (yych) {
136 case 0x00:
137 case '\t':
138 case '\n':
139 case '\r':
140 case ' ':
141 case '!':
142 case '%':
143 case '&':
144 case '(':
145 case ')':
146 case '*':
147 case '+':
148 case '-':
149 case '/':
150 case '<':
151 case '=':
152 case '>':
153 case '?':
154 case '|':
155 case '}': goto yy3;
156 case '{': goto yy36;
157 default: goto yy34;
158 }
159 yy9:
160 ++YYCURSOR;
161 #line 115 "lexer.re"
162 { s->cursor = YYCURSOR; return TOK_MODULO; }
163 #line 164 "lexer.c"
164 yy10:
165 yych = *++YYCURSOR;
166 switch (yych) {
167 case '&': goto yy38;
168 default: goto yy3;
169 }
170 yy11:
171 ++YYCURSOR;
172 #line 147 "lexer.re"
173 { s->cursor = YYCURSOR; return TOK_LPAREN; }
174 #line 175 "lexer.c"
175 yy12:
176 ++YYCURSOR;
177 #line 148 "lexer.re"
178 { s->cursor = YYCURSOR; return TOK_RPAREN; }
179 #line 180 "lexer.c"
180 yy13:
181 ++YYCURSOR;
182 #line 113 "lexer.re"
183 { s->cursor = YYCURSOR; return TOK_MULTIPLY; }
184 #line 185 "lexer.c"
185 yy14:
186 ++YYCURSOR;
187 #line 111 "lexer.re"
188 { s->cursor = YYCURSOR; return TOK_PLUS; }
189 #line 190 "lexer.c"
190 yy15:
191 ++YYCURSOR;
192 #line 112 "lexer.re"
193 { s->cursor = YYCURSOR; return TOK_MINUS; }
194 #line 195 "lexer.c"
195 yy16:
196 yych = *++YYCURSOR;
197 switch (yych) {
198 case '0':
199 case '1':
200 case '2':
201 case '3':
202 case '4':
203 case '5':
204 case '6':
205 case '7':
206 case '8':
207 case '9': goto yy39;
208 default: goto yy3;
209 }
210 yy17:
211 ++YYCURSOR;
212 #line 114 "lexer.re"
213 { s->cursor = YYCURSOR; return TOK_DIVIDE; }
214 #line 215 "lexer.c"
215 yy18:
216 yyaccept = 0;
217 yych = *(YYMARKER = ++YYCURSOR);
218 switch (yych) {
219 case '.': goto yy39;
220 case '0':
221 case '1':
222 case '2':
223 case '3':
224 case '4':
225 case '5':
226 case '6':
227 case '7':
228 case '8':
229 case '9': goto yy18;
230 case 'E':
231 case 'e': goto yy40;
232 default: goto yy19;
233 }
234 yy19:
235 #line 71 "lexer.re"
236 {
237 char *endptr;
238 lval->dval = str2ndd(s->token, &endptr);
239 s->cursor = YYCURSOR;
240 return TOK_NUMBER;
241 }
242 #line 243 "lexer.c"
243 yy20:
244 ++YYCURSOR;
245 #line 144 "lexer.re"
246 { s->cursor = YYCURSOR; return TOK_COLON; }
247 #line 248 "lexer.c"
248 yy21:
249 yych = *++YYCURSOR;
250 switch (yych) {
251 case '=': goto yy42;
252 case '>': goto yy33;
253 default: goto yy22;
254 }
255 yy22:
256 #line 137 "lexer.re"
257 { s->cursor = YYCURSOR; return TOK_LT; }
258 #line 259 "lexer.c"
259 yy23:
260 yych = *++YYCURSOR;
261 switch (yych) {
262 case '=': goto yy43;
263 default: goto yy24;
264 }
265 yy24:
266 #line 135 "lexer.re"
267 { s->cursor = YYCURSOR; return TOK_EQ; }
268 #line 269 "lexer.c"
269 yy25:
270 yych = *++YYCURSOR;
271 switch (yych) {
272 case '=': goto yy44;
273 default: goto yy26;
274 }
275 yy26:
276 #line 139 "lexer.re"
277 { s->cursor = YYCURSOR; return TOK_GT; }
278 #line 279 "lexer.c"
279 yy27:
280 ++YYCURSOR;
281 #line 143 "lexer.re"
282 { s->cursor = YYCURSOR; return TOK_QMARK; }
283 #line 284 "lexer.c"
284 yy28:
285 yyaccept = 1;
286 yych = *(YYMARKER = ++YYCURSOR);
287 switch (yych) {
288 case 'B':
289 case 'b': goto yy45;
290 case 'N':
291 case 'n': goto yy46;
292 default: goto yy3;
293 }
294 yy29:
295 yyaccept = 1;
296 yych = *(YYMARKER = ++YYCURSOR);
297 switch (yych) {
298 case 'N':
299 case 'n': goto yy47;
300 default: goto yy3;
301 }
302 yy30:
303 yyaccept = 1;
304 yych = *(YYMARKER = ++YYCURSOR);
305 switch (yych) {
306 case 'A':
307 case 'a': goto yy48;
308 case 'O':
309 case 'o': goto yy49;
310 case 'U':
311 case 'u': goto yy50;
312 default: goto yy3;
313 }
314 yy31:
315 yych = *++YYCURSOR;
316 switch (yych) {
317 case 'R':
318 case 'r': goto yy51;
319 default: goto yy3;
320 }
321 yy32:
322 yych = *++YYCURSOR;
323 switch (yych) {
324 case '|': goto yy51;
325 default: goto yy3;
326 }
327 yy33:
328 ++YYCURSOR;
329 #line 136 "lexer.re"
330 { s->cursor = YYCURSOR; return TOK_NE; }
331 #line 332 "lexer.c"
332 yy34:
333 yych = *++YYCURSOR;
334 switch (yych) {
335 case 0x00:
336 case '\t':
337 case '\n':
338 case '\r':
339 case ' ':
340 case '!':
341 case '%':
342 case '&':
343 case '(':
344 case ')':
345 case '*':
346 case '+':
347 case '-':
348 case '/':
349 case '<':
350 case '=':
351 case '>':
352 case '?':
353 case '{':
354 case '|':
355 case '}': goto yy35;
356 default: goto yy34;
357 }
358 yy35:
359 #line 81 "lexer.re"
360 {
361 size_t len = YYCURSOR - s->token - 1; // -1 to skip the $
362 if (len >= EVAL_MAX_VARIABLE_NAME_LENGTH) {
363 len = EVAL_MAX_VARIABLE_NAME_LENGTH - 1;
364 }
365 memcpy(variable_buffer, s->token + 1, len);
366 variable_buffer[len] = '\0';
367 lval->strval = strdupz(variable_buffer);
368 s->cursor = YYCURSOR;
369 return TOK_VARIABLE;
370 }
371 #line 372 "lexer.c"
372 yy36:
373 yyaccept = 2;
374 yych = *(YYMARKER = ++YYCURSOR);
375 switch (yych) {
376 case 0x00: goto yy37;
377 case '}': goto yy53;
378 default: goto yy52;
379 }
380 yy37:
381 #line 155 "lexer.re"
382 { s->cursor = YYCURSOR; s->error = 1; return 0; }
383 #line 384 "lexer.c"
384 yy38:
385 ++YYCURSOR;
386 #line 119 "lexer.re"
387 {
388 s->cursor = YYCURSOR;
389 return TOK_AND;
390 }
391 #line 392 "lexer.c"
392 yy39:
393 yyaccept = 0;
394 yych = *(YYMARKER = ++YYCURSOR);
395 switch (yych) {
396 case '0':
397 case '1':
398 case '2':
399 case '3':
400 case '4':
401 case '5':
402 case '6':
403 case '7':
404 case '8':
405 case '9': goto yy39;
406 case 'E':
407 case 'e': goto yy40;
408 default: goto yy19;
409 }
410 yy40:
411 yych = *++YYCURSOR;
412 switch (yych) {
413 case '+':
414 case '-': goto yy54;
415 case '0':
416 case '1':
417 case '2':
418 case '3':
419 case '4':
420 case '5':
421 case '6':
422 case '7':
423 case '8':
424 case '9': goto yy55;
425 default: goto yy41;
426 }
427 yy41:
428 YYCURSOR = YYMARKER;
429 switch (yyaccept) {
430 case 0: goto yy19;
431 case 1: goto yy3;
432 case 2: goto yy37;
433 default: goto yy58;
434 }
435 yy42:
436 ++YYCURSOR;
437 #line 138 "lexer.re"
438 { s->cursor = YYCURSOR; return TOK_LE; }
439 #line 440 "lexer.c"
440 yy43:
441 ++YYCURSOR;
442 goto yy24;
443 yy44:
444 ++YYCURSOR;
445 #line 140 "lexer.re"
446 { s->cursor = YYCURSOR; return TOK_GE; }
447 #line 448 "lexer.c"
448 yy45:
449 yych = *++YYCURSOR;
450 switch (yych) {
451 case 'S':
452 case 's': goto yy56;
453 default: goto yy41;
454 }
455 yy46:
456 yych = *++YYCURSOR;
457 switch (yych) {
458 case 'D':
459 case 'd': goto yy38;
460 default: goto yy41;
461 }
462 yy47:
463 yych = *++YYCURSOR;
464 switch (yych) {
465 case 'F':
466 case 'f': goto yy57;
467 default: goto yy41;
468 }
469 yy48:
470 yych = *++YYCURSOR;
471 switch (yych) {
472 case 'N':
473 case 'n': goto yy59;
474 default: goto yy41;
475 }
476 yy49:
477 yych = *++YYCURSOR;
478 switch (yych) {
479 case 'T':
480 case 't': goto yy60;
481 default: goto yy41;
482 }
483 yy50:
484 yych = *++YYCURSOR;
485 switch (yych) {
486 case 'L':
487 case 'l': goto yy61;
488 default: goto yy41;
489 }
490 yy51:
491 ++YYCURSOR;
492 #line 124 "lexer.re"
493 {
494 s->cursor = YYCURSOR;
495 return TOK_OR;
496 }
497 #line 498 "lexer.c"
498 yy52:
499 yych = *++YYCURSOR;
500 switch (yych) {
501 case 0x00: goto yy41;
502 case '}': goto yy62;
503 default: goto yy52;
504 }
505 yy53:
506 ++YYCURSOR;
507 #line 94 "lexer.re"
508 { s->cursor = YYCURSOR; s->error = 1; return 0; }
509 #line 510 "lexer.c"
510 yy54:
511 yych = *++YYCURSOR;
512 switch (yych) {
513 case '0':
514 case '1':
515 case '2':
516 case '3':
517 case '4':
518 case '5':
519 case '6':
520 case '7':
521 case '8':
522 case '9': goto yy55;
523 default: goto yy41;
524 }
525 yy55:
526 yych = *++YYCURSOR;
527 switch (yych) {
528 case '0':
529 case '1':
530 case '2':
531 case '3':
532 case '4':
533 case '5':
534 case '6':
535 case '7':
536 case '8':
537 case '9': goto yy55;
538 default: goto yy19;
539 }
540 yy56:
541 ++YYCURSOR;
542 #line 152 "lexer.re"
543 { s->cursor = YYCURSOR; return TOK_FUNCTION_ABS; }
544 #line 545 "lexer.c"
545 yy57:
546 yyaccept = 3;
547 yych = *(YYMARKER = ++YYCURSOR);
548 switch (yych) {
549 case 'I':
550 case 'i': goto yy63;
551 default: goto yy58;
552 }
553 yy58:
554 #line 59 "lexer.re"
555 {
556 lval->dval = INFINITY;
557 s->cursor = YYCURSOR;
558 return TOK_NUMBER;
559 }
560 #line 561 "lexer.c"
561 yy59:
562 ++YYCURSOR;
563 #line 51 "lexer.re"
564 {
565 lval->dval = NAN;
566 s->cursor = YYCURSOR;
567 return TOK_NUMBER;
568 }
569 #line 570 "lexer.c"
570 yy60:
571 ++YYCURSOR;
572 goto yy7;
573 yy61:
574 yych = *++YYCURSOR;
575 switch (yych) {
576 case 'L':
577 case 'l': goto yy59;
578 default: goto yy41;
579 }
580 yy62:
581 ++YYCURSOR;
582 #line 97 "lexer.re"
583 {
584 // Calculate length, excluding the ${ prefix and the } suffix
585 size_t len = YYCURSOR - s->token - 3; // -3 to skip ${ and }
586 if (len >= EVAL_MAX_VARIABLE_NAME_LENGTH) {
587 len = EVAL_MAX_VARIABLE_NAME_LENGTH - 1;
588 }
589 memcpy(variable_buffer, s->token + 2, len);
590 variable_buffer[len] = '\0';
591 lval->strval = strdupz(variable_buffer);
592 s->cursor = YYCURSOR;
593 return TOK_VARIABLE;
594 }
595 #line 596 "lexer.c"
596 yy63:
597 yych = *++YYCURSOR;
598 switch (yych) {
599 case 'N':
600 case 'n': goto yy64;
601 default: goto yy41;
602 }
603 yy64:
604 yych = *++YYCURSOR;
605 switch (yych) {
606 case 'I':
607 case 'i': goto yy65;
608 default: goto yy41;
609 }
610 yy65:
611 yych = *++YYCURSOR;
612 switch (yych) {
613 case 'T':
614 case 't': goto yy66;
615 default: goto yy41;
616 }
617 yy66:
618 yych = *++YYCURSOR;
619 switch (yych) {
620 case 'Y':
621 case 'y': goto yy67;
622 default: goto yy41;
623 }
624 yy67:
625 ++YYCURSOR;
626 goto yy58;
627 }
628 #line 166 "lexer.re"
629
630 }
631 }
632
633 // Function to parse an expression with re2c/lemon
634 EVAL_NODE *parse_expression_with_re2c_lemon(const char *string, const char **failed_at, int *error) {
635 Scanner scanner;
636 scanner_init(&scanner, string);
637
638 if(failed_at)
639 *failed_at = NULL;
640
641 // Use ParseAlloc with mallocz instead of malloc - mallocz will handle allocation failures
642 void *parser = ParseAlloc(mallocz);
643
644 EVAL_NODE *result = NULL;
645
646 YYSTYPE token_value;
647 int token_type;
648
649 // Initialize error code
650 if (error) *error = EVAL_ERROR_OK;
651
652 // Save the token start position for error reporting
653 const char *error_pos = scanner.cursor;
654
655 // Variable to track if we need to free token_value.strval
656 int free_strval = 0;
657
658 while ((token_type = scan(&scanner, &token_value)) > 0) {
659 // If the token is a variable, remember to free it if there's an error
660 free_strval = (token_type == TOK_VARIABLE);
661
662 Parse(parser, token_type, token_value, &result);
663
664 // Save position before potential error
665 error_pos = scanner.token;
666
667 // Check for syntax errors after each token
668 if (result && result->operator == EVAL_OPERATOR_NOP && result->count == 0) {
669 // This is an error marker
670 if (error) *error = EVAL_ERROR_SYNTAX;
671 if (failed_at) {
672 *failed_at = error_pos;
673 }
674
675 // Clean up
676 eval_node_free(result);
677 ParseFree(parser, freez);
678
679 // If we just scanned a variable, free its strval
680 if (free_strval && token_value.strval) {
681 freez(token_value.strval);
682 }
683
684 return NULL;
685 }
686
687 // Reset free_strval since the parser has taken ownership of the string
688 free_strval = 0;
689 }
690
691 // If the last token was a variable and scanning stopped due to an error,
692 // we need to free the token_value.strval
693 if (free_strval && token_value.strval) {
694 freez(token_value.strval);
695 token_value.strval = NULL;
696 }
697
698 // Finish parsing
699 Parse(parser, 0, token_value, &result);
700
701 // Clean up the parser
702 ParseFree(parser, freez);
703
704 // Check for lexer errors
705 if (scanner.error) {
706 if (error) *error = EVAL_ERROR_UNKNOWN_OPERAND;
707 if (failed_at) {
708 *failed_at = error_pos;
709 }
710
711 // Clean up result if it was created
712 if (result) {
713 eval_node_free(result);
714 }
715
716 return NULL;
717 }
718
719 if (!result) {
720 if (error) *error = EVAL_ERROR_SYNTAX;
721 if (failed_at) {
722 *failed_at = error_pos;
723 }
724 return NULL;
725 }
726
727 if (failed_at)
728 *failed_at = NULL;
729
730 return result;
731 }