From a7a5734ef0e3bfcb1c2670baad973de2d3477433 Mon Sep 17 00:00:00 2001 From: erg Date: Thu, 2 Jul 2009 14:59:04 +0000 Subject: [PATCH] Add # and in operators for arrays, forr statement for reverse transversal, and array unset function. Add split function as in awk. --- lib/expr/excc.c | 34 +++++++++- lib/expr/exdata.c | 4 ++ lib/expr/exeval.c | 158 +++++++++++++++++++++++++++++++++++++++++++++ lib/expr/exgram.h | 54 +++++++++++++++- lib/expr/exlib.h | 6 ++ lib/expr/exparse.y | 81 ++++++++++++++++++++--- lib/expr/extoken.c | 12 ++++ 7 files changed, 338 insertions(+), 11 deletions(-) diff --git a/lib/expr/excc.c b/lib/expr/excc.c index d5759cf19..9a8fc6fd1 100644 --- a/lib/expr/excc.c +++ b/lib/expr/excc.c @@ -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: diff --git a/lib/expr/exdata.c b/lib/expr/exdata.c index dc966772b..0a8f5634d 100644 --- a/lib/expr/exdata.c +++ b/lib/expr/exdata.c @@ -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) diff --git a/lib/expr/exeval.c b/lib/expr/exeval.c index 307be7ae8..0d9bef8e1 100644 --- a/lib/expr/exeval.c +++ b/lib/expr/exeval.c @@ -32,6 +32,7 @@ #include "exlib.h" #include "exop.h" #include +#include #include #ifdef WIN32 #include @@ -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 = diff --git a/lib/expr/exgram.h b/lib/expr/exgram.h index fc590d1e1..3fd2f29ef 100644 --- a/lib/expr/exgram.h +++ b/lib/expr/exgram.h @@ -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. diff --git a/lib/expr/exlib.h b/lib/expr/exlib.h index 3dbdb416e..cc7c3219a 100644 --- a/lib/expr/exlib.h +++ b/lib/expr/exlib.h @@ -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 */ \ diff --git a/lib/expr/exparse.y b/lib/expr/exparse.y index ab4481001..54124e705 100644 --- a/lib/expr/exparse.y +++ b/lib/expr/exparse.y @@ -78,9 +78,11 @@ %token ELSE %token EXIT %token FOR +%token FORR %token FUNCTION %token GSUB %token ITERATE +%token ITERATER %token ID %token IF %token LABEL @@ -96,12 +98,14 @@ %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 @@ -132,11 +136,11 @@ %binary EQ NE %binary '<' '>' LE GE %left LS RS -%left '+' '-' +%left '+' '-' IN %left '*' '/' '%' -%right '!' '~' UNARY +%right '!' '~' '#' UNARY %right INC DEC -%right CAST +%right CAST %left '(' %type statement statement_list arg_list @@ -147,13 +151,14 @@ %type formals formal_list formal_item %type members %type ID LABEL NAME -%type CONSTANT ARRAY FUNCTION DECLARE -%type EXIT PRINT PRINTF QUERY +%type CONSTANT ARRAY FUNCTION DECLARE +%type EXIT PRINT PRINTF QUERY %type RAND SRAND -%type SPRINTF GSUB SUB SUBSTR PROCEDURE name dcl_name -%type IF WHILE FOR -%type BREAK CONTINUE print member -%type RETURN DYNAMIC SWITCH +%type SPRINTF GSUB SUB SPLIT +%type SUBSTR PROCEDURE name dcl_name +%type IF WHILE FOR FORR +%type BREAK CONTINUE print member +%type RETURN DYNAMIC SWITCH UNSET %type SCANF SSCANF scan %type FLOATING %type 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; diff --git a/lib/expr/extoken.c b/lib/expr/extoken.c index ace4b640f..b603ec92c 100644 --- a/lib/expr/extoken.c +++ b/lib/expr/extoken.c @@ -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; -- 2.40.0