]> granicus.if.org Git - graphviz/commitdiff
Add # and in operators for arrays, forr statement for reverse transversal, and
authorerg <devnull@localhost>
Thu, 2 Jul 2009 14:59:04 +0000 (14:59 +0000)
committererg <devnull@localhost>
Thu, 2 Jul 2009 14:59:04 +0000 (14:59 +0000)
array unset function.
Add split function as in awk.

lib/expr/excc.c
lib/expr/exdata.c
lib/expr/exeval.c
lib/expr/exgram.h
lib/expr/exlib.h
lib/expr/exparse.y
lib/expr/extoken.c

index d5759cf192dccbd50d83455c0915160cc606693b..9a8fc6fd187752df9f681b8e83fd0e265616a0aa 100644 (file)
@@ -264,6 +264,10 @@ static void gen(Excc_t * cc, register Exnode_t * expr)
        }
        sfprintf(cc->ccdisc->text, ")");
        return;
+    case IN:
+        gen(cc, expr->data.variable.index);
+       sfprintf(cc->ccdisc->text, " in %s", expr->data.variable.symbol->name);
+       return;
     case IF:
        sfprintf(cc->ccdisc->text, "if (");
        gen(cc, x);
@@ -276,7 +280,11 @@ static void gen(Excc_t * cc, register Exnode_t * expr)
        sfprintf(cc->ccdisc->text, "}\n");
        return;
     case FOR:
-       sfprintf(cc->ccdisc->text, "for (;");
+    case FORR:
+       if (expr->op == FOR)
+               sfprintf(cc->ccdisc->text, "for (;");
+       else
+               sfprintf(cc->ccdisc->text, "forr (;");
        gen(cc, x);
        sfprintf(cc->ccdisc->text, ");");
        if (expr->data.operand.left) {
@@ -335,6 +343,16 @@ static void gen(Excc_t * cc, register Exnode_t * expr)
     case SCANF:
        scan(cc, expr);
        return;
+    case SPLIT:
+       sfprintf(cc->ccdisc->text, "split (");
+        gen(cc, expr->data.split.string);
+       sfprintf(cc->ccdisc->text, ", %s", expr->data.split.array->name);
+        if (expr->data.split.seps) {
+         sfprintf(cc->ccdisc->text, ",");
+          gen(cc, expr->data.split.seps);
+        }
+       sfprintf(cc->ccdisc->text, ")");
+       return;
     case SWITCH:
        t = x->type;
        sfprintf(cc->ccdisc->text, "{ %s %stmp_%d = ", extype(t), cc->id,
@@ -391,6 +409,14 @@ static void gen(Excc_t * cc, register Exnode_t * expr)
        }
        sfprintf(cc->ccdisc->text, "}");
        return;
+    case UNSET:
+       sfprintf(cc->ccdisc->text, "unset(%s", expr->data.variable.symbol->name);
+        if (expr->data.variable.index) {
+         sfprintf(cc->ccdisc->text, ",");
+          gen(cc, expr->data.variable.index);
+        }
+       sfprintf(cc->ccdisc->text, ")");
+       return;
     case WHILE:
        sfprintf(cc->ccdisc->text, "while (");
        gen(cc, x);
@@ -399,6 +425,10 @@ static void gen(Excc_t * cc, register Exnode_t * expr)
            gen(cc, expr->data.operand.right);
        sfprintf(cc->ccdisc->text, "}");
        return;
+    case '#':
+       sfprintf(cc->ccdisc->text, "# %s", 
+           expr->data.variable.symbol->name);
+       return;
     case '=':
        sfprintf(cc->ccdisc->text, "(%s%s=", x->data.variable.symbol->name,
                 expr->subop == '=' ? "" : exopname(expr->subop));
@@ -410,6 +440,7 @@ static void gen(Excc_t * cc, register Exnode_t * expr)
            if (!(x = expr->data.operand.right))
                switch (cc->lastop = expr->data.operand.left->op) {
                case FOR:
+               case FORR:
                case IF:
                case PRINTF:
                case PRINT:
@@ -428,6 +459,7 @@ static void gen(Excc_t * cc, register Exnode_t * expr)
            case ';':
                continue;
            case FOR:
+           case FORR:
            case IF:
            case PRINTF:
            case PRINT:
index dc966772b7df06a1fd38e0afa899cd583c385d5b..0a8f5634d886ec93848788d3f78ab39dcf463d6b 100644 (file)
@@ -45,9 +45,11 @@ Exid_t exbuiltin[] = {
     EX_ID("else", ELSE, ELSE, 0, 0),
     EX_ID("exit", EXIT, EXIT, INTEGER, 0),
     EX_ID("for", FOR, FOR, 0, 0),
+    EX_ID("forr", FORR, FORR, 0, 0),
     EX_ID("float", DECLARE, FLOATING, FLOATING, 0),
     EX_ID("gsub", GSUB, GSUB, STRING, 0),
     EX_ID("if", IF, IF, 0, 0),
+    EX_ID("in", IN, IN, 0, 0),
     EX_ID("int", DECLARE, INTEGER, INTEGER, 0),
     EX_ID("long", DECLARE, INTEGER, INTEGER, 0),
     EX_ID("print", PRINT, PRINT, INTEGER, 0),
@@ -57,6 +59,7 @@ Exid_t exbuiltin[] = {
     EX_ID("return", RETURN, RETURN, 0, 0),
     EX_ID("scanf", SCANF, SCANF, INTEGER, 0),
     EX_ID("sscanf", SSCANF, SSCANF, INTEGER, 0),
+    EX_ID("split", SPLIT, SPLIT, INTEGER, 0),
     EX_ID("sprintf", SPRINTF, SPRINTF, STRING, 0),
     EX_ID("srand", SRAND, SRAND, INTEGER, 0),
     EX_ID("sub", SUB, SUB, STRING, 0),
@@ -64,6 +67,7 @@ Exid_t exbuiltin[] = {
     EX_ID("switch", SWITCH, SWITCH, 0, 0),
     EX_ID("unsigned", DECLARE, UNSIGNED, UNSIGNED, 0),
     EX_ID("void", DECLARE, VOIDTYPE, 0, 0),
+    EX_ID("unset", UNSET, UNSET, 0, 0),
     EX_ID("while", WHILE, WHILE, 0, 0),
     EX_ID({0}, 0, 0, 0, 0)
 
index 307be7ae89dca86c28dce5753251de847327ee8d..0d9bef8e18d04a0f9ebe254624c2913d7dd84c58 100644 (file)
@@ -32,6 +32,7 @@
 #include "exlib.h"
 #include "exop.h"
 #include <string.h>
+#include <assert.h>
 #include <time.h>
 #ifdef WIN32
 #include <stdlib.h>
@@ -74,6 +75,51 @@ static char *lexname(int op, int subop)
     return b;
 }
 
+/* evaldyn:
+ * Evaluate item from array given key.
+ * Returns 1 if item existed, zero otherwise
+ * 
+ */
+static int
+evaldyn (Expr_t * ex, register Exnode_t * expr, void *env, int delete)
+{
+    Exassoc_t *b;
+    Extype_t v;
+    char buf[32];
+    Extype_t key;
+    char *keyname;
+
+    v = eval(ex, expr->data.variable.index, env);
+    if (expr->data.variable.symbol->index_type == INTEGER) {
+       if (!(b = (Exassoc_t *) dtmatch((Dt_t *) expr->data.variable.
+               symbol->local.pointer, &v))) {
+           return 0;
+       }
+    } 
+    else {
+       int type = expr->data.variable.index->type;
+       if (type != STRING) {
+               if (!BUILTIN(type)) {
+                   key = (*ex->disc->keyf) (ex, v, type, ex->disc);
+               } else
+                   key.integer = v.integer;
+               sfsprintf(buf, sizeof(buf), "0x%I*x", sizeof(v.integer),
+                         key.integer);
+               keyname = buf;
+       } else
+               keyname = v.string;
+       if (!(b = (Exassoc_t *) dtmatch((Dt_t *) expr->data.variable.
+               symbol->local.pointer, keyname))) {
+           return 0;
+       }
+    }
+    if (delete) {
+       dtdelete ((Dt_t*)expr->data.variable.symbol->local.pointer, b);
+       free (b);    
+    }
+    return 1;
+}
+
 /*
  * return dynamic (associative array) variable value
  * assoc will point to the associative array bucket
@@ -606,6 +652,57 @@ replace(Sfio_t * s, char *base, register char *repl, int ng, int *sub)
 
 #define MCNT(s) (sizeof(s)/(2*sizeof(int)))
 
+/* exsplit:
+ * tokenize string and store in array
+ * return number of tokens
+ */
+Extype_t
+exsplit(Expr_t * ex, register Exnode_t * expr, void *env)
+{
+    Extype_t v;
+    char *str;
+    char *seps;
+    char *tok;
+    Exassoc_t* b;
+    size_t sz;
+    Sfio_t* fp = ex->tmp;
+    int cnt = 0;
+    Dt_t* arr = (Dt_t*)expr->data.split.array->local.pointer;
+
+    str = (eval(ex, expr->data.split.string, env)).string;
+    if (expr->data.split.seps)
+       seps = (eval(ex, expr->data.string.pat, env)).string;
+    else
+       seps = " \t\n";
+
+    v.integer = 0;
+    while (*str) {
+       sz = strspn (str, seps);
+       str += sz;
+       if (*str == '\0')
+           break;
+       sz = strcspn (str, seps);
+       assert (sz);
+       sfwrite (fp, str, sz);
+       tok = vmstrdup(ex->vc, sfstruse(fp));
+
+       if (!(b = (Exassoc_t *) dtmatch(arr, &v))) {
+           if (!(b = newof(0, Exassoc_t, 1, 0)))
+               exerror("out of space [assoc]");
+           b->key = v;
+           dtinsert(arr, b);
+       }
+       b->value.string = tok;
+
+       v.integer++;
+       str += sz;
+    }
+
+    v.integer = cnt;
+    return v;
+    
+}
+
 /* exsub:
  * return string after pattern substitution
  */
@@ -854,6 +951,8 @@ static Extype_t eval(Expr_t * ex, register Exnode_t * expr, void *env)
        return r;
     case DYNAMIC:
        return getdyn(ex, expr, env, &assoc);
+    case SPLIT:
+       return exsplit(ex, expr, env);
     case GSUB:
        return exsub(ex, expr, env, 1);
     case SUB:
@@ -1009,6 +1108,65 @@ static Extype_t eval(Expr_t * ex, register Exnode_t * expr, void *env)
            }
        }
        return v;
+    case ITERATER:
+       v.integer = 0;
+       if (expr->data.generate.array->op == DYNAMIC) {
+           n = expr->data.generate.index->type == STRING;
+           for (assoc =
+                (Exassoc_t *) dtlast((Dt_t *) expr->data.generate.array->
+                                      data.variable.symbol->local.
+                                      pointer); assoc;
+                assoc =
+                (Exassoc_t *) dtprev((Dt_t *) expr->data.generate.array->
+                                     data.variable.symbol->local.pointer,
+                                     assoc)) {
+               v.integer++;
+               if (n)
+                   expr->data.generate.index->value->data.constant.value.
+                       string = assoc->name;
+               else
+                   expr->data.generate.index->value->data.constant.value =
+                       assoc->key;
+               eval(ex, expr->data.generate.statement, env);
+               if (ex->loopcount > 0
+                   && (--ex->loopcount > 0 || ex->loopop != CONTINUE)) {
+                   v.integer = 0;
+                   break;
+               }
+           }
+       } else {
+           r = (*ex->disc->getf) (ex, expr,
+                                  expr->data.generate.array->data.
+                                  variable.symbol,
+                                  expr->data.generate.array->data.
+                                  variable.reference, env, 0, ex->disc);
+           for (v.integer = r.integer-1; 0 <= v.integer; v.integer--) {
+               expr->data.generate.index->value->data.constant.value.
+                   integer = v.integer;
+               eval(ex, expr->data.generate.statement, env);
+               if (ex->loopcount > 0
+                   && (--ex->loopcount > 0 || ex->loopop != CONTINUE)) {
+                   v.integer = 0;
+                   break;
+               }
+           }
+       }
+       return v;
+    case '#':
+       v.integer = dtsize ((Dt_t*)expr->data.variable.symbol->local.pointer);
+       return v;
+    case IN:
+       v.integer = evaldyn (ex, expr, env, 0);
+       return v;
+    case UNSET:
+       if (expr->data.variable.index) {
+           v.integer = evaldyn (ex, expr, env, 1);
+       }
+       else {
+           dtclear ((Dt_t*)expr->data.variable.symbol->local.pointer);
+           v.integer = 0;
+       }
+       return v;
     case CALL:
        x = expr->data.call.args;
        for (n = 0, a =
index fc590d1e138024522accfaac5cccf44b9c15713f..3fd2f29ef25869c6d3e25f3ea7e3c983a64b9939 100644 (file)
@@ -104,7 +104,23 @@ extern "C" {
                x->data.variable.symbol->local.pointer = 0;
            }
            break;
+       case '#':
+           if (x->data.variable.symbol->local.pointer) {
+               dtclose((Dt_t *) x->data.variable.symbol->local.pointer);
+               x->data.variable.symbol->local.pointer = 0;
+           }
+           break;
+       case IN:
+       case UNSET:
+           if (x->data.variable.index)
+               exfreenode(p, x->data.variable.index);
+           if (x->data.variable.symbol->local.pointer) {
+               dtclose((Dt_t *) x->data.variable.symbol->local.pointer);
+               x->data.variable.symbol->local.pointer = 0;
+           }
+           break;
        case ITERATE:
+       case ITERATER:
            if (x->data.generate.statement)
                exfreenode(p, x->data.generate.statement);
            break;
@@ -115,7 +131,6 @@ extern "C" {
                vmfree(p->vm, r);
            }
            if (x->data.variable.index)
-               exfreenode(p, x->data.variable.index);
            break;
        case GSUB:
        case SUB:
@@ -125,6 +140,15 @@ extern "C" {
            if (x->data.string.repl)
                exfreenode(p, x->data.string.repl);
            break;
+       case SPLIT:
+           if (x->data.split.seps)
+               exfreenode(p, x->data.split.seps);
+           exfreenode(p, x->data.split.string);
+           if (x->data.split.array->local.pointer) {
+               dtclose((Dt_t *) x->data.split.array->local.pointer);
+               x->data.split.array->local.pointer = 0;
+           }
+           break;
        case PRINT:
            exfreenode(p, x->data.operand.left);
            break;
@@ -171,6 +195,34 @@ extern "C" {
        return left;
     }
 
+/* exnewsplit:
+ * Generate split node.
+ * Fourth argument is optional.
+ */
+    static Exnode_t *exnewsplit(Expr_t * p, Exid_t* dyn, Exnode_t * s, Exnode_t* seps) {
+       Exnode_t *ss = 0;
+
+       if (dyn->local.pointer == 0)
+               exerror("cannot use non-array %s in split", dyn->name);
+       if ((dyn->index_type > 0) && (dyn->index_type != INTEGER))
+            exerror("in split, array %s must have integer index type, not %s", 
+               dyn->name, extypename(p, s->type));
+       if (dyn->type != STRING)
+            exerror("in split, array %s entries must have string type, not %s", 
+               dyn->name, extypename(p, s->type));
+       if (s->type != STRING)
+            exerror("first argument to split must have string type, not %s", 
+               extypename(p, s->type));
+       if (seps && (seps->type != STRING))
+            exerror("third argument to split must have string type, not %s", 
+               extypename(p, seps->type));
+       ss = exnewnode(p, SPLIT, 0, INTEGER, NiL, NiL);
+       ss->data.split.array = dyn;
+       ss->data.split.string = s;
+       ss->data.split.seps = seps;
+       return ss;
+    }
+
 /* exnewsub:
  * Generate sub node.
  * Third argument is optional.
index 3dbdb416eeece377fd43329b1fd3ea549e5b1737..cc7c3219ae3523f85d1cf3c231ff6680dac24435 100644 (file)
@@ -69,6 +69,12 @@ extern "C" {
        }               generate;       /* associative array generator  */ \
        struct                                                             \
        {                                                                  \
+       Exid_t*         array;          /* array                        */ \
+       Exnode_t*       string;         /* string                       */ \
+       Exnode_t*       seps;           /* optional separators          */ \
+       }               split;          /* string split */ \
+       struct                                                             \
+       {                                                                  \
        Exnode_t*       descriptor;     /* Expr_t.file index            */ \
        Print_t*        args;           /* compiler printf args         */ \
        }               print;          /* printf                       */ \
index ab4481001b016d4bffffaebbc47097e08c8906b9..54124e7052ead8854c6647b0e1d4195f972493a9 100644 (file)
 %token ELSE
 %token EXIT
 %token FOR
+%token FORR
 %token FUNCTION
 %token GSUB
 %token ITERATE
+%token ITERATER
 %token ID
 %token IF
 %token LABEL
 %token RAND
 %token RETURN
 %token SCANF
+%token SPLIT
 %token SPRINTF
 %token SRAND
 %token SSCANF
 %token SUB
 %token SUBSTR
 %token SWITCH
+%token UNSET
 %token WHILE
 
 %token F2I
 %binary        <op>    EQ      NE
 %binary        <op>    '<'     '>'     LE      GE
 %left  <op>    LS      RS
-%left  <op>    '+'     '-'
+%left  <op>    '+'     '-'     IN
 %left  <op>    '*'     '/'     '%'
-%right <op>    '!'     '~'     UNARY
+%right <op>    '!'     '~'     '#'     UNARY
 %right <op>    INC     DEC
-%right <op>    CAST
+%right <op>    CAST    
 %left  <op>    '('
 
 %type <expr>           statement       statement_list  arg_list
 %type <expr>           formals         formal_list     formal_item
 %type <reference>      members
 %type <id>             ID              LABEL           NAME
-%type <id>             CONSTANT        ARRAY   FUNCTION        DECLARE
-%type <id>             EXIT            PRINT   PRINTF          QUERY
+%type <id>             CONSTANT        ARRAY           FUNCTION        DECLARE
+%type <id>             EXIT            PRINT           PRINTF          QUERY
 %type <id>             RAND            SRAND
-%type <id>             SPRINTF         GSUB    SUB             SUBSTR  PROCEDURE       name    dcl_name
-%type <id>             IF              WHILE           FOR
-%type <id>             BREAK           CONTINUE        print member
-%type <id>             RETURN          DYNAMIC         SWITCH
+%type <id>             SPRINTF         GSUB            SUB             SPLIT
+%type <id>             SUBSTR          PROCEDURE       name            dcl_name
+%type <id>             IF              WHILE           FOR             FORR
+%type <id>             BREAK           CONTINUE        print           member
+%type <id>             RETURN          DYNAMIC         SWITCH          UNSET
 %type <id>             SCANF           SSCANF          scan
 %type <floating>       FLOATING
 %type <integer>                INTEGER         UNSIGNED        array
@@ -298,6 +303,38 @@ statement  :       '{' statement_list '}'
                        if ($3)
                                $$ = exnewnode(expr.program, ';', 1, INTEGER, $3, $$);
                }
+               |       FORR '(' variable ')' statement
+               {
+                       $$ = exnewnode(expr.program, ITERATER, 0, INTEGER, NiL, NiL);
+                       $$->data.generate.array = $3;
+                       if (!$3->data.variable.index || $3->data.variable.index->op != DYNAMIC)
+                               exerror("simple index variable expected");
+                       $$->data.generate.index = $3->data.variable.index->data.variable.symbol;
+                       if ($3->op == ID && $$->data.generate.index->type != INTEGER)
+                               exerror("integer index variable expected");
+                       exfreenode(expr.program, $3->data.variable.index);
+                       $3->data.variable.index = 0;
+                       $$->data.generate.statement = $5;
+               }
+               |       UNSET '(' DYNAMIC ')'
+               {
+                       if ($3->local.pointer == 0)
+                               exerror("cannot apply unset to non-array %s", $3->name);
+                       $$ = exnewnode(expr.program, UNSET, 0, INTEGER, NiL, NiL);
+                       $$->data.variable.symbol = $3;
+                       $$->data.variable.index = NiL;
+               }
+               |       UNSET '(' DYNAMIC ',' expr  ')'
+               {
+                       if ($3->local.pointer == 0)
+                               exerror("cannot apply unset to non-array %s", $3->name);
+                       if (($3->index_type > 0) && ($5->type != $3->index_type))
+                           exerror("%s indices must have type %s, not %s", 
+                               $3->name, extypename(expr.program, $3->index_type),extypename(expr.program, $5->type));
+                       $$ = exnewnode(expr.program, UNSET, 0, INTEGER, NiL, NiL);
+                       $$->data.variable.symbol = $3;
+                       $$->data.variable.index = $5;
+               }
                |       WHILE '(' expr ')' statement
                {
                        if (exisAssign ($3))
@@ -722,6 +759,13 @@ expr               :       '(' expr ')'
                                checkBinary(expr.program, $2, $$, 0);
                        }
                }
+               |       '#' DYNAMIC
+               {
+                       if ($2->local.pointer == 0)
+                               exerror("cannot apply '#' operator to non-array %s", $2->name);
+                       $$ = exnewnode(expr.program, '#', 0, INTEGER, NiL, NiL);
+                       $$->data.variable.symbol = $2;
+               }
                |       '~' expr
                {
                        goto iunary;
@@ -758,6 +802,14 @@ expr               :       '(' expr ')'
                {
                        $$ = exnewsubstr (expr.program, $3);
                }
+               |       SPLIT '(' expr ',' DYNAMIC ')'
+               {
+                       $$ = exnewsplit (expr.program, $5, $3, NiL);
+               }
+               |       SPLIT '(' expr ',' DYNAMIC ',' expr ')'
+               {
+                       $$ = exnewsplit (expr.program, $5, $3, $7);
+               }
                |       EXIT '(' expr ')'
                {
                        if (!INTEGRAL($3->type))
@@ -886,6 +938,17 @@ expr               :       '(' expr ')'
                        $$ = exnewnode(expr.program, $2, 0, $1->type, $1, NiL);
                        $$->subop = POS;
                }
+               |       expr IN DYNAMIC
+               {
+                       if ($3->local.pointer == 0)
+                               exerror("cannot apply IN to non-array %s", $3->name);
+                       if (($3->index_type > 0) && ($1->type != $3->index_type))
+                           exerror("%s indices must have type %s, not %s", 
+                               $3->name, extypename(expr.program, $3->index_type),extypename(expr.program, $1->type));
+                       $$ = exnewnode(expr.program, IN, 0, INTEGER, NiL, NiL);
+                       $$->data.variable.symbol = $3;
+                       $$->data.variable.index = $1;
+               }
                |       DEC variable
                {
                        goto pre;
index ace4b640f2f2e2010af7d88a7d9a9e9ad552acc4..b603ec92c28eab327f966f51798f585062cb5fcc 100644 (file)
@@ -174,12 +174,18 @@ static void trace(Expr_t * ex, int lev, char *op, int c)
     case FOR:
        s = " for";
        break;
+    case FORR:
+       s = " forr";
+       break;
     case GSUB:
        s = " gsub";
        break;
     case IF:
        s = " if";
        break;
+    case IN:
+       s = " in";
+       break;
     case PRAGMA:
        s = " pragma";
        break;
@@ -198,6 +204,9 @@ static void trace(Expr_t * ex, int lev, char *op, int c)
     case RETURN:
        s = " return";
        break;
+    case SPLIT:
+       s = " split";
+       break;
     case SPRINTF:
        s = " sprintf";
        break;
@@ -213,6 +222,9 @@ static void trace(Expr_t * ex, int lev, char *op, int c)
     case SWITCH:
        s = " switch";
        break;
+    case UNSET:
+       s = " unset";
+       break;
     case WHILE:
        s = " while";
        break;