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