changeset 670:0d37fe455b86

More work on evaluator.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 16 Apr 2013 11:30:52 +0300
parents 440b77b635a5
children e5e56d16597e
files dmeval.c dmeval.h
diffstat 2 files changed, 140 insertions(+), 67 deletions(-) [+]
line wrap: on
line diff
--- 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;
--- 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);