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