. 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
\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]
.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
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
.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
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
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.
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
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) {
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);
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) {
if (!(x = expr->data.operand.right))
switch (cc->lastop = expr->data.operand.left->op) {
case FOR:
- case FORR:
case IF:
case PRINTF:
case PRINT:
case ';':
continue;
case FOR:
- case FORR:
case IF:
case PRINTF:
case PRINT:
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),
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),
#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";
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:
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:
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);
}
/* 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;
%token ELSE
%token EXIT
%token FOR
-%token FORR
%token FUNCTION
%token GSUB
%token ITERATE
%token SUB
%token SUBSTR
%token SWITCH
+%token TOKENS
%token UNSET
%token WHILE
%type <id> CONSTANT ARRAY FUNCTION DECLARE
%type <id> EXIT PRINT PRINTF QUERY
%type <id> RAND SRAND
-%type <id> SPRINTF GSUB SUB SPLIT
+%type <id> SPRINTF GSUB SUB
+%type <id> SPLIT TOKENS splitop
%type <id> SUBSTR PROCEDURE name dcl_name
-%type <id> IF WHILE FOR FORR
+%type <id> IF WHILE FOR ITERATER
%type <id> BREAK CONTINUE print member
%type <id> RETURN DYNAMIC SWITCH UNSET
%type <id> SCANF SSCANF scan
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;
{
$$ = 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 ')'
{
| constant
;
+splitop : SPLIT
+ | TOKENS
+ ;
constant : CONSTANT
{
$$ = exnewnode(expr.program, CONSTANT, 0, $1->type, NiL, NiL);
case FOR:
s = " for";
break;
- case FORR:
+ case ITERATER:
s = " forr";
break;
case GSUB:
case SWITCH:
s = " switch";
break;
+ case TOKENS:
+ s = " tokens";
+ break;
case UNSET:
s = " unset";
break;
-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
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
#include <string.h>
#include <stdio.h>
#include <ctype.h>
+#include <colorprocs.h>
#define KINDS(p) ((AGTYPE(p) == AGRAPH) ? "graph" : (AGTYPE(p) == AGNODE) ? "node" : "edge")
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'))
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));
+}
+
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
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");
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;
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;
case V_travroot:
v.integer = PTR2INT(state->tvroot);
break;
+ case V_travedge:
+ v.integer = PTR2INT(state->tvedge);
+ break;
}
return v;
} else {
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)
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)
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
state->tvt = TV_flat;
state->tvroot = 0;
+ state->tvedge = 0;
state->outFile = info->outFile;
state->argc = info->argc;
state->argv = info->argv;
Sfio_t *outFile;
trav_type tvt;
Agnode_t *tvroot;
+ Agedge_t *tvedge;
int name_used;
int argc;
char **argv;
#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 *);
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)) {
evalEdge(state, prog, xprog, cure);
if (!ONSTACK(nd)) {
push(q, cure->node);
- PUSH(nd);
+ PUSH(nd,cure);
}
}
}
}
+ state->tvedge = 0;
freeQ(q);
}
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;
} 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)
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
}
}
}
+ state->tvedge = 0;
freeQ(stk);
}
if (isFile) {
mode = "r";
prog->source = input;
+
} else {
mode = "rs";
prog->source = 0; /* command line */