changeset 764:181d659bba39

More work.
author Matti Hamalainen <ccr@tnsp.org>
date Thu, 09 May 2013 08:28:39 +0300
parents ad512e54c689
children c68258fd81a1
files dmeval.c dmeval.h
diffstat 2 files changed, 221 insertions(+), 260 deletions(-) [+]
line wrap: on
line diff
--- a/dmeval.c	Thu May 09 06:36:54 2013 +0300
+++ b/dmeval.c	Thu May 09 08:28:39 2013 +0300
@@ -4,6 +4,8 @@
 #define DM_MAX_BUF     512
 
 
+/* Operators
+ */
 const DMEvalOper dmEvalOpers[OP_NOPERS] =
 {
     { "-" , OT_UNARY },
@@ -66,12 +68,12 @@
  */
 static const DMEvalSymbol dmEvalBasicFuncs[] =
 {
-    { "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 },
+    { "sin",  SYM_FUNC, 1, func_sin, NULL, 0 },
+    { "cos",  SYM_FUNC, 1, func_cos, NULL, 0 },
+    { "clip", SYM_FUNC, 1, func_int_clip, NULL, 0 },
+    { "pow",  SYM_FUNC, 2, func_pow, NULL, 0 },
 
-    { "pi",   ID_CVAR, 0, NULL, NULL, DM_PI },
+    { "pi",   SYM_CVAR, 0, NULL, NULL, DM_PI },
 };
 
 static const int ndmEvalBasicFuncs = sizeof(dmEvalBasicFuncs) / sizeof(dmEvalBasicFuncs[0]);
@@ -122,62 +124,68 @@
 }
 
 
-static DMEvalSymbol *dmEvalContextAddSymbol(DMEvalContext *ev, const char *name, const int type)
+// Add a new symbol to the evaluation context.
+// Return pointer to newly allocated symbol struct if successful.
+// If the symbol already exists or there was a memory allocation
+// error, NULL is returned.
+static DMEvalSymbol * dmEvalContextAddSymbol(DMEvalContext *ev, const char *name, const int type)
 {
-    DMEvalSymbol *id = dmEvalContextFindSymbol(ev, name);
-    if (id != NULL)
+    DMEvalSymbol *symbol = dmEvalContextFindSymbol(ev, name);
+    if (symbol != NULL)
         return NULL;
 
     ev->symbols = dmRealloc(ev->symbols, sizeof(DMEvalSymbol) * (ev->nsymbols + 1));
     if (ev->symbols == NULL)
     {
-        dmEvalError(ev, "Could not reallocate eval symbols array (#%d). Fatal error.\n", ev->nsymbols + 1);
+        dmEvalError(ev,
+            "Could not reallocate eval symbols array (#%d). Fatal error.\n",
+            ev->nsymbols + 1);
         return NULL;
     }
     
-    id = &(ev->symbols[ev->nsymbols]);
+    symbol = &(ev->symbols[ev->nsymbols]);
     ev->nsymbols++;
 
-    id->name = dm_strdup(name);
-    id->type = type;
-    id->func = NULL;
-    id->var = NULL;
+    memset(symbol, 0, sizeof(DMEvalSymbol));
+    symbol->name = dm_strdup(name);
+    symbol->type = type;
 
-    return id;
+    return symbol;
 }
 
 
 DMEvalSymbol *dmEvalContextAddVar(DMEvalContext *ev, const char *name, DMValue *var)
 {
-    DMEvalSymbol *id = dmEvalContextAddSymbol(ev, name, ID_VAR);
-    if (id == NULL)
+    DMEvalSymbol *symbol = dmEvalContextAddSymbol(ev, name, SYM_VAR);
+    if (symbol == NULL)
         return NULL;
     
-    id->var = var;
-    return id;
+    symbol->var = var;
+    return symbol;
 }
 
 
 DMEvalSymbol *dmEvalContextAddConst(DMEvalContext *ev, const char *name, DMValue value)
 {
-    DMEvalSymbol *id = dmEvalContextAddSymbol(ev, name, ID_CVAR);
-    if (id == NULL)
+    DMEvalSymbol *symbol = dmEvalContextAddSymbol(ev, name, SYM_CVAR);
+    if (symbol == NULL)
         return NULL;
     
-    id->cvalue = value;
-    return id;
+    symbol->cvalue = value;
+    return symbol;
 }
 
 
 DMEvalSymbol *dmEvalContextAddFunc(DMEvalContext *ev, const char *name, DMValue (*func)(DMValue *), int nargs)
 {
-    DMEvalSymbol *id = dmEvalContextAddSymbol(ev, name, ID_VAR);
-    if (id == NULL)
+    DMEvalSymbol *symbol = dmEvalContextAddSymbol(ev, name, SYM_VAR);
+    if (symbol == NULL)
         return NULL;
     
-    id->func  = func;
-    id->nargs = nargs;
-    return id;
+    symbol->func  = func;
+    symbol->nargs = nargs;
+
+    return DMERR_OK;
 }
 
 
@@ -191,12 +199,15 @@
 
     for (i = 0; i < ndmEvalBasicFuncs; i++)
     {
-        const DMEvalSymbol *id = &dmEvalBasicFuncs[i];
-        DMEvalSymbol *nid = dmEvalContextAddSymbol(ev, id->name, id->type);
-        nid->nargs    = id->nargs;
-        nid->func     = id->func;
-        nid->var      = id->var;
-        nid->cvalue   = id->cvalue;
+        const DMEvalSymbol *symbol= &dmEvalBasicFuncs[i];
+        DMEvalSymbol *nsymbol = dmEvalContextAddSymbol(ev, symbol->name, symbol->type);
+        if (nsymbol != NULL)
+        {
+            nsymbol->nargs    = symbol->nargs;
+            nsymbol->func     = symbol->func;
+            nsymbol->var      = symbol->var;
+            nsymbol->cvalue   = symbol->cvalue;
+        }
     }
 
     return ev;
@@ -343,8 +354,8 @@
 static int dmEvalTokenizeExpr(DMEvalContext *ev, DMEvalNode **list, char **str, int depth)
 {
     char *c = *str;
-    char tmpStr[DM_MAX_BUF + 2];
-    int tmpStrLen = 0, argIndex;
+    char tmpStr[DM_MAX_BUF + 2], *tmp;
+    int tmpStrLen = 0, argIndex, op;
     DMEvalNode *node = NULL, *func = NULL;
     BOOL first = FALSE, decimal = FALSE;
 
@@ -355,49 +366,46 @@
     switch (ev->mode)
     {
         case PARSE_SUBEXPR_START:
-            {
-                char *tmp = c + 1;
+            tmp = c + 1;
 
-                ev->expect = PARSE_NORMAL;
+            ev->expect = PARSE_NORMAL;
 
-                if ((node = dmEvalAddNode(list, OP_SUBEXPR)) == NULL)
-                    dmEvalSetMode(ev, PARSE_ERROR);
-                else
-                if (dmEvalTokenizeExpr(ev, &(node->subexpr), &tmp, depth + 1) != 0)
-                {
-                    dmEvalError(ev, "Subexpression starting at '%s' contained errors.\n", c);
-                    dmEvalSetMode(ev, PARSE_ERROR);
-                }
+            if ((node = dmEvalAddNode(list, OP_SUBEXPR)) == NULL)
+                dmEvalSetMode(ev, PARSE_ERROR);
+            else
+            if (dmEvalTokenizeExpr(ev, &(node->subexpr), &tmp, depth + 1) != 0)
+            {
+                dmEvalError(ev, "Subexpression starting at '%s' contained errors.\n", c);
+                dmEvalSetMode(ev, PARSE_ERROR);
+            }
 
-                if (ev->mode != PARSE_ERROR)
-                {
-                    dmEvalSetMode(ev, PARSE_START);
-                    ev->expect = PARSE_OPER | PARSE_SUBEXPR_END;
-                    c = tmp;
-                }
+            if (ev->mode != PARSE_ERROR)
+            {
+                dmEvalSetMode(ev, PARSE_START);
+                ev->expect = PARSE_OPER | PARSE_SUBEXPR_END;
+                c = tmp;
             }
             break;
 
         case PARSE_ARGS:
+            tmp = c + 1;
+            
+            for (argIndex = 0; argIndex < func->symbol->nargs; argIndex++)
             {
-                char *tmp = c + 1;
-                for (argIndex = 0; argIndex < func->id->nargs; argIndex++)
+                if (dmEvalTokenizeExpr(ev, &(func->args[argIndex]), &tmp, depth + 1) != 0)
                 {
-                    if (dmEvalTokenizeExpr(ev, &(func->args[argIndex]), &tmp, depth + 1) != 0)
-                    {
-                        dmEvalError(ev, "Function argument subexpression starting at '%s' contained errors.\n", c);
-                        dmEvalSetMode(ev, PARSE_ERROR);
-                    }
+                    dmEvalError(ev, "Function argument subexpression starting at '%s' contained errors.\n", c);
+                    dmEvalSetMode(ev, PARSE_ERROR);
                 }
+            }
 
-                func = NULL;
+            func = NULL;
 
-                if (ev->mode != PARSE_ERROR)
-                {
-                    dmEvalSetMode(ev, PARSE_START);
-                    ev->expect = PARSE_OPER | PARSE_END;
-                    c = tmp;
-                }
+            if (ev->mode != PARSE_ERROR)
+            {
+                dmEvalSetMode(ev, PARSE_START);
+                ev->expect = PARSE_OPER | PARSE_END;
+                c = tmp;
             }
             break;
 
@@ -492,7 +500,7 @@
                 {
                     tmpStr[tmpStrLen] = 0;
 
-                    if ((node = dmEvalAddNode(list, OP_CONST)) == NULL)
+                    if ((node = dmEvalAddNode(list, OP_VALUE)) == NULL)
                     {
                         dmEvalSetMode(ev, PARSE_ERROR);
                     }
@@ -530,61 +538,59 @@
             break;
 
         case PARSE_OPER:
-            {
-                int op = OP_INVALID;
-
-                switch (*c)
-                {
-                    case '+': op = OP_ADD; c++; break;
-                    case '-': op = OP_SUB; c++; break;
-                    case '*': op = OP_MUL; c++; break;
-                    case '/': op = OP_DIV; c++; break;
-                    case '%': op = OP_MOD; c++; break;
-                    case '&': op = OP_BIT_AND; c++; break;
-                    case '^': op = OP_BIT_XOR; c++; break;
-                    case '|': op = OP_BIT_OR; c++; break;
+            op = OP_INVALID;
 
-                    case '>':
-                        if (c[1] == '>')
-                        {
-                            c += 2;
-                            op = OP_BIT_RSHIFT;
-                        }
-                        else
-                        {
-                            op = (c[1] == '=') ? OP_GT_EQ : OP_GT;
-                            c++;
-                        }
-                        break;
-                        
-                    case '<':
-                        if (c[1] == '<')
-                        {
-                            c += 2;
-                            op = OP_BIT_LSHIFT;
-                        }
-                        else
-                        {
-                            op = (c[1] == '=') ? OP_LT_EQ : OP_LT;
-                            c++;
-                        }
-                        break;
+            switch (*c)
+            {
+                case '+': op = OP_ADD; c++; break;
+                case '-': op = OP_SUB; c++; break;
+                case '*': op = OP_MUL; c++; break;
+                case '/': op = OP_DIV; c++; break;
+                case '%': op = OP_MOD; c++; break;
+                case '&': op = OP_BIT_AND; c++; break;
+                case '^': op = OP_BIT_XOR; c++; break;
+                case '|': op = OP_BIT_OR; c++; break;
 
-                    default:
-                        dmEvalError(ev, "Unknown operator '%c' at %s\n", *c, c);
-                        dmEvalSetMode(ev, PARSE_ERROR);
-                }
-
-                if (op != OP_INVALID)
-                {
-                    if ((node = dmEvalAddNode(list, op)) != NULL)
+                case '>':
+                    if (c[1] == '>')
                     {
-                        ev->expect = PARSE_NORMAL | PARSE_OPER_UNARY;
-                        dmEvalSetMode(ev, PARSE_START);
+                        c += 2;
+                        op = OP_BIT_RSHIFT;
                     }
                     else
-                        dmEvalSetMode(ev, PARSE_ERROR);
+                    {
+                        op = (c[1] == '=') ? OP_GT_EQ : OP_GT;
+                        c++;
+                    }
+                    break;
+                    
+                case '<':
+                    if (c[1] == '<')
+                    {
+                        c += 2;
+                        op = OP_BIT_LSHIFT;
+                    }
+                    else
+                    {
+                        op = (c[1] == '=') ? OP_LT_EQ : OP_LT;
+                        c++;
+                    }
+                    break;
+
+                default:
+                    dmEvalError(ev, "Unknown operator '%c' at %s\n", *c, c);
+                    dmEvalSetMode(ev, PARSE_ERROR);
+            }
+
+            if (op != OP_INVALID)
+            {
+                if ((node = dmEvalAddNode(list, op)) != NULL)
+                {
+                    ev->expect = PARSE_NORMAL | PARSE_OPER_UNARY;
+                    dmEvalSetMode(ev, PARSE_START);
                 }
+                else
+                    dmEvalSetMode(ev, PARSE_ERROR);
             }
             break;
 
@@ -608,13 +614,13 @@
             else
             {
                 tmpStr[tmpStrLen] = 0;
-                DMEvalSymbol *id = dmEvalContextFindSymbol(ev, tmpStr);
-                if (id != NULL)
+                DMEvalSymbol *symbol = dmEvalContextFindSymbol(ev, tmpStr);
+                if (symbol != NULL)
                 {
-                    if ((node = dmEvalAddNode(list, id->type == ID_FUNC ? OP_FUNC : OP_VAR)) != NULL)
+                    if ((node = dmEvalAddNode(list, symbol->type == SYM_FUNC ? OP_FUNC : OP_VAR)) != NULL)
                     {
-                        node->id = id;
-                        if (id->type == ID_FUNC)
+                        node->symbol = symbol;
+                        if (symbol->type == SYM_FUNC)
                         {
                             func = node;
                             ev->expect = PARSE_ARGS;
@@ -658,143 +664,96 @@
 
 
 
-
-
-static int dmEvalGet(DMEvalContext *ev, const DMEvalNode *node, DMValue *result)
+BOOL dmEvalTreeExecute(DMEvalContext *ev, DMEvalNode *node, DMValue *presult)
 {
+    DMValue val1, val2;
+
     if (node == NULL)
-        return -32;
-    
+        return FALSE;
+
     switch (node->op)
     {
-        case OP_VAR:
-            if (node->id->type == ID_VAR)
-                *result = *(node->id->var);
-            else
-                *result = node->id->cvalue;
-            break;
-
-        case OP_CONST:
-            *result = node->val;
-            break;
-
-        case OP_SUBEXPR:
-            return dmEvalTreeExecute(ev, node->subexpr, result);
+        case OP_VALUE:
+            *presult = node->val;
+            return TRUE;
         
         case OP_FUNC:
+            return TRUE;
+        
+        case OP_SUBEXPR:
+            return dmEvalTreeExecute(ev, node->subexpr, presult);
+    
+        // Binary operators
+        case OP_BIT_LSHIFT:
+        case OP_BIT_RSHIFT:
+        
+        case OP_BIT_AND:
+        case OP_BIT_XOR:
+        case OP_BIT_OR:
+
+        case OP_ADD:
+        case OP_SUB:
+        case OP_MUL:
+        case OP_DIV:
+        case OP_MOD:
+            if (!dmEvalTreeExecute(ev, node->left, &val1) ||
+                !dmEvalTreeExecute(ev, node->right, &val2))
+                return FALSE;
+
+            switch (node->op)
             {
-                DMValue tmp[DM_MAX_ARGS];
-                int i;
-                for (i = 0; i < node->id->nargs; i++)
-                {
-                    if (dmEvalTreeExecute(ev, node->args[i], &tmp[i]) != 0)
-                        return -1;
-                }
-                
-                *result = node->id->func(tmp);
-            }
-            break;
-
-        default:
-            return -16;
-    }
-
-    return 0;
-}
+                case OP_DIV:
+                    if (val2 == 0)
+                    {
+                        dmEvalError(ev, "Division by zero.\n");
+                        return FALSE;
+                    }
+                    *presult = val1 / val2;
+                    break;
 
 
-int dmEvalTreeExecute(DMEvalContext *ev, DMEvalNode *tree, DMValue *presult)
-{
-    DMValue result = 0;
-    DMEvalNode *node = tree;
-
-    while (node != NULL)
-    {
-        DMValue tmp = 0;
-
-        switch (node->op)
-        {
-            case OP_BIT_LSHIFT:
-            case OP_BIT_RSHIFT:
-            
-            case OP_BIT_AND:
-            case OP_BIT_XOR:
-            case OP_BIT_OR:
+                case OP_MOD:
+                    if (val2 == 0)
+                    {
+                        dmEvalError(ev, "Division by zero.\n");
+                        return FALSE;
+                    }
+                    *presult = DMCONVTYPE val1 % DMCONVTYPE val2;
+                    break;
 
-            case OP_MUL:
-            case OP_DIV:
-            case OP_MOD:
-                if (dmEvalGet(ev, node->next, &tmp) != 0)
-                    return -6;
-                
-                switch (node->op)
-                {
-                    case OP_DIV:
-                        if (tmp == 0)
-                        {
-                            dmEvalError(ev, "Division by zero.\n");
-                            return -1;
-                        }
-                        result /= tmp;
-                        break;
+                case OP_BIT_LSHIFT:
+                    if (val2 > 31)
+                        dmEvalError(ev, "Left shift count >= width of type (%d << %d)\n", val1, val2);
+                    *presult = DMCONVTYPE val1 << DMCONVTYPE val2; break;
 
-                    case OP_MUL:     result  *= tmp; break;
-
-                    case OP_MOD:
-                        if (tmp == 0)
-                        {
-                            dmEvalError(ev, "Division by zero.\n");
-                            return -1;
-                        }
-                        result = DMCONVTYPE result % DMCONVTYPE tmp;
-                        break;
+                case OP_BIT_RSHIFT:
+                    if (val2 > 31)
+                        dmEvalError(ev, "Right shift count >= width of type (%d >> %d)\n", val1, val2);
+                    *presult = DMCONVTYPE val1 >> DMCONVTYPE val2; break;
 
-                    case OP_BIT_LSHIFT:
-                        if (tmp > 31)
-                            dmEvalError(ev, "Left shift count >= width of type");
-                        result = DMCONVTYPE result << DMCONVTYPE tmp; break;
-
-                    case OP_BIT_RSHIFT:
-                        if (tmp > 31)
-                            dmEvalError(ev, "Right shift count >= width of type");
-                        result = DMCONVTYPE result >> DMCONVTYPE tmp; break;
+                case OP_MUL     : *presult = val1 * val2; break;
+                case OP_ADD     : *presult = val1 + val2; break;
+                case OP_SUB     : *presult = val1 - val2; break;
+                case OP_BIT_AND : *presult = DMCONVTYPE val1 & DMCONVTYPE val2; break;
+                case OP_BIT_OR  : *presult = DMCONVTYPE val1 | DMCONVTYPE val2; break;
+                case OP_BIT_XOR : *presult = DMCONVTYPE val1 ^ DMCONVTYPE val2; break;
+            }
+            return TRUE;
 
-                    case OP_BIT_AND:     result = DMCONVTYPE result & DMCONVTYPE tmp; break;
-                    case OP_BIT_OR:      result = DMCONVTYPE result | DMCONVTYPE tmp; break;
-                    case OP_BIT_XOR:     result = DMCONVTYPE result ^ DMCONVTYPE tmp; break;
-                }
-                
-                node = node->next;
-                break;
-            
-            case OP_ADD:
-            case OP_SUB:
-            case OP_SUB_UNARY:
-            case OP_BIT_COMPLEMENT:
-                if (dmEvalGet(ev, node->next, &tmp) != 0)
-                    return -6;
-                
-                switch (node->op)
-                {
-                    case OP_ADD: result += tmp; break;
-                    case OP_SUB: result -= tmp; break;
-                    case OP_SUB_UNARY: result -= tmp; break;
-                    case OP_BIT_COMPLEMENT: result = DMCONVTYPE ~(DMCONVTYPE tmp); break;
-                }
+        // Unary operators
+        case OP_SUB_UNARY:
+        case OP_BIT_COMPLEMENT:
+/*
+            switch (node->op)
+            {
+                case OP_SUB_UNARY: *presult -= tmp; break;
+                case OP_BIT_COMPLEMENT: *presult = DMCONVTYPE ~(DMCONVTYPE tmp); break;
+            }
+*/
+            return TRUE;
 
-                node = node->next;
-                break;
-
-            default:
-                if (dmEvalGet(ev, node, &result) != 0)
-                {
-                    dmEvalError(ev, "Invalid opcode %d in node %p.\n", node->op, node);
-                    return -4;
-                }
-        }
-        node = node->next;
+        default:
+            dmEvalError(ev, "Invalid opcode %d in node %p.\n", node->op, node);
+            return FALSE;
     }
-
-    *presult = result;
-    return 0;
 }
--- a/dmeval.h	Thu May 09 06:36:54 2013 +0300
+++ b/dmeval.h	Thu May 09 08:28:39 2013 +0300
@@ -36,7 +36,7 @@
     // Special ops
     OP_FUNC,
     OP_VAR,
-    OP_CONST,
+    OP_VALUE,
     OP_SUBEXPR,
 
     // Total number of operators
@@ -65,32 +65,34 @@
 
 enum
 {
-    ID_FUNC,
-    ID_VAR,
-    ID_CVAR,
+    SYM_FUNC,
+    SYM_VAR,
+    SYM_CVAR,
 } DMEvalSymbolType;
 
 
 typedef struct
 {
-    char *name;
-    int type;
-    int nargs;
+    char *name;     // Name of the symbol
+    int type;       // Type (SYM_*)
+    int nargs;      // Number of arguments, if SYM_FUNC
+
     DMValue (*func)(DMValue arg[DM_MAX_ARGS]);
-    DMValue *var, cvalue;
+
+    DMValue *var;   // Pointer to variable value if SYM_VAR
+    DMValue cvalue; // Const value, if SYM_CVAR
 } DMEvalSymbol;
 
 
 typedef struct DMEvalNode
 {
-    BOOL ok;
-    int op;
-    DMValue val;
-    DMEvalSymbol *id;
+    int op;               // Operator/token type
+    DMValue val;          // Value, if immediate constant 
+    DMEvalSymbol *symbol; // Symbol pointer, if function/variable/constvar
 
-    struct DMEvalNode *args[DM_MAX_ARGS];
+    struct DMEvalNode *args[DM_MAX_ARGS]; // Arguments, if function
 
-    struct DMEvalNode *subexpr, *next, *prev;
+    struct DMEvalNode *subexpr, *left, *right, *next, *prev;
 } DMEvalNode;