8
#define ISEDGE(e) (AGTYPE(e)&2)
12
#define BITS_PER_BYTE 8
17
if (op >= MINNAME && op <= MAXNAME)
18
return gprnames[op - MINNAME];
19
else return "<unknown>";
23
* Convert string argument to graph to type of graph desired.
29
* By default, the graph is directed, non-strict.
34
Agdesc_t desc = Agdirected;
56
error (1, "unknown graph descriptor '%c' : ignored", c);
64
* Recreate string representation of expression involving
65
* a reference and a symbol.
66
* The parameter sf must be a string stream.
69
deparse (Expr_t* ex, Exnode_t* n, Sfio_t* sf)
72
return (sfstruse (sf));
76
* Evaluate reference to derive desired graph object.
77
* A reference is either DI* or II*
78
* The parameter objp is the current object.
79
* Assume ref is type-correct.
82
deref (Exnode_t* x, Exref_t* ref, Agobj_t* objp, Gpr_t* state)
88
else if (ref->symbol->lex == DYNAMIC) {
89
ptr = x->data.variable.dyna->data.variable.dyna->data.constant.value.user;
90
return deref (x, ref->next, (Agobj_t*)ptr, state);
92
else switch (ref->symbol->index) { /* sym->lex == ID */
94
return deref (x, ref->next, (Agobj_t*)state->outgraph, state);
97
return deref (x, ref->next, state->curobj, state);
100
return deref (x, ref->next, (Agobj_t*)state->curgraph, state);
103
return deref (x, ref->next, (Agobj_t*)state->target, state);
106
if (!objp && !(objp = state->curobj)) {
107
error (1, "Current object $ not defined");
111
return deref (x, ref->next, (Agobj_t*)AGHEAD((Agedge_t*)objp), state);
112
else error (3, "head of non-edge");
115
if (!objp && !(objp = state->curobj)) {
116
error (3, "Current object $ not defined");
120
return deref (x, ref->next, (Agobj_t*)AGTAIL((Agedge_t*)objp), state);
121
else error (3, "tail of non-edge %x", objp);
124
error (1, "%s : illegal reference", ref->symbol->name);
133
* Apply symbol to get field value of objp
136
lookup (Agobj_t* objp, Exid_t* sym, Extype_t* v)
138
if (sym->lex == ID) {
139
switch (sym->index) {
141
if (ISEDGE(objp)) v->user = AGHEAD((Agedge_t*)objp);
143
error (1, "head of non-edge");
148
if (ISEDGE(objp)) v->user = AGTAIL((Agedge_t*)objp);
150
error (1, "tail of non-edge");
155
v->string = agnameof (objp);
158
if (AGTYPE(objp) == AGNODE) v->integer = agdegree((Agnode_t*)objp,1,0);
160
error (3, "indegree of non-node");
165
if (AGTYPE(objp) == AGNODE) v->integer = agdegree((Agnode_t*)objp,0,1);
167
error (3, "outdegree of non-node");
172
if (AGTYPE(objp) == AGNODE) v->integer = agdegree((Agnode_t*)objp,1,1);
174
error (3, "degree of non-node");
179
error (1, "%s : illegal reference", sym->name);
184
else v->string = agget (objp, sym->name);
190
* Return value associated with gpr identifier.
193
getval(Expr_t* pgm, Exnode_t* node, Exid_t* sym, Exref_t* ref,
194
void* env, int elt, Exdisc_t* disc)
201
assert (sym->lex != CONSTANT);
202
if (elt == EX_CALL) {
203
args = (Extype_t*)env;
204
state = (Gpr_t*)(disc->user);
205
switch (sym->index) {
207
v.user = agopen (args[0].string, xargs(args[1].string), &AgDefaultDisc);
209
agbindrec (v.user,UDATA,sizeof(gdata),0);
212
v.user = agnode ((Agraph_t*)args[0].user, args[1].string, 1);
214
agbindrec (v.user,UDATA,sizeof(ndata),0);
217
v.user = agedge ((Agnode_t*)args[0].user, (Agnode_t*)args[1].user,
220
agbindrec (v.user,UDATA,sizeof(edata),0);
223
v.user = clone ((Agraph_t*)args[0].user, args[1].user);
226
nodeInduce ((Agraph_t*)args[0].user);
230
v.integer = agwrite ((Agraph_t*)args[0].user, state->outFile);
232
v.integer = agisdirected ((Agraph_t*)args[0].user);
235
v.integer = agisstrict ((Agraph_t*)args[0].user);
238
if (args[1].user == state->curgraph) {
239
error (1, "cannot delete current graph $G");
242
else if (args[1].user == state->target) {
243
error (1, "cannot delete current graph $T");
247
v.integer = agdelete ((Agraph_t*)args[0].user, args[1].user);
250
v.integer = agnnodes ((Agraph_t*)args[0].user);
253
v.integer = agnedges ((Agraph_t*)args[0].user);
256
error (3, "unknown function call: %s", sym->name);
263
objp = deref (node, ref, 0, state);
265
error (3, "null reference in expression %s",
266
deparse (pgm, node, state->tmp));
268
else if ((sym->lex == ID) && (sym->index <= LAST_V)) {
269
switch (sym->index) {
271
v.user = state->curobj;
274
v.user = state->curgraph;
277
v.user = state->target;
280
v.user = state->outgraph;
283
v.string = state->tgtname;
286
v.integer = state->tvt;
292
objp = state->curobj;
294
error (3, "current object $ not defined as reference for %s",
295
deparse(pgm, node, state->tmp));
298
if (lookup (objp, sym, &v))
299
error (3, "in expression %s", deparse (pgm, node, state->tmp));
305
* Set sym to value v.
306
* Return -1 if not allowed.
307
* Assume already type correct.
310
setval(Expr_t* pgm, Exnode_t* x, Exid_t* sym, Exref_t* ref,
311
void* env, int elt, Extype_t v, Exdisc_t* disc)
321
objp = deref (x, ref, 0, state);
323
error (3, "in expression %s", deparse (pgm, x, state->tmp));
325
else if ((MINNAME <= sym->index) && (sym->index <= MAXNAME)) {
326
switch (sym->index) {
328
state->outgraph = v.user;
332
if (validTVT(v.integer))
335
error(1,"unexpected value %d assigned to %s : ignored",
336
iv, symName(V_travtype));
339
if (!streq(state->tgtname,v.string)) {
340
vmfree (pgm->vm, state->tgtname);
341
state->tgtname = vmstrdup (pgm->vm, v.string);
342
state->name_used = 0;
352
objp = state->curobj;
354
error (3, "current object $ undefined in expression %s",
355
deparse(pgm, x, state->tmp));
358
gsym = agattrsym (objp, sym->name);
360
gsym = agattr(agroot(agraphof(objp)),AGTYPE(objp),sym->name,"");
362
return agxset (objp, gsym, v.string);
365
static int codePhase;
367
#define haveGraph ((1 <= codePhase) && (codePhase <= 4))
368
#define haveTarget ((2 <= codePhase) && (codePhase <= 4))
369
#define inWalk ((2 <= codePhase) && (codePhase <= 3))
372
* Type check input type against implied type of symbol sym.
373
* If okay, return result type; else return 0.
374
* For functions, input type set must intersect with function domain.
375
* This means type errors may occur, but these will be caught at runtime.
376
* For non-functions, input type must be 0.
379
typeChk (tctype intype, Exid_t* sym)
409
exerror ( "\n -- unknown dynamic type %d of symbol %s", sym->lex, sym->name);
414
if (sym->index <= MAXNAME) {
415
if ((sym->index == V_this) && !inWalk)
416
exerror ("\n -- keyword %s can only be used in N and E statements",
418
else if ((sym->index == V_thisg) && !haveGraph)
419
exerror ("\n -- keyword %s cannot be used in BEGIN/END statements",
421
else if ((sym->index == V_targt) && !haveTarget)
422
exerror ("\n -- keyword %s cannot be used in BEGIN/BEG_G/END statements",
424
dom = tchk[sym->index][0];
425
rng = tchk[sym->index][1];
433
if (!intype && !inWalk)
434
exerror ("\n -- undeclared, unmodified names like \"%s\" can only be\nused in N and E statements",
440
exerror ("\n -- unexpected symbol in typeChk: name %s, lex %d",
441
sym->name, sym->lex);
446
if (!intype) intype = Y(E)|Y(V); /* type of $ */
447
if (!(dom & intype)) rng = 0;
449
else if (intype) rng = 0;
454
* Type check variable expression.
457
typeChkExp (Exref_t* ref, Exid_t* sym)
462
ty = typeChk (0, ref->symbol);
463
for (ref = ref->next; ty && ref; ref = ref->next)
464
ty = typeChk (ty, ref->symbol);
468
return typeChk (ty, sym);
472
* Called during compilation for uses of references: abc.x
473
* Also for abc.f(..), type abc.v, "abc".x and CONSTANTS.
474
* The grammar has been altered to disallow the first 3.
475
* Type check expressions; return value unused.
478
refval(Expr_t* pgm, Exnode_t* node, Exid_t* sym, Exref_t* ref,
479
char* str, int elt, Exdisc_t* disc)
483
if (sym->lex == CONSTANT) {
484
switch (sym->index) {
492
v = exzero(node->type);
497
if (!typeChkExp (ref, sym))
498
exerror ("\n -- type error in %s", deparse (pgm, node, sfstropen()));
499
v = exzero(node->type);
504
#include <../expr/exop.h>
509
if (op > MINTOKEN && op < MAXTOKEN)
510
return (char*)exop[op - MINTOKEN];
516
cvtError (Exid_t* xref, char* msg)
519
error(1, "%s: %s", xref->name, msg);
526
* Convert value x of type x->type to type type.
527
* Return -1 if conversion cannot be done, 0 otherwise.
528
* If arg is > 0, conversion unnecessary; just report possibility.
529
* In particular, assume x != 0 if arg == 0.
532
convert(Expr_t* prog, register Exnode_t* x, int type, register Exid_t* xref, int arg, Exdisc_t* disc)
538
/* If both types are built-in, let libexpr handle */
539
if ((type >= MINTOKEN) && (x->type >= MINTOKEN)) return -1;
541
if (x->type < MINTOKEN) ret = 0;
543
else if (type == INTEGER) {
544
if (x->type != T_tvtyp)
545
x->data.constant.value.integer = (Sflong_t)x->data.constant.value.user;
548
else if (x->type == T_obj) {
549
/* check dynamic type */
550
objp = (Agobj_t*)x->data.constant.value.user;
554
cvtError (xref, "Uninitialized object");
557
if (AGTYPE(objp) == AGRAPH) ret = 0;
560
if (AGTYPE(objp) == AGNODE) ret = 0;
563
if (ISEDGE(objp)) ret = 0;
568
else if (type == STRING) {
571
objp = (Agobj_t*)x->data.constant.value.user;
573
x->data.constant.value.string = agnameof (objp);
576
else cvtError (xref, "Uninitialized object");
580
else if (x->type == STRING) {
590
* Pattern match strings.
593
matchval(Expr_t* pgm, Exnode_t* xstr, const char* str, Exnode_t* xpat,
594
const char* pat, void* env, Exdisc_t* disc)
596
return strgrpmatch(str, pat, NiL, 0, STR_MAXIMAL|STR_LEFT|STR_RIGHT);
600
* Convert type indices to symbolic name.
603
a2t[] = { 0, FLOATING, INTEGER, STRING,
604
T_node, T_edge, T_graph, T_obj };
607
* Create and initialize expr discipline.
610
initDisc (Gpr_t* state)
614
dp = newof (0, Exdisc_t, 1, 0);
616
error (3, "could not create libexp discipline: out of memory");
618
dp->version = EX_VERSION;
619
dp->flags = EX_CHARSTRING|EX_FATAL|EX_UNDECLARED;
620
dp->symbols = symbols;
621
dp->convertf = convert;
622
dp->errorf = (Exerror_f)errorf;
626
dp->matchf = matchval;
634
* Compile given string, then extract and return
638
compile (Expr_t* prog, char* src, char* input, int line, char* lbl,
645
/* create input stream */
647
sf = sfopen (0, sfx, "rs");
649
prefix = sfopen (0, input, "rs");
650
sfstack (sf, prefix);
653
else sf = sfopen (0, input, "rs");
655
/* prefixing label if necessary */
657
prefix = sfopen (0, 0, "sr+");
658
sfprintf (prefix, "%s:\n", lbl);
659
sfseek (prefix, 0,0);
660
sfstack (sf, prefix);
664
/* prog is set to exit on errors */
665
excomp (prog, src, line, 0, sf);
668
e = exexpr(prog, lbl, NiL, kind);
676
mkStmts (Expr_t* prog, char* src, case_info* sp, int cnt, char* lbl)
680
Sfio_t* tmps = sfstropen();
682
cs = newof (0, case_stmt, cnt, 0);
684
for (i = 0; i < cnt ; i++) {
686
sfprintf (tmps, "%s_g%d", lbl, i);
687
cs[i].guard = compile (prog, src, sp->guard, sp->gstart,
688
sfstruse(tmps), 0, INTEGER);
691
sfprintf (tmps, "%s_a%d", lbl, i);
692
cs[i].action = compile (prog, src, sp->action, sp->astart,
693
sfstruse(tmps), 0, INTEGER);
703
* Convert command line flags to actions in END_G.
706
doFlags (int flags, Sfio_t* s)
709
if (flags & SRCOUT) sfprintf (s, "$O = $G;\n");
710
if (flags & INDUCE) sfprintf (s, "induce($O);\n");
715
* Convert gpr sections in libexpr program.
718
compileProg (parse_prog* inp, Gpr_t* state, int flags)
722
Sfio_t* tmps = sfstropen();
725
/* Make sure we have enough bits for types */
726
assert (BITS_PER_BYTE*sizeof(tctype) >= (1<<TBITS));
728
p = newof (0, comp_prog, 1, 0);
730
error (3, "could not create compiled program: out of memory");
733
endg_sfx = doFlags (flags, tmps);
734
if (*endg_sfx == '\0') endg_sfx = 0;
737
dp = initDisc (state);
738
p->prog = exopen (dp);
742
p->begin_stmt = compile (p->prog, inp->source, inp->begin_stmt,
743
inp->l_begin, 0, 0, VOID);
746
p->begg_stmt = compile (p->prog, inp->source, inp->begg_stmt,
747
inp->l_beging, "_begin_g", 0, VOID);
750
if (inp->node_stmts) {
751
tchk[V_this][1] = Y(V);
752
p->n_nstmts = inp->n_nstmts;
753
p->node_stmts = mkStmts (p->prog, inp->source, inp->node_stmts,
754
inp->n_nstmts, "_nd");
758
if (inp->edge_stmts) {
759
tchk[V_this][1] = Y(E);
760
p->n_estmts = inp->n_estmts;
761
p->edge_stmts = mkStmts (p->prog, inp->source, inp->edge_stmts,
762
inp->n_estmts, "_eg");
766
if (inp->endg_stmt || endg_sfx)
767
p->endg_stmt = compile (p->prog, inp->source, inp->endg_stmt,
768
inp->l_endg, "_end_g", endg_sfx, VOID);
772
p->end_stmt = compile (p->prog, inp->source, inp->end_stmt,
773
inp->l_end, "_end_", 0, VOID);
779
* Returns true if program actually has node or edge statements.
782
walksGraph (comp_prog* p)
784
return (p->n_nstmts || p->n_estmts);
788
* Returns true if program uses the graph, i.e., has
789
* N/E/BEG_G/END_G statments
792
usesGraph (comp_prog* p)
794
return (walksGraph(p) || p->begg_stmt || p->endg_stmt);
801
for (i = 0; i <= LAST_M; i++)
802
printf ("%d: %d %d\n", i, tchk[i][0], tchk[i][1]);