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