From c19a3f5945026e8d1654195a9a92aee20b6b3df5 Mon Sep 17 00:00:00 2001 From: erg Date: Fri, 3 Jul 2009 14:35:17 +0000 Subject: [PATCH] Many new features, especially for string processing, array handling --- cmd/gvpr/gvpr.1 | 58 +++++++++++++++++++++++++++--- lib/expr/Makefile.am | 2 +- lib/expr/excc.c | 15 ++++---- lib/expr/exdata.c | 3 +- lib/expr/exeval.c | 85 +++++++++++++++++++++++++++++++++++--------- lib/expr/exgram.h | 27 +++++++------- lib/expr/exparse.y | 20 ++++++----- lib/expr/extoken.c | 5 ++- lib/gvpr/Makefile.am | 4 ++- lib/gvpr/actions.c | 74 +++++++++++++++++++++++++++++++++++++- lib/gvpr/actions.h | 1 + lib/gvpr/compile.c | 20 +++++++++++ lib/gvpr/compile.h | 9 ++--- lib/gvpr/gprdata | 4 +++ lib/gvpr/gprstate.c | 1 + lib/gvpr/gprstate.h | 1 + lib/gvpr/gvpr.c | 21 +++++++---- lib/gvpr/parse.c | 1 + 18 files changed, 286 insertions(+), 65 deletions(-) diff --git a/cmd/gvpr/gvpr.1 b/cmd/gvpr/gvpr.1 index a198c07fc..fde4f61d1 100644 --- a/cmd/gvpr/gvpr.1 +++ b/cmd/gvpr/gvpr.1 @@ -3,7 +3,7 @@ . ns . TP \\$1 .. -.TH GVPR 1 "24 April 2008" +.TH GVPR 1 "3 July 2009" .SH NAME gvpr \- graph pattern scanning and processing language .br @@ -236,6 +236,7 @@ Executable statements can be one of the following: \fBif(\fI expression \fP)\fI statement \fR[ \fBelse\fI statement \fR] \fBfor(\fI expression \fP;\fI expression \fP;\fI expression \fP)\fI statement\fP \fBfor(\fI array \fP[\fI var \fP])\fI statement\fP +\fBforr(\fI array \fP[\fI var \fP])\fI statement\fP \fBwhile(\fI expression \fP)\fI statement\fP \fBswitch(\fI expression \fP)\fI case statements\fP \fBbreak [\fI expression \fP] @@ -246,10 +247,13 @@ Executable statements can be one of the following: .ST Items in brackets are optional. .PP -In the second form of the \fBfor\fP statement, the variable \fIvar\fP +In the second form of the \fBfor\fP statement and the \fBforr\fP statement, the variable \fIvar\fP is set to each value used as an index in the specified array and then -the associated \fIstatement\fP is evaluated. Function definitions can -only appear in the \fBBEGIN\fP clause. +the associated \fIstatement\fP is evaluated. For numeric and string indices, the indices are +returned in increasing (decreasing) numeric or lexicographic order for +\fBfor\fP (\fBforr\fP, respectively). This can be used for sorting. +.PP +Function definitions can only appear in the \fBBEGIN\fP clause. .PP Expressions include the usual C expressions. String comparisons using \fB==\fP and \fB!=\fP @@ -679,6 +683,27 @@ The values are stored in the addresses following \fIfmt\fP, addresses having the form \fB&\fP\fIv\fP, where \fIv\fP is some declared variable of the correct type. Returns the number of items successfully scanned. +.TP +\fBsplit\fP(\fIs\fP : \fBstring\fP, \fIarr\fP : \fBarray\fP, \fIseps\fP : \fBstring\fP) : \fBint\fP +.TP +\fBsplit\fP(\fIs\fP : \fBstring\fP, \fIarr\fP : \fBarray\fP) : \fBint\fP +.TP +\fBtokens\fP(\fIs\fP : \fBstring\fP, \fIarr\fP : \fBarray\fP, \fIseps\fP : \fBstring\fP) : \fBint\fP +.TP +\fBtokens\fP(\fIs\fP : \fBstring\fP, \fIarr\fP : \fBarray\fP) : \fBint\fP +The \fBsplit\fP function breaks the string \fIs\fP into fields, while the \fBtokens\fP function +breaks the string into tokens. +A field consists of all non-separator characters between two separator characters or the beginning or +end of the string. Thus, a field may be the empty string. A +token is a maximal, non-empty substring not containing a separator character. +The separator characters are those given in the \fIseps\fP argument. +If \fIseps\fP is not provided, the default value is " \\t\\n". +The functions return the number of fields or tokens. +.sp +The fields and tokens are stored in the argument array. The array must be \fBstring\fP-valued and, +if an index type is specified, it must be \fBint\fP. The entries are indexed by consecutive +integers, starting at 0. Any values already stored in the array will be either overwritten, or +still be present after the function returns. .SS "I/O" .TP \fBprint\fP(\fI...\fP) : \fBvoid\fP @@ -763,6 +788,20 @@ returns the minimum of \fIy\fP and \fIx\fP. .TP \fBMAX\fP(\fIy\fP : \fBdouble\fP, \fIx\fP : \fBdouble\fP) : \fBdouble\fP returns the maximum of \fIy\fP and \fIx\fP. +.SS "Associative Arrays" +.TP +\fB#\fP \fIarr\fP : \fBint\fP +returns the number of elements in the array \fIarr\fP. +.TP +\fIidx\fP \fBin\fP \fIarr\fP : \fBint\fP +returns 1 if a value has been set for index \fIidx\fP in the array \fIarr\fP. +It returns 0 otherwise. +.TP +\fBunset\fP(\fIv\fP : \fBarray\fP, \Iidx\P) : \fBint\fP +removes the item indexed by \fIidx\fP. It returns 1 if the item existed, 0 otherwise. +.TP +\fBunset\fP(\fIv\fP : \fBarray\fP) : \fBvoid\fP +re-initializes the array. .SS "Miscellaneous" .TP \fBexit\fP(\fIv\fP : \fBint\fP) : \fBvoid\fP @@ -787,6 +826,12 @@ sets a seed for the random number generator. The optional argument gives the seed; if it is omitted, the current time is used. The previous seed value is returned. \fBsrand\fP should be called before any calls to \fBrand\fP. +.TP +\fBcolorx\fP(\fIcolor\fP : \fBstring\fP, \fIfmt\fP : \fBstring\fP) : \fBstring\fP +translates a color from one format to another. The \fIcolor\fP argument should be +a color in one of the recognized string representations. The \fIfmt\fP value should +be one of "RGB", "RGBA", "HSV", "HSVA", or "CMYK". +An empty string is returned on error. .SH "BUILT\(hyIN VARIABLES" .PP .B gvpr @@ -830,6 +875,11 @@ depth\(hyfirst traversal of the graph (cf. \fB$tvtype\fP below). The default value is \fBNULL\fP for each input graph. .TP +\fB$tvedge\fP : \fBedge_t\fP +For BFS and DFS traversals, this is set to the edge used to arrive at the +current node or edge. At the beginning of a traversal, or for other traversal +types, the value is \fBNULL\fP. +.TP \fB$tvtype\fP : \fBtvtype_t\fP indicates how \fBgvpr\fP traverses a graph. It can only take one of the constant values with the previx "TV_" described below. diff --git a/lib/expr/Makefile.am b/lib/expr/Makefile.am index ba61ff2b0..0d90031e8 100644 --- a/lib/expr/Makefile.am +++ b/lib/expr/Makefile.am @@ -47,7 +47,7 @@ $(libexpr_C_la_OBJECTS) $(libexpr_la_OBJECTS): \ exop.h: exparse.h echo "static const char* exop[] = {" > exop.h echo " \"MINTOKEN\"," >> exop.h - $(SED) -e '1,/MINTOKEN/d' -e '/^[ ]*#[ ]*define[ ][ ]*[A-Z]/!d' -e 's/^[ ]*#[ ]*define[ ]*\([A-Z0-9_]*\).*/ "\1",/' < exparse.h >> exop.h + $(SED) -e '1,/^[ ]*#[ ]*define[ ][ ]*MINTOKEN/d' -e '/MAXTOKEN/,$$d' -e '/^[ ]*#[ ]*define[ ][ ]*[A-Z]/!d' -e 's/^[ ]*#[ ]*define[ ]*\([A-Z0-9_]*\).*/ "\1",/' < exparse.h >> exop.h echo "};" >> exop.h exparse.c: y.tab.c diff --git a/lib/expr/excc.c b/lib/expr/excc.c index 9a8fc6fd1..409f3b193 100644 --- a/lib/expr/excc.c +++ b/lib/expr/excc.c @@ -280,11 +280,7 @@ static void gen(Excc_t * cc, register Exnode_t * expr) sfprintf(cc->ccdisc->text, "}\n"); return; case FOR: - case FORR: - if (expr->op == FOR) - sfprintf(cc->ccdisc->text, "for (;"); - else - sfprintf(cc->ccdisc->text, "forr (;"); + sfprintf(cc->ccdisc->text, "for ("); gen(cc, x); sfprintf(cc->ccdisc->text, ");"); if (expr->data.operand.left) { @@ -310,6 +306,7 @@ static void gen(Excc_t * cc, register Exnode_t * expr) sfprintf(cc->ccdisc->text, "%s++", x->data.variable.symbol->name); return; case ITERATE: + case ITERATER: if (expr->op == DYNAMIC) { sfprintf(cc->ccdisc->text, "{ Exassoc_t* %stmp_%d;", cc->id, ++cc->tmp); @@ -344,7 +341,11 @@ static void gen(Excc_t * cc, register Exnode_t * expr) scan(cc, expr); return; case SPLIT: - sfprintf(cc->ccdisc->text, "split ("); + case TOKENS: + if (expr->op == SPLIT) + sfprintf(cc->ccdisc->text, "split ("); + else + sfprintf(cc->ccdisc->text, "tokens ("); gen(cc, expr->data.split.string); sfprintf(cc->ccdisc->text, ", %s", expr->data.split.array->name); if (expr->data.split.seps) { @@ -440,7 +441,6 @@ 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: @@ -459,7 +459,6 @@ 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 0a8f5634d..dbf1a4664 100644 --- a/lib/expr/exdata.c +++ b/lib/expr/exdata.c @@ -45,7 +45,7 @@ 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("forr", ITERATER, ITERATER, 0, 0), EX_ID("float", DECLARE, FLOATING, FLOATING, 0), EX_ID("gsub", GSUB, GSUB, STRING, 0), EX_ID("if", IF, IF, 0, 0), @@ -65,6 +65,7 @@ Exid_t exbuiltin[] = { EX_ID("sub", SUB, SUB, STRING, 0), EX_ID("substr", SUBSTR, SUBSTR, STRING, 0), EX_ID("switch", SWITCH, SWITCH, 0, 0), + EX_ID("tokens", TOKENS, TOKENS, INTEGER, 0), EX_ID("unsigned", DECLARE, UNSIGNED, UNSIGNED, 0), EX_ID("void", DECLARE, VOIDTYPE, 0, 0), EX_ID("unset", UNSET, UNSET, 0, 0), diff --git a/lib/expr/exeval.c b/lib/expr/exeval.c index 0d9bef8e1..6f18203e5 100644 --- a/lib/expr/exeval.c +++ b/lib/expr/exeval.c @@ -652,26 +652,86 @@ replace(Sfio_t * s, char *base, register char *repl, int ng, int *sub) #define MCNT(s) (sizeof(s)/(2*sizeof(int))) +static void +addItem (Dt_t* arr, Extype_t v, char* tok) +{ + Exassoc_t* b; + + 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; +} + /* exsplit: + * break string into possibly empty fields and store in array + * return number of fields + */ +Extype_t +exsplit(Expr_t * ex, register Exnode_t * expr, void *env) +{ + Extype_t v; + char *str; + char *seps; + char *tok; + size_t sz; + Sfio_t* fp = ex->tmp; + Dt_t* arr = (Dt_t*)expr->data.split.array->local.pointer; + int i; + + str = (eval(ex, expr->data.split.string, env)).string; + if (expr->data.split.seps) + seps = (eval(ex, expr->data.split.seps, env)).string; + else + seps = " \t\n"; + + v.integer = 0; + while (*str) { + sz = strspn (str, seps); + for (i = 0; i < sz; i++) { + addItem (arr, v, ""); + v.integer++; + } + str += sz; + if (*str == '\0') { + if (v.integer == sz) { /* only separators */ + addItem (arr, v, ""); + v.integer++; + } + break; + } + sz = strcspn (str, seps); + sfwrite (fp, str, sz); + tok = exstrdup(ex, sfstruse(fp)); + addItem (arr, v, tok); + v.integer++; + str += sz; + } + + return v; +} + +/* extoken: * tokenize string and store in array * return number of tokens */ Extype_t -exsplit(Expr_t * ex, register Exnode_t * expr, void *env) +extokens(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; + seps = (eval(ex, expr->data.split.seps, env)).string; else seps = " \t\n"; @@ -681,26 +741,17 @@ exsplit(Expr_t * ex, register Exnode_t * expr, void *env) 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; - + tok = exstrdup(ex, sfstruse(fp)); + addItem (arr, v, tok); v.integer++; str += sz; } - v.integer = cnt; return v; - } /* exsub: @@ -953,6 +1004,8 @@ static Extype_t eval(Expr_t * ex, register Exnode_t * expr, void *env) return getdyn(ex, expr, env, &assoc); case SPLIT: return exsplit(ex, expr, env); + case TOKENS: + return extokens(ex, expr, env); case GSUB: return exsub(ex, expr, env, 1); case SUB: diff --git a/lib/expr/exgram.h b/lib/expr/exgram.h index 3fd2f29ef..ea97eeeed 100644 --- a/lib/expr/exgram.h +++ b/lib/expr/exgram.h @@ -140,6 +140,7 @@ extern "C" { if (x->data.string.repl) exfreenode(p, x->data.string.repl); break; + case TOKENS: case SPLIT: if (x->data.split.seps) exfreenode(p, x->data.split.seps); @@ -196,27 +197,27 @@ extern "C" { } /* exnewsplit: - * Generate split node. - * Fourth argument is optional. + * Generate split/tokens node. + * Fifth argument is optional. */ - static Exnode_t *exnewsplit(Expr_t * p, Exid_t* dyn, Exnode_t * s, Exnode_t* seps) { + static Exnode_t *exnewsplit(Expr_t * p, int op, 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); + exerror("cannot use non-array %s in %s", dyn->name, exopname(op)); 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)); + exerror("in %s, array %s must have integer index type, not %s", + exopname(op), 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)); + exerror("in %s, array %s entries must have string type, not %s", + exopname(op), 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)); + exerror("first argument to %s must have string type, not %s", + exopname(op), 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); + exerror("third argument to %s must have string type, not %s", + exopname(op), extypename(p, seps->type)); + ss = exnewnode(p, op, 0, INTEGER, NiL, NiL); ss->data.split.array = dyn; ss->data.split.string = s; ss->data.split.seps = seps; diff --git a/lib/expr/exparse.y b/lib/expr/exparse.y index 54124e705..77ce46061 100644 --- a/lib/expr/exparse.y +++ b/lib/expr/exparse.y @@ -78,7 +78,6 @@ %token ELSE %token EXIT %token FOR -%token FORR %token FUNCTION %token GSUB %token ITERATE @@ -105,6 +104,7 @@ %token SUB %token SUBSTR %token SWITCH +%token TOKENS %token UNSET %token WHILE @@ -154,9 +154,10 @@ %type CONSTANT ARRAY FUNCTION DECLARE %type EXIT PRINT PRINTF QUERY %type RAND SRAND -%type SPRINTF GSUB SUB SPLIT +%type SPRINTF GSUB SUB +%type SPLIT TOKENS splitop %type SUBSTR PROCEDURE name dcl_name -%type IF WHILE FOR FORR +%type IF WHILE FOR ITERATER %type BREAK CONTINUE print member %type RETURN DYNAMIC SWITCH UNSET %type SCANF SSCANF scan @@ -303,7 +304,7 @@ statement : '{' statement_list '}' if ($3) $$ = exnewnode(expr.program, ';', 1, INTEGER, $3, $$); } - | FORR '(' variable ')' statement + | ITERATER '(' variable ')' statement { $$ = exnewnode(expr.program, ITERATER, 0, INTEGER, NiL, NiL); $$->data.generate.array = $3; @@ -802,13 +803,13 @@ expr : '(' expr ')' { $$ = exnewsubstr (expr.program, $3); } - | SPLIT '(' expr ',' DYNAMIC ')' + | splitop '(' expr ',' DYNAMIC ')' { - $$ = exnewsplit (expr.program, $5, $3, NiL); + $$ = exnewsplit (expr.program, $1->index, $5, $3, NiL); } - | SPLIT '(' expr ',' DYNAMIC ',' expr ')' + | splitop '(' expr ',' DYNAMIC ',' expr ')' { - $$ = exnewsplit (expr.program, $5, $3, $7); + $$ = exnewsplit (expr.program, $1->index, $5, $3, $7); } | EXIT '(' expr ')' { @@ -960,6 +961,9 @@ expr : '(' expr ')' | constant ; +splitop : SPLIT + | TOKENS + ; constant : CONSTANT { $$ = exnewnode(expr.program, CONSTANT, 0, $1->type, NiL, NiL); diff --git a/lib/expr/extoken.c b/lib/expr/extoken.c index b603ec92c..e115ec5b7 100644 --- a/lib/expr/extoken.c +++ b/lib/expr/extoken.c @@ -174,7 +174,7 @@ static void trace(Expr_t * ex, int lev, char *op, int c) case FOR: s = " for"; break; - case FORR: + case ITERATER: s = " forr"; break; case GSUB: @@ -222,6 +222,9 @@ static void trace(Expr_t * ex, int lev, char *op, int c) case SWITCH: s = " switch"; break; + case TOKENS: + s = " tokens"; + break; case UNSET: s = " unset"; break; diff --git a/lib/gvpr/Makefile.am b/lib/gvpr/Makefile.am index eadab6b9b..31da95a74 100644 --- a/lib/gvpr/Makefile.am +++ b/lib/gvpr/Makefile.am @@ -13,6 +13,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/lib/sfio \ -I$(top_srcdir)/lib/ast \ -I$(top_srcdir)/lib/ingraphs \ + -I$(top_srcdir)/lib/common \ -I$(top_srcdir)/lib/cgraph \ -I$(top_srcdir)/lib/cdt @@ -23,10 +24,11 @@ noinst_LTLIBRARIES = libgvpr_C.la lib_LTLIBRARIES = libgvpr.la pkgconfig_DATA = libgvpr.pc -libgvpr_C_la_SOURCES = actions.c compile.c gvpr.c gprstate.c parse.c queue.c +libgvpr_C_la_SOURCES = actions.c compile.c gvpr.c gprstate.c parse.c queue.c ../common/colxlate.c $(libgvpr_C_la_OBJECTS): gdefs.h libgvpr_C_la_DEPENDENCIES = \ $(top_builddir)/lib/expr/libexpr_C.la \ + $(top_builddir)/lib/common/libcommon_C.la \ $(top_builddir)/lib/ingraphs/libingraphs_C.la diff --git a/lib/gvpr/actions.c b/lib/gvpr/actions.c index 879e9cfc1..cf8132029 100644 --- a/lib/gvpr/actions.c +++ b/lib/gvpr/actions.c @@ -27,6 +27,7 @@ #include #include #include +#include #define KINDS(p) ((AGTYPE(p) == AGRAPH) ? "graph" : (AGTYPE(p) == AGNODE) ? "node" : "edge") @@ -663,7 +664,7 @@ char *readLine(Expr_t * ex, int fd) if (fd < 0 || fd >= elementsof(ex->file) || !((sp = ex->file[fd]))) { exerror("readL: %d: invalid descriptor", fd); - return exstring(ex, ""); + return ""; } tmps = sfstropen(); while (((c = sfgetc(sp)) > 0) && (c != '\n')) @@ -746,3 +747,74 @@ char *canon(Expr_t * pgm, char *arg) return p; } + +void *grealloc(void *ptr, size_t size) +{ + void *p = realloc(ptr, size); + if (p == NULL && size) { + fprintf(stderr, "out of memory\n"); + abort(); + } + return p; +} + +/* colorx: + * RGB, RGBA, HSV, HSVA, CMYK + */ +char *colorx (Expr_t* ex, char* incolor, char* fmt, Sfio_t* fp) +{ + gvcolor_t color; + color_type_t type; + int rc; + int alpha; + + if ((*fmt == '\0') || (*incolor == '\0')) + return ""; + if (*fmt == 'R') { + type = RGBA_BYTE; + if (!strcmp (fmt, "RGBA")) + alpha = 1; + else + alpha = 0; + } + else if (*fmt == 'H') { + type = HSVA_DOUBLE; + if (!strcmp (fmt, "HSVA")) + alpha = 1; + else + alpha = 0; + } + else if (*fmt == 'C') { + type = CMYK_BYTE; + } + else + return ""; + + rc = colorxlate (incolor, &color, type); + if (rc != COLOR_OK) + return ""; + + switch (type) { + case HSVA_DOUBLE : + sfprintf (fp, ".03f .03f .03f", + color.u.HSVA[0], color.u.HSVA[1], color.u.HSVA[2]); + if (alpha) + sfprintf (fp, " .03f", color.u.HSVA[3]); + break; + case RGBA_BYTE : + sfprintf (fp, "#%02x%02x%02x", + color.u.rgba[0], color.u.rgba[1], color.u.rgba[2]); + if (alpha) + sfprintf (fp, "%02x", color.u.rgba[3]); + break; + case CMYK_BYTE : + sfprintf (fp, "#%02x%02x%02x%02x", + color.u.cmyk[0], color.u.cmyk[1], color.u.cmyk[2], color.u.cmyk[3]); + break; + default : + break; + } + + return exstring(ex, sfstruse(fp)); +} + diff --git a/lib/gvpr/actions.h b/lib/gvpr/actions.h index 2ac1d7bbc..59190573f 100644 --- a/lib/gvpr/actions.h +++ b/lib/gvpr/actions.h @@ -49,6 +49,7 @@ extern "C" { extern char *toLower(Expr_t * pgm, char *, Sfio_t*); extern char *toUpper(Expr_t * pgm, char *, Sfio_t*); extern int deleteObj(Agraph_t * g, Agobj_t * obj); + extern char *colorx (Expr_t* ex, char* incolor, char* fmt, Sfio_t* fp); #endif diff --git a/lib/gvpr/compile.c b/lib/gvpr/compile.c index 2b4d706f1..2e9c13ebd 100644 --- a/lib/gvpr/compile.c +++ b/lib/gvpr/compile.c @@ -257,6 +257,14 @@ static Agobj_t *deref(Expr_t * pgm, Exnode_t * x, Exref_t * ref, return deref(pgm, x, ref->next, (Agobj_t *) state->target, state); break; + case V_travedge: + return deref(pgm, x, ref->next, (Agobj_t *) state->tvedge, + state); + break; + case V_travroot: + return deref(pgm, x, ref->next, (Agobj_t *) state->tvroot, + state); + break; case M_head: if (!objp && !(objp = state->curobj)) { exerror("Current object $ not defined"); @@ -1176,6 +1184,12 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref, v.integer = agnedges(gp); } break; + case F_atoi: + v.integer = atoi(args[0].string); + break; + case F_atof: + v.floating = atof(args[0].string); + break; case F_sqrt: v.floating = sqrt(args[0].floating); break; @@ -1328,6 +1342,9 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref, case F_tolower: v.string = toLower(pgm, args[0].string, state->tmp); break; + case F_colorx: + v.string = colorx(pgm, args[0].string, args[1].string, state->tmp); + break; case F_toupper: v.string = toUpper(pgm, args[0].string, state->tmp); break; @@ -1408,6 +1425,9 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref, case V_travroot: v.integer = PTR2INT(state->tvroot); break; + case V_travedge: + v.integer = PTR2INT(state->tvedge); + break; } return v; } else { diff --git a/lib/gvpr/compile.h b/lib/gvpr/compile.h index 5c2e7e372..7ad52eb1c 100644 --- a/lib/gvpr/compile.h +++ b/lib/gvpr/compile.h @@ -35,20 +35,21 @@ extern "C" { typedef struct { Agrec_t h; - Extype_t xu; + /* Extype_t xu; */ Extype_t iu; + Agedge_t* ine; } nval_t; typedef struct { Agrec_t h; - Extype_t xu; - Extype_t iu; + /* Extype_t xu; */ + /* Extype_t iu; */ char lock; } gval_t; typedef struct { Agrec_t h; - Extype_t xu; + /* Extype_t xu; */ } uval_t; #define OBJ(p) ((Agobj_t*)p) diff --git a/lib/gvpr/gprdata b/lib/gvpr/gprdata index 0c96f4afe..3c8831d87 100644 --- a/lib/gvpr/gprdata +++ b/lib/gvpr/gprdata @@ -5,6 +5,7 @@ V_outgraph "$O" ID T_graph 0 Y(G) V_tgtname "$tgtname" ID STRING 0 Y(S) V_infname "$F" ID STRING 0 Y(S) V_travroot "$tvroot" ID T_node 0 Y(V) +V_travedge "$tvedge" ID T_edge 0 Y(E) V_travtype "$tvtype" ID T_tvtyp 0 Y(TV) V_ARGC "ARGC" ID INTEGER 0 Y(I) M_degree "degree" ID INTEGER Y(V) Y(I) @@ -108,6 +109,9 @@ F_fstattr "fstAttr" FUNCTION S|A(1,G)|A(2,S) F_nxtattr "nxtAttr" FUNCTION S|A(1,G)|A(2,S)|A(3,S) F_tolower "tolower" FUNCTION S|A(1,S) F_toupper "toupper" FUNCTION S|A(1,S) +F_atoi "atoi" FUNCTION I|A(1,S) +F_atof "atof" FUNCTION F|A(1,S) +F_colorx "colorx" FUNCTION S|A(1,S)|A(2,S) C_flat "TV_flat" CONSTANT T_tvtyp C_ne "TV_ne" CONSTANT T_tvtyp C_en "TV_en" CONSTANT T_tvtyp diff --git a/lib/gvpr/gprstate.c b/lib/gvpr/gprstate.c index ad237bff9..796f648c2 100644 --- a/lib/gvpr/gprstate.c +++ b/lib/gvpr/gprstate.c @@ -56,6 +56,7 @@ Gpr_t *openGPRState(gpr_info* info) state->tvt = TV_flat; state->tvroot = 0; + state->tvedge = 0; state->outFile = info->outFile; state->argc = info->argc; state->argv = info->argv; diff --git a/lib/gvpr/gprstate.h b/lib/gvpr/gprstate.h index e14333511..aa57fe3f3 100644 --- a/lib/gvpr/gprstate.h +++ b/lib/gvpr/gprstate.h @@ -48,6 +48,7 @@ extern "C" { Sfio_t *outFile; trav_type tvt; Agnode_t *tvroot; + Agedge_t *tvedge; int name_used; int argc; char **argv; diff --git a/lib/gvpr/gvpr.c b/lib/gvpr/gvpr.c index 947aa4c43..38cc017bf 100644 --- a/lib/gvpr/gvpr.c +++ b/lib/gvpr/gvpr.c @@ -487,7 +487,7 @@ static Agnode_t *nextNode(Gpr_t * state, nodestream * nodes) #define MARKED(x) (((x)->iu.integer)&1) #define MARK(x) (((x)->iu.integer) = 1) #define ONSTACK(x) (((x)->iu.integer)&2) -#define PUSH(x) (((x)->iu.integer)|=2) +#define PUSH(x,e) (((x)->iu.integer)|=2,(x)->ine=(e)) #define POP(x) (((x)->iu.integer)&=(~2)) typedef Agedge_t *(*fstedgefn_t) (Agraph_t *, Agnode_t *); @@ -523,12 +523,13 @@ static void travBFS(Gpr_t * state, Expr_t* prog, comp_block * xprog) nd = nData(n); if (MARKED(nd)) continue; - PUSH(nd); + PUSH(nd, 0); push(q, n); while ((n = pull(q))) { nd = nData(n); MARK(nd); POP(nd); + state->tvedge = nd->ine; evalNode(state, prog, xprog, n); for (cure = agfstedge(g, n); cure; cure = agnxtedge(g, cure, n)) { @@ -538,11 +539,12 @@ static void travBFS(Gpr_t * state, Expr_t* prog, comp_block * xprog) evalEdge(state, prog, xprog, cure); if (!ONSTACK(nd)) { push(q, cure->node); - PUSH(nd); + PUSH(nd,cure); } } } } + state->tvedge = 0; freeQ(q); } @@ -569,9 +571,9 @@ static void travDFS(Gpr_t * state, Expr_t* prog, comp_block * xprog, trav_fns * seed.in.node = 0; curn = n; entry = &(seed.out); - cure = 0; + state->tvedge = cure = 0; MARK(nd); - PUSH(nd); + PUSH(nd,0); if (fns->visit & PRE_VISIT) evalNode(state, prog, xprog, n); more = 1; @@ -597,13 +599,13 @@ static void travDFS(Gpr_t * state, Expr_t* prog, comp_block * xprog, trav_fns * } else { evalEdge(state, prog, xprog, cure); push(stk, entry); - entry = cure; + state->tvedge = entry = cure; curn = cure->node; cure = 0; if (fns->visit & PRE_VISIT) evalNode(state, prog, xprog, curn); MARK(nd); - PUSH(nd); + PUSH(nd, entry); } } else { if (fns->visit & POST_VISIT) @@ -612,6 +614,10 @@ static void travDFS(Gpr_t * state, Expr_t* prog, comp_block * xprog, trav_fns * POP(nd); cure = entry; entry = (Agedge_t *) pull(stk); + if (entry == &seed) + state->tvedge = 0; + else + state->tvedge = entry; if (entry) curn = entry->node; else @@ -619,6 +625,7 @@ static void travDFS(Gpr_t * state, Expr_t* prog, comp_block * xprog, trav_fns * } } } + state->tvedge = 0; freeQ(stk); } diff --git a/lib/gvpr/parse.c b/lib/gvpr/parse.c index 98a2a010d..c7b8511e7 100644 --- a/lib/gvpr/parse.c +++ b/lib/gvpr/parse.c @@ -499,6 +499,7 @@ parse_prog *parseProg(char *input, int isFile) if (isFile) { mode = "r"; prog->source = input; + } else { mode = "rs"; prog->source = 0; /* command line */ -- 2.40.0