@cryptotaxi247 / netdata-1 / commits / ac6925def

expression parser now re-generates the expression showing the precedence it applied to it; more code cleanups

Costa Tsaousis committed Aug 11, 2016 at 14:28 UTC ac6925def2988f29fd21c8226e4b435bc0f34b62
7 files changed +435 -240
profile/test-eval.c
+22 -5
@@ -3,7 +3,7 @@
3 * 1. build netdata (as normally)
4 * 2. cd profile/
5 * 3. compile with:
6 - * gcc -O1 -ggdb -Wall -Wextra -I ../src/ -I ../ -o test-eval test-eval.c ../src/log.o ../src/eval.o ../src/common.o -pthread
6 + * gcc -O1 -ggdb -Wall -Wextra -I ../src/ -I ../ -o test-eval test-eval.c ../src/log.o ../src/eval.o ../src/common.o ../src/web_buffer.o ../src/storage_number.o -pthread -lm
7 *
8 */
9
@@ -11,6 +11,7 @@
11
12 void netdata_cleanup_and_exit(int ret) { exit(ret); }
13
14 +/*
15 void indent(int level, int show) {
16 int i = level;
17 while(i--) printf(" | ");
@@ -237,6 +238,7 @@ calculated_number evaluate(EVAL_NODE *op, int depth) {
238 return r;
239 }
240
241 +
242 void print_expression(EVAL_NODE *op, const char *failed_at, int error) {
243 if(op) {
244 printf("expression tree:\n");
@@ -255,17 +257,32 @@ void print_expression(EVAL_NODE *op, const char *failed_at, int error) {
257 printf("error: %d, failed_at: '%s'\n", error, (failed_at)?failed_at:"<NONE>");
258 }
259 }
258 -
260 +*/
261
262 int main(int argc, char **argv) {
263 if(argc != 2) {
262 - fprintf(stderr, "I need an epxression\n");
264 + fprintf(stderr, "I need an epxression (enclose it in single-quotes (') as a single parameter)\n");
265 exit(1);
266 }
267
268 const char *failed_at = NULL;
269 int error;
268 - EVAL_NODE *op = expression_parse(argv[1], &failed_at, &error);
269 - print_expression(op, failed_at, error);
270 +
271 + EVAL_EXPRESSION *exp = expression_parse(argv[1], &failed_at, &error);
272 + if(!exp)
273 + printf("\nFAILED\nExpression: '%s'\nParsing stopped at: '%s'\nError code: %d (%s)\n", argv[1], (failed_at)?failed_at:"<NONE>", error, expression_strerror(error));
274 +
275 + else {
276 + printf("\nOK\nExpression: '%s'\nParsed as : '%s'\nError code: %d (%s)\n", argv[1], exp->parsed_as, error, expression_strerror(error));
277 +
278 + if(expression_evaluate(exp)) {
279 + printf("\nEvaluates to: %Lf\n\n", exp->result);
280 + }
281 + else {
282 + printf("\nEvaluation failed with code %d and message: %s\n\n", exp->error, buffer_tostring(exp->error_msg));
283 + }
284 + expression_free(exp);
285 + }
286 +
287 return 0;
288 }
src/eval.c
+376 -186
@@ -1,30 +1,310 @@
1 #include "common.h"
2
3 -// forward definitions
3 +// ----------------------------------------------------------------------------
4 +// data structures for storing the parsed expression in memory
5 +
6 +typedef struct eval_value {
7 + int type;
8 +
9 + union {
10 + calculated_number number;
11 + EVAL_VARIABLE *variable;
12 + struct eval_node *expression;
13 + };
14 +} EVAL_VALUE;
15 +
16 +typedef struct eval_node {
17 + int id;
18 + unsigned char operator;
19 + int precedence;
20 +
21 + int count;
22 + EVAL_VALUE ops[];
23 +} EVAL_NODE;
24 +
25 +// these are used for EVAL_NODE.operator
26 +// they are used as internal IDs to identify an operator
27 +// THEY ARE NOT USED FOR PARSING OPERATORS LIKE THAT
28 +#define EVAL_OPERATOR_NOP '\0'
29 +#define EVAL_OPERATOR_VALUE ':'
30 +#define EVAL_OPERATOR_EXPRESSION_OPEN '('
31 +#define EVAL_OPERATOR_EXPRESSION_CLOSE ')'
32 +#define EVAL_OPERATOR_NOT '!'
33 +#define EVAL_OPERATOR_PLUS '+'
34 +#define EVAL_OPERATOR_MINUS '-'
35 +#define EVAL_OPERATOR_AND '&'
36 +#define EVAL_OPERATOR_OR '|'
37 +#define EVAL_OPERATOR_GREATER_THAN_OR_EQUAL 'G'
38 +#define EVAL_OPERATOR_LESS_THAN_OR_EQUAL 'L'
39 +#define EVAL_OPERATOR_NOT_EQUAL '~'
40 +#define EVAL_OPERATOR_EQUAL '='
41 +#define EVAL_OPERATOR_LESS '<'
42 +#define EVAL_OPERATOR_GREATER '>'
43 +#define EVAL_OPERATOR_MULTIPLY '*'
44 +#define EVAL_OPERATOR_DIVIDE '/'
45 +#define EVAL_OPERATOR_SIGN_PLUS 'P'
46 +#define EVAL_OPERATOR_SIGN_MINUS 'M'
47 +
48 +// ----------------------------------------------------------------------------
49 +// forward function definitions
50 +
51 static inline void eval_node_free(EVAL_NODE *op);
52 static inline EVAL_NODE *parse_full_expression(const char **string, int *error);
53 static inline EVAL_NODE *parse_one_full_operand(const char **string, int *error);
7 -static inline calculated_number eval_node(EVAL_NODE *op, int *error);
54 +static inline calculated_number eval_node(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error);
55 +static inline void print_parsed_as_node(BUFFER *out, EVAL_NODE *op, int *error);
56 +
57 +// ----------------------------------------------------------------------------
58 +// evaluation of expressions
59 +
60 +static inline calculated_number eval_check_number(calculated_number n, int *error) {
61 + if(unlikely(isnan(n))) {
62 + *error = EVAL_ERROR_VALUE_IS_NAN;
63 + return 0;
64 + }
65 +
66 + if(unlikely(isinf(n))) {
67 + *error = EVAL_ERROR_VALUE_IS_INFINITE;
68 + return 0;
69 + }
70 +
71 + return n;
72 +}
73 +
74 +static inline calculated_number eval_variable(EVAL_EXPRESSION *exp, EVAL_VARIABLE *v, int *error) {
75 + // FIXME: do the variable look up here
76 +
77 +// if(!exp->data) {
78 + *error = EVAL_ERROR_UNKNOWN_VARIABLE;
79 + buffer_sprintf(exp->error_msg, "unknown variable '%s'", v->name);
80 +// }
81 +
82 + return 0;
83 +}
84 +
85 +static inline calculated_number eval_value(EVAL_EXPRESSION *exp, EVAL_VALUE *v, int *error) {
86 + calculated_number n;
87 +
88 + switch(v->type) {
89 + case EVAL_VALUE_EXPRESSION:
90 + n = eval_node(exp, v->expression, error);
91 + break;
92
93 + case EVAL_VALUE_NUMBER:
94 + n = v->number;
95 + break;
96 +
97 + case EVAL_VALUE_VARIABLE:
98 + n = eval_variable(exp, v->variable, error);
99 + break;
100 +
101 + default:
102 + *error = EVAL_ERROR_INVALID_VALUE;
103 + n = 0;
104 + break;
105 + }
106 +
107 + return eval_check_number(n, error);
108 +}
109 +
110 +calculated_number eval_and(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
111 + return eval_value(exp, &op->ops[0], error) && eval_value(exp, &op->ops[1], error);
112 +}
113 +calculated_number eval_or(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
114 + return eval_value(exp, &op->ops[0], error) || eval_value(exp, &op->ops[1], error);
115 +}
116 +calculated_number eval_greater_than_or_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
117 + return eval_value(exp, &op->ops[0], error) >= eval_value(exp, &op->ops[1], error);
118 +}
119 +calculated_number eval_less_than_or_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
120 + return eval_value(exp, &op->ops[0], error) <= eval_value(exp, &op->ops[1], error);
121 +}
122 +calculated_number eval_not_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
123 + return eval_value(exp, &op->ops[0], error) != eval_value(exp, &op->ops[1], error);
124 +}
125 +calculated_number eval_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
126 + return eval_value(exp, &op->ops[0], error) == eval_value(exp, &op->ops[1], error);
127 +}
128 +calculated_number eval_less(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
129 + return eval_value(exp, &op->ops[0], error) < eval_value(exp, &op->ops[1], error);
130 +}
131 +calculated_number eval_greater(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
132 + return eval_value(exp, &op->ops[0], error) > eval_value(exp, &op->ops[1], error);
133 +}
134 +calculated_number eval_plus(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
135 + return eval_value(exp, &op->ops[0], error) + eval_value(exp, &op->ops[1], error);
136 +}
137 +calculated_number eval_minus(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
138 + return eval_value(exp, &op->ops[0], error) - eval_value(exp, &op->ops[1], error);
139 +}
140 +calculated_number eval_multiply(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
141 + return eval_value(exp, &op->ops[0], error) * eval_value(exp, &op->ops[1], error);
142 +}
143 +calculated_number eval_divide(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
144 + return eval_value(exp, &op->ops[0], error) / eval_value(exp, &op->ops[1], error);
145 +}
146 +calculated_number eval_nop(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
147 + return eval_value(exp, &op->ops[0], error);
148 +}
149 +calculated_number eval_not(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
150 + return !eval_value(exp, &op->ops[0], error);
151 +}
152 +calculated_number eval_sign_plus(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
153 + return eval_value(exp, &op->ops[0], error);
154 +}
155 +calculated_number eval_sign_minus(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
156 + return -eval_value(exp, &op->ops[0], error);
157 +}
158 +
159 +static struct operator {
160 + const char *print_as;
161 + char precedence;
162 + char parameters;
163 + calculated_number (*eval)(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error);
164 +} operators[256] = {
165 + // this is a random access array
166 + // we always access it with a known EVAL_OPERATOR_X
167 +
168 + [EVAL_OPERATOR_AND] = { "&&", 2, 2, eval_and },
169 + [EVAL_OPERATOR_OR] = { "||", 2, 2, eval_or },
170 + [EVAL_OPERATOR_GREATER_THAN_OR_EQUAL] = { ">=", 3, 2, eval_greater_than_or_equal },
171 + [EVAL_OPERATOR_LESS_THAN_OR_EQUAL] = { "<=", 3, 2, eval_less_than_or_equal },
172 + [EVAL_OPERATOR_NOT_EQUAL] = { "!=", 3, 2, eval_not_equal },
173 + [EVAL_OPERATOR_EQUAL] = { "==", 3, 2, eval_equal },
174 + [EVAL_OPERATOR_LESS] = { "<", 3, 2, eval_less },
175 + [EVAL_OPERATOR_GREATER] = { ">", 3, 2, eval_greater },
176 + [EVAL_OPERATOR_PLUS] = { "+", 4, 2, eval_plus },
177 + [EVAL_OPERATOR_MINUS] = { "-", 4, 2, eval_minus },
178 + [EVAL_OPERATOR_MULTIPLY] = { "*", 5, 2, eval_multiply },
179 + [EVAL_OPERATOR_DIVIDE] = { "/", 5, 2, eval_divide },
180 + [EVAL_OPERATOR_NOT] = { "!", 6, 1, eval_not },
181 + [EVAL_OPERATOR_SIGN_PLUS] = { "+", 6, 1, eval_sign_plus },
182 + [EVAL_OPERATOR_SIGN_MINUS] = { "-", 6, 1, eval_sign_minus },
183 + [EVAL_OPERATOR_NOP] = { NULL, 7, 1, eval_nop },
184 + [EVAL_OPERATOR_VALUE] = { NULL, 7, 1, eval_nop },
185 + [EVAL_OPERATOR_EXPRESSION_OPEN] = { NULL, 7, 1, eval_nop },
186 +
187 + // this should exist in our evaluation list
188 + [EVAL_OPERATOR_EXPRESSION_CLOSE] = { NULL, 7, 1, eval_nop }
189 +};
190 +
191 +#define eval_precedence(operator) (operators[(unsigned char)(operator)].precedence)
192 +
193 +static inline calculated_number eval_node(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
194 + if(unlikely(op->count != operators[op->operator].parameters)) {
195 + *error = EVAL_ERROR_INVALID_NUMBER_OF_OPERANDS;
196 + return 0;
197 + }
198 +
199 + calculated_number n = operators[op->operator].eval(exp, op, error);
200 +
201 + return eval_check_number(n, error);
202 +}
203 +
204 +// ----------------------------------------------------------------------------
205 +// parsed-as generation
206 +
207 +static inline void print_parsed_as_variable(BUFFER *out, EVAL_VARIABLE *v, int *error) {
208 + (void)error;
209 + buffer_sprintf(out, "$%s", v->name);
210 +}
211 +
212 +static inline void print_parsed_as_constant(BUFFER *out, calculated_number n) {
213 + char b[100+1], *s;
214 + snprintfz(b, 100, CALCULATED_NUMBER_FORMAT, n);
215 +
216 + s = &b[strlen(b) - 1];
217 + while(s > b && *s == '0') {
218 + *s ='\0';
219 + s--;
220 + }
221 +
222 + if(s > b && *s == '.')
223 + *s = '\0';
224 +
225 + buffer_strcat(out, b);
226 +}
227 +
228 +static inline void print_parsed_as_value(BUFFER *out, EVAL_VALUE *v, int *error) {
229 + switch(v->type) {
230 + case EVAL_VALUE_EXPRESSION:
231 + print_parsed_as_node(out, v->expression, error);
232 + break;
233 +
234 + case EVAL_VALUE_NUMBER:
235 + print_parsed_as_constant(out, v->number);
236 + break;
237 +
238 + case EVAL_VALUE_VARIABLE:
239 + print_parsed_as_variable(out, v->variable, error);
240 + break;
241 +
242 + default:
243 + *error = EVAL_ERROR_INVALID_VALUE;
244 + break;
245 + }
246 +}
247 +
248 +static inline void print_parsed_as_node(BUFFER *out, EVAL_NODE *op, int *error) {
249 + if(unlikely(op->count != operators[op->operator].parameters)) {
250 + *error = EVAL_ERROR_INVALID_NUMBER_OF_OPERANDS;
251 + return;
252 + }
253 +
254 + if(operators[op->operator].parameters == 1) {
255 +
256 + if(operators[op->operator].print_as)
257 + buffer_sprintf(out, "%s", operators[op->operator].print_as);
258 +
259 + //if(op->operator == EVAL_OPERATOR_EXPRESSION_OPEN)
260 + // buffer_strcat(out, "(");
261 +
262 + print_parsed_as_value(out, &op->ops[0], error);
263 +
264 + //if(op->operator == EVAL_OPERATOR_EXPRESSION_OPEN)
265 + // buffer_strcat(out, ")");
266 + }
267 +
268 + else if(operators[op->operator].parameters == 2) {
269 + buffer_strcat(out, "(");
270 + print_parsed_as_value(out, &op->ops[0], error);
271 +
272 + if(operators[op->operator].print_as)
273 + buffer_sprintf(out, " %s ", operators[op->operator].print_as);
274 +
275 + print_parsed_as_value(out, &op->ops[1], error);
276 + buffer_strcat(out, ")");
277 + }
278 +}
279 +
280 +// ----------------------------------------------------------------------------
281 +// parsing expressions
282 +
283 +// skip spaces
284 static inline void skip_spaces(const char **string) {
285 const char *s = *string;
286 while(isspace(*s)) s++;
287 *string = s;
288 }
289
15 -// ----------------------------------------------------------------------------
16 -// operators that work on 2 operands
17 -
290 +// what character can appear just after an operator keyword
291 +// like NOT AND OR ?
292 static inline int isoperatorterm_word(const char s) {
19 - if(isspace(s) || s == '(' || s == '$' || s == '!' || s == '-' || s == '+' || isdigit(s)) return 1;
293 + if(isspace(s) || s == '(' || s == '$' || s == '!' || s == '-' || s == '+' || isdigit(s) || !s)
294 + return 1;
295 +
296 return 0;
297 }
298
299 +// what character can appear just after an operator symbol?
300 static inline int isoperatorterm_symbol(const char s) {
301 if(isoperatorterm_word(s) || isalpha(s)) return 1;
302 return 0;
303 }
304
305 +// ----------------------------------------------------------------------------
306 +// parse operators
307 +
308 static inline int parse_and(const char **string) {
309 const char *s = *string;
310
@@ -144,6 +424,23 @@ static inline int parse_not_equal(const char **string) {
424 return 0;
425 }
426
427 +static inline int parse_not(const char **string) {
428 + const char *s = *string;
429 +
430 + // NOT
431 + if((s[0] == 'N' || s[0] == 'n') && (s[1] == 'O' || s[1] == 'o') && (s[2] == 'T' || s[2] == 't') && isoperatorterm_word(s[3])) {
432 + *string = &s[3];
433 + return 1;
434 + }
435 +
436 + if(s[0] == '!') {
437 + *string = &s[1];
438 + return 1;
439 + }
440 +
441 + return 0;
442 +}
443 +
444 static inline int parse_multiply(const char **string) {
445 const char *s = *string;
446
@@ -228,26 +525,6 @@ static inline int parse_constant(const char **string, calculated_number *number)
525 return 1;
526 }
527
231 -// ----------------------------------------------------------------------------
232 -// operators that affect a single operand
233 -
234 -static inline int parse_not(const char **string) {
235 - const char *s = *string;
236 -
237 - // NOT
238 - if((s[0] == 'N' || s[0] == 'n') && (s[1] == 'O' || s[1] == 'o') && (s[2] == 'T' || s[2] == 't') && isoperatorterm_word(s[3])) {
239 - *string = &s[3];
240 - return 1;
241 - }
242 -
243 - if(s[0] == EVAL_OPERATOR_NOT) {
244 - *string = &s[1];
245 - return 1;
246 - }
247 -
248 - return 0;
249 -}
250 -
528 static struct operator_parser {
529 unsigned char id;
530 int (*parse)(const char **);
@@ -279,146 +556,10 @@ static struct operator_parser {
556 * these are handled in code
557 */
558
559 + // termination
560 { EVAL_OPERATOR_NOP, NULL }
561 };
562
285 -// ----------------------------------------------------------------------------
286 -// evaluation of operations
287 -
288 -static inline calculated_number eval_check_number(calculated_number n, int *error) {
289 - if(unlikely(isnan(n))) {
290 - *error = EVAL_ERROR_VALUE_IS_NAN;
291 - return 0;
292 - }
293 -
294 - if(unlikely(isinf(n))) {
295 - *error = EVAL_ERROR_VALUE_IS_INFINITE;
296 - return 0;
297 - }
298 -
299 - return n;
300 -}
301 -
302 -static inline calculated_number eval_value(EVAL_VALUE *v, int *error) {
303 - calculated_number n;
304 -
305 - switch(v->type) {
306 - case EVAL_VALUE_EXPRESSION:
307 - n = eval_node(v->expression, error);
308 - break;
309 -
310 - case EVAL_VALUE_NUMBER:
311 - n = v->number;
312 - break;
313 -
314 -// case EVAL_VALUE_VARIABLE:
315 -// break;
316 -
317 - default:
318 - *error = EVAL_ERROR_INVALID_VALUE;
319 - n = 0;
320 - break;
321 - }
322 -
323 - return eval_check_number(n, error);
324 -}
325 -
326 -calculated_number eval_and(EVAL_NODE *op, int *error) {
327 - return eval_value(&op->ops[0], error) && eval_value(&op->ops[1], error);
328 -}
329 -calculated_number eval_or(EVAL_NODE *op, int *error) {
330 - return eval_value(&op->ops[0], error) || eval_value(&op->ops[1], error);
331 -}
332 -calculated_number eval_greater_than_or_equal(EVAL_NODE *op, int *error) {
333 - return eval_value(&op->ops[0], error) >= eval_value(&op->ops[1], error);
334 -}
335 -calculated_number eval_less_than_or_equal(EVAL_NODE *op, int *error) {
336 - return eval_value(&op->ops[0], error) <= eval_value(&op->ops[1], error);
337 -}
338 -calculated_number eval_not_equal(EVAL_NODE *op, int *error) {
339 - return eval_value(&op->ops[0], error) != eval_value(&op->ops[1], error);
340 -}
341 -calculated_number eval_equal(EVAL_NODE *op, int *error) {
342 - return eval_value(&op->ops[0], error) == eval_value(&op->ops[1], error);
343 -}
344 -calculated_number eval_less(EVAL_NODE *op, int *error) {
345 - return eval_value(&op->ops[0], error) < eval_value(&op->ops[1], error);
346 -}
347 -calculated_number eval_greater(EVAL_NODE *op, int *error) {
348 - return eval_value(&op->ops[0], error) > eval_value(&op->ops[1], error);
349 -}
350 -calculated_number eval_plus(EVAL_NODE *op, int *error) {
351 - return eval_value(&op->ops[0], error) + eval_value(&op->ops[1], error);
352 -}
353 -calculated_number eval_minus(EVAL_NODE *op, int *error) {
354 - return eval_value(&op->ops[0], error) - eval_value(&op->ops[1], error);
355 -}
356 -calculated_number eval_multiply(EVAL_NODE *op, int *error) {
357 - return eval_value(&op->ops[0], error) * eval_value(&op->ops[1], error);
358 -}
359 -calculated_number eval_divide(EVAL_NODE *op, int *error) {
360 - return eval_value(&op->ops[0], error) / eval_value(&op->ops[1], error);
361 -}
362 -calculated_number eval_nop(EVAL_NODE *op, int *error) {
363 - return eval_value(&op->ops[0], error);
364 -}
365 -calculated_number eval_not(EVAL_NODE *op, int *error) {
366 - return !eval_value(&op->ops[0], error);
367 -}
368 -calculated_number eval_sign_plus(EVAL_NODE *op, int *error) {
369 - return eval_value(&op->ops[0], error);
370 -}
371 -calculated_number eval_sign_minus(EVAL_NODE *op, int *error) {
372 - return -eval_value(&op->ops[0], error);
373 -}
374 -
375 -static struct operator {
376 - const char *print_as;
377 - char precedence;
378 - char parameters;
379 - calculated_number (*eval)(EVAL_NODE *op, int *error);
380 -} operators[256] = {
381 - // this is a random access array
382 - // we always access it with a known EVAL_OPERATOR_X
383 -
384 - [EVAL_OPERATOR_AND] = { "&&", 2, 2, eval_and },
385 - [EVAL_OPERATOR_OR] = { "||", 2, 2, eval_or },
386 - [EVAL_OPERATOR_GREATER_THAN_OR_EQUAL] = { ">=", 3, 2, eval_greater_than_or_equal },
387 - [EVAL_OPERATOR_LESS_THAN_OR_EQUAL] = { "<=", 3, 2, eval_less_than_or_equal },
388 - [EVAL_OPERATOR_NOT_EQUAL] = { "!=", 3, 2, eval_not_equal },
389 - [EVAL_OPERATOR_EQUAL] = { "==", 3, 2, eval_equal },
390 - [EVAL_OPERATOR_LESS] = { "<", 3, 2, eval_less },
391 - [EVAL_OPERATOR_GREATER] = { ">", 3, 2, eval_greater },
392 - [EVAL_OPERATOR_PLUS] = { "+", 4, 2, eval_plus },
393 - [EVAL_OPERATOR_MINUS] = { "-", 4, 2, eval_minus },
394 - [EVAL_OPERATOR_MULTIPLY] = { "*", 5, 2, eval_multiply },
395 - [EVAL_OPERATOR_DIVIDE] = { "/", 5, 2, eval_divide },
396 - [EVAL_OPERATOR_NOT] = { "!", 6, 1, eval_not },
397 - [EVAL_OPERATOR_SIGN_PLUS] = { "+", 6, 1, eval_sign_plus },
398 - [EVAL_OPERATOR_SIGN_MINUS] = { "-", 6, 1, eval_sign_minus },
399 - [EVAL_OPERATOR_NOP] = { NULL, 7, 1, eval_nop },
400 - [EVAL_OPERATOR_VALUE] = { NULL, 7, 1, eval_nop },
401 - [EVAL_OPERATOR_EXPRESSION_OPEN] = { "(", 7, 1, eval_nop },
402 -
403 - // this should exist in our evaluation list
404 - [EVAL_OPERATOR_EXPRESSION_CLOSE] = { ")", 7, 1, eval_nop }
405 -};
406 -
407 -#define eval_precedence(operator) (operators[(unsigned char)(operator)].precedence)
408 -
409 -static inline calculated_number eval_node(EVAL_NODE *op, int *error) {
410 - if(unlikely(op->count != operators[op->operator].parameters)) {
411 - *error = EVAL_ERROR_INVALID_NUMBER_OF_OPERANDS;
412 - return 0;
413 - }
414 -
415 - calculated_number n = operators[op->operator].eval(op, error);
416 -
417 - return eval_check_number(n, error);
418 -}
419 -
420 -// ----------------------------------------------------------------------------
421 -
563 static inline unsigned char parse_operator(const char **string, int *precedence) {
564 skip_spaces(string);
565
@@ -432,6 +573,9 @@ static inline unsigned char parse_operator(const char **string, int *precedence)
573 return EVAL_OPERATOR_NOP;
574 }
575
576 +// ----------------------------------------------------------------------------
577 +// memory management
578 +
579 static inline EVAL_NODE *eval_node_alloc(int count) {
580 static int id = 1;
581
@@ -453,7 +597,7 @@ static inline void eval_node_set_value_to_node(EVAL_NODE *op, int pos, EVAL_NODE
597 op->ops[pos].expression = value;
598 }
599
456 -static inline void node_set_value_to_constant(EVAL_NODE *op, int pos, calculated_number value) {
600 +static inline void eval_node_set_value_to_constant(EVAL_NODE *op, int pos, calculated_number value) {
601 if(pos >= op->count)
602 fatal("Invalid request to set position %d of OPERAND that has only %d values", pos + 1, op->count + 1);
603
@@ -461,19 +605,19 @@ static inline void node_set_value_to_constant(EVAL_NODE *op, int pos, calculated
605 op->ops[pos].number = value;
606 }
607
464 -static inline void variable_free(VARIABLE *v) {
608 +static inline void eval_variable_free(EVAL_VARIABLE *v) {
609 free(v);
610 }
611
468 -static inline void value_free(EVAL_VALUE *v) {
612 +static inline void eval_value_free(EVAL_VALUE *v) {
613 switch(v->type) {
614 case EVAL_VALUE_EXPRESSION:
615 eval_node_free(v->expression);
616 break;
617
474 -// case EVAL_VALUE_VARIABLE:
475 -// variable_free(v->variable);
476 -// break;
618 + case EVAL_VALUE_VARIABLE:
619 + eval_variable_free(v->variable);
620 + break;
621
622 default:
623 break;
@@ -484,12 +628,16 @@ static inline void eval_node_free(EVAL_NODE *op) {
628 if(op->count) {
629 int i;
630 for(i = op->count - 1; i >= 0 ;i--)
487 - value_free(&op->ops[i]);
631 + eval_value_free(&op->ops[i]);
632 }
633
634 free(op);
635 }
636
637 +// ----------------------------------------------------------------------------
638 +// the parsing logic
639 +
640 +// helper function to avoid allocations all over the place
641 static inline EVAL_NODE *parse_next_operand_given_its_operator(const char **string, unsigned char operator_type, int *error) {
642 EVAL_NODE *sub = parse_one_full_operand(string, error);
643 if(!sub) return NULL;
@@ -500,6 +648,7 @@ static inline EVAL_NODE *parse_next_operand_given_its_operator(const char **stri
648 return op;
649 }
650
651 +// parse a full operand, including its sign or other associative operator (e.g. NOT)
652 static inline EVAL_NODE *parse_one_full_operand(const char **string, int *error) {
653 EVAL_NODE *op1 = NULL;
654 calculated_number number;
@@ -544,7 +693,7 @@ static inline EVAL_NODE *parse_one_full_operand(const char **string, int *error)
693 else if(parse_constant(string, &number)) {
694 op1 = eval_node_alloc(1);
695 op1->operator = EVAL_OPERATOR_VALUE;
547 - node_set_value_to_constant(op1, 0, number);
696 + eval_node_set_value_to_constant(op1, 0, number);
697 }
698 else if(*string)
699 *error = EVAL_ERROR_UNKNOWN_OPERAND;
@@ -554,6 +703,8 @@ static inline EVAL_NODE *parse_one_full_operand(const char **string, int *error)
703 return op1;
704 }
705
706 +// parse an operator and the rest of the expression
707 +// precedence processing is handled here
708 static inline EVAL_NODE *parse_rest_of_expression(const char **string, int *error, EVAL_NODE *op1) {
709 EVAL_NODE *op2 = NULL;
710 unsigned char operator;
@@ -574,14 +725,19 @@ static inline EVAL_NODE *parse_rest_of_expression(const char **string, int *erro
725 op->operator = operator;
726 op->precedence = precedence;
727
577 - eval_node_set_value_to_node(op, 0, op1);
728 eval_node_set_value_to_node(op, 1, op2);
729
730 + // precedence processing
731 + // if this operator has a higher precedence compared to its next
732 + // put the next operator on top of us (top = evaluated later)
733 + // function recursion does the rest...
734 if(op->precedence > op1->precedence && op1->count == 2 && op1->operator != '(' && op1->ops[1].type == EVAL_VALUE_EXPRESSION) {
735 eval_node_set_value_to_node(op, 0, op1->ops[1].expression);
736 op1->ops[1].expression = op;
737 op = op1;
738 }
739 + else
740 + eval_node_set_value_to_node(op, 0, op1);
741
742 return parse_rest_of_expression(string, error, op);
743 }
@@ -597,6 +753,7 @@ static inline EVAL_NODE *parse_rest_of_expression(const char **string, int *erro
753 return op1;
754 }
755
756 +// high level function to parse an expression or a sub-expression
757 static inline EVAL_NODE *parse_full_expression(const char **string, int *error) {
758 EVAL_NODE *op1 = NULL;
759
@@ -612,7 +769,24 @@ static inline EVAL_NODE *parse_full_expression(const char **string, int *error)
769 // ----------------------------------------------------------------------------
770 // public API
771
615 -EVAL_NODE *expression_parse(const char *string, const char **failed_at, int *error) {
772 +int expression_evaluate(EVAL_EXPRESSION *exp) {
773 + exp->error = EVAL_ERROR_OK;
774 +
775 + buffer_reset(exp->error_msg);
776 + exp->result = eval_node(exp, (EVAL_NODE *)exp->nodes, &exp->error);
777 +
778 + if(exp->error != EVAL_ERROR_OK) {
779 + if(buffer_strlen(exp->error_msg))
780 + buffer_strcat(exp->error_msg, "; ");
781 +
782 + buffer_sprintf(exp->error_msg, "failed to evaluate expression with error %d (%s)", exp->error, expression_strerror(exp->error));
783 + return 0;
784 + }
785 +
786 + return 1;
787 +}
788 +
789 +EVAL_EXPRESSION *expression_parse(const char *string, const char **failed_at, int *error) {
790 const char *s;
791 int err = EVAL_ERROR_OK;
792 unsigned long pos = 0;
@@ -626,26 +800,39 @@ EVAL_NODE *expression_parse(const char *string, const char **failed_at, int *err
800 if(!op) {
801 pos = s - string + 1;
802 error("failed to parse expression '%s': %s at character %lu (i.e.: '%s').", string, expression_strerror(err), pos, s);
803 + return NULL;
804 }
805
631 - return op;
632 -}
633 -
634 -calculated_number expression_evaluate(EVAL_NODE *expression, int *error) {
635 - int err = EVAL_ERROR_OK;
636 - calculated_number ret = eval_node(expression, &err);
637 -
806 + BUFFER *out = buffer_create(1024);
807 + print_parsed_as_node(out, op, &err);
808 if(err != EVAL_ERROR_OK) {
639 - error("Failed to execute expression with error %d (%s)", err, expression_strerror(err));
640 - if(error) *error = err;
641 - return 0;
809 + error("failed to re-generate expression '%s' with reason: %s", string, expression_strerror(err));
810 + eval_node_free(op);
811 + buffer_free(out);
812 + return NULL;
813 }
814
644 - return ret;
815 + EVAL_EXPRESSION *exp = calloc(1, sizeof(EVAL_EXPRESSION));
816 + if(!exp) fatal("Cannot allocate EVAL_EXPRESSION");
817 +
818 + exp->parsed_as = strdup(buffer_tostring(out));
819 + if(!exp->parsed_as) fatal("Cannot allocate memory for parsed-as string");
820 + buffer_free(out);
821 +
822 + exp->error_msg = buffer_create(100);
823 + exp->nodes = (void *)op;
824 +
825 + return exp;
826 }
827
647 -void expression_free(EVAL_NODE *op) {
648 - if(op) eval_node_free(op);
828 +void expression_free(EVAL_EXPRESSION *exp) {
829 + if(!exp) return;
830 +
831 + if(exp->nodes) eval_node_free((EVAL_NODE *)exp->nodes);
832 + free((void *)exp->source);
833 + free((void *)exp->parsed_as);
834 + buffer_free(exp->error_msg);
835 + free(exp);
836 }
837
838 const char *expression_strerror(int error) {
@@ -677,6 +864,9 @@ const char *expression_strerror(int error) {
864 case EVAL_ERROR_VALUE_IS_INFINITE:
865 return "computed value is infinite";
866
867 + case EVAL_ERROR_UNKNOWN_VARIABLE:
868 + return "undefined variable";
869 +
870 default:
871 return "unknown error";
872 }
src/eval.h
+32 -44
@@ -1,38 +1,33 @@
1 #ifndef NETDATA_EVAL_H
2 #define NETDATA_EVAL_H
3
4 -typedef struct variable {
4 +typedef struct eval_variable {
5 char *name;
6 struct rrdvar *rrdvar;
7 - struct variable *next;
8 -} VARIABLE;
7 + struct eval_variable *next;
8 +} EVAL_VARIABLE;
9 +
10 +typedef struct eval_expression {
11 + const char *source;
12 + const char *parsed_as;
13 +
14 + calculated_number result;
15 +
16 + int error;
17 + BUFFER *error_msg;
18 +
19 + // hidden EVAL_NODE *
20 + void *nodes;
21 +
22 + // custom data to be used for looking up variables
23 + void *data;
24 +} EVAL_EXPRESSION;
25
26 #define EVAL_VALUE_INVALID 0
27 #define EVAL_VALUE_NUMBER 1
28 #define EVAL_VALUE_VARIABLE 2
29 #define EVAL_VALUE_EXPRESSION 3
30
15 -// these are used for EVAL_NODE.operator
16 -#define EVAL_OPERATOR_NOP '\0'
17 -#define EVAL_OPERATOR_VALUE ':'
18 -#define EVAL_OPERATOR_EXPRESSION_OPEN '('
19 -#define EVAL_OPERATOR_EXPRESSION_CLOSE ')'
20 -#define EVAL_OPERATOR_NOT '!'
21 -#define EVAL_OPERATOR_PLUS '+'
22 -#define EVAL_OPERATOR_MINUS '-'
23 -#define EVAL_OPERATOR_AND '&'
24 -#define EVAL_OPERATOR_OR '|'
25 -#define EVAL_OPERATOR_GREATER_THAN_OR_EQUAL 'G'
26 -#define EVAL_OPERATOR_LESS_THAN_OR_EQUAL 'L'
27 -#define EVAL_OPERATOR_NOT_EQUAL '~'
28 -#define EVAL_OPERATOR_EQUAL '='
29 -#define EVAL_OPERATOR_LESS '<'
30 -#define EVAL_OPERATOR_GREATER '>'
31 -#define EVAL_OPERATOR_MULTIPLY '*'
32 -#define EVAL_OPERATOR_DIVIDE '/'
33 -#define EVAL_OPERATOR_SIGN_PLUS 'P'
34 -#define EVAL_OPERATOR_SIGN_MINUS 'M'
35 -
31 #define EVAL_ERROR_OK 0
32
33 // parsing errors
@@ -46,29 +41,22 @@ typedef struct variable {
41 #define EVAL_ERROR_INVALID_NUMBER_OF_OPERANDS 6
42 #define EVAL_ERROR_VALUE_IS_NAN 7
43 #define EVAL_ERROR_VALUE_IS_INFINITE 8
44 +#define EVAL_ERROR_UNKNOWN_VARIABLE 9
45
50 -typedef struct eval_value {
51 - int type;
52 -
53 - union {
54 - calculated_number number;
55 - VARIABLE *variable;
56 - struct eval_node *expression;
57 - };
58 -} EVAL_VALUE;
46 +// parse the given string as an expression and return:
47 +// a pointer to an expression if it parsed OK
48 +// NULL in which case the pointer to error has the error code
49 +extern EVAL_EXPRESSION *expression_parse(const char *string, const char **failed_at, int *error);
50
60 -typedef struct eval_node {
61 - int id;
62 - unsigned char operator;
63 - int precedence;
51 +// free all resources allocated for an expression
52 +extern void expression_free(EVAL_EXPRESSION *op);
53
65 - int count;
66 - EVAL_VALUE ops[];
67 -} EVAL_NODE;
68 -
69 -extern EVAL_NODE *expression_parse(const char *string, const char **failed_at, int *error);
70 -extern calculated_number expression_evaluate(EVAL_NODE *expression, int *error);
71 -extern void expression_free(EVAL_NODE *op);
54 +// convert an error code to a message
55 extern const char *expression_strerror(int error);
56
57 +// evaluate an expression and return
58 +// 1 = OK, the result is in: expression->result
59 +// 2 = FAILED, the error message is in: buffer_tostring(expression->error_msg)
60 +extern int expression_evaluate(EVAL_EXPRESSION *expression);
61 +
62 #endif //NETDATA_EVAL_H
src/health.c
+1 -1
@@ -49,7 +49,7 @@ static inline void rrdvar_free(RRDHOST *host, RRDVAR *rv) {
49 if(host) {
50 // FIXME: we may need some kind of locking here
51 // to have mutually exclusive access with eval()
52 - VARIABLE *rf;
52 + EVAL_VARIABLE *rf;
53 for (rf = host->references; rf; rf = rf->next)
54 if (rf->rrdvar == rv) rf->rrdvar = NULL;
55 }
src/rrd.h
+1 -1
@@ -301,7 +301,7 @@ struct rrdhost {
301 // all variable references are linked here
302 // RRDVARs may be free'd, so every time this happens
303 // we need to find all their references and invalidate them
304 - VARIABLE *references;
304 + EVAL_VARIABLE *references;
305 };
306 typedef struct rrdhost RRDHOST;
307
src/web_buffer.h
+1 -1
@@ -1,7 +1,7 @@
1 #ifndef NETDATA_WEB_BUFFER_H
2 #define NETDATA_WEB_BUFFER_H 1
3
4 -#define WEB_DATA_LENGTH_INCREASE_STEP 16384
4 +#define WEB_DATA_LENGTH_INCREASE_STEP 1024
5
6 typedef struct web_buffer {
7 size_t size; // allocation size of buffer
src/web_client.c
+2 -2
@@ -698,7 +698,7 @@ int web_client_api_v1_badge(struct web_client *w, char *url) {
698 if(!strcmp(name, "chart")) chart = value;
699 else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
700 if(!dimensions)
701 - dimensions = buffer_create(strlen(value));
701 + dimensions = buffer_create(100);
702
703 if(dimensions) {
704 buffer_strcat(dimensions, "|");
@@ -860,7 +860,7 @@ int web_client_api_request_v1_data(struct web_client *w, char *url)
860
861 if(!strcmp(name, "chart")) chart = value;
862 else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
863 - if(!dimensions) dimensions = buffer_create(strlen(value));
863 + if(!dimensions) dimensions = buffer_create(100);
864 if(dimensions) {
865 buffer_strcat(dimensions, "|");
866 buffer_strcat(dimensions, value);