master
c 886 lines 25.3 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 /*
4 * THIS CODE IS NOT USED ANY MORE
5 * IT IS KEPT HERE ONLY FOR REFERENCE (AND POTENTIALLY RUNNING UNIT TESTS)
6 */
7
8 #include "../libnetdata.h"
9 #include "eval-internal.h"
10 #include <ctype.h> // For tolower
11
12 // Character validation functions for parsing
13 ALWAYS_INLINE
14 static bool is_operator_first_symbol_or_space(const char s) {
15 return (
16 isspace((uint8_t)s) || !s ||
17 s == '&' || s == '|' || s == '!' || s == '>' || s == '<' ||
18 s == '=' || s == '+' || s == '-' || s == '*' || s == '/' || s == '?');
19 }
20
21 ALWAYS_INLINE
22 static bool is_valid_after_operator_word(const char s) {
23 return isspace((uint8_t)s) || s == '(' || s == '$' || s == '!' ||
24 s == '-' || s == '+' || isdigit((uint8_t)s) || !s;
25 }
26
27 ALWAYS_INLINE
28 static bool is_valid_after_operator_symbol(const char s) {
29 return is_valid_after_operator_word(s) || is_operator_first_symbol_or_space(s);
30 }
31
32 ALWAYS_INLINE
33 static bool is_valid_variable_character(const char s) {
34 return !is_operator_first_symbol_or_space(s) && s != ')' && s != '}';
35 }
36
37 // Forward function declarations
38 static inline EVAL_NODE *parse_full_expression(const char **string, int *error);
39 static inline EVAL_NODE *parse_one_full_operand(const char **string, int *error);
40
41 // ----------------------------------------------------------------------------
42 // parsing expressions
43
44 // skip spaces
45 ALWAYS_INLINE
46 static void skip_spaces(const char **string) {
47 const char *s = *string;
48 while(isspace((uint8_t)*s)) s++;
49 *string = s;
50 }
51
52 // ----------------------------------------------------------------------------
53 // parse operators
54
55 ALWAYS_INLINE
56 static int parse_and(const char **string) {
57 const char *s = *string;
58
59 // AND
60 if((s[0] == 'A' || s[0] == 'a') && (s[1] == 'N' || s[1] == 'n') && (s[2] == 'D' || s[2] == 'd') &&
61 is_valid_after_operator_word(s[3])) {
62 *string = &s[4];
63 return 1;
64 }
65
66 // &&
67 if(s[0] == '&' && s[1] == '&' && is_valid_after_operator_symbol(s[2])) {
68 *string = &s[2];
69 return 1;
70 }
71
72 return 0;
73 }
74
75 ALWAYS_INLINE
76 static int parse_or(const char **string) {
77 const char *s = *string;
78
79 // OR
80 if((s[0] == 'O' || s[0] == 'o') && (s[1] == 'R' || s[1] == 'r') && is_valid_after_operator_word(s[2])) {
81 *string = &s[3];
82 return 1;
83 }
84
85 // ||
86 if(s[0] == '|' && s[1] == '|' && is_valid_after_operator_symbol(s[2])) {
87 *string = &s[2];
88 return 1;
89 }
90
91 return 0;
92 }
93
94 ALWAYS_INLINE
95 static int parse_greater_than_or_equal(const char **string) {
96 const char *s = *string;
97
98 // >=
99 if(s[0] == '>' && s[1] == '=' && is_valid_after_operator_symbol(s[2])) {
100 *string = &s[2];
101 return 1;
102 }
103
104 return 0;
105 }
106
107 ALWAYS_INLINE
108 static int parse_less_than_or_equal(const char **string) {
109 const char *s = *string;
110
111 // <=
112 if (s[0] == '<' && s[1] == '=' && is_valid_after_operator_symbol(s[2])) {
113 *string = &s[2];
114 return 1;
115 }
116
117 return 0;
118 }
119
120 ALWAYS_INLINE
121 static int parse_greater(const char **string) {
122 const char *s = *string;
123
124 // >
125 if(s[0] == '>' && is_valid_after_operator_symbol(s[1])) {
126 *string = &s[1];
127 return 1;
128 }
129
130 return 0;
131 }
132
133 ALWAYS_INLINE
134 static int parse_less(const char **string) {
135 const char *s = *string;
136
137 // <
138 if(s[0] == '<' && is_valid_after_operator_symbol(s[1])) {
139 *string = &s[1];
140 return 1;
141 }
142
143 return 0;
144 }
145
146 ALWAYS_INLINE
147 static int parse_equal(const char **string) {
148 const char *s = *string;
149
150 // ==
151 if(s[0] == '=' && s[1] == '=' && is_valid_after_operator_symbol(s[2])) {
152 *string = &s[2];
153 return 1;
154 }
155
156 // =
157 if(s[0] == '=' && is_valid_after_operator_symbol(s[1])) {
158 *string = &s[1];
159 return 1;
160 }
161
162 return 0;
163 }
164
165 ALWAYS_INLINE
166 static int parse_not_equal(const char **string) {
167 const char *s = *string;
168
169 // !=
170 if(s[0] == '!' && s[1] == '=' && is_valid_after_operator_symbol(s[2])) {
171 *string = &s[2];
172 return 1;
173 }
174
175 // <>
176 if(s[0] == '<' && s[1] == '>' && is_valid_after_operator_symbol(s[2])) {
177 *string = &s[2];
178 }
179
180 return 0;
181 }
182
183 ALWAYS_INLINE
184 static int parse_not(const char **string) {
185 const char *s = *string;
186
187 // NOT
188 if((s[0] == 'N' || s[0] == 'n') && (s[1] == 'O' || s[1] == 'o') && (s[2] == 'T' || s[2] == 't') &&
189 is_valid_after_operator_word(s[3])) {
190 *string = &s[3];
191 return 1;
192 }
193
194 if(s[0] == '!') {
195 *string = &s[1];
196 return 1;
197 }
198
199 return 0;
200 }
201
202 ALWAYS_INLINE
203 static int parse_multiply(const char **string) {
204 const char *s = *string;
205
206 // *
207 if(s[0] == '*' && is_valid_after_operator_symbol(s[1])) {
208 *string = &s[1];
209 return 1;
210 }
211
212 return 0;
213 }
214
215 ALWAYS_INLINE
216 static int parse_divide(const char **string) {
217 const char *s = *string;
218
219 // /
220 if(s[0] == '/' && is_valid_after_operator_symbol(s[1])) {
221 *string = &s[1];
222 return 1;
223 }
224
225 return 0;
226 }
227
228 ALWAYS_INLINE
229 static int parse_minus(const char **string) {
230 const char *s = *string;
231
232 // -
233 if(s[0] == '-' && is_valid_after_operator_symbol(s[1])) {
234 *string = &s[1];
235 return 1;
236 }
237
238 return 0;
239 }
240
241 ALWAYS_INLINE
242 static int parse_plus(const char **string) {
243 const char *s = *string;
244
245 // +
246 if(s[0] == '+' && is_valid_after_operator_symbol(s[1])) {
247 *string = &s[1];
248 return 1;
249 }
250
251 return 0;
252 }
253
254 ALWAYS_INLINE
255 static int parse_open_subexpression(const char **string) {
256 const char *s = *string;
257
258 // (
259 if(s[0] == '(') {
260 *string = &s[1];
261 return 1;
262 }
263
264 return 0;
265 }
266
267 ALWAYS_INLINE
268 static int parse_close_subexpression(const char **string) {
269 const char *s = *string;
270
271 // )
272 if(s[0] == ')') {
273 *string = &s[1];
274 return 1;
275 }
276
277 return 0;
278 }
279
280 ALWAYS_INLINE
281 static int parse_variable(const char **string, char *buffer, size_t len) {
282 const char *s = *string;
283
284 // $
285 if(*s == '$') {
286 size_t i = 0;
287 s++;
288
289 if(*s == '{') {
290 // ${variable_name}
291
292 s++;
293 while (*s && *s != '}' && i < len)
294 buffer[i++] = *s++;
295
296 if(*s == '}')
297 s++;
298 }
299 else {
300 // $variable_name
301
302 while (*s && is_valid_variable_character(*s) && i < len)
303 buffer[i++] = *s++;
304 }
305
306 buffer[i] = '\0';
307
308 if (buffer[0]) {
309 *string = s;
310 return 1;
311 }
312 }
313
314 return 0;
315 }
316
317 ALWAYS_INLINE
318 static int parse_constant(const char **string, NETDATA_DOUBLE *number) {
319 char *end = NULL;
320 NETDATA_DOUBLE n = str2ndd(*string, &end);
321 if(unlikely(!end || *string == end)) {
322 *number = 0;
323 return 0;
324 }
325 *number = n;
326 *string = end;
327 return 1;
328 }
329
330 // Define the functions we support
331 static EVAL_FUNCTION eval_functions[] = {
332 {"abs", EVAL_OPERATOR_ABS, 6},
333 {NULL, 0, 0} // Terminator
334 };
335
336 // Parse function call
337 ALWAYS_INLINE
338 static int parse_function(const char **string, unsigned char *op, int *precedence) {
339 const char *s = *string;
340 skip_spaces(&s);
341
342 // Check for each function in our list
343 for (int i = 0; eval_functions[i].name != NULL; i++) {
344 const char *name = eval_functions[i].name;
345 int len = strlen(name);
346 int j;
347
348 // Case-insensitive comparison of function name
349 for (j = 0; j < len; j++) {
350 if (!s[j] || (tolower((unsigned char)s[j]) != name[j])) {
351 break;
352 }
353 }
354
355 // Check if we matched the entire function name and it's followed by '('
356 if (j == len && s[j] == '(') {
357 *string = &s[j+1]; // Move past "function_name("
358 *op = eval_functions[i].op;
359 if (precedence) *precedence = eval_functions[i].precedence;
360 return 1;
361 }
362 }
363
364 return 0;
365 }
366
367 ALWAYS_INLINE
368 static int parse_if_then_else(const char **string) {
369 const char *s = *string;
370
371 // ?
372 if(s[0] == '?') {
373 *string = &s[1];
374 return 1;
375 }
376
377 return 0;
378 }
379
380 static struct operator_parser {
381 unsigned char id;
382 int (*parse)(const char **);
383 } operator_parsers[] = {
384 // the order in this list is important!
385 // the first matching will be used
386 // so place the longer of overlapping ones
387 // at the top
388
389 { EVAL_OPERATOR_AND, parse_and },
390 { EVAL_OPERATOR_OR, parse_or },
391 { EVAL_OPERATOR_GREATER_THAN_OR_EQUAL, parse_greater_than_or_equal },
392 { EVAL_OPERATOR_LESS_THAN_OR_EQUAL, parse_less_than_or_equal },
393 { EVAL_OPERATOR_NOT_EQUAL, parse_not_equal },
394 { EVAL_OPERATOR_EQUAL, parse_equal },
395 { EVAL_OPERATOR_LESS, parse_less },
396 { EVAL_OPERATOR_GREATER, parse_greater },
397 { EVAL_OPERATOR_PLUS, parse_plus },
398 { EVAL_OPERATOR_MINUS, parse_minus },
399 { EVAL_OPERATOR_MULTIPLY, parse_multiply },
400 { EVAL_OPERATOR_DIVIDE, parse_divide },
401 { EVAL_OPERATOR_IF_THEN_ELSE, parse_if_then_else },
402
403 /* we should not put in this list the following:
404 *
405 * - NOT
406 * - (
407 * - )
408 *
409 * these are handled in code
410 */
411
412 // termination
413 { EVAL_OPERATOR_NOP, NULL }
414 };
415
416 ALWAYS_INLINE
417 static unsigned char parse_operator(const char **string, int *precedence) {
418 skip_spaces(string);
419
420 int i;
421 for(i = 0 ; operator_parsers[i].parse != NULL ; i++)
422 if(operator_parsers[i].parse(string)) {
423 if(precedence) *precedence = eval_precedence(operator_parsers[i].id);
424 return operator_parsers[i].id;
425 }
426
427 return EVAL_OPERATOR_NOP;
428 }
429
430 // ----------------------------------------------------------------------------
431 // the parsing logic
432
433 // Forward declarations needed for recursive parsing
434 static inline EVAL_NODE *parse_expression(const char **string, int *error, int allow_functions);
435 static int starts_with_function(const char *s);
436
437 // Helper function to parse a function call
438 static EVAL_NODE *parse_function_call(const char **string, int *error) {
439 unsigned char op_type;
440 int precedence;
441
442 // Parse the function name and opening parenthesis
443 if (!parse_function(string, &op_type, &precedence)) {
444 *error = EVAL_ERROR_UNKNOWN_OPERAND;
445 return NULL;
446 }
447
448 // Special handling for nested expressions that may include unary operators
449 // followed by function calls
450 const char *arg_start = *string;
451 skip_spaces(&arg_start);
452
453 // Check if what follows inside the function's argument is a unary operator followed by another function
454 if (arg_start[0] == '-' || arg_start[0] == '+' || arg_start[0] == '!') {
455 // Move past this operator character
456 arg_start++;
457 skip_spaces(&arg_start);
458
459 // If what follows is a function call, we need special handling
460 if (starts_with_function(arg_start)) {
461 // Go back to normal parsing at the start of function arguments
462 // and use parse_expression which will handle unary operators correctly
463 EVAL_NODE *func_arg = parse_expression(string, error, 1);
464 if (!func_arg) {
465 *error = EVAL_ERROR_MISSING_OPERAND;
466 return NULL;
467 }
468
469 // Skip the closing parenthesis
470 if (!parse_close_subexpression(string)) {
471 *error = EVAL_ERROR_MISSING_CLOSE_SUBEXPRESSION;
472 eval_node_free(func_arg);
473 return NULL;
474 }
475
476 // Create the function node
477 EVAL_NODE *func_node = eval_node_alloc(1);
478 func_node->operator = op_type;
479 func_node->precedence = precedence;
480 eval_node_set_value_to_node(func_node, 0, func_arg);
481
482 return func_node;
483 }
484 }
485
486 // Regular parsing for function arguments
487 EVAL_NODE *func_arg = parse_full_expression(string, error);
488 if (!func_arg) {
489 *error = EVAL_ERROR_MISSING_OPERAND;
490 return NULL;
491 }
492
493 // Skip the closing parenthesis
494 if (!parse_close_subexpression(string)) {
495 *error = EVAL_ERROR_MISSING_CLOSE_SUBEXPRESSION;
496 eval_node_free(func_arg);
497 return NULL;
498 }
499
500 // Create the function node
501 EVAL_NODE *func_node = eval_node_alloc(1);
502 func_node->operator = op_type;
503 func_node->precedence = precedence;
504 eval_node_set_value_to_node(func_node, 0, func_arg);
505
506 return func_node;
507 }
508
509 // Helper function to check if a string starts with a function name
510 static int starts_with_function(const char *s) {
511 for (int i = 0; eval_functions[i].name != NULL; i++) {
512 const char *name = eval_functions[i].name;
513 int len = strlen(name);
514 int j;
515
516 // Case-insensitive comparison of function name
517 for (j = 0; j < len; j++) {
518 if (!s[j] || (tolower((unsigned char)s[j]) != name[j])) {
519 break;
520 }
521 }
522
523 // Check if we matched the entire function name and it's followed by '('
524 if (j == len && s[j] == '(') {
525 return 1;
526 }
527 }
528
529 return 0;
530 }
531
532 // Helper function to avoid allocations all over the place
533 static EVAL_NODE *parse_next_operand_given_its_operator(const char **string, unsigned char operator_type, int *error) {
534 // Save current position to check for function calls
535 const char *current_pos = *string;
536 skip_spaces(&current_pos);
537
538 // Check if what follows is a function call
539 if (starts_with_function(current_pos)) {
540 // This is a function - we need special handling
541
542 // Parse the function call
543 EVAL_NODE *func_node = parse_function_call(&current_pos, error);
544 if (!func_node) {
545 return NULL;
546 }
547
548 // Create the unary operator node
549 EVAL_NODE *op = eval_node_alloc(1);
550 op->operator = operator_type;
551 op->precedence = eval_precedence(operator_type);
552 eval_node_set_value_to_node(op, 0, func_node);
553
554 // Update the string position
555 *string = current_pos;
556
557 return op;
558 }
559
560 // Standard parsing for normal operands
561 EVAL_NODE *sub = parse_one_full_operand(string, error);
562 if(!sub) return NULL;
563
564 EVAL_NODE *op = eval_node_alloc(1);
565 op->operator = operator_type;
566 eval_node_set_value_to_node(op, 0, sub);
567 return op;
568 }
569
570 // parse a full operand, including its sign or other associative operator (e.g. NOT)
571 static EVAL_NODE *parse_one_full_operand(const char **string, int *error) {
572 char variable_buffer[EVAL_MAX_VARIABLE_NAME_LENGTH + 1];
573 EVAL_NODE *op1 = NULL;
574 NETDATA_DOUBLE number;
575
576 *error = EVAL_ERROR_OK;
577
578 skip_spaces(string);
579 if(!(**string)) {
580 *error = EVAL_ERROR_MISSING_OPERAND;
581 return NULL;
582 }
583
584 if(parse_not(string)) {
585 // Check if what follows is a function
586 skip_spaces(string);
587 if (starts_with_function(*string)) {
588 // Special case: !function_call()
589 EVAL_NODE *func_node = parse_function_call(string, error);
590 if (!func_node) return NULL;
591
592 op1 = eval_node_alloc(1);
593 op1->operator = EVAL_OPERATOR_NOT;
594 op1->precedence = eval_precedence(EVAL_OPERATOR_NOT);
595 eval_node_set_value_to_node(op1, 0, func_node);
596 } else {
597 op1 = parse_next_operand_given_its_operator(string, EVAL_OPERATOR_NOT, error);
598 if (op1) op1->precedence = eval_precedence(EVAL_OPERATOR_NOT);
599 }
600 }
601 else if(parse_plus(string)) {
602 // Check if what follows is a function
603 skip_spaces(string);
604 if (starts_with_function(*string)) {
605 // Special case: +function_call()
606 EVAL_NODE *func_node = parse_function_call(string, error);
607 if (!func_node) return NULL;
608
609 op1 = eval_node_alloc(1);
610 op1->operator = EVAL_OPERATOR_SIGN_PLUS;
611 op1->precedence = eval_precedence(EVAL_OPERATOR_SIGN_PLUS);
612 eval_node_set_value_to_node(op1, 0, func_node);
613 } else {
614 op1 = parse_next_operand_given_its_operator(string, EVAL_OPERATOR_SIGN_PLUS, error);
615 if (op1) op1->precedence = eval_precedence(EVAL_OPERATOR_SIGN_PLUS);
616 }
617 }
618 else if(parse_minus(string)) {
619 // Check if what follows is a function
620 skip_spaces(string);
621 if (starts_with_function(*string)) {
622 // Special case: -function_call()
623 EVAL_NODE *func_node = parse_function_call(string, error);
624 if (!func_node) return NULL;
625
626 op1 = eval_node_alloc(1);
627 op1->operator = EVAL_OPERATOR_SIGN_MINUS;
628 op1->precedence = eval_precedence(EVAL_OPERATOR_SIGN_MINUS);
629 eval_node_set_value_to_node(op1, 0, func_node);
630 } else {
631 op1 = parse_next_operand_given_its_operator(string, EVAL_OPERATOR_SIGN_MINUS, error);
632 if (op1) op1->precedence = eval_precedence(EVAL_OPERATOR_SIGN_MINUS);
633 }
634 }
635 else if (starts_with_function(*string)) {
636 // Handle the function call
637 op1 = parse_function_call(string, error);
638 }
639 else if(parse_open_subexpression(string)) {
640 EVAL_NODE *sub = parse_full_expression(string, error);
641 if(sub) {
642 op1 = eval_node_alloc(1);
643 op1->operator = EVAL_OPERATOR_EXPRESSION_OPEN;
644 op1->precedence = eval_precedence(EVAL_OPERATOR_EXPRESSION_OPEN);
645 eval_node_set_value_to_node(op1, 0, sub);
646 if(!parse_close_subexpression(string)) {
647 *error = EVAL_ERROR_MISSING_CLOSE_SUBEXPRESSION;
648 eval_node_free(op1);
649 return NULL;
650 }
651 }
652 }
653 else if(parse_variable(string, variable_buffer, EVAL_MAX_VARIABLE_NAME_LENGTH)) {
654 op1 = eval_node_alloc(1);
655 op1->operator = EVAL_OPERATOR_NOP;
656 eval_node_set_value_to_variable(op1, 0, variable_buffer);
657 }
658 else if(parse_constant(string, &number)) {
659 op1 = eval_node_alloc(1);
660 op1->operator = EVAL_OPERATOR_NOP;
661 eval_node_set_value_to_constant(op1, 0, number);
662 }
663 else if(**string)
664 *error = EVAL_ERROR_UNKNOWN_OPERAND;
665 else
666 *error = EVAL_ERROR_MISSING_OPERAND;
667
668 return op1;
669 }
670
671 // parse an operator and the rest of the expression
672 // precedence processing is handled here
673 static EVAL_NODE *parse_rest_of_expression(const char **string, int *error, EVAL_NODE *op1) {
674 EVAL_NODE *op2 = NULL;
675 unsigned char operator;
676 int precedence;
677
678 operator = parse_operator(string, &precedence);
679 skip_spaces(string);
680
681 if(operator != EVAL_OPERATOR_NOP) {
682 op2 = parse_one_full_operand(string, error);
683 if(!op2) {
684 // error is already reported
685 eval_node_free(op1);
686 return NULL;
687 }
688
689 EVAL_NODE *op = eval_node_alloc(operators[operator].parameters);
690 op->operator = operator;
691 op->precedence = precedence;
692
693 if(operator == EVAL_OPERATOR_IF_THEN_ELSE && op->count == 3) {
694 skip_spaces(string);
695
696 if(**string != ':') {
697 eval_node_free(op);
698 eval_node_free(op1);
699 eval_node_free(op2);
700 *error = EVAL_ERROR_IF_THEN_ELSE_MISSING_ELSE;
701 return NULL;
702 }
703 (*string)++;
704
705 skip_spaces(string);
706
707 // For the else part, we need to handle nested ternary operators
708 // So we use parse_full_expression instead of parse_one_full_operand
709 // This ensures proper parsing of nested ternary operators
710 EVAL_NODE *op3 = parse_full_expression(string, error);
711 if(!op3) {
712 eval_node_free(op);
713 eval_node_free(op1);
714 eval_node_free(op2);
715 // error is already reported
716 return NULL;
717 }
718
719 eval_node_set_value_to_node(op, 2, op3);
720 }
721
722 eval_node_set_value_to_node(op, 1, op2);
723
724 // precedence processing
725 // if this operator has a higher precedence compared to its next
726 // put the next operator on top of us (top = evaluated later)
727 // function recursion does the rest...
728 if(op->precedence > op1->precedence && op1->count == 2 && op1->operator != '(' && op1->ops[1].type == EVAL_VALUE_EXPRESSION) {
729 eval_node_set_value_to_node(op, 0, op1->ops[1].expression);
730 op1->ops[1].expression = op;
731 op = op1;
732 }
733 else
734 eval_node_set_value_to_node(op, 0, op1);
735
736 return parse_rest_of_expression(string, error, op);
737 }
738 else if(**string == ')') {
739 ;
740 }
741 else if(**string) {
742 eval_node_free(op1);
743 op1 = NULL;
744 *error = EVAL_ERROR_MISSING_OPERATOR;
745 }
746
747 return op1;
748 }
749
750 // Parse an expression with optional function support
751 static inline EVAL_NODE *parse_expression(const char **string, int *error, int allow_functions) {
752 // Special handling for functions as arguments
753 if (allow_functions) {
754 const char *s = *string;
755 skip_spaces(&s);
756
757 // Check for unary operators
758 if (s[0] == '-' || s[0] == '+' || s[0] == '!') {
759 unsigned char op_type;
760 if (s[0] == '-') op_type = EVAL_OPERATOR_SIGN_MINUS;
761 else if (s[0] == '+') op_type = EVAL_OPERATOR_SIGN_PLUS;
762 else op_type = EVAL_OPERATOR_NOT;
763
764 // Move past the unary operator
765 s++;
766 skip_spaces(&s);
767
768 // Check if followed by a function
769 if (starts_with_function(s)) {
770 // Update the string position to include the consumed unary operator
771 *string = s;
772
773 // Parse the function
774 EVAL_NODE *func_node = parse_function_call(string, error);
775 if (!func_node) return NULL;
776
777 // Create the unary operator node
778 EVAL_NODE *op = eval_node_alloc(1);
779 op->operator = op_type;
780 op->precedence = eval_precedence(op_type);
781 eval_node_set_value_to_node(op, 0, func_node);
782
783 return op;
784 }
785 }
786 // Check for a direct function call
787 else if (starts_with_function(s)) {
788 *string = s;
789 return parse_function_call(string, error);
790 }
791 }
792
793 // If no special handling needed, fall back to normal parsing
794 return parse_full_expression(string, error);
795 }
796
797 // high level function to parse an expression or a sub-expression
798 static inline EVAL_NODE *parse_full_expression(const char **string, int *error) {
799 EVAL_NODE *op1 = parse_one_full_operand(string, error);
800 if(!op1) {
801 *error = EVAL_ERROR_MISSING_OPERAND;
802 return NULL;
803 }
804
805 return parse_rest_of_expression(string, error, op1);
806 }
807
808 // ----------------------------------------------------------------------------
809 // public API for parsing
810
811 EVAL_EXPRESSION *expression_parse(const char *string, const char **failed_at, int *error) {
812 if(!string || !*string)
813 return NULL;
814
815 const char *s = string;
816 int err = EVAL_ERROR_OK;
817 EVAL_NODE *op = NULL;
818
819 #ifdef USE_RE2C_LEMON_PARSER
820 // Use the re2c/lemon parser
821 op = parse_expression_with_re2c_lemon(string, &s, &err);
822 #else
823 // Use the original recursive descent parser
824
825 // First, let's check if the expression starts with a function
826 skip_spaces(&s);
827
828 // Check if the expression starts with a unary op followed by function
829 // Removed condition that was too restrictive - we want to handle any unary operator
830 // followed by a function, not just when there's whitespace after the operator
831 if (s[0] == '-' || s[0] == '+' || s[0] == '!') {
832
833 const char *after_op = s + 1;
834 skip_spaces(&after_op);
835
836 if (starts_with_function(after_op)) {
837 // This is a special case like "-abs(...)" - use our special parser
838 s = string; // Reset to beginning
839 op = parse_expression(&s, &err, 1);
840 }
841 }
842
843 // If we haven't parsed it with the special function, use regular parsing
844 if (!op) {
845 s = string; // Reset to beginning
846 op = parse_full_expression(&s, &err);
847 }
848 #endif
849
850 if(s && *s) {
851 if(op) {
852 eval_node_free(op);
853 op = NULL;
854 }
855 err = EVAL_ERROR_REMAINING_GARBAGE;
856 }
857
858 if (failed_at) *failed_at = s;
859 if (error) *error = err;
860
861 if(!op) {
862 unsigned long pos = s - string + 1;
863 netdata_log_error("failed to parse expression '%s': %s at character %lu (i.e.: '%s').", string, expression_strerror(err), pos, s);
864 return NULL;
865 }
866
867 BUFFER *out = buffer_create(1024, NULL);
868 print_parsed_as_node(out, op, &err);
869 if(err != EVAL_ERROR_OK) {
870 netdata_log_error("failed to re-generate expression '%s' with reason: %s", string, expression_strerror(err));
871 eval_node_free(op);
872 buffer_free(out);
873 return NULL;
874 }
875
876 EVAL_EXPRESSION *exp = callocz(1, sizeof(EVAL_EXPRESSION));
877
878 exp->source = string_strdupz(string);
879 exp->parsed_as = string_strdupz(buffer_tostring(out));
880 buffer_free(out);
881
882 exp->error_msg = buffer_create(100, NULL);
883 exp->nodes = op;
884
885 return exp;
886 }