Graphviz 13.1.0~dev.20250626.0830
Loading...
Searching...
No Matches
compile.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11/*
12 * Compile-time and run-time interface between gvpr and libexpr
13 */
14
15#include "config.h"
16#include <assert.h>
17#include <ast/error.h>
18#include <cgraph/cgraph.h>
19#include <gvpr/actions.h>
20#include <gvpr/compile.h>
21#include <inttypes.h>
22#include <limits.h>
23#include <math.h>
24#include <stdbool.h>
25#include <stddef.h>
26#include <stdint.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <unistd.h>
31#include <util/agxbuf.h>
32#include <util/alloc.h>
33#include <util/prisize_t.h>
34#include <util/startswith.h>
35#include <util/unreachable.h>
36
37static int isedge(Agobj_t *obj) {
38 return AGTYPE(obj) == AGOUTEDGE || AGTYPE(obj) == AGINEDGE;
39}
40
41#define MIN(a, b) ((a) < (b) ? (a) : (b))
42#define MAX(a, b) ((a) > (b) ? (a) : (b))
43
44#include <gvpr/gdefs.h>
45
46#include <ctype.h>
47#include <gvpr/trie.c>
48
49static void *int2ptr(long long i) { return (void *)(intptr_t)i; }
50
51static long long ptr2int(const void *p) { return (long long)(intptr_t)p; }
52
53/* Return name of object.
54 * Assumes obj != NULL
55 */
56static char *nameOf(Expr_t *ex, Agobj_t *obj, agxbuf *tmps) {
57 char *s;
58 char *key;
59 Agedge_t *e;
60
61 switch (AGTYPE(obj)) {
62 case AGNODE:
63 case AGRAPH:
64 s = agnameof(obj);
65 break;
66 default: /* edge */
67 e = (Agedge_t *)obj;
68 key = agnameof(AGMKOUT(e));
69 agxbput(tmps, agnameof(AGTAIL(e)));
70 if (agisdirected(agraphof(e)))
71 agxbput(tmps, "->");
72 else
73 agxbput(tmps, "--");
74 agxbput(tmps, agnameof(AGHEAD(e)));
75 if (key && *key) {
76 agxbputc(tmps, '[');
77 agxbput(tmps, key);
78 agxbputc(tmps, ']');
79 }
80 s = exstring(ex, agxbuse(tmps));
81 break;
82 }
83 return s;
84}
85
86/* If string as form "x,y,u,v" where is all are numeric,
87 * return "x,y" or "u,v", depending on getll, else return ""
88 */
89static char *bbOf(Expr_t *pgm, char *pt, bool getll) {
90 double x, y, u, v;
91
92 if (sscanf(pt, "%lf,%lf,%lf,%lf", &x, &y, &u, &v) == 4) {
93 char *p = strchr(pt, ',');
94 p = strchr(p + 1, ',');
95 if (getll) {
96 size_t len = (size_t)(p - pt);
97 char *const s = exstralloc(pgm, len + 1);
98 strncpy(s, pt, len);
99 s[len] = '\0';
100 return s;
101 }
102 return exstring(pgm, p + 1);
103 }
104 return "";
105}
106
107/* If string as form "x,y" where is x and y are numeric,
108 * return "x" or "y", depending on getx, else return ""
109 */
110static char *xyOf(Expr_t *pgm, char *pt, bool getx) {
111 double x, y;
112
113 if (sscanf(pt, "%lf,%lf", &x, &y) == 2) {
114 char *const p = strchr(pt, ',');
115 if (getx) {
116 size_t len = (size_t)(p - pt);
117 char *const v = exstralloc(pgm, len + 1);
118 strncpy(v, pt, len);
119 v[len] = '\0';
120 return v;
121 }
122 return exstring(pgm, p + 1);
123 }
124 return "";
125}
126
127/* Get pos data from node; store x or y into v if successful and return 0;
128 * else return -1
129 */
130static int posOf(Agnode_t *np, int idx, double *v) {
131 static Agraph_t *root;
132 static Agsym_t *pos;
133 Agraph_t *nroot = agroot(np);
134 char *ps;
135 double p[2];
136
137 if (root != nroot) {
138 root = nroot;
139 pos = agattr_text(root, AGNODE, "pos", 0);
140 }
141 if (!pos)
142 return -1;
143 ps = agxget(np, pos);
144 if (sscanf(ps, "%lf,%lf", &p[0], &p[1]) == 2) {
145 *v = p[idx];
146 return 0;
147 } else
148 return -1;
149}
150
151/* Convert string argument to graph to type of graph desired.
152 * u => undirected
153 * d => directed
154 * s => strict
155 * n => non-strict
156 * Case-insensitive
157 * By default, the graph is directed, non-strict.
158 */
159static Agdesc_t xargs(char *args) {
160 Agdesc_t desc = Agdirected;
161 char c;
162
163 while ((c = *args++)) {
164 switch (c) {
165 case 'u':
166 case 'U':
167 desc.directed = false;
168 break;
169 case 'd':
170 case 'D':
171 desc.directed = true;
172 break;
173 case 's':
174 case 'S':
175 desc.strict = true;
176 break;
177 case 'n':
178 case 'N':
179 desc.directed = false;
180 break;
181 default:
182 error(ERROR_WARNING, "unknown graph descriptor '%c' : ignored", c);
183 break;
184 }
185 }
186 return desc;
187}
188
189/* Recreate string representation of expression involving
190 * a reference and a symbol.
191 */
192static char *deparse(Expr_t *ex, Exnode_t *n, agxbuf *xb) {
193 exdump(ex, n, xb);
194 return agxbuse(xb);
195}
196
197/* Evaluate reference to derive desired graph object.
198 * A reference is either DI* or II*
199 * The parameter objp is the current object.
200 * Assume ref is type-correct.
201 */
202static Agobj_t *deref(Expr_t *pgm, Exnode_t *x, Exref_t *ref, Agobj_t *objp,
203 Gpr_t *state) {
204 void *ptr;
205
206 if (ref == 0)
207 return objp;
208 else if (ref->symbol->lex == DYNAMIC) {
209 ptr = int2ptr(
211 if (!ptr) {
212 agxbuf xb = {0};
213 exerror("null reference %s in expression %s.%s", ref->symbol->name,
214 ref->symbol->name, deparse(pgm, x, &xb));
215 agxbfree(&xb);
216 return ptr;
217 } else
218 return deref(pgm, x, ref->next, (Agobj_t *)ptr, state);
219 } else
220 switch (ref->symbol->index) { /* sym->lex == ID */
221 case V_outgraph:
222 return deref(pgm, x, ref->next, (Agobj_t *)state->outgraph, state);
223 case V_this:
224 return deref(pgm, x, ref->next, state->curobj, state);
225 case V_thisg:
226 return deref(pgm, x, ref->next, (Agobj_t *)state->curgraph, state);
227 case V_nextg:
228 return deref(pgm, x, ref->next, (Agobj_t *)state->nextgraph, state);
229 case V_targt:
230 return deref(pgm, x, ref->next, (Agobj_t *)state->target, state);
231 case V_travedge:
232 return deref(pgm, x, ref->next, (Agobj_t *)state->tvedge, state);
233 case V_travroot:
234 return deref(pgm, x, ref->next, (Agobj_t *)state->tvroot, state);
235 case V_travnext:
236 return deref(pgm, x, ref->next, (Agobj_t *)state->tvnext, state);
237 case M_head:
238 if (!objp && !(objp = state->curobj)) {
239 exerror("Current object $ not defined");
240 return 0;
241 }
242 if (isedge(objp))
243 return deref(pgm, x, ref->next, (Agobj_t *)AGHEAD((Agedge_t *)objp),
244 state);
245 else
246 exerror("head of non-edge");
247 break;
248 case M_tail:
249 if (!objp && !(objp = state->curobj)) {
250 exerror("Current object $ not defined");
251 return 0;
252 }
253 if (isedge(objp))
254 return deref(pgm, x, ref->next, (Agobj_t *)AGTAIL((Agedge_t *)objp),
255 state);
256 else
257 exerror("tail of non-edge %p", objp);
258 break;
259 default:
260 exerror("%s : illegal reference", ref->symbol->name);
261 break;
262 }
263 return 0;
264}
265
266/* Check that attribute is not a read-only, pseudo-attribute.
267 * fatal if not OK.
268 */
269static void assignable(Agobj_t *objp, unsigned char *name) {
270 unsigned int ch;
271 int rv;
272 unsigned char *p = name;
273
274 TFA_Init();
275 while (TFA_State >= 0 && (ch = *p)) {
276 TFA_Advance(ch > 127 ? 127 : (char)ch);
277 p++;
278 }
279 rv = TFA_Definition();
280 if (rv < 0)
281 return;
282
283 switch (AGTYPE(objp)) {
284 case AGRAPH:
285 if (rv & Y(G))
286 exerror("Cannot assign to pseudo-graph attribute %s", name);
287 break;
288 case AGNODE:
289 if (rv & Y(V))
290 exerror("Cannot assign to pseudo-node attribute %s", name);
291 break;
292 default: /* edge */
293 if (rv & Y(E))
294 exerror("Cannot assign to pseudo-edge attribute %s", name);
295 break;
296 }
297}
298
299/* Set object's attribute name to val.
300 * Initialize attribute if necessary.
301 */
302static int setattr(Agobj_t *objp, char *name, char *val) {
303 Agsym_t *gsym = agattrsym(objp, name);
304 if (!gsym) {
305 gsym = agattr_text(agroot(agraphof(objp)), AGTYPE(objp), name, "");
306 }
307 return agxset(objp, gsym, val);
308}
309
310static char *kindToStr(int kind) {
311 char *s;
312
313 switch (kind) {
314 case AGRAPH:
315 s = "graph";
316 break;
317 case AGNODE:
318 s = "node";
319 break;
320 default:
321 s = "edge";
322 break;
323 }
324 return s;
325}
326
327// return string rep of object’s kind
328static char *kindOf(Agobj_t *objp) { return kindToStr(agobjkind(objp)); }
329
330/* Apply symbol to get field value of objp
331 * Assume objp != NULL
332 */
333static int lookup(Expr_t *pgm, Agobj_t *objp, Exid_t *sym, Extype_t *v) {
334 if (sym->lex == ID) {
335 switch (sym->index) {
336 case M_head:
337 if (isedge(objp))
338 v->integer = ptr2int(AGHEAD((Agedge_t *)objp));
339 else {
340 error(ERROR_WARNING, "head of non-edge");
341 return -1;
342 }
343 break;
344 case M_tail:
345 if (isedge(objp))
346 v->integer = ptr2int(AGTAIL((Agedge_t *)objp));
347 else {
348 error(ERROR_WARNING, "tail of non-edge");
349 return -1;
350 }
351 break;
352 case M_name: {
353 agxbuf tmp = {0};
354 v->string = nameOf(pgm, objp, &tmp);
355 agxbfree(&tmp);
356 break;
357 }
358 case M_indegree:
359 if (AGTYPE(objp) == AGNODE)
360 v->integer = agdegree(agroot(objp), (Agnode_t *)objp, 1, 0);
361 else {
362 exerror("indegree of non-node");
363 return -1;
364 }
365 break;
366 case M_outdegree:
367 if (AGTYPE(objp) == AGNODE)
368 v->integer = agdegree(agroot(objp), (Agnode_t *)objp, 0, 1);
369 else {
370 exerror("outdegree of non-node");
371 return -1;
372 }
373 break;
374 case M_degree:
375 if (AGTYPE(objp) == AGNODE)
376 v->integer = agdegree(agroot(objp), (Agnode_t *)objp, 1, 1);
377 else {
378 exerror("degree of non-node");
379 return -1;
380 }
381 break;
382 case M_X:
383 if (AGTYPE(objp) == AGNODE) {
384 if (posOf((Agnode_t *)objp, 0, &v->floating))
385 exerror("no x coordinate for node \"%s\"", agnameof(objp));
386 } else {
387 exerror("x coordinate of non-node");
388 return -1;
389 }
390 break;
391 case M_Y:
392 if (AGTYPE(objp) == AGNODE) {
393 if (posOf((Agnode_t *)objp, 1, &v->floating))
394 exerror("no y coordinate for node \"%s\"", agnameof(objp));
395 } else {
396 exerror("x coordinate of non-node");
397 return -1;
398 }
399 break;
400 case M_parent:
401 if (AGTYPE(objp) == AGRAPH)
402 v->integer = ptr2int(agparent((Agraph_t *)objp));
403 else {
404 exerror("parent of non-graph");
405 return -1;
406 }
407 break;
408 case M_root:
409 v->integer = ptr2int(agroot(agraphof(objp)));
410 break;
411 case M_n_edges:
412 if (AGTYPE(objp) == AGRAPH)
413 v->integer = agnedges((Agraph_t *)objp);
414 else {
415 exerror("n_edges of non-graph");
416 return -1;
417 }
418 break;
419 case M_n_nodes:
420 if (AGTYPE(objp) == AGRAPH)
421 v->integer = agnnodes((Agraph_t *)objp);
422 else {
423 exerror("n_nodes of non-graph");
424 return -1;
425 }
426 break;
427 case M_directed:
428 if (AGTYPE(objp) == AGRAPH)
429 v->integer = agisdirected((Agraph_t *)objp);
430 else {
431 exerror("directed of non-graph");
432 return -1;
433 }
434 break;
435 case M_strict:
436 if (AGTYPE(objp) == AGRAPH)
437 v->integer = agisstrict((Agraph_t *)objp);
438 else {
439 exerror("strict of non-graph");
440 return -1;
441 }
442 break;
443 default:
444 error(ERROR_WARNING, "%s : illegal reference", sym->name);
445 return -1;
446 break;
447 }
448 } else {
449 Agsym_t *gsym = agattrsym(objp, sym->name);
450 if (!gsym) {
451 gsym = agattr_text(agroot(agraphof(objp)), AGTYPE(objp), sym->name, "");
452 agxbuf tmp = {0};
454 "Using value of uninitialized %s attribute \"%s\" of \"%s\"",
455 kindOf(objp), sym->name, nameOf(pgm, objp, &tmp));
456 agxbfree(&tmp);
457 }
458 v->string = agxget(objp, gsym);
459 }
460
461 return 0;
462}
463
464// return value associated with $n
465static char *getArg(int n, Gpr_t *state) {
466 if (n >= state->argc) {
467 exerror("program references ARGV[%d] - undefined", n);
468 return 0;
469 }
470 return state->argv[n];
471}
472
473static int setDfltAttr(Agraph_t *gp, char *k, char *name, char *value) {
474 int kind;
475
476 switch (*k) {
477 case 'G':
478 kind = AGRAPH;
479 break;
480 case 'E':
481 kind = AGEDGE;
482 break;
483 case 'N':
484 kind = AGNODE;
485 break;
486 default:
487 error(ERROR_WARNING, "Unknown kind \"%s\" passed to setDflt()", k);
488 return 1;
489 }
490
491 // make the implicit default on the root graph explicit in order to avoid the
492 // next `agattr_text` thinking its assignment should be hoisted to the root
493 {
494 Agraph_t *const root = agroot(gp);
495 if (agattr_text(root, kind, name, NULL) == NULL) {
496 agattr_text(root, kind, name, "");
497 }
498 }
499
500 agattr_text(gp, kind, name, value);
501 return 0;
502}
503
504// map string to object kind
505static int toKind(char *k, char *fn) {
506 switch (*k) {
507 case 'G':
508 return AGRAPH;
509 case 'E':
510 return AGEDGE;
511 case 'N':
512 return AGNODE;
513 default:
514 exerror("Unknown kind \"%s\" passed to %s()", k, fn);
515 break;
516 }
517 return 0;
518}
519
520static char *nxtAttr(Agraph_t *gp, char *k, char *name) {
521 char *fn = name ? "nxtAttr" : "fstAttr";
522 int kind = toKind(k, fn);
523 Agsym_t *sym;
524
525 if (name) {
526 sym = agattr_text(gp, kind, name, 0);
527 if (!sym) {
528 exerror("Third argument \"%s\" in nxtAttr() must be the name of an "
529 "existing attribute",
530 name);
531 return "";
532 }
533
534 } else
535 sym = NULL;
536
537 sym = agnxtattr(gp, kind, sym);
538 if (sym)
539 return sym->name;
540 else
541 return "";
542}
543
544static char *getDfltAttr(Agraph_t *gp, char *k, char *name) {
545 int kind = toKind(k, "getDflt");
546 Agsym_t *sym = agattr_text(gp, kind, name, 0);
547 if (!sym) {
548 sym = agattr_text(gp, kind, name, "");
549 error(ERROR_WARNING, "Uninitialized %s attribute \"%s\" in %s",
550 kindToStr(kind), name, "getDflt");
551 }
552 return sym->defval;
553}
554
555// return value associated with gpr identifier
557 void *env, int elt, Exdisc_t *disc) {
558 Extype_t v;
559 Gpr_t *state;
560 Extype_t *args;
561 Agobj_t *objp;
562 Agobj_t *objp1;
563 char *key;
564 Agraph_t *gp;
565 Agnode_t *np;
566 Agnode_t *hp;
567 Agedge_t *ep;
568 gvprbinding *bp;
569
570 assert(sym->lex != CONSTANT);
571 if (elt == EX_CALL) {
572 args = env;
573 state = disc->user;
574 switch (sym->index) {
575 case F_graph:
576 gp = openG(args[0].string, xargs(args[1].string));
577 v.integer = ptr2int(gp);
578 break;
579 case F_subg:
580 gp = int2ptr(args[0].integer);
581 if (gp) {
582 gp = openSubg(gp, args[1].string);
583 v.integer = ptr2int(gp);
584 } else {
585 error(ERROR_WARNING, "NULL graph passed to subg()");
586 v.integer = 0;
587 }
588 break;
589 case F_issubg:
590 gp = int2ptr(args[0].integer);
591 if (gp) {
592 v.integer = ptr2int(agsubg(gp, args[1].string, 0));
593 } else {
594 error(ERROR_WARNING, "NULL graph passed to isSubg()");
595 v.integer = 0;
596 }
597 break;
598 case F_fstsubg:
599 gp = int2ptr(args[0].integer);
600 if (gp) {
601 gp = agfstsubg(gp);
602 v.integer = ptr2int(gp);
603 } else {
604 error(ERROR_WARNING, "NULL graph passed to fstsubg()");
605 v.integer = 0;
606 }
607 break;
608 case F_nxtsubg:
609 gp = int2ptr(args[0].integer);
610 if (gp) {
611 gp = agnxtsubg(gp);
612 v.integer = ptr2int(gp);
613 } else {
614 error(ERROR_WARNING, "NULL graph passed to nxtsubg()");
615 v.integer = 0;
616 }
617 break;
618 case F_node:
619 gp = int2ptr(args[0].integer);
620 if (gp) {
621 np = openNode(gp, args[1].string);
622 v.integer = ptr2int(np);
623 } else {
624 error(ERROR_WARNING, "NULL graph passed to node()");
625 v.integer = 0;
626 }
627 break;
628 case F_addnode:
629 gp = int2ptr(args[0].integer);
630 np = int2ptr(args[1].integer);
631 if (!gp) {
632 error(ERROR_WARNING, "NULL graph passed to addNode()");
633 v.integer = 0;
634 } else if (!np) {
635 error(ERROR_WARNING, "NULL node passed to addNode()");
636 v.integer = 0;
637 } else
638 v.integer = ptr2int(addNode(gp, np, 1));
639 break;
640 case F_fstnode:
641 gp = int2ptr(args[0].integer);
642 if (gp) {
643 np = agfstnode(gp);
644 v.integer = ptr2int(np);
645 } else {
646 error(ERROR_WARNING, "NULL graph passed to fstnode()");
647 v.integer = 0;
648 }
649 break;
650 case F_nxtnode:
651 np = int2ptr(args[0].integer);
652 if (np) {
653 np = agnxtnode(agroot(np), np);
654 v.integer = ptr2int(np);
655 } else {
656 error(ERROR_WARNING, "NULL node passed to nxtnode()");
657 v.integer = 0;
658 }
659 break;
660 case F_nxtnodesg:
661 gp = int2ptr(args[0].integer);
662 np = int2ptr(args[1].integer);
663 if (!gp)
664 gp = agroot(np);
665 if (np) {
666 np = agnxtnode(gp, np);
667 v.integer = ptr2int(np);
668 } else {
669 error(ERROR_WARNING, "NULL node passed to nxtnode_sg()");
670 v.integer = 0;
671 }
672 break;
673 case F_isnode:
674 gp = int2ptr(args[0].integer);
675 if (gp) {
676 v.integer = ptr2int(agnode(gp, args[1].string, 0));
677 } else {
678 error(ERROR_WARNING, "NULL graph passed to isNode()");
679 v.integer = 0;
680 }
681 break;
682 case F_issubnode:
683 gp = int2ptr(args[0].integer);
684 np = int2ptr(args[1].integer);
685 if (!gp)
686 gp = agroot(np);
687 if (np) {
688 v.integer = ptr2int(addNode(gp, np, 0));
689 } else {
690 error(ERROR_WARNING, "NULL node passed to isSubnode()");
691 v.integer = 0;
692 }
693 break;
694 case F_indegree:
695 gp = int2ptr(args[0].integer);
696 np = int2ptr(args[1].integer);
697 if (!gp)
698 gp = agroot(np);
699 if (np) {
700 v.integer = agdegree(gp, np, 1, 0);
701 } else {
702 error(ERROR_WARNING, "NULL node passed to indegreeOf()");
703 v.integer = 0;
704 }
705 break;
706 case F_outdegree:
707 gp = int2ptr(args[0].integer);
708 np = int2ptr(args[1].integer);
709 if (!gp)
710 gp = agroot(np);
711 if (np) {
712 v.integer = agdegree(gp, np, 0, 1);
713 } else {
714 error(ERROR_WARNING, "NULL node passed to outdegreeOf()");
715 v.integer = 0;
716 }
717 break;
718 case F_degree:
719 gp = int2ptr(args[0].integer);
720 np = int2ptr(args[1].integer);
721 if (!gp)
722 gp = agroot(np);
723 if (np) {
724 v.integer = agdegree(gp, np, 1, 1);
725 } else {
726 error(ERROR_WARNING, "NULL node passed to degreeOf()");
727 v.integer = 0;
728 }
729 break;
730 case F_isin:
731 gp = int2ptr(args[0].integer);
732 objp = int2ptr(args[1].integer);
733 if (!gp) {
734 error(ERROR_WARNING, "NULL graph passed to isIn()");
735 v.integer = 0;
736 } else if (!objp) {
737 error(ERROR_WARNING, "NULL object passed to isIn()");
738 v.integer = 0;
739 } else
740 v.integer = agcontains(gp, objp);
741 break;
742 case F_compof:
743 gp = int2ptr(args[0].integer);
744 np = int2ptr(args[1].integer);
745 if (!gp) {
746 error(ERROR_WARNING, "NULL graph passed to compOf()");
747 v.integer = 0;
748 } else if (!np) {
749 error(ERROR_WARNING, "NULL node passed to compOf()");
750 v.integer = 0;
751 } else
752 v.integer = ptr2int(compOf(gp, np));
753 break;
754 case F_kindof:
755 objp = int2ptr(args[0].integer);
756 if (!objp) {
757 exerror("NULL object passed to kindOf()");
758 v.string = 0;
759 } else
760 switch (AGTYPE(objp)) {
761 case AGRAPH:
762 v.string = "G";
763 break;
764 case AGNODE:
765 v.string = "N";
766 break;
767 case AGINEDGE:
768 case AGOUTEDGE:
769 v.string = "E";
770 break;
771 default:
772 UNREACHABLE();
773 }
774 break;
775 case F_edge:
776 key = args[2].string;
777 if (*key == '\0')
778 key = 0;
779 np = int2ptr(args[0].integer);
780 hp = int2ptr(args[1].integer);
781 if (!np) {
782 error(ERROR_WARNING, "NULL tail node passed to edge()");
783 v.integer = 0;
784 } else if (!hp) {
785 error(ERROR_WARNING, "NULL head node passed to edge()");
786 v.integer = 0;
787 } else {
788 ep = openEdge(0, np, hp, key);
789 v.integer = ptr2int(ep);
790 }
791 break;
792 case F_edgesg:
793 key = args[3].string;
794 if (*key == '\0')
795 key = 0;
796 gp = int2ptr(args[0].integer);
797 np = int2ptr(args[1].integer);
798 hp = int2ptr(args[2].integer);
799 if (!np) {
800 error(ERROR_WARNING, "NULL tail node passed to edge_sg()");
801 v.integer = 0;
802 } else if (!hp) {
803 error(ERROR_WARNING, "NULL head node passed to edge_sg()");
804 v.integer = 0;
805 } else {
806 ep = openEdge(gp, np, hp, key);
807 v.integer = ptr2int(ep);
808 }
809 break;
810 case F_addedge:
811 gp = int2ptr(args[0].integer);
812 ep = int2ptr(args[1].integer);
813 if (!gp) {
814 error(ERROR_WARNING, "NULL graph passed to addEdge()");
815 v.integer = 0;
816 } else if (!ep) {
817 error(ERROR_WARNING, "NULL edge passed to addEdge()");
818 v.integer = 0;
819 } else
820 v.integer = ptr2int(addEdge(gp, ep, 1));
821 break;
822 case F_opp:
823 ep = int2ptr(args[0].integer);
824 np = int2ptr(args[1].integer);
825 if (!ep) {
826 error(ERROR_WARNING, "NULL edge passed to opp()");
827 v.integer = 0;
828 } else if (!np) {
829 error(ERROR_WARNING, "NULL node passed to opp()");
830 v.integer = 0;
831 } else {
832 if (aghead(ep) == np)
833 np = agtail(ep);
834 else
835 np = aghead(ep);
836 v.integer = ptr2int(np);
837 }
838 break;
839 case F_isedge:
840 key = args[2].string;
841 if (*key == '\0')
842 key = 0;
843 np = int2ptr(args[0].integer);
844 hp = int2ptr(args[1].integer);
845 if (!np) {
846 error(ERROR_WARNING, "NULL tail node passed to isEdge()");
847 v.integer = 0;
848 } else if (!hp) {
849 error(ERROR_WARNING, "NULL head node passed to isEdge()");
850 v.integer = 0;
851 } else
852 v.integer = ptr2int(isEdge(agroot(np), np, hp, key));
853 break;
854 case F_isedgesg:
855 key = args[3].string;
856 if (*key == '\0')
857 key = 0;
858 gp = int2ptr(args[0].integer);
859 np = int2ptr(args[1].integer);
860 hp = int2ptr(args[2].integer);
861 if (!gp)
862 gp = agroot(np);
863 if (!np) {
864 error(ERROR_WARNING, "NULL tail node passed to isEdge_sg()");
865 v.integer = 0;
866 } else if (!hp) {
867 error(ERROR_WARNING, "NULL head node passed to isEdge_sg()");
868 v.integer = 0;
869 } else
870 v.integer = ptr2int(isEdge(gp, np, hp, key));
871 break;
872 case F_issubedge:
873 gp = int2ptr(args[0].integer);
874 ep = int2ptr(args[1].integer);
875 if (!gp)
876 gp = agroot(ep);
877 if (ep) {
878 v.integer = ptr2int(addEdge(gp, ep, 0));
879 } else {
880 error(ERROR_WARNING, "NULL edge passed to isSubedge()");
881 v.integer = 0;
882 }
883 break;
884 case F_fstout:
885 np = int2ptr(args[0].integer);
886 if (np) {
887 ep = agfstout(agroot(np), np);
888 v.integer = ptr2int(ep);
889 } else {
890 error(ERROR_WARNING, "NULL node passed to fstout()");
891 v.integer = 0;
892 }
893 break;
894 case F_fstoutsg:
895 gp = int2ptr(args[0].integer);
896 np = int2ptr(args[1].integer);
897 if (!gp)
898 gp = agroot(np);
899 if (np) {
900 ep = agfstout(gp, np);
901 v.integer = ptr2int(ep);
902 } else {
903 error(ERROR_WARNING, "NULL node passed to fstout_sg()");
904 v.integer = 0;
905 }
906 break;
907 case F_nxtout:
908 ep = int2ptr(args[0].integer);
909 if (ep) {
910 ep = agnxtout(agroot(ep), ep);
911 v.integer = ptr2int(ep);
912 } else {
913 error(ERROR_WARNING, "NULL edge passed to nxtout()");
914 v.integer = 0;
915 }
916 break;
917 case F_nxtoutsg:
918 gp = int2ptr(args[0].integer);
919 ep = int2ptr(args[1].integer);
920 if (!gp)
921 gp = agroot(ep);
922 if (ep) {
923 ep = agnxtout(gp, ep);
924 v.integer = ptr2int(ep);
925 } else {
926 error(ERROR_WARNING, "NULL edge passed to nxtout_sg()");
927 v.integer = 0;
928 }
929 break;
930 case F_fstin:
931 np = int2ptr(args[0].integer);
932 if (np) {
933 ep = agfstin(agroot(np), np);
934 v.integer = ptr2int(ep);
935 } else {
936 error(ERROR_WARNING, "NULL node passed to fstin()");
937 v.integer = 0;
938 }
939 break;
940 case F_fstinsg:
941 gp = int2ptr(args[0].integer);
942 np = int2ptr(args[1].integer);
943 if (!gp)
944 gp = agroot(np);
945 if (np) {
946 ep = agfstin(gp, np);
947 v.integer = ptr2int(ep);
948 } else {
949 error(ERROR_WARNING, "NULL node passed to fstin_sg()");
950 v.integer = 0;
951 }
952 break;
953 case F_nxtin:
954 ep = int2ptr(args[0].integer);
955 if (ep) {
956 ep = agnxtin(agroot(ep), ep);
957 v.integer = ptr2int(ep);
958 } else {
959 error(ERROR_WARNING, "NULL edge passed to nxtin()");
960 v.integer = 0;
961 }
962 break;
963 case F_nxtinsg:
964 gp = int2ptr(args[0].integer);
965 ep = int2ptr(args[1].integer);
966 if (!gp)
967 gp = agroot(ep);
968 if (ep) {
969 ep = agnxtin(gp, ep);
970 v.integer = ptr2int(ep);
971 } else {
972 error(ERROR_WARNING, "NULL edge passed to nxtin_sg()");
973 v.integer = 0;
974 }
975 break;
976 case F_fstedge:
977 np = int2ptr(args[0].integer);
978 if (np) {
979 ep = agfstedge(agroot(np), np);
980 v.integer = ptr2int(ep);
981 } else {
982 error(ERROR_WARNING, "NULL node passed to fstedge()");
983 v.integer = 0;
984 }
985 break;
986 case F_fstedgesg:
987 gp = int2ptr(args[0].integer);
988 np = int2ptr(args[1].integer);
989 if (!gp)
990 gp = agroot(np);
991 if (np) {
992 ep = agfstedge(gp, np);
993 v.integer = ptr2int(ep);
994 } else {
995 error(ERROR_WARNING, "NULL node passed to fstedge_sg()");
996 v.integer = 0;
997 }
998 break;
999 case F_nxtedge:
1000 ep = int2ptr(args[0].integer);
1001 np = int2ptr(args[1].integer);
1002 if (!ep) {
1003 error(ERROR_WARNING, "NULL edge passed to nxtedge()");
1004 v.integer = 0;
1005 } else if (!np) {
1006 error(ERROR_WARNING, "NULL node passed to nxtedge()");
1007 v.integer = 0;
1008 } else {
1009 ep = agnxtedge(agroot(np), ep, np);
1010 v.integer = ptr2int(ep);
1011 }
1012 break;
1013 case F_nxtedgesg:
1014 gp = int2ptr(args[0].integer);
1015 ep = int2ptr(args[1].integer);
1016 np = int2ptr(args[2].integer);
1017 if (!gp)
1018 gp = agroot(np);
1019 if (!ep) {
1020 error(ERROR_WARNING, "NULL edge passed to nxtedge_sg()");
1021 v.integer = 0;
1022 } else if (!np) {
1023 error(ERROR_WARNING, "NULL node passed to nxtedge_sg()");
1024 v.integer = 0;
1025 } else {
1026 ep = agnxtedge(gp, ep, np);
1027 v.integer = ptr2int(ep);
1028 }
1029 break;
1030 case F_copy:
1031 gp = int2ptr(args[0].integer);
1032 objp = int2ptr(args[1].integer);
1033 if (!objp) {
1034 error(ERROR_WARNING, "NULL object passed to clone()");
1035 v.integer = 0;
1036 } else
1037 v.integer = ptr2int(copy(gp, objp));
1038 break;
1039 case F_clone:
1040 gp = int2ptr(args[0].integer);
1041 objp = int2ptr(args[1].integer);
1042 if (!objp) {
1043 error(ERROR_WARNING, "NULL object passed to clone()");
1044 v.integer = 0;
1045 } else
1046 v.integer = ptr2int(cloneO(gp, objp));
1047 break;
1048 case F_cloneG:
1049 gp = int2ptr(args[0].integer);
1050 if (gp) {
1051 gp = cloneG(gp, args[1].string);
1052 v.integer = ptr2int(gp);
1053 } else {
1054 error(ERROR_WARNING, "NULL graph passed to cloneG()");
1055 v.integer = 0;
1056 }
1057 break;
1058 case F_copya:
1059 objp = int2ptr(args[0].integer);
1060 objp1 = int2ptr(args[1].integer);
1061 if (!(objp && objp1)) {
1062 error(ERROR_WARNING, "NULL object passed to copyA()");
1063 v.integer = 0;
1064 } else
1065 v.integer = copyAttr(objp, objp1);
1066 break;
1067 case F_rename:
1068 objp = int2ptr(args[0].integer);
1069 if (!objp) {
1070 error(ERROR_WARNING, "NULL object passed to rename()");
1071 v.integer = -1;
1072 } else
1073 v.integer = agrelabel_node((Agnode_t *)objp, args[1].string);
1074 break;
1075 case F_induce:
1076 gp = int2ptr(args[0].integer);
1077 if (!gp) {
1078 error(ERROR_WARNING, "NULL graph passed to induce()");
1079 v.integer = 1;
1080 } else {
1081 (void)graphviz_node_induce(gp, NULL);
1082 v.integer = 0;
1083 }
1084 break;
1085 case F_write:
1086 gp = int2ptr(args[0].integer);
1087 if (!gp) {
1088 error(ERROR_WARNING, "NULL graph passed to write()");
1089 v.integer = 1;
1090 } else
1091 v.integer = sfioWrite(gp, state->outFile);
1092 break;
1093 case F_writeg:
1094 gp = int2ptr(args[0].integer);
1095 if (!gp) {
1096 error(ERROR_WARNING, "NULL graph passed to writeG()");
1097 v.integer = 1;
1098 } else
1099 v.integer = writeFile(gp, args[1].string);
1100 break;
1101 case F_readg:
1102 gp = readFile(args[0].string);
1103 v.integer = ptr2int(gp);
1104 break;
1105 case F_fwriteg:
1106 gp = int2ptr(args[0].integer);
1107 if (!gp) {
1108 error(ERROR_WARNING, "NULL graph passed to fwriteG()");
1109 v.integer = 1;
1110 } else
1111 v.integer = fwriteFile(pgm, gp, args[1].integer);
1112 break;
1113 case F_freadg:
1114 gp = freadFile(pgm, args[0].integer);
1115 v.integer = ptr2int(gp);
1116 break;
1117 case F_openf:
1118 v.integer = openFile(pgm, args[0].string, args[1].string);
1119 break;
1120 case F_closef:
1121 v.integer = closeFile(pgm, args[0].integer);
1122 break;
1123 case F_readl:
1124 v.string = readLine(pgm, args[0].integer);
1125 break;
1126 case F_isdirect:
1127 gp = int2ptr(args[0].integer);
1128 if (!gp) {
1129 error(ERROR_WARNING, "NULL graph passed to isDirect()");
1130 v.integer = 0;
1131 } else {
1132 v.integer = agisdirected(gp);
1133 }
1134 break;
1135 case F_isstrict:
1136 gp = int2ptr(args[0].integer);
1137 if (!gp) {
1138 error(ERROR_WARNING, "NULL graph passed to isStrict()");
1139 v.integer = 0;
1140 } else {
1141 v.integer = agisstrict(gp);
1142 }
1143 break;
1144 case F_delete:
1145 gp = int2ptr(args[0].integer);
1146 objp = int2ptr(args[1].integer);
1147 if (!objp) {
1148 error(ERROR_WARNING, "NULL object passed to delete()");
1149 v.integer = 1;
1150 } else if (objp == (Agobj_t *)state->curgraph) {
1151 error(ERROR_WARNING, "cannot delete current graph $G");
1152 v.integer = 1;
1153 } else if (objp == (Agobj_t *)state->target) {
1154 error(ERROR_WARNING, "cannot delete target graph $T");
1155 v.integer = 1;
1156 } else if (objp == state->curobj) {
1157 if (!(v.integer = deleteObj(gp, objp)))
1158 state->curobj = NULL;
1159 } else
1160 v.integer = deleteObj(gp, objp);
1161 break;
1162 case F_lock:
1163 gp = int2ptr(args[0].integer);
1164 if (!gp) {
1165 error(ERROR_WARNING, "NULL graph passed to lock()");
1166 v.integer = -1;
1167 } else {
1168 const int op = args[1].integer > 0 ? 1 : args[1].integer < 0 ? -1 : 0;
1169 v.integer = lockGraph(gp, op);
1170 }
1171 break;
1172 case F_nnodes:
1173 gp = int2ptr(args[0].integer);
1174 if (!gp) {
1175 error(ERROR_WARNING, "NULL graph passed to nNodes()");
1176 v.integer = 0;
1177 } else {
1178 v.integer = agnnodes(gp);
1179 }
1180 break;
1181 case F_nedges:
1182 gp = int2ptr(args[0].integer);
1183 if (!gp) {
1184 error(ERROR_WARNING, "NULL graph passed to nEdges()");
1185 v.integer = 0;
1186 } else {
1187 v.integer = agnedges(gp);
1188 }
1189 break;
1190 case F_atoi:
1191 v.integer = atoi(args[0].string);
1192 break;
1193 case F_atof:
1194 v.floating = atof(args[0].string);
1195 break;
1196 case F_sqrt:
1197 v.floating = sqrt(args[0].floating);
1198 break;
1199 case F_cos:
1200 v.floating = cos(args[0].floating);
1201 break;
1202 case F_sin:
1203 v.floating = sin(args[0].floating);
1204 break;
1205 case F_atan2:
1206 v.floating = atan2(args[0].floating, args[1].floating);
1207 break;
1208 case F_exp:
1209 v.floating = exp(args[0].floating);
1210 break;
1211 case F_pow:
1212 v.floating = pow(args[0].floating, args[1].floating);
1213 break;
1214 case F_log:
1215 v.floating = log(args[0].floating);
1216 break;
1217 case F_min:
1218 v.floating = MIN(args[0].floating, args[1].floating);
1219 break;
1220 case F_max:
1221 v.floating = MAX(args[0].floating, args[1].floating);
1222 break;
1223 case F_sys:
1224 v.integer = system(args[0].string);
1225 break;
1226 case F_hasattr:
1227 case F_get: {
1228 objp = int2ptr(args[0].integer);
1229 char *name = args[1].string;
1230 if (!objp) {
1231 exerror("NULL object passed to aget()/hasAttr()");
1232 v.integer = 0;
1233 } else if (!name) {
1234 exerror("NULL name passed to aget()/hasAttr()");
1235 v.integer = 0;
1236 } else {
1237 Agsym_t *gsym = agattrsym(objp, name);
1238 if (sym->index == F_hasattr)
1239 v.integer = (gsym != NULL);
1240 else {
1241 if (!gsym) {
1242 gsym = agattr_text(agroot(agraphof(objp)), AGTYPE(objp), name, "");
1243 agxbuf tmp = {0};
1245 "Using value of %s uninitialized attribute \"%s\" of \"%s\" "
1246 "in aget()",
1247 kindOf(objp), name, nameOf(pgm, objp, &tmp));
1248 agxbfree(&tmp);
1249 }
1250 v.string = agxget(objp, gsym);
1251 }
1252 }
1253 break;
1254 }
1255 case F_set:
1256 objp = int2ptr(args[0].integer);
1257 if (!objp) {
1258 error(ERROR_WARNING, "NULL object passed to aset()");
1259 v.integer = 1;
1260 } else {
1261 char *name = args[1].string;
1262 char *value = args[2].string;
1263 if (!name) {
1264 error(ERROR_WARNING, "NULL name passed to aset()");
1265 v.integer = 1;
1266 } else if (!value) {
1267 error(ERROR_WARNING, "NULL value passed to aset()");
1268 v.integer = 1;
1269 } else {
1270 v.integer = setattr(objp, name, value);
1271 }
1272 }
1273 break;
1274 case F_dset:
1275 gp = int2ptr(args[0].integer);
1276 if (gp) {
1277 char *kind = args[1].string;
1278 char *name = args[2].string;
1279 char *value = args[3].string;
1280 if (!name) {
1281 error(ERROR_WARNING, "NULL name passed to setDflt()");
1282 v.integer = 1;
1283 } else if (!value) {
1284 error(ERROR_WARNING, "NULL value passed to setDflt()");
1285 v.integer = 1;
1286 } else if (!kind) {
1287 error(ERROR_WARNING, "NULL kind passed to setDflt()");
1288 v.integer = 1;
1289 } else {
1290 v.integer = setDfltAttr(gp, kind, name, value);
1291 }
1292 } else {
1293 error(ERROR_WARNING, "NULL graph passed to node()");
1294 v.integer = 0;
1295 }
1296 break;
1297 case F_fstattr:
1298 gp = int2ptr(args[0].integer);
1299 if (gp) {
1300 char *kind = args[1].string;
1301 if (!kind) {
1302 error(ERROR_ERROR, "NULL kind passed to fstAttr()");
1303 v.string = 0;
1304 } else {
1305 v.string = nxtAttr(gp, kind, NULL);
1306 }
1307 } else {
1308 exerror("NULL graph passed to fstAttr()");
1309 v.string = 0;
1310 }
1311 break;
1312 case F_nxtattr:
1313 case F_isattr:
1314 case F_dget:
1315 gp = int2ptr(args[0].integer);
1316 if (gp) {
1317 char *kind = args[1].string;
1318 char *name = args[2].string;
1319 if (!name) {
1320 exerror("NULL name passed to %s", sym->name);
1321 v.string = 0;
1322 } else if (!kind) {
1323 exerror("NULL kind passed to %s", sym->name);
1324 v.string = 0;
1325 } else if (sym->index == F_isattr) {
1326 v.integer = agattr_text(gp, toKind(kind, sym->name), name, 0) != NULL;
1327 } else if (sym->index == F_nxtattr) {
1328 v.string = nxtAttr(gp, kind, name);
1329 } else {
1330 v.string = getDfltAttr(gp, kind, name);
1331 }
1332 } else {
1333 exerror("NULL graph passed to %s", sym->name);
1334 v.string = 0;
1335 }
1336 break;
1337 case F_canon:
1338 v.string = canon(pgm, args[0].string);
1339 break;
1340 case F_ishtml:
1341 v.integer = aghtmlstr(args[0].string);
1342 break;
1343 case F_html:
1344 gp = int2ptr(args[0].integer);
1345 if (gp) {
1346 v.string = toHtml(gp, args[1].string);
1347 } else {
1348 error(ERROR_WARNING, "NULL graph passed to html()");
1349 v.string = 0;
1350 }
1351 break;
1352 case F_tolower:
1353 v.string = toLower(pgm, args[0].string);
1354 break;
1355 case F_colorx:
1356 v.string = colorx(pgm, args[0].string, args[1].string);
1357 break;
1358 case F_strcmp:
1359 if (args[0].string) {
1360 if (args[1].string)
1361 v.integer = strcmp(args[0].string, args[1].string);
1362 else
1363 v.integer = -1;
1364 } else if (args[1].string)
1365 v.integer = 1;
1366 else
1367 v.integer = 0;
1368 break;
1369 case F_toupper:
1370 v.string = toUpper(pgm, args[0].string);
1371 break;
1372 case F_xof:
1373 v.string = xyOf(pgm, args[0].string, true);
1374 break;
1375 case F_yof:
1376 v.string = xyOf(pgm, args[0].string, false);
1377 break;
1378 case F_llof:
1379 v.string = bbOf(pgm, args[0].string, true);
1380 break;
1381 case F_urof:
1382 v.string = bbOf(pgm, args[0].string, false);
1383 break;
1384 case F_length:
1385 v.integer = strlen(args[0].string);
1386 break;
1387 case F_index:
1388 v.integer = indexOf(args[0].string, args[1].string);
1389 break;
1390 case F_rindex:
1391 v.integer = rindexOf(args[0].string, args[1].string);
1392 break;
1393 case F_match: {
1394 const size_t m = match(args[0].string, args[1].string);
1395 if (m == SIZE_MAX) {
1396 v.integer = -1;
1397 } else {
1398 v.integer = (long long)m;
1399 }
1400 break;
1401 }
1402 case F_call:
1403 if ((bp = findBinding(state, args[0].string)))
1404 v.integer = (bp->fn)(args[1].string);
1405 else
1406 v.integer = -1;
1407 break;
1408 default:
1409 v.integer = -1;
1410 exerror("unknown function call: %s", sym->name);
1411 }
1412 return v;
1413 } else if (elt == EX_ARRAY) {
1414 args = env;
1415 state = disc->user;
1416 switch (sym->index) {
1417 case A_ARGV:
1418 v.string = getArg(args[0].integer, state);
1419 break;
1420 default:
1421 exerror("unknown array name: %s", sym->name);
1422 v.string = 0;
1423 }
1424 return v;
1425 }
1426
1427 state = env;
1428 if (ref) {
1429 objp = deref(pgm, node, ref, 0, state);
1430 if (!objp) {
1431 agxbuf xb = {0};
1432 exerror("null reference in expression %s", deparse(pgm, node, &xb));
1433 agxbfree(&xb);
1434 }
1435 } else if (sym->lex == ID && sym->index <= LAST_V) {
1436 switch (sym->index) {
1437 case V_this:
1438 v.integer = ptr2int(state->curobj);
1439 break;
1440 case V_thisg:
1441 v.integer = ptr2int(state->curgraph);
1442 break;
1443 case V_nextg:
1444 v.integer = ptr2int(state->nextgraph);
1445 break;
1446 case V_targt:
1447 v.integer = ptr2int(state->target);
1448 break;
1449 case V_outgraph:
1450 v.integer = ptr2int(state->outgraph);
1451 break;
1452 case V_tgtname:
1453 v.string = state->tgtname;
1454 break;
1455 case V_infname:
1456 v.string = state->infname;
1457 break;
1458 case V_ARGC:
1459 v.integer = state->argc;
1460 break;
1461 case V_travtype:
1462 v.integer = state->tvt;
1463 break;
1464 case V_travroot:
1465 v.integer = ptr2int(state->tvroot);
1466 break;
1467 case V_travnext:
1468 v.integer = ptr2int(state->tvnext);
1469 break;
1470 case V_travedge:
1471 v.integer = ptr2int(state->tvedge);
1472 break;
1473 }
1474 return v;
1475 } else {
1476 objp = state->curobj;
1477 if (!objp) {
1478 agxbuf xb = {0};
1479 exerror("current object $ not defined as reference for %s",
1480 deparse(pgm, node, &xb));
1481 agxbfree(&xb);
1482 }
1483 }
1484
1485 if (objp) {
1486 if (lookup(pgm, objp, sym, &v)) {
1487 agxbuf xb = {0};
1488 exerror("in expression %s", deparse(pgm, node, &xb));
1489 agxbfree(&xb);
1490 v.integer = 0;
1491 }
1492 } else
1493 v.integer = 0;
1494
1495 return v;
1496}
1497
1498#define MINTYPE (LAST_M + 1) /* First type occurs after last M_ */
1499
1500static char *typeName(long op) { return typenames[op - MINTYPE]; }
1501
1502/* Set sym to value v.
1503 * Return -1 if not allowed.
1504 * Assume already type correct.
1505 */
1506static int setval(Expr_t *pgm, Exnode_t *x, Exid_t *sym, Exref_t *ref,
1507 void *env, Extype_t v) {
1508 Gpr_t *state;
1509 Agobj_t *objp;
1510 Agnode_t *np;
1511 int rv = 0;
1512
1513 state = env;
1514 if (ref) {
1515 objp = deref(pgm, x, ref, 0, state);
1516 if (!objp) {
1517 agxbuf xb = {0};
1518 exerror("in expression %s.%s", ref->symbol->name, deparse(pgm, x, &xb));
1519 agxbfree(&xb);
1520 return -1;
1521 }
1522 } else if (MINNAME <= sym->index && sym->index <= MAXNAME) {
1523 switch (sym->index) {
1524 case V_outgraph:
1525 state->outgraph = int2ptr(v.integer);
1526 break;
1527 case V_travtype: {
1528 long long iv = v.integer;
1529 if (validTVT(v.integer))
1530 state->tvt = (trav_type)iv;
1531 else
1532 error(1, "unexpected value %lld assigned to %s : ignored", iv,
1533 typeName(T_tvtyp));
1534 break;
1535 }
1536 case V_travroot:
1537 np = int2ptr(v.integer);
1538 if (!np || agroot(np) == state->curgraph)
1539 state->tvroot = np;
1540 else {
1541 error(1, "cannot set $tvroot, node %s not in $G : ignored",
1542 agnameof(np));
1543 }
1544 break;
1545 case V_travnext:
1546 np = int2ptr(v.integer);
1547 if (!np || agroot(np) == state->curgraph) {
1548 state->tvnext = np;
1549 state->flags |= GV_NEXT_SET;
1550 } else {
1551 error(1, "cannot set $tvnext, node %s not in $G : ignored",
1552 agnameof(np));
1553 }
1554 break;
1555 case V_tgtname:
1556 free(state->tgtname);
1557 state->tgtname = strdup(v.string);
1558 state->name_used = 0;
1559 break;
1560 default:
1561 rv = -1;
1562 break;
1563 }
1564 return rv;
1565 } else {
1566 objp = state->curobj;
1567 if (!objp) {
1568 agxbuf xb = {0};
1569 exerror("current object $ undefined in expression %s",
1570 deparse(pgm, x, &xb));
1571 agxbfree(&xb);
1572 return -1;
1573 }
1574 }
1575
1576 assignable(objp, (unsigned char *)sym->name);
1577 return setattr(objp, sym->name, v.string);
1578}
1579
1589 Extype_t v = {0};
1590 switch (rhs->index) {
1591 case A_ARGV: {
1592 Gpr_t *const state = disc->user;
1593 v.integer = state->argc;
1594 break;
1595 }
1596 default:
1597 exerror("unknown array name: %s", rhs->name);
1598 break;
1599 }
1600 return v;
1601}
1602
1612static int in(Extype_t lhs, Exid_t *rhs, Exdisc_t *disc) {
1613 switch (rhs->index) {
1614 case A_ARGV: {
1615 Gpr_t *const state = disc->user;
1616 return lhs.integer >= 0 && lhs.integer < state->argc;
1617 }
1618 default:
1619 exerror("unknown array name: %s", rhs->name);
1620 break;
1621 }
1622 return 0;
1623}
1624
1625static int codePhase;
1626
1627#define haveGraph (1 <= codePhase && codePhase <= 4)
1628#define haveTarget (2 <= codePhase && codePhase <= 4)
1629#define inWalk (2 <= codePhase && codePhase <= 3)
1630
1631/* typeChk:
1632 * Type check input type against implied type of symbol sym.
1633 * If okay, return result type; else return 0.
1634 * For functions, input type set must intersect with function domain.
1635 * This means type errors may occur, but these will be caught at runtime.
1636 * For non-functions, input type must be 0.
1637 */
1638static tctype typeChk(tctype intype, Exid_t *sym) {
1639 tctype dom = 0, rng = 0;
1640
1641 switch (sym->lex) {
1642 case DYNAMIC:
1643 dom = 0;
1644 switch (sym->type) {
1645 case T_obj:
1646 rng = YALL;
1647 break;
1648 case T_node:
1649 rng = Y(V);
1650 break;
1651 case T_graph:
1652 rng = Y(G);
1653 break;
1654 case T_edge:
1655 rng = Y(E);
1656 break;
1657 case INTEGER:
1658 rng = Y(I);
1659 break;
1660 case FLOATING:
1661 rng = Y(F);
1662 break;
1663 case STRING:
1664 rng = Y(S);
1665 break;
1666 default:
1667 exerror("unknown dynamic type %" PRIdMAX " of symbol %s",
1668 (intmax_t)sym->type, sym->name);
1669 break;
1670 }
1671 break;
1672 case ID:
1673 if (sym->index <= MAXNAME) {
1674 switch (sym->index) {
1675 case V_travroot:
1676 case V_this:
1677 case V_thisg:
1678 case V_nextg:
1679 if (!haveGraph)
1680 exerror("keyword %s cannot be used in BEGIN/END statements",
1681 sym->name);
1682 break;
1683 case V_targt:
1684 if (!haveTarget)
1685 exerror("keyword %s cannot be used in BEGIN/BEG_G/END statements",
1686 sym->name);
1687 break;
1688 }
1689 dom = tchk[sym->index][0];
1690 rng = tchk[sym->index][1];
1691 } else {
1692 dom = YALL;
1693 rng = Y(S);
1694 }
1695 break;
1696 case NAME:
1697 if (!intype && !haveGraph)
1698 exerror("undeclared, unmodified names like \"%s\" cannot be\nused in "
1699 "BEGIN and END statements",
1700 sym->name);
1701 dom = YALL;
1702 rng = Y(S);
1703 break;
1704 default:
1705 exerror("unexpected symbol in typeChk: name %s, lex %" PRIdMAX, sym->name,
1706 (intmax_t)sym->lex);
1707 break;
1708 }
1709
1710 if (dom) {
1711 if (!intype)
1712 intype = YALL; /* type of $ */
1713 if (!(dom & intype))
1714 rng = 0;
1715 } else if (intype)
1716 rng = 0;
1717 return rng;
1718}
1719
1720// type check variable expression
1722 tctype ty;
1723
1724 if (ref) {
1725 ty = typeChk(0, ref->symbol);
1726 for (ref = ref->next; ty && ref; ref = ref->next)
1727 ty = typeChk(ty, ref->symbol);
1728 if (!ty)
1729 return 0;
1730 } else
1731 ty = 0;
1732 return typeChk(ty, sym);
1733}
1734
1735/* Called during compilation for uses of references: abc.x
1736 * Also for abc.f(..), type abc.v, "abc".x and CONSTANTS.
1737 * The grammar has been altered to disallow the first 3.
1738 * Type check expressions; return value unused.
1739 */
1741
1742 Extype_t v;
1743 if (sym->lex == CONSTANT) {
1744 switch (sym->index) {
1745 case C_flat:
1746 v.integer = TV_flat;
1747 break;
1748 case C_ne:
1749 v.integer = TV_ne;
1750 break;
1751 case C_en:
1752 v.integer = TV_en;
1753 break;
1754 case C_bfs:
1755 v.integer = TV_bfs;
1756 break;
1757 case C_dfs:
1758 v.integer = TV_dfs;
1759 break;
1760 case C_fwd:
1761 v.integer = TV_fwd;
1762 break;
1763 case C_rev:
1764 v.integer = TV_rev;
1765 break;
1766 case C_postdfs:
1767 v.integer = TV_postdfs;
1768 break;
1769 case C_postfwd:
1770 v.integer = TV_postfwd;
1771 break;
1772 case C_postrev:
1773 v.integer = TV_postrev;
1774 break;
1775 case C_prepostdfs:
1777 break;
1778 case C_prepostfwd:
1780 break;
1781 case C_prepostrev:
1783 break;
1784 case C_null:
1785 v.integer = 0;
1786 break;
1787 default:
1788 v = exzero(node->type);
1789 break;
1790 }
1791 } else {
1792 if (!typeChkExp(ref, sym)) {
1793 agxbuf xb = {0};
1794 exerror("type error using %s", deparse(pgm, node, &xb));
1795 agxbfree(&xb);
1796 }
1797 v = exzero(node->type);
1798 }
1799 return v;
1800}
1801
1802/* Evaluate (l ex->op r) producing a value of type ex->type,
1803 * stored in l.
1804 * May be unary, with r = NULL
1805 * Return -1 if operation cannot be done, 0 otherwise.
1806 * If arg is != 0, operation unnecessary; just report possibility.
1807 */
1808static int binary(Exnode_t *l, Exnode_t *ex, Exnode_t *r, int arg) {
1809 Agobj_t *lobjp;
1810 Agobj_t *robjp;
1811 int ret = -1;
1812
1813 if (BUILTIN(l->type))
1814 return -1;
1815 if (r && BUILTIN(r->type))
1816 return -1;
1817 if (!INTEGRAL(ex->type))
1818 return -1;
1819
1820 if (l->type == T_tvtyp) {
1821
1822 if (!r)
1823 return -1; /* Assume libexpr handled unary */
1824 if (r->type != T_tvtyp)
1825 return -1;
1826
1827 long long li = l->data.constant.value.integer;
1828 long long ri = r->data.constant.value.integer;
1829 switch (ex->op) {
1830 case EQ:
1831 if (arg)
1832 return 0;
1833 l->data.constant.value.integer = li == ri;
1834 ret = 0;
1835 break;
1836 case NE:
1837 if (arg)
1838 return 0;
1839 l->data.constant.value.integer = li != ri;
1840 ret = 0;
1841 break;
1842 case '<':
1843 if (arg)
1844 return 0;
1845 l->data.constant.value.integer = li < ri;
1846 ret = 0;
1847 break;
1848 case LE:
1849 if (arg)
1850 return 0;
1851 l->data.constant.value.integer = li <= ri;
1852 ret = 0;
1853 break;
1854 case GE:
1855 if (arg)
1856 return 0;
1857 l->data.constant.value.integer = li >= ri;
1858 ret = 0;
1859 break;
1860 case '>':
1861 if (arg)
1862 return 0;
1863 l->data.constant.value.integer = li > ri;
1864 ret = 0;
1865 break;
1866 }
1867 }
1868
1869 /* l is a graph object; make sure r is also */
1870 if (r && r->type == T_tvtyp)
1871 return -1;
1872
1873 lobjp = int2ptr(l->data.constant.value.integer);
1874 if (r)
1875 robjp = int2ptr(r->data.constant.value.integer);
1876 else
1877 robjp = 0;
1878 switch (ex->op) {
1879 case EQ:
1880 if (arg)
1881 return 0;
1882 l->data.constant.value.integer = !compare(lobjp, robjp);
1883 ret = 0;
1884 break;
1885 case NE:
1886 if (arg)
1887 return 0;
1888 l->data.constant.value.integer = compare(lobjp, robjp);
1889 ret = 0;
1890 break;
1891 case '<':
1892 if (arg)
1893 return 0;
1894 l->data.constant.value.integer = compare(lobjp, robjp) < 0;
1895 ret = 0;
1896 break;
1897 case LE:
1898 if (arg)
1899 return 0;
1900 l->data.constant.value.integer = compare(lobjp, robjp) <= 0;
1901 ret = 0;
1902 break;
1903 case GE:
1904 if (arg)
1905 return 0;
1906 l->data.constant.value.integer = compare(lobjp, robjp) >= 0;
1907 ret = 0;
1908 break;
1909 case '>':
1910 if (arg)
1911 return 0;
1912 l->data.constant.value.integer = compare(lobjp, robjp) > 0;
1913 ret = 0;
1914 break;
1915 }
1916
1917 return ret;
1918}
1919
1920static int strToTvtype(char *s) {
1921 int rt = 0;
1922 char *sfx;
1923
1924 if (startswith(s, "TV_")) {
1925 sfx = s + 3;
1926 if (!strcmp(sfx, "flat")) {
1927 rt = TV_flat;
1928 } else if (!strcmp(sfx, "ne")) {
1929 rt = TV_ne;
1930 } else if (!strcmp(sfx, "en")) {
1931 rt = TV_en;
1932 } else if (!strcmp(sfx, "bfs")) {
1933 rt = TV_bfs;
1934 } else if (!strcmp(sfx, "dfs")) {
1935 rt = TV_dfs;
1936 } else if (!strcmp(sfx, "fwd")) {
1937 rt = TV_fwd;
1938 } else if (!strcmp(sfx, "rev")) {
1939 rt = TV_rev;
1940 } else if (!strcmp(sfx, "postdfs")) {
1941 rt = TV_postdfs;
1942 } else if (!strcmp(sfx, "postfwd")) {
1943 rt = TV_postfwd;
1944 } else if (!strcmp(sfx, "postrev")) {
1945 rt = TV_postrev;
1946 } else if (!strcmp(sfx, "prepostdfs")) {
1947 rt = TV_prepostdfs;
1948 } else if (!strcmp(sfx, "prepostfwd")) {
1949 rt = TV_prepostfwd;
1950 } else if (!strcmp(sfx, "prepostrev")) {
1951 rt = TV_prepostrev;
1952 } else
1953 exerror("illegal string \"%s\" for type tvtype_t", s);
1954 } else
1955 exerror("illegal string \"%s\" for type tvtype_t", s);
1956 return rt;
1957}
1958
1959static char *tvtypeToStr(long long v) {
1960 char *s = 0;
1961
1962 switch (v) {
1963 case TV_flat:
1964 s = "TV_flat";
1965 break;
1966 case TV_ne:
1967 s = "TV_ne";
1968 break;
1969 case TV_en:
1970 s = "TV_en";
1971 break;
1972 case TV_bfs:
1973 s = "TV_bfs";
1974 break;
1975 case TV_dfs:
1976 s = "TV_dfs";
1977 break;
1978 case TV_fwd:
1979 s = "TV_fwd";
1980 break;
1981 case TV_rev:
1982 s = "TV_rev";
1983 break;
1984 case TV_postdfs:
1985 s = "TV_postdfs";
1986 break;
1987 case TV_postfwd:
1988 s = "TV_postfwd";
1989 break;
1990 case TV_postrev:
1991 s = "TV_postrev";
1992 break;
1993 case TV_prepostdfs:
1994 s = "TV_prepostdfs";
1995 break;
1996 case TV_prepostfwd:
1997 s = "TV_prepostfwd";
1998 break;
1999 case TV_prepostrev:
2000 s = "TV_prepostrev";
2001 break;
2002 default:
2003 exerror("Unexpected value %lld for type tvtype_t", v);
2004 break;
2005 }
2006 return s;
2007}
2008
2009/* Convert value x to type string.
2010 * Assume x does not have a built-in type
2011 * Return -1 if conversion cannot be done, 0 otherwise.
2012 * If arg is != 0, conversion unnecessary; just report possibility.
2013 */
2014static int stringOf(Expr_t *prog, Exnode_t *x, int arg) {
2015 Agobj_t *objp;
2016 int rv = 0;
2017
2018 if (arg)
2019 return 0;
2020
2021 if (x->type == T_tvtyp) {
2022 if (!(x->data.constant.value.string =
2024 rv = -1;
2025 } else {
2026 objp = int2ptr(x->data.constant.value.integer);
2027 if (!objp) {
2028 exerror("cannot generate name for NULL %s", typeName(x->type));
2029 rv = -1;
2030 } else {
2031 agxbuf tmp = {0};
2032 x->data.constant.value.string = nameOf(prog, objp, &tmp);
2033 agxbfree(&tmp);
2034 }
2035 }
2036 x->type = STRING;
2037 return rv;
2038}
2039
2040/* Convert value x of type x->type to type type.
2041 * Return -1 if conversion cannot be done, 0 otherwise.
2042 * If arg is != 0, conversion unnecessary; just report possibility.
2043 * In particular, assume x != 0 if arg == 0.
2044 */
2045static int convert(Exnode_t *x, long type, int arg) {
2046 Agobj_t *objp;
2047 int ret = -1;
2048
2049 /* If both types are built-in, let libexpr handle */
2050 if (BUILTIN(type) && BUILTIN(x->type))
2051 return -1;
2052 if (type == T_obj && x->type <= T_obj)
2053 ret = 0; /* trivial cast from specific graph object to T_obj */
2054 else if (type <= T_obj && x->type == INTEGER) {
2055 if (x->data.constant.value.integer == 0)
2056 ret = 0; /* allow NULL pointer */
2057 } else if (type == INTEGER) {
2058 ret = 0;
2059 } else if (x->type == T_obj) {
2060 /* check dynamic type */
2061 if (arg) {
2062 if (type != FLOATING && type <= T_obj)
2063 ret = 0;
2064 } else {
2065 objp = int2ptr(x->data.constant.value.integer);
2066 switch (type) {
2067 case T_graph:
2068 if (!objp || AGTYPE(objp) == AGRAPH)
2069 ret = 0;
2070 break;
2071 case T_node:
2072 if (!objp || AGTYPE(objp) == AGNODE)
2073 ret = 0;
2074 break;
2075 case T_edge:
2076 if (!objp || isedge(objp))
2077 ret = 0;
2078 break;
2079 }
2080 }
2081 } else if (type == STRING) {
2082 if (x->type == T_tvtyp) {
2083 ret = 0;
2084 if (!arg) {
2087 }
2088 }
2089 } else if (type == T_tvtyp && x->type == INTEGER) {
2090 if (arg)
2091 ret = 0;
2092 else if (validTVT(x->data.constant.value.integer))
2093 ret = 0;
2094 else
2095 exerror("Integer value %lld not legal for type tvtype_t",
2097 }
2098 /* in case libexpr hands us the trivial case */
2099 else if (x->type == type) {
2100 ret = 0;
2101 } else if (x->type == STRING) {
2102 char *s;
2103 if (type == T_tvtyp) {
2104 if (arg)
2105 ret = 0;
2106 else {
2107 ret = 0;
2108 s = x->data.constant.value.string;
2110 }
2111 }
2112 }
2113 if (!arg && ret == 0)
2114 x->type = type;
2115 return ret;
2116}
2117
2118/* Calculate unique key for object.
2119 * We use this to unify local copies of nodes and edges.
2120 */
2121static Extype_t keyval(Extype_t v, long type) {
2122 if (type <= T_obj) {
2123 v.integer = AGID(int2ptr(v.integer));
2124 }
2125 return v;
2126}
2127
2128// convert type indices to symbolic name
2129static int a2t[] = {0, FLOATING, INTEGER, STRING,
2130 T_node, T_edge, T_graph, T_obj};
2131
2132// create and initialize expr discipline
2133static Exdisc_t *initDisc(Gpr_t *state) {
2134 Exdisc_t *dp = calloc(1, sizeof(Exdisc_t));
2135 if (!dp) {
2136 error(ERROR_ERROR, "could not create libexp discipline: out of memory");
2137 return 0;
2138 }
2139
2140 dp->version = EX_VERSION;
2142 dp->symbols = symbols;
2143 dp->convertf = convert;
2144 dp->stringof = stringOf;
2145 dp->binaryf = binary;
2146 dp->typename = typeName;
2147 if (state->errf)
2148 dp->errorf = state->errf;
2149 else
2150 dp->errorf = (Exerror_f)errorf;
2151 dp->keyf = keyval;
2152 dp->getf = getval;
2153 dp->reff = refval;
2154 dp->setf = setval;
2155 dp->lengthf = length;
2156 dp->inf = in;
2157 dp->exitf = state->exitf;
2158 dp->types = a2t;
2159 dp->user = state;
2160
2161 state->dp = dp; /* dp is freed when state is freed */
2162
2163 return dp;
2164}
2165
2166/* Compile given string, then extract and return
2167 * typed expression.
2168 */
2169static Exnode_t *compile(Expr_t *prog, char *src, char *input, int line,
2170 const char *lbl, const char *sfx, int kind) {
2171 Exnode_t *e = 0;
2172 int rv;
2173
2174 /* create input stream */
2175 FILE *sf = tmpfile();
2176 assert(sf != NULL);
2177 if (input) {
2178 fputs(input, sf);
2179 }
2180 if (sfx) {
2181 fputs(sfx, sf);
2182 }
2183 rewind(sf);
2184
2185 /* prefixing label if necessary */
2186 agxbuf label = {0};
2187 if (lbl) {
2188 agxbprint(&label, "%s:\n", lbl);
2189 line--;
2190 }
2191
2192 if (!src)
2193 src = "<command line>";
2194 rv = excomp(prog, src, line, sf, lbl ? agxbdisown(&label) : NULL);
2195 fclose(sf);
2196
2197 if (rv >= 0 && getErrorErrors() == 0)
2198 e = exexpr(prog, lbl, NULL, kind);
2199
2200 return e;
2201}
2202
2203// check if guard is an assignment and warn
2204static void checkGuard(Exnode_t *gp, char *src, int line) {
2205 gp = exnoncast(gp);
2206 if (gp && exisAssign(gp)) {
2207 if (src) {
2208 setErrorFileLine(src, line);
2209 }
2210 error(ERROR_WARNING, "assignment used as bool in guard");
2211 }
2212}
2213
2214static case_stmt *mkStmts(Expr_t *prog, char *src, case_infos_t cases,
2215 const char *lbl) {
2216 agxbuf tmp = {0};
2217
2218 case_stmt *cs = gv_calloc(case_infos_size(&cases), sizeof(case_stmt));
2219
2220 for (size_t i = 0; i < case_infos_size(&cases); i++) {
2221 case_info *sp = case_infos_at(&cases, i);
2222 if (sp->guard) {
2223 agxbprint(&tmp, "%s_g%" PRISIZE_T, lbl, i);
2224 cs[i].guard =
2225 compile(prog, src, sp->guard, sp->gstart, agxbuse(&tmp), 0, INTEGER);
2226 if (getErrorErrors())
2227 break;
2228 checkGuard(cs[i].guard, src, sp->gstart);
2229 }
2230 if (sp->action) {
2231 agxbprint(&tmp, "%s_a%" PRISIZE_T, lbl, i);
2232 cs[i].action =
2233 compile(prog, src, sp->action, sp->astart, agxbuse(&tmp), 0, INTEGER);
2234 if (getErrorErrors())
2235 break;
2236 /* If no error but no compiled action, the input action must
2237 * have been essentially an empty block, which should be
2238 * considered different from a missing block. So, compile a
2239 * trivial block.
2240 */
2241 if (!cs[i].action) {
2242 agxbprint(&tmp, "%s__a%" PRISIZE_T, lbl, i);
2243 cs[i].action =
2244 compile(prog, src, "1", sp->astart, agxbuse(&tmp), 0, INTEGER);
2245 }
2246 }
2247 }
2248 agxbfree(&tmp);
2249 return cs;
2250}
2251
2253static bool mkBlock(comp_block *bp, Expr_t *prog, char *src, parse_block *inp,
2254 size_t i) {
2255 bool has_begin_g = false; // does this block use a `BEG_G` statement?
2256
2257 codePhase = 1;
2258 if (inp->begg_stmt) {
2259 static const char PREFIX[] = "_begin_g_";
2260 agxbuf label = {0};
2261 agxbprint(&label, "%s%" PRISIZE_T, PREFIX, i);
2262 symbols[0].type = T_graph;
2263 tchk[V_this][1] = Y(G);
2264 bp->begg_stmt = compile(prog, src, inp->begg_stmt, inp->l_beging,
2265 agxbuse(&label), 0, VOIDTYPE);
2266 agxbfree(&label);
2267 if (getErrorErrors())
2268 goto finishBlk;
2269 has_begin_g = true;
2270 }
2271
2272 codePhase = 2;
2273 if (!case_infos_is_empty(&inp->node_stmts)) {
2274 static const char PREFIX[] = "_nd";
2275 agxbuf label = {0};
2276 symbols[0].type = T_node;
2277 tchk[V_this][1] = Y(V);
2278 bp->n_nstmts = case_infos_size(&inp->node_stmts);
2279 agxbprint(&label, "%s%" PRISIZE_T, PREFIX, i);
2280 bp->node_stmts = mkStmts(prog, src, inp->node_stmts, agxbuse(&label));
2281 agxbfree(&label);
2282 if (getErrorErrors())
2283 goto finishBlk;
2284 bp->does_walk_graph = true;
2285 }
2286
2287 codePhase = 3;
2288 if (!case_infos_is_empty(&inp->edge_stmts)) {
2289 static const char PREFIX[] = "_eg";
2290 agxbuf label = {0};
2291 symbols[0].type = T_edge;
2292 tchk[V_this][1] = Y(E);
2293 bp->n_estmts = case_infos_size(&inp->edge_stmts);
2294 agxbprint(&label, "%s%" PRISIZE_T, PREFIX, i);
2295 bp->edge_stmts = mkStmts(prog, src, inp->edge_stmts, agxbuse(&label));
2296 agxbfree(&label);
2297 if (getErrorErrors())
2298 goto finishBlk;
2299 bp->does_walk_graph = true;
2300 }
2301
2302finishBlk:
2303 if (getErrorErrors()) {
2304 free(bp->node_stmts);
2305 free(bp->edge_stmts);
2306 bp->node_stmts = 0;
2307 bp->edge_stmts = 0;
2308 }
2309
2310 return has_begin_g || bp->does_walk_graph;
2311}
2312
2313// convert command line flags to actions in END_G
2314static const char *doFlags(compflags_t flags) {
2315 if (flags.srcout) {
2316 if (flags.induce) {
2317 return "\n$O = $G;\ninduce($O);\n";
2318 }
2319 return "\n$O = $G;\n";
2320 }
2321 if (flags.induce) {
2322 return "\ninduce($O);\n";
2323 }
2324 return "\n";
2325}
2326
2327// convert gpr sections in libexpr program
2329 const char *endg_sfx = NULL;
2330 bool uses_graph = false;
2331
2332 /* Make sure we have enough bits for types */
2333 assert(CHAR_BIT * sizeof(tctype) >= (1 << TBITS));
2334
2335 comp_prog *p = calloc(1, sizeof(comp_prog));
2336 if (!p) {
2337 error(ERROR_ERROR, "could not create compiled program: out of memory");
2338 goto finish;
2339 }
2340
2341 if (flags.srcout || flags.induce || flags.clone) {
2342 endg_sfx = doFlags(flags);
2343 }
2344
2345 if (!initDisc(state))
2346 goto finish;
2347
2348 exinit();
2349 if (!(p->prog = exopen(state->dp)))
2350 goto finish;
2351
2352 codePhase = 0;
2353 if (inp->begin_stmt) {
2354 p->begin_stmt = compile(p->prog, inp->source, inp->begin_stmt, inp->l_begin,
2355 0, 0, VOIDTYPE);
2356 if (getErrorErrors())
2357 goto finish;
2358 }
2359
2360 if (!parse_blocks_is_empty(&inp->blocks)) {
2361 comp_block *bp;
2362
2363 p->blocks = bp =
2364 gv_calloc(parse_blocks_size(&inp->blocks), sizeof(comp_block));
2365
2366 for (size_t i = 0; i < parse_blocks_size(&inp->blocks); bp++, i++) {
2367 parse_block *ibp = parse_blocks_at(&inp->blocks, i);
2368 uses_graph |= mkBlock(bp, p->prog, inp->source, ibp, i);
2369 if (getErrorErrors())
2370 goto finish;
2371 p->n_blocks++;
2372 }
2373 }
2374 p->uses_graph = uses_graph;
2375
2376 codePhase = 4;
2377 if (inp->endg_stmt || endg_sfx) {
2378 symbols[0].type = T_graph;
2379 tchk[V_this][1] = Y(G);
2380 p->endg_stmt = compile(p->prog, inp->source, inp->endg_stmt, inp->l_endg,
2381 "_end_g", endg_sfx, VOIDTYPE);
2382 if (getErrorErrors())
2383 goto finish;
2384 }
2385
2386 codePhase = 5;
2387 if (inp->end_stmt) {
2388 symbols[0].type = T_obj;
2389 p->end_stmt = compile(p->prog, inp->source, inp->end_stmt, inp->l_end,
2390 "_end_", 0, VOIDTYPE);
2391 if (getErrorErrors())
2392 goto finish;
2393 }
2394 setErrorLine(0); /* execution errors have no line numbers */
2395
2396 if (p->end_stmt)
2397 p->uses_graph = true;
2398
2399finish:
2400 if (getErrorErrors()) {
2401 freeCompileProg(p);
2402 p = 0;
2403 }
2404
2405 return p;
2406}
2407
2409 comp_block *bp;
2410
2411 if (!p)
2412 return;
2413
2414 exclose(p->prog);
2415 for (size_t i = 0; i < p->n_blocks; i++) {
2416 bp = p->blocks + i;
2417 free(bp->node_stmts);
2418 free(bp->edge_stmts);
2419 }
2420 free(p->blocks);
2421 free(p);
2422}
2423
2424/* Read graph from file and initialize
2425 * dynamic data.
2426 */
2427Agraph_t *readG(FILE *fp) {
2428 Agraph_t *g = agread(fp, NULL);
2429 if (g) {
2430 aginit(g, AGRAPH, UDATA, sizeof(gdata), false);
2431 aginit(g, AGNODE, UDATA, sizeof(ndata), false);
2432 aginit(g, AGEDGE, UDATA, sizeof(edata), false);
2433 }
2434 return g;
2435}
2436
2437// open graph and initialize dynamic data
2438Agraph_t *openG(char *name, Agdesc_t desc) {
2439 Agraph_t *g = agopen(name, desc, NULL);
2440 if (g)
2441 agbindrec(g, UDATA, sizeof(gdata), false);
2442 return g;
2443}
2444
2445// open subgraph and initialize dynamic data
2446Agraph_t *openSubg(Agraph_t *g, char *name) {
2447 Agraph_t *sg;
2448
2449 sg = agsubg(g, name, 1);
2450 if (sg && !aggetrec(sg, UDATA, 0))
2451 agbindrec(sg, UDATA, sizeof(gdata), false);
2452 return sg;
2453}
2454
2455// create node and initialize dynamic data
2456Agnode_t *openNode(Agraph_t *g, char *name) {
2457 Agnode_t *np;
2458
2459 np = agnode(g, name, 1);
2460 if (np && !aggetrec(np, UDATA, 0))
2461 agbindrec(np, UDATA, sizeof(ndata), false);
2462 return np;
2463}
2464
2465// create edge and initialize dynamic data
2466Agedge_t *openEdge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *key) {
2467 Agedge_t *ep;
2468 Agraph_t *root;
2469
2470 root = sameG(t, h, "openEdge", "tail and head nodes");
2471 if (!root)
2472 return 0;
2473 if (g) {
2474 if (!sameG(g, root, "openEdge", "subgraph and nodes"))
2475 return 0;
2476 } else
2477 g = root;
2478
2479 ep = agedge(g, t, h, key, 1);
2480 if (ep && !aggetrec(ep, UDATA, 0))
2481 agbindrec(ep, UDATA, sizeof(edata), false);
2482 return ep;
2483}
Agedge_t * isEdge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *key)
Definition actions.c:435
int indexOf(char *s1, char *s2)
Definition actions.c:61
Agraph_t * sameG(void *p1, void *p2, char *fn, char *msg)
Definition actions.c:41
Agraph_t * freadFile(Expr_t *ex, long long fd)
Definition actions.c:599
Agobj_t * cloneO(Agraph_t *g, Agobj_t *obj)
Definition actions.c:342
size_t match(char *str, char *pat)
Definition actions.c:95
int deleteObj(Agraph_t *g, Agobj_t *obj)
Definition actions.c:507
int writeFile(Agraph_t *g, char *f)
Definition actions.c:550
int fwriteFile(Expr_t *ex, Agraph_t *g, long long fd)
Definition actions.c:589
long rindexOf(char *s1, char *s2)
Definition actions.c:69
int sfioWrite(Agraph_t *g, FILE *fp)
Definition actions.c:536
char * toLower(Expr_t *pgm, char *src)
Definition actions.c:706
Agraph_t * cloneG(Agraph_t *g, char *name)
Definition actions.c:321
int lockGraph(Agraph_t *g, int v)
Definition actions.c:479
char * toHtml(Agraph_t *g, char *arg)
Definition actions.c:744
int compare(Agobj_t *l, Agobj_t *r)
Definition actions.c:675
Agobj_t * copy(Agraph_t *g, Agobj_t *obj)
Definition actions.c:145
Agraph_t * readFile(char *f)
Definition actions.c:571
Agraph_t * compOf(Agraph_t *g, Agnode_t *n)
Definition actions.c:413
char * colorx(Expr_t *ex, const char *incolor, char *fmt)
Definition actions.c:773
char * toUpper(Expr_t *pgm, char *src)
Definition actions.c:725
char * readLine(Expr_t *ex, long long fd)
Definition actions.c:652
int closeFile(Expr_t *ex, long long fd)
Definition actions.c:627
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:78
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:234
static WUR char * agxbuse(agxbuf *xb)
Definition agxbuf.h:307
static int agxbputc(agxbuf *xb, char c)
add character to buffer
Definition agxbuf.h:277
static char * agxbdisown(agxbuf *xb)
Definition agxbuf.h:327
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
static void addNode(block_t *bp, Agnode_t *n)
Definition blocktree.c:16
abstract graph C library, Cgraph API
static char * deparse(Expr_t *ex, Exnode_t *n, agxbuf *xb)
Definition compile.c:192
static tctype typeChkExp(Exref_t *ref, Exid_t *sym)
Definition compile.c:1721
static char * getDfltAttr(Agraph_t *gp, char *k, char *name)
Definition compile.c:544
#define MINTYPE
Definition compile.c:1498
Agedge_t * openEdge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *key)
Definition compile.c:2466
comp_prog * compileProg(parse_prog *inp, Gpr_t *state, compflags_t flags)
Definition compile.c:2328
static bool mkBlock(comp_block *bp, Expr_t *prog, char *src, parse_block *inp, size_t i)
Definition compile.c:2253
#define MIN(a, b)
Definition compile.c:41
static int lookup(Expr_t *pgm, Agobj_t *objp, Exid_t *sym, Extype_t *v)
Definition compile.c:333
static Agdesc_t xargs(char *args)
Definition compile.c:159
static tctype typeChk(tctype intype, Exid_t *sym)
Definition compile.c:1638
static int codePhase
Definition compile.c:1625
static int strToTvtype(char *s)
Definition compile.c:1920
static case_stmt * mkStmts(Expr_t *prog, char *src, case_infos_t cases, const char *lbl)
Definition compile.c:2214
Agraph_t * openG(char *name, Agdesc_t desc)
Definition compile.c:2438
static char * getArg(int n, Gpr_t *state)
Definition compile.c:465
#define haveTarget
Definition compile.c:1628
Agraph_t * openSubg(Agraph_t *g, char *name)
Definition compile.c:2446
static char * tvtypeToStr(long long v)
Definition compile.c:1959
static int stringOf(Expr_t *prog, Exnode_t *x, int arg)
Definition compile.c:2014
static Agobj_t * deref(Expr_t *pgm, Exnode_t *x, Exref_t *ref, Agobj_t *objp, Gpr_t *state)
Definition compile.c:202
static int binary(Exnode_t *l, Exnode_t *ex, Exnode_t *r, int arg)
Definition compile.c:1808
static char * bbOf(Expr_t *pgm, char *pt, bool getll)
Definition compile.c:89
void freeCompileProg(comp_prog *p)
Definition compile.c:2408
static Exdisc_t * initDisc(Gpr_t *state)
Definition compile.c:2133
#define haveGraph
Definition compile.c:1627
static Extype_t getval(Expr_t *pgm, Exnode_t *node, Exid_t *sym, Exref_t *ref, void *env, int elt, Exdisc_t *disc)
Definition compile.c:556
Agnode_t * openNode(Agraph_t *g, char *name)
Definition compile.c:2456
static char * typeName(long op)
Definition compile.c:1500
Agraph_t * readG(FILE *fp)
Definition compile.c:2427
static char * xyOf(Expr_t *pgm, char *pt, bool getx)
Definition compile.c:110
static char * kindToStr(int kind)
Definition compile.c:310
static char * nameOf(Expr_t *ex, Agobj_t *obj, agxbuf *tmps)
Definition compile.c:56
static int a2t[]
Definition compile.c:2129
static int setDfltAttr(Agraph_t *gp, char *k, char *name, char *value)
Definition compile.c:473
static const char * doFlags(compflags_t flags)
Definition compile.c:2314
static Extype_t refval(Expr_t *pgm, Exnode_t *node, Exid_t *sym, Exref_t *ref)
Definition compile.c:1740
static long long ptr2int(const void *p)
Definition compile.c:51
static int setattr(Agobj_t *objp, char *name, char *val)
Definition compile.c:302
static Exnode_t * compile(Expr_t *prog, char *src, char *input, int line, const char *lbl, const char *sfx, int kind)
Definition compile.c:2169
static void assignable(Agobj_t *objp, unsigned char *name)
Definition compile.c:269
static int convert(Exnode_t *x, long type, int arg)
Definition compile.c:2045
static int setval(Expr_t *pgm, Exnode_t *x, Exid_t *sym, Exref_t *ref, void *env, Extype_t v)
Definition compile.c:1506
static char * nxtAttr(Agraph_t *gp, char *k, char *name)
Definition compile.c:520
static Extype_t keyval(Extype_t v, long type)
Definition compile.c:2121
static char * kindOf(Agobj_t *objp)
Definition compile.c:328
static void * int2ptr(long long i)
Definition compile.c:49
static void checkGuard(Exnode_t *gp, char *src, int line)
Definition compile.c:2204
static Extype_t length(Exid_t *rhs, Exdisc_t *disc)
Definition compile.c:1588
static int toKind(char *k, char *fn)
Definition compile.c:505
static int isedge(Agobj_t *obj)
Definition compile.c:37
static int in(Extype_t lhs, Exid_t *rhs, Exdisc_t *disc)
Definition compile.c:1612
#define MAX(a, b)
Definition compile.c:42
static int posOf(Agnode_t *np, int idx, double *v)
Definition compile.c:130
#define UDATA
Definition compile.h:30
int getErrorErrors(void)
Definition error.c:32
void errorf(void *handle, void *discipline, int level, const char *s,...)
Definition error.c:92
void setErrorLine(int line)
Definition error.c:25
void setErrorFileLine(char *src, int line)
Definition error.c:26
#define ERROR_WARNING
Definition error.h:35
#define ERROR_ERROR
Definition error.h:36
void exdump(Expr_t *ex, Exnode_t *node, agxbuf *xb)
Definition excc.c:629
void exerror(const char *format,...)
Definition exerror.c:62
char * exstring(Expr_t *ex, char *s)
Definition exeval.c:2026
void * exstralloc(Expr_t *ex, size_t sz)
Definition exeval.c:2034
Exnode_t * exexpr(Expr_t *ex, const char *name, Exid_t *sym, int type)
Definition exexpr.c:26
Expr_t * exopen(Exdisc_t *disc)
Definition exopen.c:38
#define DYNAMIC
Definition exparse.h:167
#define GE
Definition exparse.h:220
#define NE
Definition exparse.h:218
#define FLOATING
Definition exparse.h:155
#define VOIDTYPE
Definition exparse.h:157
#define CONSTANT
Definition exparse.h:163
#define LE
Definition exparse.h:219
#define EQ
Definition exparse.h:217
static Dtdisc_t disc
Definition exparse.y:207
expr procedure type
Definition exparse.y:206
int exisAssign(Exnode_t *)
#define TBITS
Definition expr.h:74
#define EX_VERSION
Definition expr.h:38
#define F
Definition expr.h:70
void(* Exerror_f)(Expr_t *, Exdisc_t *, int, const char *,...)
Definition expr.h:89
#define I
Definition expr.h:71
#define EX_CHARSTRING
Definition expr.h:44
Exnode_t * exnoncast(Exnode_t *)
#define EX_CALL
Definition expr.h:48
#define BUILTIN(t)
Definition expr.h:58
void exinit(void)
#define EX_ARRAY
Definition expr.h:47
void exclose(Expr_t *)
#define EX_UNDECLARED
Definition expr.h:45
#define INTEGRAL(t)
Definition expr.h:57
int excomp(Expr_t *p, const char *name, int line, FILE *fp, char *prefix)
#define S
Definition expr.h:72
Extype_t exzero(long int)
Definition exzero.c:24
static snode guard
Definition fPQ.c:21
static int flags
Definition gc.c:61
#define E
Definition gdefs.h:6
@ LAST_V
Definition gdefs.h:19
@ MAXNAME
Definition gdefs.h:46
static Exid_t symbols[]
Definition gdefs.h:52
static char * typenames[]
Definition gdefs.h:60
#define YALL
Definition gdefs.h:10
static tctype tchk[][2]
Definition gdefs.h:87
unsigned short tctype
Definition gdefs.h:85
#define Y(i)
Definition gdefs.h:3
#define G
Definition gdefs.h:7
#define V
Definition gdefs.h:5
static double len(glCompPoint p)
Definition glutils.c:136
void free(void *)
#define NAME
Definition gmlparse.h:135
#define ID
Definition gmlparse.h:134
#define STRING
Definition gmlparse.h:133
#define INTEGER
Definition gmlparse.h:131
#define SIZE_MAX
Definition gmlscan.c:347
gvprbinding * findBinding(Gpr_t *state, char *fname)
Definition gprstate.c:67
bool validTVT(long long c)
Definition gprstate.c:26
trav_type
Definition gprstate.h:27
@ TV_flat
Definition gprstate.h:27
@ TV_fwd
Definition gprstate.h:29
@ TV_rev
Definition gprstate.h:29
@ TV_postdfs
Definition gprstate.h:30
@ TV_dfs
Definition gprstate.h:29
@ TV_prepostfwd
Definition gprstate.h:31
@ TV_en
Definition gprstate.h:27
@ TV_prepostrev
Definition gprstate.h:31
@ TV_prepostdfs
Definition gprstate.h:31
@ TV_postfwd
Definition gprstate.h:30
@ TV_bfs
Definition gprstate.h:28
@ TV_ne
Definition gprstate.h:27
@ TV_postrev
Definition gprstate.h:30
#define T_node
Definition grammar.h:114
#define T_edge
Definition grammar.h:115
#define T_graph
Definition grammar.h:113
node NULL
Definition grammar.y:181
int agnedges(Agraph_t *g)
Definition graph.c:163
int agdegree(Agraph_t *g, Agnode_t *n, int in, int out)
Definition graph.c:225
int agnnodes(Agraph_t *g)
Definition graph.c:157
size_t graphviz_node_induce(Agraph_t *g, Agraph_t *edgeset)
Definition node_induce.c:9
Agsym_t * agattr_text(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up text attributes of a graph
Definition attr.c:348
Agsym_t * agattrsym(void *obj, char *name)
looks up a string attribute for a graph object given as an argument
Definition attr.c:153
Agsym_t * agnxtattr(Agraph_t *g, int kind, Agsym_t *attr)
permits traversing the list of attributes of a given type
Definition attr.c:377
int agxset(void *obj, Agsym_t *sym, const char *value)
Definition attr.c:536
char * agxget(void *obj, Agsym_t *sym)
Definition attr.c:472
Agedge_t * agedge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *name, int createflag)
Definition edge.c:253
#define AGMKOUT(e)
Definition cgraph.h:982
Agedge_t * agnxtin(Agraph_t *g, Agedge_t *e)
Definition edge.c:71
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:26
#define agtail(e)
Definition cgraph.h:988
Agedge_t * agnxtedge(Agraph_t *g, Agedge_t *e, Agnode_t *n)
Definition edge.c:96
#define aghead(e)
Definition cgraph.h:989
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:41
Agedge_t * agfstedge(Agraph_t *g, Agnode_t *n)
Definition edge.c:87
#define AGTAIL(e)
Definition cgraph.h:984
Agedge_t * agfstin(Agraph_t *g, Agnode_t *n)
Definition edge.c:57
#define AGHEAD(e)
Definition cgraph.h:985
int agisdirected(Agraph_t *g)
Definition graph.c:178
int agisstrict(Agraph_t *g)
Definition graph.c:188
Agraph_t * agopen(char *name, Agdesc_t desc, Agdisc_t *disc)
creates a new graph with the given name and kind
Definition graph.c:42
Agraph_t * agread(void *chan, Agdisc_t *disc)
constructs a new graph
Definition grammar.c:2063
Agdesc_t Agdirected
directed
Definition graph.c:272
Agnode_t * agnode(Agraph_t *g, char *name, int createflag)
Definition node.c:141
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:48
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:41
int agrelabel_node(Agnode_t *n, char *newname)
Definition node.c:230
Agraph_t * agraphof(void *obj)
Definition obj.c:185
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:143
#define AGID(obj)
returns the unique integer ID associated with the object
Definition cgraph.h:221
#define AGTYPE(obj)
returns AGRAPH, AGNODE, or AGEDGE depending on the type of the object
Definition cgraph.h:216
int agcontains(Agraph_t *, void *obj)
returns non-zero if obj is a member of (sub)graph
Definition obj.c:233
int agobjkind(void *obj)
Definition obj.c:252
Agraph_t * agroot(void *obj)
Definition obj.c:168
@ AGOUTEDGE
Definition cgraph.h:207
@ AGEDGE
Definition cgraph.h:207
@ AGNODE
Definition cgraph.h:207
@ AGINEDGE
Definition cgraph.h:207
@ AGRAPH
Definition cgraph.h:207
Agrec_t * aggetrec(void *obj, const char *name, int move_to_front)
find record in circular list and do optional move-to-front and lock
Definition rec.c:41
void aginit(Agraph_t *g, int kind, const char *rec_name, int rec_size, int move_to_front)
attach new records to objects of specified kind
Definition rec.c:170
void * agbindrec(void *obj, const char *name, unsigned int recsize, int move_to_front)
attaches a new record of the given size to the object
Definition rec.c:89
int aghtmlstr(const char *)
Definition refstr.c:438
Agraph_t * agparent(Agraph_t *g)
Definition subg.c:86
Agraph_t * agfstsubg(Agraph_t *g)
Definition subg.c:73
Agraph_t * agnxtsubg(Agraph_t *subg)
Definition subg.c:78
Agraph_t * agsubg(Agraph_t *g, char *name, int cflag)
Definition subg.c:53
agxbput(xb, staging)
#define GV_NEXT_SET
Definition gvpr.h:53
table Syntax error
Definition htmlparse.y:294
static void addEdge(edge_t *de, edge_t *e)
Definition layout.c:349
static void copyAttr(graph_t *g, graph_t *dg, char *attr)
Definition layout.c:365
static int * ps
Definition lu.c:51
static FILE * openFile(const char *argv0, const char *name, const char *mode)
Definition openFile.h:8
static char * canon(graph_t *g, char *s, char *buffer)
Definition output.c:101
#define PRISIZE_T
Definition prisize_t.h:25
static int label(Agnode_t *n, int nodecnt, int *edgecnt)
Definition sccmap.c:161
void ref(Site *v)
Definition site.c:59
static bool startswith(const char *s, const char *prefix)
does the string s begin with the string prefix?
Definition startswith.h:11
graph descriptor
Definition cgraph.h:284
unsigned strict
Definition cgraph.h:286
unsigned directed
Definition cgraph.h:285
a generic header of Agraph_s, Agnode_s and Agedge_s
Definition cgraph.h:210
graph or subgraph
Definition cgraph.h:424
string attribute descriptor symbol in Agattr_s.dict
Definition cgraph.h:651
char * name
Definition cgraph.h:653
char * defval
Definition cgraph.h:654
Exid_t * symbols
Definition expr.h:170
char *(* typename)(long)
Definition expr.h:178
Extype_t(* reff)(Expr_t *, Exnode_t *, Exid_t *, Exref_t *)
Definition expr.h:187
int * types
Definition expr.h:215
Exerror_f errorf
Definition expr.h:184
Extype_t(* keyf)(Extype_t, long)
Definition expr.h:182
int(* convertf)(Exnode_t *, long, int)
Definition expr.h:174
int(* binaryf)(Exnode_t *, Exnode_t *, Exnode_t *, int)
Definition expr.h:176
Extype_t(* getf)(Expr_t *, Exnode_t *, Exid_t *, Exref_t *, void *, int, Exdisc_t *)
Definition expr.h:185
uint64_t version
Definition expr.h:168
int(* stringof)(Expr_t *, Exnode_t *, int)
Definition expr.h:180
int(* inf)(Extype_t lhs, Exid_t *rhs, Exdisc_t *disc)
Definition expr.h:212
Exexit_f exitf
Definition expr.h:214
uint64_t flags
Definition expr.h:169
int(* setf)(Expr_t *, Exnode_t *, Exid_t *, Exref_t *, void *, Extype_t)
Definition expr.h:189
void * user
Definition expr.h:216
Extype_t(* lengthf)(Exid_t *rhs, Exdisc_t *disc)
Definition expr.h:200
Definition expr.h:93
long type
Definition expr.h:97
long lex
Definition expr.h:95
char name[EX_NAMELEN]
Definition expr.h:101
long index
Definition expr.h:96
long op
operator
Definition expr.h:150
long type
value type
Definition expr.h:149
Exdata_t data
Definition expr.h:158
Definition expr.h:220
char ** argv
Definition gprstate.h:52
Agedge_t * tvedge
Definition gprstate.h:49
char * tgtname
Definition gprstate.h:43
Exexit_f exitf
Definition gprstate.h:42
Agobj_t * curobj
Definition gprstate.h:39
Agraph_t * target
Definition gprstate.h:37
Agraph_t * curgraph
Definition gprstate.h:35
int flags
Definition gprstate.h:53
FILE * outFile
Definition gprstate.h:45
Agraph_t * outgraph
Definition gprstate.h:38
Exdisc_t * dp
Definition gprstate.h:40
Agnode_t * tvroot
Definition gprstate.h:47
Agnode_t * tvnext
Definition gprstate.h:48
char * infname
Definition gprstate.h:44
Agraph_t * nextgraph
Definition gprstate.h:36
Exerror_f errf
Definition gprstate.h:41
int name_used
Definition gprstate.h:50
int argc
Definition gprstate.h:51
trav_type tvt
Definition gprstate.h:46
char * guard
Definition parse.h:25
int astart
Definition parse.h:26
char * action
Definition parse.h:27
int gstart
Definition parse.h:24
Exnode_t * guard
Definition compile.h:26
Exnode_t * action
Definition compile.h:27
case_stmt * node_stmts
Definition compile.h:71
Exnode_t * begg_stmt
Definition compile.h:67
size_t n_nstmts
Definition compile.h:69
size_t n_estmts
Definition compile.h:70
case_stmt * edge_stmts
Definition compile.h:72
bool does_walk_graph
does this block have a node or edge statement?
Definition compile.h:68
Exnode_t * begin_stmt
Definition compile.h:78
comp_block * blocks
Definition compile.h:80
Expr_t * prog
Definition compile.h:77
size_t n_blocks
Definition compile.h:79
bool uses_graph
does this program use the input graph?
Definition compile.h:76
Exnode_t * endg_stmt
Definition compile.h:81
Exnode_t * end_stmt
Definition compile.h:82
gvpruserfn fn
Definition gvpr.h:60
int l_beging
Definition parse.h:38
case_infos_t node_stmts
Definition parse.h:40
case_infos_t edge_stmts
Definition parse.h:41
char * begg_stmt
Definition parse.h:39
int l_end
Definition parse.h:48
int l_begin
Definition parse.h:48
int l_endg
Definition parse.h:48
char * end_stmt
Definition parse.h:52
char * endg_stmt
Definition parse.h:51
char * begin_stmt
Definition parse.h:49
parse_blocks_t blocks
Definition parse.h:50
char * source
Definition parse.h:47
static short TFA_State
Definition trieFA.h:49
#define TFA_Init()
Definition trieFA.h:55
#define TFA_Advance(C)
Definition trieFA.h:61
#define TFA_Definition()
Definition trieFA.h:86
long long integer
Definition exparse.h:240
double floating
Definition exparse.h:237
char * string
Definition exparse.h:242
struct Exdata_u::@89 constant
struct Exdata_u::@92 variable
Exnode_t * dyna
Definition expr.h:138
Extype_t value
Definition expr.h:116
Definition grammar.c:89
#define UNREACHABLE()
Definition unreachable.h:30