else printf(" \\_ ");
}
-void print_operand(EVAL_OPERAND *op, int level);
+void print_node(EVAL_NODE *op, int level);
void print_value(EVAL_VALUE *v, int level) {
indent(level, 0);
switch(v->type) {
case EVAL_VALUE_INVALID:
- printf("VALUE (NOP)\n");
+ printf("value (NOP)\n");
break;
case EVAL_VALUE_NUMBER:
- printf("VALUE %Lf (NUMBER)\n", v->number);
+ printf("value %Lf (NUMBER)\n", v->number);
break;
case EVAL_VALUE_EXPRESSION:
- printf("VALUE (SUB-EXPRESSION)\n");
- print_operand(v->expression, level+1);
+ printf("value (SUB-EXPRESSION)\n");
+ print_node(v->expression, level+1);
break;
default:
- printf("VALUE (INVALID type %d)\n", v->type);
+ printf("value (INVALID type %d)\n", v->type);
break;
}
}
-void print_operand(EVAL_OPERAND *op, int level) {
+void print_node(EVAL_NODE *op, int level) {
// if(op->operator != EVAL_OPERATOR_NOP) {
indent(level, 1);
- if(op->operator) printf("%c (OPERATOR %d, prec: %d)\n", op->operator, op->id, op->precedence);
- else printf("NOP (OPERATOR %d, prec: %d)\n", op->id, op->precedence);
+ if(op->operator) printf("%c (node %d, precedence: %d)\n", op->operator, op->id, op->precedence);
+ else printf("NOP (node %d, precedence: %d)\n", op->id, op->precedence);
// }
int i = op->count;
while(i--) print_value(&op->ops[i], level + 1);
}
-calculated_number evaluate(EVAL_OPERAND *op, int depth);
+calculated_number evaluate(EVAL_NODE *op, int depth);
calculated_number evaluate_value(EVAL_VALUE *v, int depth) {
switch(v->type) {
while(depth--) printf(" ");
}
-calculated_number evaluate(EVAL_OPERAND *op, int depth) {
+calculated_number evaluate(EVAL_NODE *op, int depth) {
calculated_number n1, n2, r;
switch(op->operator) {
return r;
}
-void print_expression(EVAL_OPERAND *op, const char *failed_at, int error) {
+void print_expression(EVAL_NODE *op, const char *failed_at, int error) {
if(op) {
printf("expression tree:\n");
- print_operand(op, 0);
+ print_node(op, 0);
printf("\nevaluation steps:\n");
evaluate(op, 0);
int error;
- calculated_number ret = evaluate_expression(op, &error);
+ calculated_number ret = expression_evaluate(op, &error);
printf("\ninternal evaluator:\nSTATUS: %d, RESULT = %Lf\n", error, ret);
- free_expression(op);
+ expression_free(op);
}
else {
printf("error: %d, failed_at: '%s'\n", error, (failed_at)?failed_at:"<NONE>");
const char *failed_at = NULL;
int error;
- EVAL_OPERAND *op = parse_expression(argv[1], &failed_at, &error);
+ EVAL_NODE *op = expression_parse(argv[1], &failed_at, &error);
print_expression(op, failed_at, error);
return 0;
}
#include "common.h"
// forward definitions
-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 calculated_number eval_operand(EVAL_OPERAND *op, int *error);
-
+static inline void eval_node_free(EVAL_NODE *op);
+static inline EVAL_NODE *parse_full_expression(const char **string, int *error);
+static inline EVAL_NODE *parse_one_full_operand(const char **string, int *error);
+static inline calculated_number eval_node(EVAL_NODE *op, int *error);
static inline void skip_spaces(const char **string) {
const char *s = *string;
return 0;
}
-static inline int parse_literal(const char **string, calculated_number *number) {
+static inline int parse_constant(const char **string, calculated_number *number) {
char *end = NULL;
calculated_number n = strtold(*string, &end);
if(unlikely(!end || *string == end || isnan(n) || isinf(n))) {
return 0;
}
*number = n;
-
*string = end;
return 1;
}
}
static struct operator_parser {
- char id;
+ unsigned char id;
int (*parse)(const char **);
} operator_parsers[] = {
// the order in this list is important!
{ EVAL_OPERATOR_MULTIPLY, parse_multiply },
{ EVAL_OPERATOR_DIVIDE, parse_divide },
- /* we should not put
+ /* we should not put in this list the following:
*
* - NOT
* - (
* - )
*
- * in this list
+ * these are handled in code
*/
{ EVAL_OPERATOR_NOP, NULL }
switch(v->type) {
case EVAL_VALUE_EXPRESSION:
- n = eval_operand(v->expression, error);
+ n = eval_node(v->expression, error);
break;
case EVAL_VALUE_NUMBER:
return eval_check_number(n, error);
}
-calculated_number eval_and(EVAL_OPERAND *op, int *error) {
+calculated_number eval_and(EVAL_NODE *op, int *error) {
return eval_value(&op->ops[0], error) && eval_value(&op->ops[1], error);
}
-calculated_number eval_or(EVAL_OPERAND *op, int *error) {
+calculated_number eval_or(EVAL_NODE *op, int *error) {
return eval_value(&op->ops[0], error) || eval_value(&op->ops[1], error);
}
-calculated_number eval_greater_than_or_equal(EVAL_OPERAND *op, int *error) {
+calculated_number eval_greater_than_or_equal(EVAL_NODE *op, int *error) {
return eval_value(&op->ops[0], error) >= eval_value(&op->ops[1], error);
}
-calculated_number eval_less_than_or_equal(EVAL_OPERAND *op, int *error) {
+calculated_number eval_less_than_or_equal(EVAL_NODE *op, int *error) {
return eval_value(&op->ops[0], error) <= eval_value(&op->ops[1], error);
}
-calculated_number eval_not_equal(EVAL_OPERAND *op, int *error) {
+calculated_number eval_not_equal(EVAL_NODE *op, int *error) {
return eval_value(&op->ops[0], error) != eval_value(&op->ops[1], error);
}
-calculated_number eval_equal(EVAL_OPERAND *op, int *error) {
+calculated_number eval_equal(EVAL_NODE *op, int *error) {
return eval_value(&op->ops[0], error) == eval_value(&op->ops[1], error);
}
-calculated_number eval_less(EVAL_OPERAND *op, int *error) {
+calculated_number eval_less(EVAL_NODE *op, int *error) {
return eval_value(&op->ops[0], error) < eval_value(&op->ops[1], error);
}
-calculated_number eval_greater(EVAL_OPERAND *op, int *error) {
+calculated_number eval_greater(EVAL_NODE *op, int *error) {
return eval_value(&op->ops[0], error) > eval_value(&op->ops[1], error);
}
-calculated_number eval_plus(EVAL_OPERAND *op, int *error) {
+calculated_number eval_plus(EVAL_NODE *op, int *error) {
return eval_value(&op->ops[0], error) + eval_value(&op->ops[1], error);
}
-calculated_number eval_minus(EVAL_OPERAND *op, int *error) {
+calculated_number eval_minus(EVAL_NODE *op, int *error) {
return eval_value(&op->ops[0], error) - eval_value(&op->ops[1], error);
}
-calculated_number eval_multiply(EVAL_OPERAND *op, int *error) {
+calculated_number eval_multiply(EVAL_NODE *op, int *error) {
return eval_value(&op->ops[0], error) * eval_value(&op->ops[1], error);
}
-calculated_number eval_divide(EVAL_OPERAND *op, int *error) {
+calculated_number eval_divide(EVAL_NODE *op, int *error) {
return eval_value(&op->ops[0], error) / eval_value(&op->ops[1], error);
}
-calculated_number eval_nop(EVAL_OPERAND *op, int *error) {
+calculated_number eval_nop(EVAL_NODE *op, int *error) {
return eval_value(&op->ops[0], error);
}
-calculated_number eval_not(EVAL_OPERAND *op, int *error) {
+calculated_number eval_not(EVAL_NODE *op, int *error) {
return !eval_value(&op->ops[0], error);
}
-calculated_number eval_sign_plus(EVAL_OPERAND *op, int *error) {
+calculated_number eval_sign_plus(EVAL_NODE *op, int *error) {
return eval_value(&op->ops[0], error);
}
-calculated_number eval_sign_minus(EVAL_OPERAND *op, int *error) {
+calculated_number eval_sign_minus(EVAL_NODE *op, int *error) {
return -eval_value(&op->ops[0], error);
}
const char *print_as;
char precedence;
char parameters;
- calculated_number (*eval)(EVAL_OPERAND *op, int *error);
+ calculated_number (*eval)(EVAL_NODE *op, int *error);
} operators[256] = {
// this is a random access array
// we always access it with a known EVAL_OPERATOR_X
#define eval_precedence(operator) (operators[(unsigned char)(operator)].precedence)
-static inline calculated_number eval_operand(EVAL_OPERAND *op, int *error) {
+static inline calculated_number eval_node(EVAL_NODE *op, int *error) {
if(unlikely(op->count != operators[op->operator].parameters)) {
*error = EVAL_ERROR_INVALID_NUMBER_OF_OPERANDS;
return 0;
// ----------------------------------------------------------------------------
-static inline char parse_operator(const char **string, int *precedence) {
+static inline unsigned char parse_operator(const char **string, int *precedence) {
skip_spaces(string);
int i;
return EVAL_OPERATOR_NOP;
}
-
-static inline EVAL_OPERAND *operand_alloc(int count) {
+static inline EVAL_NODE *eval_node_alloc(int count) {
static int id = 1;
- EVAL_OPERAND *op = calloc(1, sizeof(EVAL_OPERAND) + (sizeof(EVAL_VALUE) * count));
+ EVAL_NODE *op = calloc(1, sizeof(EVAL_NODE) + (sizeof(EVAL_VALUE) * count));
if(!op) fatal("Cannot allocate memory for OPERAND with %d slots", count);
op->id = id++;
return op;
}
-static inline void operand_set_value_operand(EVAL_OPERAND *op, int pos, EVAL_OPERAND *value) {
+static inline void eval_node_set_value_to_node(EVAL_NODE *op, int pos, EVAL_NODE *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].expression = value;
}
-static inline void operand_set_value_literal(EVAL_OPERAND *op, int pos, calculated_number value) {
+static inline void node_set_value_to_constant(EVAL_NODE *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);
static inline void value_free(EVAL_VALUE *v) {
switch(v->type) {
case EVAL_VALUE_EXPRESSION:
- operand_free(v->expression);
+ eval_node_free(v->expression);
break;
- case EVAL_VALUE_VARIABLE:
- variable_free(v->variable);
- break;
+// case EVAL_VALUE_VARIABLE:
+// variable_free(v->variable);
+// break;
default:
break;
}
}
-static inline void operand_free(EVAL_OPERAND *op) {
+static inline void eval_node_free(EVAL_NODE *op) {
if(op->count) {
int i;
for(i = op->count - 1; i >= 0 ;i--)
free(op);
}
-static inline EVAL_OPERAND *parse_operand_with_operator(const char **string, char type, int *error) {
- EVAL_OPERAND *sub = parse_operand1(string, error);
+static inline EVAL_NODE *parse_next_operand_given_its_operator(const char **string, unsigned char operator_type, int *error) {
+ EVAL_NODE *sub = parse_one_full_operand(string, error);
if(!sub) return NULL;
- EVAL_OPERAND *op = operand_alloc(1);
- op->operator = type;
- operand_set_value_operand(op, 0, sub);
+ EVAL_NODE *op = eval_node_alloc(1);
+ op->operator = operator_type;
+ eval_node_set_value_to_node(op, 0, sub);
return op;
}
-static inline EVAL_OPERAND *parse_operand1(const char **string, int *error) {
- EVAL_OPERAND *op1 = NULL;
+static inline EVAL_NODE *parse_one_full_operand(const char **string, int *error) {
+ EVAL_NODE *op1 = NULL;
calculated_number number;
*error = EVAL_ERROR_OK;
}
if(parse_not(string)) {
- op1 = parse_operand_with_operator(string, EVAL_OPERATOR_NOT, error);
+ op1 = parse_next_operand_given_its_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 = parse_next_operand_given_its_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 = parse_next_operand_given_its_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);
+ EVAL_NODE *sub = parse_full_expression(string, error);
if(sub) {
- op1 = operand_alloc(1);
+ op1 = eval_node_alloc(1);
op1->operator = EVAL_OPERATOR_EXPRESSION_OPEN;
op1->precedence = eval_precedence(EVAL_OPERATOR_EXPRESSION_OPEN);
- operand_set_value_operand(op1, 0, sub);
+ eval_node_set_value_to_node(op1, 0, sub);
if(!parse_close_subexpression(string)) {
*error = EVAL_ERROR_MISSING_CLOSE_SUBEXPRESSION;
- operand_free(op1);
+ eval_node_free(op1);
return NULL;
}
}
// else if(parse_variable(string)) {
//
// }
- else if(parse_literal(string, &number)) {
- op1 = operand_alloc(1);
+ else if(parse_constant(string, &number)) {
+ op1 = eval_node_alloc(1);
op1->operator = EVAL_OPERATOR_VALUE;
- operand_set_value_literal(op1, 0, number);
+ node_set_value_to_constant(op1, 0, number);
}
else if(*string)
*error = EVAL_ERROR_UNKNOWN_OPERAND;
return op1;
}
-static inline EVAL_OPERAND *parse_operand_rest(const char **string, int *error, EVAL_OPERAND *op1) {
- EVAL_OPERAND *op2 = NULL;
- char operator;
+static inline EVAL_NODE *parse_rest_of_expression(const char **string, int *error, EVAL_NODE *op1) {
+ EVAL_NODE *op2 = NULL;
+ unsigned char operator;
int precedence;
operator = parse_operator(string, &precedence);
skip_spaces(string);
if(operator != EVAL_OPERATOR_NOP) {
- op2 = parse_operand1(string, error);
+ op2 = parse_one_full_operand(string, error);
if(!op2) {
- operand_free(op1);
+ // error is already reported
+ eval_node_free(op1);
return NULL;
}
- EVAL_OPERAND *op = operand_alloc(2);
+ EVAL_NODE *op = eval_node_alloc(2);
op->operator = operator;
op->precedence = precedence;
- operand_set_value_operand(op, 0, op1);
- operand_set_value_operand(op, 1, op2);
+ eval_node_set_value_to_node(op, 0, op1);
+ eval_node_set_value_to_node(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);
+ eval_node_set_value_to_node(op, 0, op1->ops[1].expression);
op1->ops[1].expression = op;
op = op1;
}
- return parse_operand_rest(string, error, op);
+ return parse_rest_of_expression(string, error, op);
}
else if(**string == EVAL_OPERATOR_EXPRESSION_CLOSE) {
;
}
else if(**string) {
- if(op1) operand_free(op1);
+ if(op1) eval_node_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;
+static inline EVAL_NODE *parse_full_expression(const char **string, int *error) {
+ EVAL_NODE *op1 = NULL;
- op1 = parse_operand1(string, error);
+ op1 = parse_one_full_operand(string, error);
if(!op1) {
*error = EVAL_ERROR_MISSING_OPERAND;
return NULL;
}
- return parse_operand_rest(string, error, op1);
+ return parse_rest_of_expression(string, error, op1);
+}
+
+// ----------------------------------------------------------------------------
+// public API
+
+EVAL_NODE *expression_parse(const char *string, const char **failed_at, int *error) {
+ const char *s;
+ int err = EVAL_ERROR_OK;
+ unsigned long pos = 0;
+
+ s = string;
+ EVAL_NODE *op = parse_full_expression(&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, expression_strerror(err), pos, s);
+ }
+
+ return op;
+}
+
+calculated_number expression_evaluate(EVAL_NODE *expression, int *error) {
+ int err = EVAL_ERROR_OK;
+ calculated_number ret = eval_node(expression, &err);
+
+ if(err != EVAL_ERROR_OK) {
+ error("Failed to execute expression with error %d (%s)", err, expression_strerror(err));
+ if(error) *error = err;
+ return 0;
+ }
+
+ return ret;
+}
+
+void expression_free(EVAL_NODE *op) {
+ if(op) eval_node_free(op);
}
-const char *eval_error(int error) {
+const char *expression_strerror(int error) {
switch(error) {
case EVAL_ERROR_OK:
return "success";
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;
-}
-
-calculated_number evaluate_expression(EVAL_OPERAND *expression, int *error) {
- int err = EVAL_ERROR_OK;
- calculated_number ret = eval_operand(expression, &err);
-
- if(err != EVAL_ERROR_OK) {
- error("Failed to execute expression with error %d (%s)", err, eval_error(err));
- if(error) *error = err;
- return 0;
- }
-
- return ret;
-}
-
-void free_expression(EVAL_OPERAND *op) {
- if(op) operand_free(op);
-}