diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/common.c | 2 | ||||
-rw-r--r-- | src/eval.c | 406 | ||||
-rw-r--r-- | src/eval.h | 42 | ||||
-rw-r--r-- | src/main.c | 2 |
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; |