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);