summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common.c2
-rw-r--r--src/eval.c406
-rw-r--r--src/eval.h42
-rw-r--r--src/main.c2
4 files changed, 395 insertions, 57 deletions
diff --git a/src/common.c b/src/common.c
index 07aa209821..237f9732fb 100644
--- a/src/common.c
+++ b/src/common.c
@@ -3,6 +3,8 @@
char *global_host_prefix = "";
int enable_ksm = 1;
+volatile sig_atomic_t netdata_exit = 0;
+
// time(NULL) in milliseconds
unsigned long long timems(void) {
struct timeval now;
diff --git a/src/eval.c b/src/eval.c
index d9377ecf6a..5ed62b21f5 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1,5 +1,11 @@
#include "common.h"
+static inline void skip_spaces(const char **string) {
+ const char *s = *string;
+ while(isspace(*s)) s++;
+ *string = s;
+}
+
// ----------------------------------------------------------------------------
// operators that work on 2 operands
@@ -35,7 +41,7 @@ static inline int parse_or(const char **string) {
const char *s = *string;
// OR
- if((s[0] == 'O' || s[0] == '0') && (s[1] == 'R' || s[1] == 'r') && isoperatorterm_word(s[2])) {
+ if((s[0] == 'O' || s[0] == 'o') && (s[1] == 'R' || s[1] == 'r') && isoperatorterm_word(s[2])) {
*string = &s[3];
return 1;
}
@@ -180,6 +186,39 @@ static inline int parse_plus(const char **string) {
return 0;
}
+static inline int parse_open_subexpression(const char **string) {
+ const char *s = *string;
+
+ // (
+ if(s[0] == '(') {
+ *string = &s[1];
+ return 1;
+ }
+
+ return 0;
+}
+
+static inline int parse_close_subexpression(const char **string) {
+ const char *s = *string;
+
+ // (
+ if(s[0] == ')') {
+ *string = &s[1];
+ return 1;
+ }
+
+ return 0;
+}
+
+static inline int parse_literal(const char **string, calculated_number *number) {
+ char *end = NULL;
+ *number = strtold(*string, &end);
+ if(!end || *string == end) return 0;
+
+ *string = end;
+ return 1;
+}
+
// ----------------------------------------------------------------------------
// operators that affect a single operand
@@ -188,7 +227,7 @@ static inline int parse_not(const char **string) {
// NOT
if((s[0] == 'N' || s[0] == 'n') && (s[1] == 'O' || s[1] == 'o') && (s[2] == 'T' || s[2] == 't') && isoperatorterm_word(s[3])) {
- *string = &s[4];
+ *string = &s[3];
return 1;
}
@@ -200,46 +239,150 @@ static inline int parse_not(const char **string) {
return 0;
}
-static struct operator {
- const char *printas;
- int precedence;
+static struct operator_parser {
char id;
int (*parse)(const char **);
-} operators[] = {
- { "&&", 2, '&', parse_and },
- { "||", 2, '|', parse_or },
- { ">=", 3, '}', parse_greater_than_or_equal },
- { "<=", 3, '{', parse_less_than_or_equal },
- { "<>", 3, '~', parse_not_equal },
- { "==", 3, '=', parse_equal },
- { "<", 3, '<', parse_less },
- { ">", 3, '>', parse_greater },
- { "+", 4, EVAL_OPERATOR_PLUS, parse_plus },
- { "-", 4, EVAL_OPERATOR_MINUS, parse_minus },
- { "*", 5, '*', parse_multiply },
- { "/", 5, '/', parse_divide },
-
- // we should not put NOT in this list
-
- { NULL, 0, EVAL_OPERATOR_NOP, NULL }
+} operator_parsers[] = {
+ // the order in this list is important!
+ // the first matching will be used
+ // so place the longer of overlapping ones
+ // at the top
+
+ { EVAL_OPERATOR_AND, parse_and },
+ { EVAL_OPERATOR_OR, parse_or },
+ { EVAL_OPERATOR_GREATER_THAN_OR_EQUAL, parse_greater_than_or_equal },
+ { EVAL_OPERATOR_LESS_THAN_OR_EQUAL, parse_less_than_or_equal },
+ { EVAL_OPERATOR_NOT_EQUAL, parse_not_equal },
+ { EVAL_OPERATOR_EQUAL, parse_equal },
+ { EVAL_OPERATOR_LESS, parse_less },
+ { EVAL_OPERATOR_GREATER, parse_greater },
+ { EVAL_OPERATOR_PLUS, parse_plus },
+ { EVAL_OPERATOR_MINUS, parse_minus },
+ { EVAL_OPERATOR_MULTIPLY, parse_multiply },
+ { EVAL_OPERATOR_DIVIDE, parse_divide },
+
+ /* we should not put
+ *
+ * - NOT
+ * - (
+ * - )
+ *
+ * in this list
+ */
+
+ { EVAL_OPERATOR_NOP, NULL }
};
-static inline char parse_operator(const char **s, int *precedence) {
- int i;
+// ----------------------------------------------------------------------------
+// evaluation of operations
+
+calculated_number eval_and(EVAL_OPERAND *op) {
+ return 0;
+}
+calculated_number eval_or(EVAL_OPERAND *op) {
+ return 0;
+}
+calculated_number eval_greater_than_or_equal(EVAL_OPERAND *op) {
+ return 0;
+}
+calculated_number eval_less_than_or_equal(EVAL_OPERAND *op) {
+ return 0;
+}
+calculated_number eval_not_equal(EVAL_OPERAND *op) {
+ return 0;
+}
+calculated_number eval_equal(EVAL_OPERAND *op) {
+ return 0;
+}
+calculated_number eval_less(EVAL_OPERAND *op) {
+ return 0;
+}
+calculated_number eval_greater(EVAL_OPERAND *op) {
+ return 0;
+}
+calculated_number eval_plus(EVAL_OPERAND *op) {
+ return 0;
+}
+calculated_number eval_minus(EVAL_OPERAND *op) {
+ return 0;
+}
+calculated_number eval_multiply(EVAL_OPERAND *op) {
+ return 0;
+}
+calculated_number eval_divide(EVAL_OPERAND *op) {
+ return 0;
+}
+calculated_number eval_nop(EVAL_OPERAND *op) {
+ return 0;
+}
+calculated_number eval_not(EVAL_OPERAND *op) {
+ return 0;
+}
+calculated_number eval_sign_plus(EVAL_OPERAND *op) {
+ return 0;
+}
+calculated_number eval_sign_minus(EVAL_OPERAND *op) {
+ return 0;
+}
+
+static struct operator {
+ const char *print_as;
+ char precedence;
+ calculated_number (*eval)(EVAL_OPERAND *op);
+} operators[256] = {
+ // this is a random access array
+ // we always access it with a known EVAL_OPERATOR_X
+
+ [EVAL_OPERATOR_AND] = { "&&", 2, eval_and },
+ [EVAL_OPERATOR_OR] = { "||", 2, eval_or },
+ [EVAL_OPERATOR_GREATER_THAN_OR_EQUAL] = { ">=", 3, eval_greater_than_or_equal },
+ [EVAL_OPERATOR_LESS_THAN_OR_EQUAL] = { "<=", 3, eval_less_than_or_equal },
+ [EVAL_OPERATOR_NOT_EQUAL] = { "!=", 3, eval_not_equal },
+ [EVAL_OPERATOR_EQUAL] = { "==", 3, eval_equal },
+ [EVAL_OPERATOR_LESS] = { "<", 3, eval_less },
+ [EVAL_OPERATOR_GREATER] = { ">", 3, eval_greater },
+ [EVAL_OPERATOR_PLUS] = { "+", 4, eval_plus },
+ [EVAL_OPERATOR_MINUS] = { "-", 4, eval_minus },
+ [EVAL_OPERATOR_MULTIPLY] = { "*", 5, eval_multiply },
+ [EVAL_OPERATOR_DIVIDE] = { "/", 5, eval_divide },
+ [EVAL_OPERATOR_NOT] = { "!", 6, eval_not },
+ [EVAL_OPERATOR_SIGN_PLUS] = { "+", 6, eval_sign_plus },
+ [EVAL_OPERATOR_SIGN_MINUS] = { "-", 6, eval_sign_minus },
+ [EVAL_OPERATOR_NOP] = { NULL, 7, eval_nop },
+ [EVAL_OPERATOR_VALUE] = { NULL, 7, eval_nop },
+ [EVAL_OPERATOR_EXPRESSION_OPEN] = { "(", 7, eval_nop },
+
+ // this should exist in our evaluation list
+ [EVAL_OPERATOR_EXPRESSION_CLOSE] = { ")", 7, eval_nop }
+};
+
+#define eval_precedence(operator) (operators[(unsigned char)(operator)].precedence)
- for(i = 0 ; operators[i].parse != NULL ; i++)
- if(operators[i].parse(s)) {
- if(precedence) *precedence = operators[i].precedence;
- return operators[i].id;
+// ----------------------------------------------------------------------------
+
+static inline char parse_operator(const char **string, int *precedence) {
+ skip_spaces(string);
+
+ int i;
+ for(i = 0 ; operator_parsers[i].parse != NULL ; i++)
+ if(operator_parsers[i].parse(string)) {
+ if(precedence) *precedence = eval_precedence(operator_parsers[i].id);
+ return operator_parsers[i].id;
}
return EVAL_OPERATOR_NOP;
}
+
static inline EVAL_OPERAND *operand_alloc(int count) {
+ static int id = 1;
+
EVAL_OPERAND *op = calloc(1, sizeof(EVAL_OPERAND) + (sizeof(EVAL_VALUE) * count));
- if(!op) fatal("Cannot allocate memory for OPERAND");
+ if(!op) fatal("Cannot allocate memory for OPERAND with %d slots", count);
+ op->id = id++;
+ op->operator = EVAL_OPERATOR_NOP;
+ op->precedence = eval_precedence(EVAL_OPERATOR_NOP);
op->count = count;
return op;
}
@@ -248,42 +391,211 @@ static inline void operand_set_value_operand(EVAL_OPERAND *op, int pos, EVAL_OPE
if(pos >= op->count)
fatal("Invalid request to set position %d of OPERAND that has only %d values", pos + 1, op->count + 1);
- op->ops[pos].type = EVAL_OPERAND_EXPRESSION;
+ op->ops[pos].type = EVAL_VALUE_EXPRESSION;
op->ops[pos].expression = value;
}
+static inline void operand_set_value_literal(EVAL_OPERAND *op, int pos, calculated_number value) {
+ if(pos >= op->count)
+ fatal("Invalid request to set position %d of OPERAND that has only %d values", pos + 1, op->count + 1);
+
+ op->ops[pos].type = EVAL_VALUE_NUMBER;
+ op->ops[pos].number = value;
+}
+
// forward definitions
-static inline EVAL_OPERAND *parse_operand(const char **string);
+static inline void operand_free(EVAL_OPERAND *op);
+static inline EVAL_OPERAND *parse_operand(const char **string, int *error);
+static inline EVAL_OPERAND *parse_operand1(const char **string, int *error);
+
+static inline void variable_free(VARIABLE *v) {
+ free(v);
+}
+
+static inline void value_free(EVAL_VALUE *v) {
+ switch(v->type) {
+ case EVAL_VALUE_EXPRESSION:
+ operand_free(v->expression);
+ break;
+
+ case EVAL_VALUE_VARIABLE:
+ variable_free(v->variable);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static inline void operand_free(EVAL_OPERAND *op) {
+ if(op->count) {
+ int i;
+ for(i = op->count - 1; i >= 0 ;i--)
+ value_free(&op->ops[i]);
+ }
+
+ free(op);
+}
-static inline EVAL_OPERAND *operand_alloc_single(const char **string, char type) {
- EVAL_OPERAND *sub = parse_operand(string);
+static inline EVAL_OPERAND *parse_operand_with_operator(const char **string, char type, int *error) {
+ EVAL_OPERAND *sub = parse_operand1(string, error);
if(!sub) return NULL;
EVAL_OPERAND *op = operand_alloc(1);
- if(!op) fatal("Cannot allocate memory for OPERAND");
-
op->operator = type;
operand_set_value_operand(op, 0, sub);
return op;
}
-static inline EVAL_OPERAND *parse_operand(const char **string) {
- const char *s = *string;
- while(isspace(*s)) s++;
+static inline EVAL_OPERAND *parse_operand1(const char **string, int *error) {
+ EVAL_OPERAND *op1 = NULL;
+ calculated_number number;
- if(!*s) return NULL;
- *string = s;
+ *error = EVAL_ERROR_OK;
+
+ skip_spaces(string);
+ if(!(**string)) {
+ *error = EVAL_ERROR_MISSING_OPERAND;
+ return NULL;
+ }
+
+ if(parse_not(string)) {
+ op1 = parse_operand_with_operator(string, EVAL_OPERATOR_NOT, error);
+ op1->precedence = eval_precedence(EVAL_OPERATOR_NOT);
+ }
+ else if(parse_plus(string)) {
+ op1 = parse_operand_with_operator(string, EVAL_OPERATOR_SIGN_PLUS, error);
+ op1->precedence = eval_precedence(EVAL_OPERATOR_SIGN_PLUS);
+ }
+ else if(parse_minus(string)) {
+ op1 = parse_operand_with_operator(string, EVAL_OPERATOR_SIGN_MINUS, error);
+ op1->precedence = eval_precedence(EVAL_OPERATOR_SIGN_MINUS);
+ }
+ else if(parse_open_subexpression(string)) {
+ EVAL_OPERAND *sub = parse_operand(string, error);
+ if(sub) {
+ op1 = operand_alloc(1);
+ op1->operator = EVAL_OPERATOR_EXPRESSION_OPEN;
+ op1->precedence = eval_precedence(EVAL_OPERATOR_EXPRESSION_OPEN);
+ operand_set_value_operand(op1, 0, sub);
+ if(!parse_close_subexpression(string)) {
+ *error = EVAL_ERROR_MISSING_CLOSE_SUBEXPRESSION;
+ operand_free(op1);
+ return NULL;
+ }
+ }
+ }
+// else if(parse_variable(string)) {
+//
+// }
+ else if(parse_literal(string, &number)) {
+ op1 = operand_alloc(1);
+ op1->operator = EVAL_OPERATOR_VALUE;
+ operand_set_value_literal(op1, 0, number);
+ }
+ else if(*string)
+ *error = EVAL_ERROR_UNKNOWN_OPERAND;
+ else
+ *error = EVAL_ERROR_MISSING_OPERAND;
+
+ return op1;
+}
+
+static inline EVAL_OPERAND *parse_operand_rest(const char **string, int *error, EVAL_OPERAND *op1) {
+ EVAL_OPERAND *op2 = NULL;
+ char operator;
+ int precedence;
+
+ operator = parse_operator(string, &precedence);
+ skip_spaces(string);
+
+ if(operator != EVAL_OPERATOR_NOP) {
+ op2 = parse_operand1(string, error);
+ if(!op2) {
+ operand_free(op1);
+ return NULL;
+ }
+
+ EVAL_OPERAND *op = operand_alloc(2);
+ op->operator = operator;
+ op->precedence = precedence;
+
+ operand_set_value_operand(op, 0, op1);
+ operand_set_value_operand(op, 1, op2);
+
+ if(op->precedence > op1->precedence && op1->count == 2 && op1->operator != '(' && op1->ops[1].type == EVAL_VALUE_EXPRESSION) {
+ operand_set_value_operand(op, 0, op1->ops[1].expression);
+ op1->ops[1].expression = op;
+ op = op1;
+ }
+
+ return parse_operand_rest(string, error, op);
+ }
+ else if(**string == EVAL_OPERATOR_EXPRESSION_CLOSE) {
+ ;
+ }
+ else if(**string) {
+ if(op1) operand_free(op1);
+ op1 = NULL;
+ *error = EVAL_ERROR_MISSING_OPERATOR;
+ }
+
+ return op1;
+}
+
+static inline EVAL_OPERAND *parse_operand(const char **string, int *error) {
+ EVAL_OPERAND *op1 = NULL;
- if(parse_not(string))
- return operand_alloc_single(string, EVAL_OPERATOR_NOT);
+ op1 = parse_operand1(string, error);
+ if(!op1) {
+ *error = EVAL_ERROR_MISSING_OPERAND;
+ return NULL;
+ }
+
+ return parse_operand_rest(string, error, op1);
+}
- if(parse_plus(string))
- return operand_alloc_single(string, EVAL_OPERATOR_PLUS);
+const char *eval_error(int error) {
+ switch(error) {
+ case EVAL_ERROR_OK:
+ return "success";
- if(parse_minus(string))
- return operand_alloc_single(string, EVAL_OPERATOR_MINUS);
+ case EVAL_ERROR_MISSING_CLOSE_SUBEXPRESSION:
+ return "missing closing parenthesis";
+ case EVAL_ERROR_UNKNOWN_OPERAND:
+ return "unknown operand";
+ case EVAL_ERROR_MISSING_OPERAND:
+ return "expected operand";
+
+ case EVAL_ERROR_MISSING_OPERATOR:
+ return "expected operator";
+
+ default:
+ return "unknown error";
+ }
+}
+
+EVAL_OPERAND *parse_expression(const char *string, const char **failed_at, int *error) {
+ const char *s;
+ int err = EVAL_ERROR_OK;
+ unsigned long pos = 0;
+
+ s = string;
+ EVAL_OPERAND *op = parse_operand(&s, &err);
+
+ if (failed_at) *failed_at = s;
+ if (error) *error = err;
+
+ if(!op) {
+ pos = s - string + 1;
+ error("failed to parse expression '%s': %s at character %lu (i.e.: '%s').", string, eval_error(err), pos, s);
+ }
+
+ return op;
+}
- return NULL;
+void free_expression(EVAL_OPERAND *op) {
+ if(op) operand_free(op);
}
diff --git a/src/eval.h b/src/eval.h
index da3be13097..ed040f6059 100644
--- a/src/eval.h
+++ b/src/eval.h
@@ -7,16 +7,37 @@ typedef struct variable {
struct variable *next;
} VARIABLE;
-#define EVAL_OPERAND_INVALID 0
-#define EVAL_OPERAND_NUMBER 1
-#define EVAL_OPERAND_VARIABLE 2
-#define EVAL_OPERAND_EXPRESSION 3
+#define EVAL_VALUE_INVALID 0
+#define EVAL_VALUE_NUMBER 1
+#define EVAL_VALUE_VARIABLE 2
+#define EVAL_VALUE_EXPRESSION 3
// these are used for EVAL_OPERAND.operator
-#define EVAL_OPERATOR_NOP '\0'
-#define EVAL_OPERATOR_NOT '!'
-#define EVAL_OPERATOR_PLUS '+'
-#define EVAL_OPERATOR_MINUS '-'
+#define EVAL_OPERATOR_NOP '\0'
+#define EVAL_OPERATOR_VALUE ':'
+#define EVAL_OPERATOR_EXPRESSION_OPEN '('
+#define EVAL_OPERATOR_EXPRESSION_CLOSE ')'
+#define EVAL_OPERATOR_NOT '!'
+#define EVAL_OPERATOR_PLUS '+'
+#define EVAL_OPERATOR_MINUS '-'
+#define EVAL_OPERATOR_AND '&'
+#define EVAL_OPERATOR_OR '|'
+#define EVAL_OPERATOR_GREATER_THAN_OR_EQUAL 'G'
+#define EVAL_OPERATOR_LESS_THAN_OR_EQUAL 'L'
+#define EVAL_OPERATOR_NOT_EQUAL '~'
+#define EVAL_OPERATOR_EQUAL '='
+#define EVAL_OPERATOR_LESS '<'
+#define EVAL_OPERATOR_GREATER '>'
+#define EVAL_OPERATOR_MULTIPLY '*'
+#define EVAL_OPERATOR_DIVIDE '/'
+#define EVAL_OPERATOR_SIGN_PLUS 'P'
+#define EVAL_OPERATOR_SIGN_MINUS 'M'
+
+#define EVAL_ERROR_OK 0
+#define EVAL_ERROR_MISSING_CLOSE_SUBEXPRESSION 1
+#define EVAL_ERROR_UNKNOWN_OPERAND 2
+#define EVAL_ERROR_MISSING_OPERAND 3
+#define EVAL_ERROR_MISSING_OPERATOR 4
typedef struct eval_value {
int type;
@@ -29,10 +50,15 @@ typedef struct eval_value {
} EVAL_VALUE;
typedef struct eval_operand {
+ int id;
char operator;
+ int precedence;
int count;
EVAL_VALUE ops[];
} EVAL_OPERAND;
+extern EVAL_OPERAND *parse_expression(const char *string, const char **failed_at, int *error);
+extern void free_expression(EVAL_OPERAND *op);
+
#endif //NETDATA_EVAL_H
diff --git a/src/main.c b/src/main.c
index 63ec24df32..ea84f976ea 100644
--- a/src/main.c
+++ b/src/main.c
@@ -2,8 +2,6 @@
extern void *cgroups_main(void *ptr);
-volatile sig_atomic_t netdata_exit = 0;
-
void netdata_cleanup_and_exit(int ret) {
netdata_exit = 1;