Graphviz 13.0.0~dev.20250511.0440
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
1655 Extype_t v = {0};
1656 switch (rhs->index) {
1657 case A_ARGV: {
1658 Gpr_t *const state = disc->user;
1659 v.integer = state->argc;
1660 break;
1661 }
1662 default:
1663 exerror("unknown array name: %s", rhs->name);
1664 break;
1665 }
1666 return v;
1667}
1668
1678static int in(Extype_t lhs, Exid_t *rhs, Exdisc_t *disc) {
1679 switch (rhs->index) {
1680 case A_ARGV: {
1681 Gpr_t *const state = disc->user;
1682 return lhs.integer >= 0 && lhs.integer < state->argc;
1683 }
1684 default:
1685 exerror("unknown array name: %s", rhs->name);
1686 break;
1687 }
1688 return 0;
1689}
1690
1691static int codePhase;
1692
1693#define haveGraph (1 <= codePhase && codePhase <= 4)
1694#define haveTarget (2 <= codePhase && codePhase <= 4)
1695#define inWalk (2 <= codePhase && codePhase <= 3)
1696
1697/* typeChk:
1698 * Type check input type against implied type of symbol sym.
1699 * If okay, return result type; else return 0.
1700 * For functions, input type set must intersect with function domain.
1701 * This means type errors may occur, but these will be caught at runtime.
1702 * For non-functions, input type must be 0.
1703 */
1704static tctype typeChk(tctype intype, Exid_t *sym) {
1705 tctype dom = 0, rng = 0;
1706
1707 switch (sym->lex) {
1708 case DYNAMIC:
1709 dom = 0;
1710 switch (sym->type) {
1711 case T_obj:
1712 rng = YALL;
1713 break;
1714 case T_node:
1715 rng = Y(V);
1716 break;
1717 case T_graph:
1718 rng = Y(G);
1719 break;
1720 case T_edge:
1721 rng = Y(E);
1722 break;
1723 case INTEGER:
1724 rng = Y(I);
1725 break;
1726 case FLOATING:
1727 rng = Y(F);
1728 break;
1729 case STRING:
1730 rng = Y(S);
1731 break;
1732 default:
1733 exerror("unknown dynamic type %" PRIdMAX " of symbol %s",
1734 (intmax_t)sym->type, sym->name);
1735 break;
1736 }
1737 break;
1738 case ID:
1739 if (sym->index <= MAXNAME) {
1740 switch (sym->index) {
1741 case V_travroot:
1742 case V_this:
1743 case V_thisg:
1744 case V_nextg:
1745 if (!haveGraph)
1746 exerror("keyword %s cannot be used in BEGIN/END statements",
1747 sym->name);
1748 break;
1749 case V_targt:
1750 if (!haveTarget)
1751 exerror("keyword %s cannot be used in BEGIN/BEG_G/END statements",
1752 sym->name);
1753 break;
1754 }
1755 dom = tchk[sym->index][0];
1756 rng = tchk[sym->index][1];
1757 } else {
1758 dom = YALL;
1759 rng = Y(S);
1760 }
1761 break;
1762 case NAME:
1763 if (!intype && !haveGraph)
1764 exerror("undeclared, unmodified names like \"%s\" cannot be\nused in "
1765 "BEGIN and END statements",
1766 sym->name);
1767 dom = YALL;
1768 rng = Y(S);
1769 break;
1770 default:
1771 exerror("unexpected symbol in typeChk: name %s, lex %" PRIdMAX, sym->name,
1772 (intmax_t)sym->lex);
1773 break;
1774 }
1775
1776 if (dom) {
1777 if (!intype)
1778 intype = YALL; /* type of $ */
1779 if (!(dom & intype))
1780 rng = 0;
1781 } else if (intype)
1782 rng = 0;
1783 return rng;
1784}
1785
1786/* typeChkExp:
1787 * Type check variable expression.
1788 */
1790 tctype ty;
1791
1792 if (ref) {
1793 ty = typeChk(0, ref->symbol);
1794 for (ref = ref->next; ty && ref; ref = ref->next)
1795 ty = typeChk(ty, ref->symbol);
1796 if (!ty)
1797 return 0;
1798 } else
1799 ty = 0;
1800 return typeChk(ty, sym);
1801}
1802
1803/* refval:
1804 * Called during compilation for uses of references: abc.x
1805 * Also for abc.f(..), type abc.v, "abc".x and CONSTANTS.
1806 * The grammar has been altered to disallow the first 3.
1807 * Type check expressions; return value unused.
1808 */
1810
1811 Extype_t v;
1812 if (sym->lex == CONSTANT) {
1813 switch (sym->index) {
1814 case C_flat:
1815 v.integer = TV_flat;
1816 break;
1817 case C_ne:
1818 v.integer = TV_ne;
1819 break;
1820 case C_en:
1821 v.integer = TV_en;
1822 break;
1823 case C_bfs:
1824 v.integer = TV_bfs;
1825 break;
1826 case C_dfs:
1827 v.integer = TV_dfs;
1828 break;
1829 case C_fwd:
1830 v.integer = TV_fwd;
1831 break;
1832 case C_rev:
1833 v.integer = TV_rev;
1834 break;
1835 case C_postdfs:
1836 v.integer = TV_postdfs;
1837 break;
1838 case C_postfwd:
1839 v.integer = TV_postfwd;
1840 break;
1841 case C_postrev:
1842 v.integer = TV_postrev;
1843 break;
1844 case C_prepostdfs:
1846 break;
1847 case C_prepostfwd:
1849 break;
1850 case C_prepostrev:
1852 break;
1853 case C_null:
1854 v.integer = 0;
1855 break;
1856 default:
1857 v = exzero(node->type);
1858 break;
1859 }
1860 } else {
1861 if (!typeChkExp(ref, sym)) {
1862 agxbuf xb = {0};
1863 exerror("type error using %s", deparse(pgm, node, &xb));
1864 agxbfree(&xb);
1865 }
1866 v = exzero(node->type);
1867 }
1868 return v;
1869}
1870
1871/* binary:
1872 * Evaluate (l ex->op r) producing a value of type ex->type,
1873 * stored in l.
1874 * May be unary, with r = NULL
1875 * Return -1 if operation cannot be done, 0 otherwise.
1876 * If arg is != 0, operation unnecessary; just report possibility.
1877 */
1878static int binary(Exnode_t *l, Exnode_t *ex, Exnode_t *r, int arg) {
1879 Agobj_t *lobjp;
1880 Agobj_t *robjp;
1881 int ret = -1;
1882
1883 if (BUILTIN(l->type))
1884 return -1;
1885 if (r && BUILTIN(r->type))
1886 return -1;
1887 if (!INTEGRAL(ex->type))
1888 return -1;
1889
1890 if (l->type == T_tvtyp) {
1891
1892 if (!r)
1893 return -1; /* Assume libexpr handled unary */
1894 if (r->type != T_tvtyp)
1895 return -1;
1896
1897 long long li = l->data.constant.value.integer;
1898 long long ri = r->data.constant.value.integer;
1899 switch (ex->op) {
1900 case EQ:
1901 if (arg)
1902 return 0;
1903 l->data.constant.value.integer = li == ri;
1904 ret = 0;
1905 break;
1906 case NE:
1907 if (arg)
1908 return 0;
1909 l->data.constant.value.integer = li != ri;
1910 ret = 0;
1911 break;
1912 case '<':
1913 if (arg)
1914 return 0;
1915 l->data.constant.value.integer = li < ri;
1916 ret = 0;
1917 break;
1918 case LE:
1919 if (arg)
1920 return 0;
1921 l->data.constant.value.integer = li <= ri;
1922 ret = 0;
1923 break;
1924 case GE:
1925 if (arg)
1926 return 0;
1927 l->data.constant.value.integer = li >= ri;
1928 ret = 0;
1929 break;
1930 case '>':
1931 if (arg)
1932 return 0;
1933 l->data.constant.value.integer = li > ri;
1934 ret = 0;
1935 break;
1936 }
1937 }
1938
1939 /* l is a graph object; make sure r is also */
1940 if (r && r->type == T_tvtyp)
1941 return -1;
1942
1943 lobjp = int2ptr(l->data.constant.value.integer);
1944 if (r)
1945 robjp = int2ptr(r->data.constant.value.integer);
1946 else
1947 robjp = 0;
1948 switch (ex->op) {
1949 case EQ:
1950 if (arg)
1951 return 0;
1952 l->data.constant.value.integer = !compare(lobjp, robjp);
1953 ret = 0;
1954 break;
1955 case NE:
1956 if (arg)
1957 return 0;
1958 l->data.constant.value.integer = compare(lobjp, robjp);
1959 ret = 0;
1960 break;
1961 case '<':
1962 if (arg)
1963 return 0;
1964 l->data.constant.value.integer = compare(lobjp, robjp) < 0;
1965 ret = 0;
1966 break;
1967 case LE:
1968 if (arg)
1969 return 0;
1970 l->data.constant.value.integer = compare(lobjp, robjp) <= 0;
1971 ret = 0;
1972 break;
1973 case GE:
1974 if (arg)
1975 return 0;
1976 l->data.constant.value.integer = compare(lobjp, robjp) >= 0;
1977 ret = 0;
1978 break;
1979 case '>':
1980 if (arg)
1981 return 0;
1982 l->data.constant.value.integer = compare(lobjp, robjp) > 0;
1983 ret = 0;
1984 break;
1985 }
1986
1987 return ret;
1988}
1989
1990/* strToTvtype:
1991 */
1992static int strToTvtype(char *s) {
1993 int rt = 0;
1994 char *sfx;
1995
1996 if (startswith(s, "TV_")) {
1997 sfx = s + 3;
1998 if (!strcmp(sfx, "flat")) {
1999 rt = TV_flat;
2000 } else if (!strcmp(sfx, "ne")) {
2001 rt = TV_ne;
2002 } else if (!strcmp(sfx, "en")) {
2003 rt = TV_en;
2004 } else if (!strcmp(sfx, "bfs")) {
2005 rt = TV_bfs;
2006 } else if (!strcmp(sfx, "dfs")) {
2007 rt = TV_dfs;
2008 } else if (!strcmp(sfx, "fwd")) {
2009 rt = TV_fwd;
2010 } else if (!strcmp(sfx, "rev")) {
2011 rt = TV_rev;
2012 } else if (!strcmp(sfx, "postdfs")) {
2013 rt = TV_postdfs;
2014 } else if (!strcmp(sfx, "postfwd")) {
2015 rt = TV_postfwd;
2016 } else if (!strcmp(sfx, "postrev")) {
2017 rt = TV_postrev;
2018 } else if (!strcmp(sfx, "prepostdfs")) {
2019 rt = TV_prepostdfs;
2020 } else if (!strcmp(sfx, "prepostfwd")) {
2021 rt = TV_prepostfwd;
2022 } else if (!strcmp(sfx, "prepostrev")) {
2023 rt = TV_prepostrev;
2024 } else
2025 exerror("illegal string \"%s\" for type tvtype_t", s);
2026 } else
2027 exerror("illegal string \"%s\" for type tvtype_t", s);
2028 return rt;
2029}
2030
2031/* tvtypeToStr:
2032 */
2033static char *tvtypeToStr(long long v) {
2034 char *s = 0;
2035
2036 switch (v) {
2037 case TV_flat:
2038 s = "TV_flat";
2039 break;
2040 case TV_ne:
2041 s = "TV_ne";
2042 break;
2043 case TV_en:
2044 s = "TV_en";
2045 break;
2046 case TV_bfs:
2047 s = "TV_bfs";
2048 break;
2049 case TV_dfs:
2050 s = "TV_dfs";
2051 break;
2052 case TV_fwd:
2053 s = "TV_fwd";
2054 break;
2055 case TV_rev:
2056 s = "TV_rev";
2057 break;
2058 case TV_postdfs:
2059 s = "TV_postdfs";
2060 break;
2061 case TV_postfwd:
2062 s = "TV_postfwd";
2063 break;
2064 case TV_postrev:
2065 s = "TV_postrev";
2066 break;
2067 case TV_prepostdfs:
2068 s = "TV_prepostdfs";
2069 break;
2070 case TV_prepostfwd:
2071 s = "TV_prepostfwd";
2072 break;
2073 case TV_prepostrev:
2074 s = "TV_prepostrev";
2075 break;
2076 default:
2077 exerror("Unexpected value %lld for type tvtype_t", v);
2078 break;
2079 }
2080 return s;
2081}
2082
2083/* stringOf:
2084 * Convert value x to type string.
2085 * Assume x does not have a built-in type
2086 * Return -1 if conversion cannot be done, 0 otherwise.
2087 * If arg is != 0, conversion unnecessary; just report possibility.
2088 */
2089static int stringOf(Expr_t *prog, Exnode_t *x, int arg) {
2090 Agobj_t *objp;
2091 int rv = 0;
2092
2093 if (arg)
2094 return 0;
2095
2096 if (x->type == T_tvtyp) {
2097 if (!(x->data.constant.value.string =
2099 rv = -1;
2100 } else {
2101 objp = int2ptr(x->data.constant.value.integer);
2102 if (!objp) {
2103 exerror("cannot generate name for NULL %s", typeName(x->type));
2104 rv = -1;
2105 } else {
2106 agxbuf tmp = {0};
2107 x->data.constant.value.string = nameOf(prog, objp, &tmp);
2108 agxbfree(&tmp);
2109 }
2110 }
2111 x->type = STRING;
2112 return rv;
2113}
2114
2115/* convert:
2116 * Convert value x of type x->type to type type.
2117 * Return -1 if conversion cannot be done, 0 otherwise.
2118 * If arg is != 0, conversion unnecessary; just report possibility.
2119 * In particular, assume x != 0 if arg == 0.
2120 */
2121static int convert(Exnode_t *x, long type, int arg) {
2122 Agobj_t *objp;
2123 int ret = -1;
2124
2125 /* If both types are built-in, let libexpr handle */
2126 if (BUILTIN(type) && BUILTIN(x->type))
2127 return -1;
2128 if (type == T_obj && x->type <= T_obj)
2129 ret = 0; /* trivial cast from specific graph object to T_obj */
2130 else if (type <= T_obj && x->type == INTEGER) {
2131 if (x->data.constant.value.integer == 0)
2132 ret = 0; /* allow NULL pointer */
2133 } else if (type == INTEGER) {
2134 ret = 0;
2135 } else if (x->type == T_obj) {
2136 /* check dynamic type */
2137 if (arg) {
2138 if (type != FLOATING && type <= T_obj)
2139 ret = 0;
2140 } else {
2141 objp = int2ptr(x->data.constant.value.integer);
2142 switch (type) {
2143 case T_graph:
2144 if (!objp || AGTYPE(objp) == AGRAPH)
2145 ret = 0;
2146 break;
2147 case T_node:
2148 if (!objp || AGTYPE(objp) == AGNODE)
2149 ret = 0;
2150 break;
2151 case T_edge:
2152 if (!objp || isedge(objp))
2153 ret = 0;
2154 break;
2155 }
2156 }
2157 } else if (type == STRING) {
2158 if (x->type == T_tvtyp) {
2159 ret = 0;
2160 if (!arg) {
2163 }
2164 }
2165 } else if (type == T_tvtyp && x->type == INTEGER) {
2166 if (arg)
2167 ret = 0;
2168 else if (validTVT(x->data.constant.value.integer))
2169 ret = 0;
2170 else
2171 exerror("Integer value %lld not legal for type tvtype_t",
2173 }
2174 /* in case libexpr hands us the trivial case */
2175 else if (x->type == type) {
2176 ret = 0;
2177 } else if (x->type == STRING) {
2178 char *s;
2179 if (type == T_tvtyp) {
2180 if (arg)
2181 ret = 0;
2182 else {
2183 ret = 0;
2184 s = x->data.constant.value.string;
2186 }
2187 }
2188 }
2189 if (!arg && ret == 0)
2190 x->type = type;
2191 return ret;
2192}
2193
2194/* keyval;
2195 * Calculate unique key for object.
2196 * We use this to unify local copies of nodes and edges.
2197 */
2198static Extype_t keyval(Extype_t v, long type) {
2199 if (type <= T_obj) {
2200 v.integer = AGID(int2ptr(v.integer));
2201 }
2202 return v;
2203}
2204
2205/* a2t:
2206 * Convert type indices to symbolic name.
2207 */
2208static int a2t[] = {0, FLOATING, INTEGER, STRING,
2209 T_node, T_edge, T_graph, T_obj};
2210
2211/* initDisc:
2212 * Create and initialize expr discipline.
2213 */
2214static Exdisc_t *initDisc(Gpr_t *state) {
2215 Exdisc_t *dp = calloc(1, sizeof(Exdisc_t));
2216 if (!dp) {
2217 error(ERROR_ERROR, "could not create libexp discipline: out of memory");
2218 return 0;
2219 }
2220
2221 dp->version = EX_VERSION;
2223 dp->symbols = symbols;
2224 dp->convertf = convert;
2225 dp->stringof = stringOf;
2226 dp->binaryf = binary;
2227 dp->typename = typeName;
2228 if (state->errf)
2229 dp->errorf = state->errf;
2230 else
2231 dp->errorf = (Exerror_f)errorf;
2232 dp->keyf = keyval;
2233 dp->getf = getval;
2234 dp->reff = refval;
2235 dp->setf = setval;
2236 dp->lengthf = length;
2237 dp->inf = in;
2238 dp->exitf = state->exitf;
2239 dp->types = a2t;
2240 dp->user = state;
2241
2242 state->dp = dp; /* dp is freed when state is freed */
2243
2244 return dp;
2245}
2246
2247/* compile:
2248 * Compile given string, then extract and return
2249 * typed expression.
2250 */
2251static Exnode_t *compile(Expr_t *prog, char *src, char *input, int line,
2252 const char *lbl, const char *sfx, int kind) {
2253 Exnode_t *e = 0;
2254 int rv;
2255
2256 /* create input stream */
2257 FILE *sf = tmpfile();
2258 assert(sf != NULL);
2259 if (input) {
2260 fputs(input, sf);
2261 }
2262 if (sfx) {
2263 fputs(sfx, sf);
2264 }
2265 rewind(sf);
2266
2267 /* prefixing label if necessary */
2268 agxbuf label = {0};
2269 if (lbl) {
2270 agxbprint(&label, "%s:\n", lbl);
2271 line--;
2272 }
2273
2274 if (!src)
2275 src = "<command line>";
2276 rv = excomp(prog, src, line, sf, lbl ? agxbdisown(&label) : NULL);
2277 fclose(sf);
2278
2279 if (rv >= 0 && getErrorErrors() == 0)
2280 e = exexpr(prog, lbl, NULL, kind);
2281
2282 return e;
2283}
2284
2285/* checkGuard:
2286 * Check if guard is an assignment and warn.
2287 */
2288static void checkGuard(Exnode_t *gp, char *src, int line) {
2289 gp = exnoncast(gp);
2290 if (gp && exisAssign(gp)) {
2291 if (src) {
2292 setErrorFileLine(src, line);
2293 }
2294 error(ERROR_WARNING, "assignment used as bool in guard");
2295 }
2296}
2297
2298/* mkStmts:
2299 */
2300static case_stmt *mkStmts(Expr_t *prog, char *src, case_infos_t cases,
2301 const char *lbl) {
2302 agxbuf tmp = {0};
2303
2304 case_stmt *cs = gv_calloc(case_infos_size(&cases), sizeof(case_stmt));
2305
2306 for (size_t i = 0; i < case_infos_size(&cases); i++) {
2307 case_info *sp = case_infos_at(&cases, i);
2308 if (sp->guard) {
2309 agxbprint(&tmp, "%s_g%" PRISIZE_T, lbl, i);
2310 cs[i].guard =
2311 compile(prog, src, sp->guard, sp->gstart, agxbuse(&tmp), 0, INTEGER);
2312 if (getErrorErrors())
2313 break;
2314 checkGuard(cs[i].guard, src, sp->gstart);
2315 }
2316 if (sp->action) {
2317 agxbprint(&tmp, "%s_a%" PRISIZE_T, lbl, i);
2318 cs[i].action =
2319 compile(prog, src, sp->action, sp->astart, agxbuse(&tmp), 0, INTEGER);
2320 if (getErrorErrors())
2321 break;
2322 /* If no error but no compiled action, the input action must
2323 * have been essentially an empty block, which should be
2324 * considered different from a missing block. So, compile a
2325 * trivial block.
2326 */
2327 if (!cs[i].action) {
2328 agxbprint(&tmp, "%s__a%" PRISIZE_T, lbl, i);
2329 cs[i].action =
2330 compile(prog, src, "1", sp->astart, agxbuse(&tmp), 0, INTEGER);
2331 }
2332 }
2333 }
2334 agxbfree(&tmp);
2335 return cs;
2336}
2337
2339static bool mkBlock(comp_block *bp, Expr_t *prog, char *src, parse_block *inp,
2340 size_t i) {
2341 bool has_begin_g = false; // does this block use a `BEG_G` statement?
2342
2343 codePhase = 1;
2344 if (inp->begg_stmt) {
2345 static const char PREFIX[] = "_begin_g_";
2346 agxbuf label = {0};
2347 agxbprint(&label, "%s%" PRISIZE_T, PREFIX, i);
2348 symbols[0].type = T_graph;
2349 tchk[V_this][1] = Y(G);
2350 bp->begg_stmt = compile(prog, src, inp->begg_stmt, inp->l_beging,
2351 agxbuse(&label), 0, VOIDTYPE);
2352 agxbfree(&label);
2353 if (getErrorErrors())
2354 goto finishBlk;
2355 has_begin_g = true;
2356 }
2357
2358 codePhase = 2;
2359 if (!case_infos_is_empty(&inp->node_stmts)) {
2360 static const char PREFIX[] = "_nd";
2361 agxbuf label = {0};
2362 symbols[0].type = T_node;
2363 tchk[V_this][1] = Y(V);
2364 bp->n_nstmts = case_infos_size(&inp->node_stmts);
2365 agxbprint(&label, "%s%" PRISIZE_T, PREFIX, i);
2366 bp->node_stmts = mkStmts(prog, src, inp->node_stmts, agxbuse(&label));
2367 agxbfree(&label);
2368 if (getErrorErrors())
2369 goto finishBlk;
2370 bp->does_walk_graph = true;
2371 }
2372
2373 codePhase = 3;
2374 if (!case_infos_is_empty(&inp->edge_stmts)) {
2375 static const char PREFIX[] = "_eg";
2376 agxbuf label = {0};
2377 symbols[0].type = T_edge;
2378 tchk[V_this][1] = Y(E);
2379 bp->n_estmts = case_infos_size(&inp->edge_stmts);
2380 agxbprint(&label, "%s%" PRISIZE_T, PREFIX, i);
2381 bp->edge_stmts = mkStmts(prog, src, inp->edge_stmts, agxbuse(&label));
2382 agxbfree(&label);
2383 if (getErrorErrors())
2384 goto finishBlk;
2385 bp->does_walk_graph = true;
2386 }
2387
2388finishBlk:
2389 if (getErrorErrors()) {
2390 free(bp->node_stmts);
2391 free(bp->edge_stmts);
2392 bp->node_stmts = 0;
2393 bp->edge_stmts = 0;
2394 }
2395
2396 return has_begin_g || bp->does_walk_graph;
2397}
2398
2399/* doFlags:
2400 * Convert command line flags to actions in END_G.
2401 */
2402static const char *doFlags(compflags_t flags) {
2403 if (flags.srcout) {
2404 if (flags.induce) {
2405 return "\n$O = $G;\ninduce($O);\n";
2406 }
2407 return "\n$O = $G;\n";
2408 }
2409 if (flags.induce) {
2410 return "\ninduce($O);\n";
2411 }
2412 return "\n";
2413}
2414
2415/* compileProg:
2416 * Convert gpr sections in libexpr program.
2417 */
2419 const char *endg_sfx = NULL;
2420 bool uses_graph = false;
2421
2422 /* Make sure we have enough bits for types */
2423 assert(BITS_PER_BYTE * sizeof(tctype) >= (1 << TBITS));
2424
2425 comp_prog *p = calloc(1, sizeof(comp_prog));
2426 if (!p) {
2427 error(ERROR_ERROR, "could not create compiled program: out of memory");
2428 goto finish;
2429 }
2430
2431 if (flags.srcout || flags.induce || flags.clone) {
2432 endg_sfx = doFlags(flags);
2433 }
2434
2435 if (!initDisc(state))
2436 goto finish;
2437
2438 exinit();
2439 if (!(p->prog = exopen(state->dp)))
2440 goto finish;
2441
2442 codePhase = 0;
2443 if (inp->begin_stmt) {
2444 p->begin_stmt = compile(p->prog, inp->source, inp->begin_stmt, inp->l_begin,
2445 0, 0, VOIDTYPE);
2446 if (getErrorErrors())
2447 goto finish;
2448 }
2449
2450 if (!parse_blocks_is_empty(&inp->blocks)) {
2451 comp_block *bp;
2452
2453 p->blocks = bp =
2454 gv_calloc(parse_blocks_size(&inp->blocks), sizeof(comp_block));
2455
2456 for (size_t i = 0; i < parse_blocks_size(&inp->blocks); bp++, i++) {
2457 parse_block *ibp = parse_blocks_at(&inp->blocks, i);
2458 uses_graph |= mkBlock(bp, p->prog, inp->source, ibp, i);
2459 if (getErrorErrors())
2460 goto finish;
2461 p->n_blocks++;
2462 }
2463 }
2464 p->uses_graph = uses_graph;
2465
2466 codePhase = 4;
2467 if (inp->endg_stmt || endg_sfx) {
2468 symbols[0].type = T_graph;
2469 tchk[V_this][1] = Y(G);
2470 p->endg_stmt = compile(p->prog, inp->source, inp->endg_stmt, inp->l_endg,
2471 "_end_g", endg_sfx, VOIDTYPE);
2472 if (getErrorErrors())
2473 goto finish;
2474 }
2475
2476 codePhase = 5;
2477 if (inp->end_stmt) {
2478 symbols[0].type = T_obj;
2479 p->end_stmt = compile(p->prog, inp->source, inp->end_stmt, inp->l_end,
2480 "_end_", 0, VOIDTYPE);
2481 if (getErrorErrors())
2482 goto finish;
2483 }
2484 setErrorLine(0); /* execution errors have no line numbers */
2485
2486 if (p->end_stmt)
2487 p->uses_graph = true;
2488
2489finish:
2490 if (getErrorErrors()) {
2491 freeCompileProg(p);
2492 p = 0;
2493 }
2494
2495 return p;
2496}
2497
2499 comp_block *bp;
2500
2501 if (!p)
2502 return;
2503
2504 exclose(p->prog);
2505 for (size_t i = 0; i < p->n_blocks; i++) {
2506 bp = p->blocks + i;
2507 free(bp->node_stmts);
2508 free(bp->edge_stmts);
2509 }
2510 free(p->blocks);
2511 free(p);
2512}
2513
2514/* readG:
2515 * Read graph from file and initialize
2516 * dynamic data.
2517 */
2518Agraph_t *readG(FILE *fp) {
2519 Agraph_t *g;
2520
2521#ifdef _WIN32
2522 gprDisc.id = &AgIdDisc;
2523#endif
2524 g = agread(fp, &gprDisc);
2525 if (g) {
2526 aginit(g, AGRAPH, UDATA, sizeof(gdata), false);
2527 aginit(g, AGNODE, UDATA, sizeof(ndata), false);
2528 aginit(g, AGEDGE, UDATA, sizeof(edata), false);
2529 }
2530 return g;
2531}
2532
2533/* openG:
2534 * Open graph and initialize dynamic data.
2535 */
2536Agraph_t *openG(char *name, Agdesc_t desc) {
2537 Agraph_t *g;
2538
2539#ifdef _WIN32
2540 gprDisc.id = &AgIdDisc;
2541#endif
2542 g = agopen(name, desc, &gprDisc);
2543 if (g)
2544 agbindrec(g, UDATA, sizeof(gdata), false);
2545 return g;
2546}
2547
2548/* openSubg:
2549 * Open subgraph and initialize dynamic data.
2550 */
2551Agraph_t *openSubg(Agraph_t *g, char *name) {
2552 Agraph_t *sg;
2553
2554 sg = agsubg(g, name, 1);
2555 if (sg && !aggetrec(sg, UDATA, 0))
2556 agbindrec(sg, UDATA, sizeof(gdata), false);
2557 return sg;
2558}
2559
2560/* openNode:
2561 * Create node and initialize dynamic data.
2562 */
2563Agnode_t *openNode(Agraph_t *g, char *name) {
2564 Agnode_t *np;
2565
2566 np = agnode(g, name, 1);
2567 if (np && !aggetrec(np, UDATA, 0))
2568 agbindrec(np, UDATA, sizeof(ndata), false);
2569 return np;
2570}
2571
2572/* openEdge:
2573 * Create edge and initialize dynamic data.
2574 */
2575Agedge_t *openEdge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *key) {
2576 Agedge_t *ep;
2577 Agraph_t *root;
2578
2579 root = sameG(t, h, "openEdge", "tail and head nodes");
2580 if (!root)
2581 return 0;
2582 if (g) {
2583 if (!sameG(g, root, "openEdge", "subgraph and nodes"))
2584 return 0;
2585 } else
2586 g = root;
2587
2588 ep = agedge(g, t, h, key, 1);
2589 if (ep && !aggetrec(ep, UDATA, 0))
2590 agbindrec(ep, UDATA, sizeof(edata), false);
2591 return ep;
2592}
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:1789
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:2575
#define BITS_PER_BYTE
Definition compile.c:49
comp_prog * compileProg(parse_prog *inp, Gpr_t *state, compflags_t flags)
Definition compile.c:2418
static bool mkBlock(comp_block *bp, Expr_t *prog, char *src, parse_block *inp, size_t i)
Definition compile.c:2339
#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:1704
static int codePhase
Definition compile.c:1691
static int strToTvtype(char *s)
Definition compile.c:1992
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:2300
Agraph_t * openG(char *name, Agdesc_t desc)
Definition compile.c:2536
static char * getArg(int n, Gpr_t *state)
Definition compile.c:530
#define haveTarget
Definition compile.c:1694
Agraph_t * openSubg(Agraph_t *g, char *name)
Definition compile.c:2551
static char * tvtypeToStr(long long v)
Definition compile.c:2033
static int stringOf(Expr_t *prog, Exnode_t *x, int arg)
Definition compile.c:2089
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:1878
static char * bbOf(Expr_t *pgm, char *pt, bool getll)
Definition compile.c:111
void freeCompileProg(comp_prog *p)
Definition compile.c:2498
static Exdisc_t * initDisc(Gpr_t *state)
Definition compile.c:2214
#define haveGraph
Definition compile.c:1693
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:2563
static char * typeName(long op)
Definition compile.c:1565
Agraph_t * readG(FILE *fp)
Definition compile.c:2518
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:2208
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:2402
static Extype_t refval(Expr_t *pgm, Exnode_t *node, Exid_t *sym, Exref_t *ref)
Definition compile.c:1809
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:2251
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:2121
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:2198
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:2288
static Extype_t length(Exid_t *rhs, Exdisc_t *disc)
Definition compile.c:1654
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
static int in(Extype_t lhs, Exid_t *rhs, Exdisc_t *disc)
Definition compile.c:1678
#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:2022
void * exstralloc(Expr_t *ex, size_t sz)
Definition exeval.c:2030
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:980
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:986
Agedge_t * agnxtedge(Agraph_t *g, Agedge_t *e, Agnode_t *n)
Definition edge.c:94
#define aghead(e)
Definition cgraph.h:987
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:982
Agedge_t * agfstin(Agraph_t *g, Agnode_t *n)
Definition edge.c:55
#define AGHEAD(e)
Definition cgraph.h:983
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:438
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: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
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