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