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