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