# HG changeset patch # User Matti Hamalainen # Date 1366101052 -10800 # Node ID 0d37fe455b86ce6a91fdf9a10fadee51f7f58f08 # Parent 440b77b635a53e06582aa6af05a9f4e84b86f1e4 More work on evaluator. diff -r 440b77b635a5 -r 0d37fe455b86 dmeval.c --- a/dmeval.c Tue Apr 16 09:46:25 2013 +0300 +++ b/dmeval.c Tue Apr 16 11:30:52 2013 +0300 @@ -6,6 +6,9 @@ #define DM_MAX_BUF 512 #define DM_STACK_SIZE 512 + +/* Function definitions + */ static DMValue func_int_clip(DMValue *v) { return (*v < -1.0f) ? -1.0f : ((*v > 1.0f) ? 1.0f : *v); @@ -34,10 +37,12 @@ */ static const DMEvalId dm_eval_basic[] = { - { "sin", ID_FUNC, 1, func_sin, NULL }, - { "cos", ID_FUNC, 1, func_cos, NULL }, - { "clip", ID_FUNC, 1, func_int_clip, NULL }, - { "pow", ID_FUNC, 2, func_pow, NULL }, + { "sin", ID_FUNC, 1, func_sin, NULL, 0 }, + { "cos", ID_FUNC, 1, func_cos, NULL, 0 }, + { "clip", ID_FUNC, 1, func_int_clip, NULL, 0 }, + { "pow", ID_FUNC, 2, func_pow, NULL, 0 }, + + { "pi", ID_CVAR, 0, NULL, NULL, DM_PI }, }; static const int ndm_eval_basic = sizeof(dm_eval_basic) / sizeof(dm_eval_basic[0]); @@ -79,8 +84,10 @@ return NULL; for (i = 0; i < ev->nids; i++) + { if (strcmp(ev->ids[i].name, name) == 0) return &(ev->ids[i]); + } return NULL; } @@ -106,7 +113,7 @@ id->type = type; id->func = NULL; id->var = NULL; - + return id; } @@ -122,13 +129,25 @@ } -DMEvalId *dm_eval_add_func(DMEvalContext *ev, const char *name, DMValue (*func)(DMValue *)) +DMEvalId *dm_eval_add_const(DMEvalContext *ev, const char *name, DMValue value) +{ + DMEvalId *id = dm_eval_add_id(ev, name, ID_CVAR); + if (id == NULL) + return NULL; + + id->cvalue = value; + return id; +} + + +DMEvalId *dm_eval_add_func(DMEvalContext *ev, const char *name, DMValue (*func)(DMValue *), int nargs) { DMEvalId *id = dm_eval_add_id(ev, name, ID_VAR); if (id == NULL) return NULL; - id->func = func; + id->func = func; + id->nargs = nargs; return id; } @@ -146,21 +165,30 @@ { const DMEvalId *id = &dm_eval_basic[i]; DMEvalId *nid = dm_eval_add_id(ev, id->name, id->type); - nid->func = id->func; + nid->nargs = id->nargs; + nid->func = id->func; + nid->var = id->var; + nid->cvalue = id->cvalue; } return ev; } + void dm_eval_free(DMEvalNode *node) { while (node != NULL) { DMEvalNode *next = node->next; + int i; - if (node->subexpr != NULL) - dm_eval_free(node->subexpr); + for (i = 0; i < DM_MAX_ARGS; i++) + { + dm_eval_free(node->args[i]); + node->args[i] = NULL; + } + dm_eval_free(node->subexpr); dmFree(node); node = next; } @@ -237,6 +265,8 @@ static DMEvalNode *dm_eval_push_node(DMEvalNode **list, DMEvalNode *src) { DMEvalNode *node = dmCalloc(1, sizeof(DMEvalNode)); + int i; + if (node == NULL) return NULL; @@ -244,6 +274,9 @@ node->val = src->val; node->id = src->id; node->subexpr = src->subexpr; + + for (i = 0; i < DM_MAX_ARGS; i++) + node->args[i] = src->args[i]; return dm_eval_insert_node(list, node); } @@ -271,8 +304,12 @@ PARSE_IDENT = 0x0001, PARSE_WS = 0x0002, PARSE_CONST = 0x0004, - PARSE_OPER = 0x0008, - PARSE_SUBEXPR = 0x0010, + PARSE_OPER = 0x0008, // All operators + PARSE_OPER2 = 0x0010, // '-' only + PARSE_SUBEXPR = 0x0020, + PARSE_ARGS = 0x0040, + + PARSE_NORMAL = PARSE_CONST | PARSE_IDENT | PARSE_SUBEXPR | PARSE_OPER2, }; #define DM_CHECK(x) { if (mode & PARSE_ ## x ) { if (str[0]) strcat(str, " or "); strcat(str, # x ); } } @@ -280,7 +317,6 @@ static char *dm_get_mode(int mode) { char str[128] = ""; - DM_CHECK(START); DM_CHECK(END); @@ -288,7 +324,9 @@ DM_CHECK(WS); DM_CHECK(CONST); DM_CHECK(OPER); + DM_CHECK(OPER2); DM_CHECK(SUBEXPR); + DM_CHECK(ARGS); return dm_strdup(str); } @@ -296,7 +334,8 @@ static void dm_set_mode(DMEvalContext *ev, const int mode) { - if (mode != PARSE_ERROR && mode != PARSE_START && + if (mode != PARSE_ERROR && + mode != PARSE_START && ev->expect != PARSE_NONE && (mode & ev->expect) == 0) { @@ -317,52 +356,32 @@ { char *c = *str; char tmpStr[DM_MAX_BUF + 2]; - int tmpStrLen = 0; + int tmpStrLen = 0, argIndex; DMEvalNode *node = NULL, *func = NULL; BOOL first = FALSE, decimal = FALSE; - ev->expect = PARSE_CONST | PARSE_IDENT | PARSE_SUBEXPR; + ev->expect = PARSE_NORMAL; ev->mode = PARSE_START; while (ev->mode != PARSE_ERROR && ev->mode != PARSE_END) { switch (ev->mode) { - case PARSE_WS: - // Skip whitespace - if (isspace(*c)) - c++; - else - dm_set_mode(ev, PARSE_START); - break; - case PARSE_SUBEXPR: { char *tmp = c + 1; - ev->expect = PARSE_SUBEXPR | PARSE_IDENT | PARSE_CONST; + ev->expect = PARSE_NORMAL; - if (func != NULL) + if ((node = dm_eval_add_node(list, OP_SUBEXPR)) == NULL) + dm_set_mode(ev, PARSE_ERROR); + else + if (dm_eval_parse_expr_do(ev, &(node->subexpr), &tmp, depth + 1) != 0) { - if (dm_eval_parse_expr_do(ev, &(func->subexpr), &tmp, depth + 1) != 0) - { - dm_eval_err(ev, "Function argument subexpression starting at '%s' contained errors.\n", c); - dm_set_mode(ev, PARSE_ERROR); - } - - func = NULL; + dm_eval_err(ev, "Subexpression starting at '%s' contained errors.\n", c); + dm_set_mode(ev, PARSE_ERROR); } - else - { - if ((node = dm_eval_add_node(list, OP_SUBEXPR)) == NULL) - dm_set_mode(ev, PARSE_ERROR); - else - if (dm_eval_parse_expr_do(ev, &(node->subexpr), &tmp, depth + 1) != 0) - { - dm_eval_err(ev, "Subexpression starting at '%s' contained errors.\n", c); - dm_set_mode(ev, PARSE_ERROR); - } - } + if (ev->mode != PARSE_ERROR) { dm_set_mode(ev, PARSE_START); @@ -371,18 +390,40 @@ } } break; - + + case PARSE_ARGS: + { + char *tmp = c + 1; + for (argIndex = 0; argIndex < func->id->nargs; argIndex++) + { + if (dm_eval_parse_expr_do(ev, &(func->args[argIndex]), &tmp, depth + 1) != 0) + { + dm_eval_err(ev, "Function argument subexpression starting at '%s' contained errors.\n", c); + dm_set_mode(ev, PARSE_ERROR); + } + } + + func = NULL; + + if (ev->mode != PARSE_ERROR) + { + dm_set_mode(ev, PARSE_START); + ev->expect = PARSE_OPER | PARSE_END; + c = tmp; + } + } + break; + case PARSE_START: // Start if (*c == 0) dm_set_mode(ev, PARSE_END); + // Skip whitespace else if (isspace(*c)) - { - ev->mode = PARSE_WS; - } + c++; - else if (*c == ')') + else if (*c == ')' || *c == ',') { if (depth > 0) dm_set_mode(ev, PARSE_END); @@ -393,10 +434,10 @@ } c++; } - + else if (*c == '(') - dm_set_mode(ev, PARSE_SUBEXPR); - + dm_set_mode(ev, func != NULL ? PARSE_ARGS : PARSE_SUBEXPR); + else if (strchr("+-*/<>%&|!^", *c)) dm_set_mode(ev, PARSE_OPER); @@ -460,6 +501,7 @@ break; case PARSE_OPER: + case PARSE_OPER2: { int op = OP_NONE; @@ -505,9 +547,12 @@ if (op != OP_NONE) { + if (ev->mode == PARSE_OPER2 && op != OP_SUB) + dm_set_mode(ev, PARSE_ERROR); + else if ((node = dm_eval_add_node(list, op)) != NULL) { - ev->expect = PARSE_IDENT | PARSE_CONST | PARSE_SUBEXPR; + ev->expect = PARSE_NORMAL | PARSE_OPER2; dm_set_mode(ev, PARSE_START); } else @@ -545,7 +590,7 @@ if (id->type == ID_FUNC) { func = node; - ev->expect = PARSE_SUBEXPR; + ev->expect = PARSE_ARGS; } else ev->expect = PARSE_END | PARSE_OPER; @@ -578,6 +623,7 @@ if (ev == NULL || result == NULL) return -1; + ev->prev = PARSE_START; ret = dm_eval_parse_expr_do(ev, result, &expr, 0); return ret; @@ -609,13 +655,19 @@ static void dm_print_optree_do(DMEvalContext *ev, DMEvalNode *node, const int level) { + int i; while (node != NULL) { switch (node->op) { case OP_FUNC: printf("%s(", node->id != NULL ? node->id->name : "?ERROR"); - dm_print_optree_do(ev, node->subexpr, level + 1); + for (i = 0; i < node->id->nargs; i++) + { + dm_print_optree_do(ev, node->args[i], level + 1); + if (i < node->id->nargs - 1) + printf(","); + } printf(")"); break; @@ -679,6 +731,7 @@ int dm_eval_reorder(DMEvalContext *ev, DMEvalNode *node, DMEvalNode **result) { DMEvalNode *list = NULL; + int i; while (node != NULL) { @@ -686,8 +739,18 @@ switch (node->op) { + case OP_FUNC: + if ((tmp = dm_eval_push_node(&list, node)) == NULL) + return -1; + + for (i = 0; i < DM_MAX_ARGS; i++) + { + if (dm_eval_reorder(ev, node->args[i], &(tmp->args[i])) != 0) + return -2; + } + break; + case OP_SUBEXPR: - case OP_FUNC: if ((tmp = dm_eval_push_node(&list, node)) == NULL) return -1; @@ -759,7 +822,8 @@ static int dm_eval_get(DMEvalContext *ev, DMEvalNode *node, DMValue *result) { - DMValue tmp[16]; + DMValue tmp[DM_MAX_ARGS]; + int i; if (node == NULL) return -32; @@ -767,7 +831,10 @@ switch (node->op) { case OP_VAR: - *result = *(node->id->var); + if (node->id->type == ID_VAR) + *result = *(node->id->var); + else + *result = node->id->cvalue; break; case OP_CONST: @@ -780,8 +847,11 @@ break; case OP_FUNC: - if (dm_eval_exec(ev, node->subexpr, &tmp) != 0) - return -1; + for (i = 0; i < node->id->nargs; i++) + { + if (dm_eval_exec(ev, node->args[i], &tmp[i]) != 0) + return -1; + } *result = node->id->func(tmp); break; diff -r 440b77b635a5 -r 0d37fe455b86 dmeval.h --- a/dmeval.h Tue Apr 16 09:46:25 2013 +0300 +++ b/dmeval.h Tue Apr 16 11:30:52 2013 +0300 @@ -5,8 +5,8 @@ typedef double DMValue; -#define DMCONVTYPE (int) - +#define DMCONVTYPE (int) +#define DM_MAX_ARGS 8 enum { @@ -36,7 +36,8 @@ enum { ID_FUNC, - ID_VAR + ID_VAR, + ID_CVAR, } DMEvalIdType; @@ -44,9 +45,9 @@ { char *name; int type; - int args; - DMValue (*func)(DMValue *); - DMValue *var; + int nargs; + DMValue (*func)(DMValue arg[DM_MAX_ARGS]); + DMValue *var, cvalue; } DMEvalId; @@ -56,6 +57,7 @@ DMValue val; DMEvalId *id; + struct DMEvalNode *args[DM_MAX_ARGS]; struct DMEvalNode *subexpr, *next, *prev; } DMEvalNode; @@ -74,7 +76,8 @@ DMEvalId *dm_eval_find_id(DMEvalContext *ev, const char *name); DMEvalId *dm_eval_add_var(DMEvalContext *ev, const char *name, DMValue *var); -DMEvalId *dm_eval_add_func(DMEvalContext *ev, const char *name, DMValue (*func)(DMValue *)); +DMEvalId *dm_eval_add_const(DMEvalContext *ev, const char *name, DMValue value); +DMEvalId *dm_eval_add_func(DMEvalContext *ev, const char *name, DMValue (*func)(DMValue *), int nargs); DMEvalContext *dm_eval_new(void); void dm_eval_close(DMEvalContext *ev);