Graphviz 16.1.1~dev.20260922.0048
Loading...
Searching...
No Matches
exeval.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11/*
12 * Glenn Fowler
13 * AT&T Research
14 *
15 * expression library evaluator
16 */
17
18#include "config.h"
19
20#include <expr/exlib.h>
21#include <expr/exop.h>
22#include <inttypes.h>
23#include <limits.h>
24#include <math.h>
25#include <stdalign.h>
26#include <stdbool.h>
27#include <stddef.h>
28#include <stdint.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <assert.h>
33#include <time.h>
34#include <util/agxbuf.h>
35#include <util/alloc.h>
36#include <util/arena.h>
37#include <util/exit.h>
38#include <util/gv_ctype.h>
39#include <util/gv_ftell.h>
40#include <util/strview.h>
41#include <util/unreachable.h>
42#ifdef _WIN32
43#define srand48 srand
44#define drand48 rand
45#endif
46
47#define TIME_LEN 80 /* max. characters to store time */
48
49static Extype_t eval(Expr_t*, Exnode_t*, void*);
50
51#define FRAME 64
52
53static char *lexname(long op, int subop) {
54 agxbuf b = {0};
55
56 if (op > MINTOKEN && op < MAXTOKEN)
57 return gv_strdup(exop((size_t)op - MINTOKEN));
58 if (op == '=')
59 {
60 if (subop > MINTOKEN && subop < MAXTOKEN)
61 agxbprint(&b, "%s=", exop((size_t)subop - MINTOKEN));
62 else if (subop > ' ' && subop <= '~')
63 agxbprint(&b, "%c=", subop);
64 else
65 agxbprint(&b, "(%d)=", subop);
66 }
67 else if (subop < 0)
68 agxbprint(&b, "(EXTERNAL:%ld)", op);
69 else if (op > ' ' && op <= '~')
70 agxbprint(&b, "%c", (char)op);
71 else
72 agxbprint(&b, "(%ld)", op);
73 return agxbdisown(&b);
74}
75
76/* evaldyn:
77 * Evaluate item from array given key.
78 * Returns 1 if item existed, zero otherwise
79 *
80 */
81static int evaldyn(Expr_t *ex, Exnode_t *exnode, void *env, int delete) {
82 Exassoc_t *b;
83 Extype_t v;
84 char buf[32];
85 Extype_t key;
86 char *keyname;
87
88 v = eval(ex, exnode->data.variable.index, env);
89 if (exnode->data.variable.symbol->index > 0) {
90 if (ex->disc->inf != NULL) {
91 return ex->disc->inf(v, exnode->data.variable.symbol, ex->disc);
92 }
93 return 0; // treat the RHS as an empty array
94 }
95 if (exnode->data.variable.symbol->index_type == INTEGER) {
96 if (!(b = dtmatch(exnode->data.variable.symbol->local, &v))) {
97 return 0;
98 }
99 }
100 else {
101 const long type = exnode->data.variable.index->type;
102 if (type != STRING) {
103 if (!BUILTIN(type)) {
104 key = ex->disc->keyf(v, type);
105 } else
106 key.integer = v.integer;
107 snprintf(buf, sizeof(buf), "%llx", (unsigned long long)key.integer);
108 keyname = buf;
109 } else
110 keyname = v.string;
111 if (!(b = dtmatch(exnode->data.variable.symbol->local, keyname))) {
112 return 0;
113 }
114 }
115 if (delete) {
116 dtdelete(exnode->data.variable.symbol->local, b);
117 }
118 return 1;
119}
120
121/*
122 * return dynamic (associative array) variable value
123 * assoc will point to the associative array bucket
124 */
125static Extype_t getdyn(Expr_t *ex, Exnode_t *exnode, void *env,
126 Exassoc_t **assoc) {
127 Exassoc_t* b;
128 Extype_t v;
129
130 if (exnode->data.variable.index)
131 {
132 Extype_t key;
133 char buf[2*sizeof(key.integer)+1]; /* no. of hex chars needed plus null byte */
134 char *keyname;
135
136 v = eval(ex, exnode->data.variable.index, env);
137 if (exnode->data.variable.symbol->index_type == INTEGER) {
138 if (!(b = dtmatch(exnode->data.variable.symbol->local, &v)))
139 {
140 b = ARENA_NEW(&ex->vm, Exassoc_t);
141 b->key = v;
142 dtinsert(exnode->data.variable.symbol->local, b);
143 }
144 } else {
145 const long type = exnode->data.variable.index->type;
146 if (type != STRING) {
147 if (!BUILTIN(type)) {
148 key = ex->disc->keyf(v, type);
149 } else
150 key.integer = v.integer;
151 snprintf(buf, sizeof(buf), "%llx", (unsigned long long)key.integer);
152 keyname = buf;
153 } else
154 keyname = v.string;
155 if (!(b = dtmatch(exnode->data.variable.symbol->local, keyname)))
156 {
157 const size_t keyname_len = strlen(keyname);
158 b = gv_arena_alloc(&ex->vm, alignof(Exassoc_t), sizeof(Exassoc_t) + keyname_len);
159 memcpy(b->name, keyname, keyname_len + 1);
160 b->key = v;
161 dtinsert(exnode->data.variable.symbol->local, b);
162 }
163 }
164 *assoc = b;
165 if (b)
166 {
167 if (exnode->data.variable.symbol->type == STRING && !b->value.string)
168 b->value = exzero(exnode->data.variable.symbol->type);
169 return b->value;
170 }
171 v = exzero(exnode->data.variable.symbol->type);
172 return v;
173 }
174 *assoc = 0;
175 return exnode->data.variable.symbol->value->data.constant.value;
176}
177
187
188/*
189 * printf %! extension function
190 */
191
192static int
193prformat(void* vp, Sffmt_t* dp)
194{
195 Fmt_t *const fmt = (Fmt_t *)((char *)dp - offsetof(Fmt_t, fmt));
196 Exnode_t* node;
197 char* s;
198 long to = 0;
199 time_t tm;
200 struct tm *stm;
201
202 dp->flags |= SFFMT_VALUE;
203 if (fmt->args)
204 {
205 if ((node = dp->fmt == '*' ? fmt->args->param[dp->size] : fmt->args->arg))
206 fmt->value = exeval(fmt->expr, node, fmt->env);
207 else
208 fmt->value.integer = 0;
209 to = fmt->args->arg->type;
210 }
211 else if (!(fmt->actuals = fmt->actuals->data.operand.right))
212 exerror("printf: not enough arguments");
213 else
214 {
215 node = fmt->actuals->data.operand.left;
216 const long from = node->type;
217 switch (dp->fmt)
218 {
219 case 'f':
220 case 'g':
221 to = FLOATING;
222 break;
223 case 's':
224 to = STRING;
225 break;
226 default:
227 switch (from)
228 {
229 case INTEGER:
230 case UNSIGNED:
231 to = from;
232 break;
233 default:
234 to = INTEGER;
235 break;
236 }
237 break;
238 }
239 if (to == from)
240 fmt->value = exeval(fmt->expr, node, fmt->env);
241 else
242 {
243 node = excast(fmt->expr, node, to, NULL, 0);
244 fmt->value = exeval(fmt->expr, node, fmt->env);
245 node->data.operand.left = 0;
246 gv_arena_free(&fmt->expr->vm, node, sizeof(*node));
247 if (to == STRING)
248 {
249 if (fmt->value.string)
250 {
251 char *const copy = gv_arena_strdup(&fmt->expr->vm, fmt->value.string);
252 gv_arena_free(&fmt->expr->vm, fmt->value.string,
253 strlen(fmt->value.string) + 1);
254 fmt->value.string = copy;
255 }
256 if (!fmt->value.string)
257 fmt->value.string = "";
258 }
259 }
260 }
261 switch (to)
262 {
263 case STRING:
264 *(char**)vp = fmt->value.string;
265 fmt->fmt.size = -1;
266 break;
267 case FLOATING:
268 *(double*)vp = fmt->value.floating;
269 fmt->fmt.size = sizeof(double);
270 break;
271 default:
272 *(long long *)vp = fmt->value.integer;
273 dp->size = sizeof(long long);
274 break;
275 }
276 strview_t txt = {0};
277 if (dp->n_str > 0)
278 {
279 txt = (strview_t){.data = dp->t_str, .size = (size_t)dp->n_str};
280 }
281 switch (dp->fmt)
282 {
283 case 'q':
284 case 'Q': {
285 s = *(char**)vp;
286 char *quoted = fmtquote(s, "$'", "'");
287 *(char**)vp = gv_arena_strdup(&fmt->expr->vm, quoted);
288 free(quoted);
289 dp->fmt = 's';
290 dp->size = -1;
291 break;
292 }
293 case 'S':
294 dp->flags &= ~SFFMT_LONG;
295 s = *(char**)vp;
296 if (txt.data != NULL)
297 {
298 if (strview_str_eq(txt, "identifier"))
299 {
300 if (*s && !gv_isalpha(*s))
301 *s++ = '_';
302 for (; *s; s++)
303 if (!gv_isalnum(*s))
304 *s = '_';
305 }
306 else if (strview_str_eq(txt, "invert"))
307 {
308 for (; *s; s++)
309 if (gv_isupper(*s))
310 *s = (char)tolower(*s);
311 else if (gv_islower(*s))
312 *s = (char)toupper(*s);
313 }
314 else if (strview_str_eq(txt, "lower"))
315 {
317 }
318 else if (strview_str_eq(txt, "upper"))
319 {
321 }
322 else if (strview_str_eq(txt, "variable"))
323 {
324 for (; *s; s++)
325 if (!gv_isalnum(*s) && *s != '_')
326 *s = '.';
327 }
328 }
329 dp->fmt = 's';
330 dp->size = -1;
331 break;
332 case 't':
333 case 'T':
334 if ((tm = *(long long *)vp) == -1)
335 tm = time(NULL);
336 if (txt.data == NULL) {
337 exerror("printf: no time format provided");
338 } else {
339 s = gv_arena_alloc(&fmt->expr->vm, 1, TIME_LEN);
340 stm = localtime(&tm);
341 char *format = malloc(sizeof(char) * (txt.size + 1));
342 if (format == NULL) {
343 gv_arena_free(&fmt->expr->vm, s, TIME_LEN);
344 exerror("printf: out of memory");
345 } else {
346 memcpy(format, txt.data, txt.size);
347 format[txt.size] = '\0';
348 strftime(s, TIME_LEN, format, stm);
349 *(char **)vp = s;
350 }
351 free(format);
352 }
353 dp->fmt = 's';
354 dp->size = -1;
355 break;
356 }
357 return 0;
358}
359
360/*
361 * print a list of strings
362 */
363static int prints(Expr_t *ex, Exnode_t *exnode, void *env, FILE *sp) {
364 Extype_t v;
365 Exnode_t *args;
366
367 args = exnode->data.operand.left;
368 while (args) {
369 v = eval(ex, args->data.operand.left, env);
370 fputs(v.string, sp);
371 args = args->data.operand.right;
372 }
373 putc('\n', sp);
374 return 0;
375}
376
377/*
378 * do printf
379 */
380static int print(Expr_t *ex, Exnode_t *exnode, void *env, FILE *sp) {
381 Print_t* x;
382 Extype_t v;
383 Fmt_t fmt;
384
385 if (!sp)
386 {
387 v = eval(ex, exnode->data.print.descriptor, env);
388 if (v.integer < 0 || v.integer >= (long long)elementsof(ex->file) ||
389 (!(sp = ex->file[v.integer]) &&
390 !(sp = ex->file[v.integer] = tmpfile())))
391 {
392 exerror("printf: %lld: invalid descriptor", v.integer);
393 return -1;
394 }
395 }
396 memset(&fmt, 0, sizeof(fmt));
397 fmt.fmt.extf = prformat;
398 fmt.expr = ex;
399 fmt.env = env;
400 x = exnode->data.print.args;
401 if (x->format)
402 do
403 {
404 if (x->arg)
405 {
406 fmt.fmt.form = x->format;
407 fmt.args = x;
408 sfprint(sp, &fmt.fmt);
409 }
410 else
411 fputs(x->format, sp);
412 } while ((x = x->next));
413 else
414 {
415 v = eval(ex, x->arg->data.operand.left, env);
416 fmt.fmt.form = v.string;
417 fmt.actuals = x->arg;
418 sfprint(sp, &fmt.fmt);
419 if (fmt.actuals->data.operand.right)
420 exerror("(s)printf: \"%s\": too many arguments", fmt.fmt.form);
421 }
422 return 0;
423}
424
425/*
426 * scanf %! extension function
427 */
428
429static int
430scformat(void* vp, Sffmt_t* dp)
431{
432 Fmt_t *const fmt = (Fmt_t *)((char *)dp - offsetof(Fmt_t, fmt));
433 Exnode_t* node;
434
435 if (!fmt->actuals)
436 {
437 exerror("scanf: not enough arguments");
438 return -1;
439 }
440 node = fmt->actuals->data.operand.left;
441 switch (dp->fmt)
442 {
443 case 'f':
444 case 'g': {
445 if (node->type != FLOATING)
446 {
447 exerror("scanf: %s: floating variable address argument expected", node->data.variable.symbol->name);
448 return -1;
449 }
450 fmt->fmt.size = sizeof(double);
451 const void *const value = &node->data.variable.symbol->value->data.constant.value;
452 memcpy(vp, &value, sizeof(value));
453 break;
454 }
455 case 's':
456 case '[': {
457 if (node->type != STRING)
458 {
459 exerror("scanf: %s: string variable address argument expected", node->data.variable.symbol->name);
460 return -1;
461 }
462 if (node->data.variable.symbol->value->data.constant.value.string == expr.nullstring)
463 node->data.variable.symbol->value->data.constant.value.string = 0;
464 fmt->fmt.size = 1024;
465 char *s = node->data.variable.symbol->value->data.constant.value.string;
466 gv_arena_free(&fmt->expr->vm, s, strlen(s) + 1);
467 s = gv_arena_alloc(&fmt->expr->vm, 1, (size_t)fmt->fmt.size);
468 memcpy(vp, &s, sizeof(s));
469 node->data.variable.symbol->value->data.constant.value.string = s;
470 break;
471 }
472 case 'c': {
473 if (node->type != CHARACTER) {
474 exerror("scanf: %s: char variable address argument expected", node->data.variable.symbol->name);
475 return -1;
476 }
477 fmt->fmt.size = sizeof(long long);
478 const void *const value = &node->data.variable.symbol->value->data.constant.value;
479 memcpy(vp, &value, sizeof(value));
480 break;
481 }
482 default: {
483 if (node->type != INTEGER && node->type != UNSIGNED)
484 {
485 exerror("scanf: %s: integer variable address argument expected", node->data.variable.symbol->name);
486 return -1;
487 }
488 dp->size = sizeof(long long);
489 const void *const value = &node->data.variable.symbol->value->data.constant.value;
490 memcpy(vp, &value, sizeof(value));
491 break;
492 }
493 }
494 fmt->actuals = fmt->actuals->data.operand.right;
495 dp->flags |= SFFMT_VALUE;
496 return 0;
497}
498
499/*
500 * do scanf
501 */
502
503static int scan(Expr_t *ex, Exnode_t *exnode, void *env, FILE *sp) {
504 Extype_t v;
505 Extype_t u;
506 Fmt_t fmt;
507 int n;
508
509 if (!sp)
510 {
511 if (exnode->data.scan.descriptor)
512 {
513 v = eval(ex, exnode->data.scan.descriptor, env);
514 if (exnode->data.scan.descriptor->type == STRING)
515 goto get;
516 }
517 else
518 v.integer = 0;
519 if (v.integer < 0 || v.integer >= (long long)elementsof(ex->file) || (!(sp = ex->file[v.integer]) && !(sp = ex->file[v.integer] = tmpfile())))
520 {
521 exerror("scanf: %lld: invalid descriptor", v.integer);
522 return 0;
523 }
524 }
525 get:
526 memset(&fmt, 0, sizeof(fmt));
527 fmt.fmt.extf = scformat;
528 fmt.expr = ex;
529 fmt.env = env;
530 u = eval(ex, exnode->data.scan.format, env);
531 fmt.fmt.form = u.string;
532 fmt.actuals = exnode->data.scan.args;
533 if (sp == NULL) {
534 sp = tmpfile();
535 if (sp == NULL) {
536 exerror("scanf: failed to open temporary file");
537 return 0;
538 }
539 fputs(v.string, sp);
540 if (fseek(sp, 0, SEEK_SET) < 0) {
541 exerror("scanf: failed to seek temporary file");
542 fclose(sp);
543 return 0;
544 }
545 n = sfvscanf(sp, &fmt.fmt);
546 fclose(sp);
547 } else {
548 n = sfvscanf(sp, &fmt.fmt);
549 }
550 if (fmt.actuals && !*fmt.fmt.form)
551 exerror("scanf: %s: too many arguments", fmt.actuals->data.operand.left->data.variable.symbol->name);
552 return n;
553}
554
555/*
556 * string add
557 */
558
559static char*
560str_add(Expr_t* ex, char* l, char* r)
561{
562 size_t sz = strlen(l) + strlen(r) + 1;
563 char *const s = gv_arena_alloc(&ex->ve, 1, sz);
564 snprintf(s, sz, "%s%s", l, r);
565 return s;
566}
567
568/*
569 * string ior
570 */
571
572static char *str_ior(Expr_t *ex, const char *l, const char *r) {
573
574 // compute how much space the result will occupy
575 size_t len = 1; // 1 for NUL terminator
576 for (const char *p = l; *p != '\0'; ++p) {
577 if (strchr(p + 1, *p) == NULL) {
578 ++len;
579 }
580 }
581 for (const char *p = r; *p != '\0'; ++p) {
582 if (strchr(l, *p) == NULL && strchr(p + 1, *p) == NULL) {
583 ++len;
584 }
585 }
586
587 // allocate a buffer to store this
588 char *const result = gv_arena_alloc(&ex->ve, 1, len);
589
590 // write the result
591 size_t i = 0;
592 for (const char *p = l; *p != '\0'; ++p) {
593 if (strchr(p + 1, *p) == NULL) {
594 assert(i < len && "incorrect preceding length computation");
595 result[i] = *p;
596 ++i;
597 }
598 }
599 for (const char *p = r; *p != '\0'; ++p) {
600 if (strchr(l, *p) == NULL && strchr(p + 1, *p) == NULL) {
601 assert(i < len && "incorrect preceding length computation");
602 result[i] = *p;
603 ++i;
604 }
605 }
606 assert(i + 1 == len && "incorrect preceding length computation");
607
608 return result;
609}
610
611/*
612 * string and
613 */
614
615static char *str_and(Expr_t *ex, const char *l, const char *r) {
616
617 // compute how much space the result will occupy
618 size_t len = 1; // 1 for NUL terminator
619 for (const char *p = l; *p != '\0'; ++p) {
620 if (strchr(r, *p) != NULL && strchr(p + 1, *p) == NULL) {
621 ++len;
622 }
623 }
624
625 // allocate a buffer to store this
626 char *const result = gv_arena_alloc(&ex->ve, 1, len);
627
628 // write the result
629 size_t i = 0;
630 for (const char *p = l; *p != '\0'; ++p) {
631 if (strchr(r, *p) != NULL && strchr(p + 1, *p) == NULL) {
632 assert(i < len && "incorrect preceding length computation");
633 result[i] = *p;
634 ++i;
635 }
636 }
637 assert(i + 1 == len && "incorrect preceding length computation");
638
639 return result;
640}
641
642/*
643 * string xor
644 */
645
646static char *str_xor(Expr_t *ex, const char *l, const char *r) {
647
648 // compute how much space the result will occupy
649 size_t len = 1; // 1 for NUL terminator
650 for (const char *p = l; *p != '\0'; ++p) {
651 if (strchr(r, *p) == NULL && strchr(p + 1, *p) == NULL) {
652 ++len;
653 }
654 }
655 for (const char *p = r; *p != '\0'; ++p) {
656 if (strchr(l, *p) == NULL && strchr(p + 1, *p) == NULL) {
657 ++len;
658 }
659 }
660
661 // allocate a buffer to store this
662 char *const result = gv_arena_alloc(&ex->ve, 1, len);
663
664 // write the result
665 size_t i = 0;
666 for (const char *p = l; *p != '\0'; ++p) {
667 if (strchr(r, *p) == NULL && strchr(p + 1, *p) == NULL) {
668 assert(i < len && "incorrect preceding length computation");
669 result[i] = *p;
670 ++i;
671 }
672 }
673 for (const char *p = r; *p != '\0'; ++p) {
674 if (strchr(l, *p) == NULL && strchr(p + 1, *p) == NULL) {
675 assert(i < len && "incorrect preceding length computation");
676 result[i] = *p;
677 ++i;
678 }
679 }
680 assert(i + 1 == len && "incorrect preceding length computation");
681
682 return result;
683}
684
685/*
686 * string mod
687 */
688
689static char *str_mod(Expr_t *ex, const char *l, const char *r) {
690
691 // compute how much space the result will occupy
692 size_t len = 1; // 1 for NUL terminator
693 for (const char *p = l; *p != '\0'; ++p) {
694 if (strchr(r, *p) == NULL && strchr(p + 1, *p) == NULL) {
695 ++len;
696 }
697 }
698
699 // allocate a buffer to store this
700 char *const result = gv_arena_alloc(&ex->ve, 1, len);
701
702 // write the result
703 size_t i = 0;
704 for (const char *p = l; *p != '\0'; ++p) {
705 if (strchr(r, *p) == NULL && strchr(p + 1, *p) == NULL) {
706 assert(i < len && "incorrect preceding length computation");
707 result[i] = *p;
708 ++i;
709 }
710 }
711 assert(i + 1 == len && "incorrect preceding length computation");
712
713 return result;
714}
715
716/*
717 * string mpy
718 */
719
720static char *str_mpy(Expr_t *ex, const char *l, const char *r) {
721
722 // compute how much space the result will occupy
723 size_t len = strlen(l);
724 {
725 size_t len2 = strlen(r);
726 if (len2 < len) {
727 len = len2;
728 }
729 }
730 ++len; // 1 for NUL terminator
731
732 // allocate a buffer to store this
733 char *const result = gv_arena_alloc(&ex->ve, 1, len);
734
735 // write the result
736 size_t i = 0;
737 for (; l[i] != '\0' && r[i] != '\0'; ++i) {
738 assert(i < len && "incorrect preceding length computation");
739 result[i] = l[i] == r[i] ? l[i] : ' ';
740 }
741 assert(i + 1 == len && "incorrect preceding length computation");
742
743 return result;
744}
745
746/* replace:
747 * Add replacement string.
748 * \digit is replaced with a subgroup match, if any.
749 */
750static void replace(agxbuf *s, char *base, char *repl, int ng, size_t *sub) {
751 char c;
752 int idx;
753
754 while ((c = *repl++)) {
755 if (c == '\\') {
756 if ((c = *repl) && gv_isdigit(c)) {
757 idx = c - '0';
758 if (idx < ng) {
759 const size_t offset = sub[2 * idx];
760 agxbput_n(s, base + offset, sub[2 * idx + 1] - offset);
761 }
762 repl++;
763 } else {
764 agxbputc(s, '\\');
765 }
766 } else {
767 agxbputc(s, c);
768 }
769 }
770}
771
772static void addItem(Expr_t *ex, Dt_t *arr, Extype_t v, char *tok) {
773 Exassoc_t* b;
774
775 if (!(b = dtmatch(arr, &v))) {
776 b = ARENA_NEW(&ex->vm, Exassoc_t);
777 b->key = v;
778 dtinsert(arr, b);
779 }
780 b->value.string = tok;
781}
782
783/* exsplit:
784 * break string into possibly empty fields and store in array
785 * return number of fields
786 */
787static Extype_t exsplit(Expr_t *ex, Exnode_t *exnode, void *env) {
788 Extype_t v;
789 char *str;
790 char *seps;
791 char *tok;
792 size_t sz;
793 Dt_t* arr = exnode->data.split.array->local;
794
795 str = eval(ex, exnode->data.split.string, env).string;
796 if (exnode->data.split.seps)
797 seps = eval(ex, exnode->data.split.seps, env).string;
798 else
799 seps = " \t\n";
800
801 v.integer = 0;
802 while (*str) {
803 sz = strspn (str, seps);
804 if (sz) {
805 if (v.integer == 0) { /* initial separator => empty field */
806 addItem(ex, arr, v, "");
807 v.integer++;
808 }
809 for (size_t i = 1; i < sz; i++) {
810 addItem(ex, arr, v, "");
811 v.integer++;
812 }
813 }
814 str += sz;
815 if (*str == '\0') { /* terminal separator => empty field */
816 addItem(ex, arr, v, "");
817 v.integer++;
818 break;
819 }
820 sz = strcspn (str, seps);
821 tok = gv_arena_alloc(&ex->vm, 1, sz + 1);
822 memcpy(tok, str, sz);
823 addItem(ex, arr, v, tok);
824 v.integer++;
825 str += sz;
826 }
827
828 return v;
829}
830
831/* extoken:
832 * tokenize string and store in array
833 * return number of tokens
834 */
835static Extype_t extokens(Expr_t *ex, Exnode_t *exnode, void *env) {
836 Extype_t v;
837 char *str;
838 char *seps;
839 char *tok;
840 size_t sz;
841 Dt_t* arr = exnode->data.split.array->local;
842
843 str = eval(ex, exnode->data.split.string, env).string;
844 if (exnode->data.split.seps)
845 seps = eval(ex, exnode->data.split.seps, env).string;
846 else
847 seps = " \t\n";
848
849 v.integer = 0;
850 while (*str) {
851 sz = strspn (str, seps);
852 str += sz;
853 if (*str == '\0')
854 break;
855
856 sz = strcspn (str, seps);
857 assert (sz);
858 tok = gv_arena_alloc(&ex->vm, 1, sz + 1);
859 memcpy(tok, str, sz);
860 addItem(ex, arr, v, tok);
861 v.integer++;
862 str += sz;
863 }
864
865 return v;
866}
867
868/* exsub:
869 * return string after pattern substitution
870 */
871static Extype_t exsub(Expr_t *ex, Exnode_t *exnode, void *env, bool global) {
872 char *str;
873 char *pat;
874 char *repl;
875 char *p;
876 char *s;
877 Extype_t v;
878 size_t sub[20];
879 int flags = 0;
880 int ng;
881
882 str = eval(ex, exnode->data.string.base, env).string;
883 pat = eval(ex, exnode->data.string.pat, env).string;
884 if (exnode->data.string.repl)
885 repl = eval(ex, exnode->data.string.repl, env).string;
886 else
887 repl = 0;
888
889 if (!global) {
890 if (*pat == '^') {
891 pat++;
892 flags |= STR_LEFT;
893 }
894 p = pat;
895 while (*p)
896 p++;
897 if (p > pat)
898 p--;
899 if (*p == '$') {
900 if (p > pat && p[-1] == '\\') {
901 *p-- = '\0';
902 *p = '$';
903 } else {
904 flags |= STR_RIGHT;
905 *p = '\0';
906 }
907 }
908 }
909 if (*pat == '\0') {
910 v.string = gv_arena_strdup(&ex->ve, str);
911 return v;
912 }
913
914 ng = strgrpmatch(str, pat, sub, sizeof(sub) / (sizeof(sub[0]) * 2), flags);
915 if (ng == 0) {
916 v.string = gv_arena_strdup(&ex->ve, str);
917 return v;
918 }
919 if (sub[0] == sub[1]) {
920 exwarn("pattern match of empty string - ill-specified pattern \"%s\"?", pat);
921 v.string = gv_arena_strdup(&ex->ve, str);
922 return v;
923 }
924
925 agxbuf buffer = {0};
926
927 agxbput_n(&buffer, str, sub[0]);
928
929 if (repl) {
930 replace(&buffer, str, repl, ng, sub);
931 }
932
933 s = str + sub[1];
934 if (global) {
935 while ((ng = strgrpmatch(s, pat, sub, sizeof(sub) / (sizeof(sub[0]) * 2), flags))) {
936 agxbput_n(&buffer, s, sub[0]);
937 if (repl) {
938 replace(&buffer, s, repl, ng, sub);
939 }
940 s = s + sub[1];
941 }
942 }
943
944 agxbput(&buffer, s);
945
946 v.string = gv_arena_strdup(&ex->ve, agxbuse(&buffer));
947 agxbfree(&buffer);
948 return v;
949}
950
951/* exsubstr:
952 * return substring.
953 */
954static Extype_t exsubstr(Expr_t *ex, Exnode_t *exnode, void *env) {
955 Extype_t s;
956 Extype_t i;
957 Extype_t l;
958 Extype_t v;
959
960 s = eval(ex, exnode->data.string.base, env);
961 const size_t len = strlen(s.string);
962 i = eval(ex, exnode->data.string.pat, env);
963 if (i.integer < 0 || len < (unsigned long long)i.integer)
964 exerror("illegal start index in substr(%s,%lld)", s.string, i.integer);
965 if (exnode->data.string.repl) {
966 l = eval(ex, exnode->data.string.repl, env);
967 if (l.integer < 0 ||
968 len - (unsigned long long)i.integer < (unsigned long long)l.integer)
969 exerror("illegal length in substr(%s,%lld,%lld)",
970 s.string, i.integer, l.integer);
971 } else
972 l.integer = (long long)(len - (unsigned long long)i.integer);
973
974 v.string = gv_arena_alloc(&ex->ve, 1, (size_t)l.integer + 1);
975 if (exnode->data.string.repl) {
976 memcpy(v.string, s.string + i.integer, (size_t)l.integer);
977 } else
978 memcpy(v.string, s.string + i.integer, len - (size_t)i.integer);
979 return v;
980}
981
982/* xConvert:
983 * Convert from external type.
984 */
985static void xConvert(Expr_t *ex, Exnode_t *exnode, long type, Extype_t v,
986 Exnode_t * tmp)
987{
988 *tmp = *exnode->data.operand.left;
989 tmp->data.constant.value = v;
990 if (ex->disc->convertf(tmp, type, 0)) {
991 exerror("%s: cannot convert %s value to %s",
993 extypename(ex, exnode->data.operand.left->type), extypename(ex, type));
994 }
995 tmp->type = type;
996}
997
998/* xPrint:
999 * Generate string representation from value of external type.
1000 */
1001static void xPrint(Expr_t *ex, Exnode_t *exnode, Extype_t v, Exnode_t *tmp) {
1002 *tmp = *exnode->data.operand.left;
1003 tmp->data.constant.value = v;
1004 if (ex->disc->stringof(ex, tmp, 0))
1005 exerror("%s: no string representation of %s value",
1007 extypename(ex, exnode->data.operand.left->type));
1008 tmp->type = STRING;
1009}
1010
1011/*
1012 * internal exeval
1013 */
1014static long seed;
1015
1016static Extype_t eval(Expr_t *ex, Exnode_t *exnode, void *env) {
1017 Exnode_t* x;
1018 Exnode_t* a;
1019 Extype_t** t;
1020 int n;
1021 Extype_t v;
1022 Extype_t r = {0};
1023 Extype_t i;
1024 char* e;
1025 Exnode_t tmp;
1026 Exnode_t rtmp;
1027 Exnode_t* rp;
1028 Exassoc_t* assoc;
1029 Extype_t args[FRAME+1];
1030 Extype_t save[FRAME];
1031
1032 if (!exnode || ex->loopcount)
1033 {
1034 v.integer = 1;
1035 return v;
1036 }
1037 x = exnode->data.operand.left;
1038 switch (exnode->op)
1039 {
1040 case BREAK:
1041 case CONTINUE:
1042 v = eval(ex, x, env);
1043 ex->loopcount = v.integer;
1044 ex->loopop = exnode->op;
1045 return v;
1046 case CONSTANT:
1047 return exnode->data.constant.value;
1048 case DEC:
1049 n = -1;
1050 add:
1051 if (x->op == DYNAMIC)
1052 r = getdyn(ex, x, env, &assoc);
1053 else
1054 {
1055 if (x->data.variable.index)
1056 i = eval(ex, x->data.variable.index, env);
1057 else
1058 i.integer = EX_SCALAR;
1059 if (x->data.variable.dyna) {
1060 Extype_t locv;
1061 locv = getdyn(ex, x->data.variable.dyna, env, &assoc);
1063 }
1064 r = ex->disc->getf(ex, x, x->data.variable.symbol,
1065 x->data.variable.reference, env, (int)i.integer,
1066 ex->disc);
1067 }
1068 v = r;
1069 switch (x->type)
1070 {
1071 case FLOATING:
1072 v.floating += n;
1073 break;
1074 case INTEGER:
1075 case UNSIGNED:
1076 v.integer += n;
1077 break;
1078 default:
1079 goto huh;
1080 }
1081 set:
1082 if (x->op == DYNAMIC)
1083 {
1084 if (x->type == STRING)
1085 {
1086 v.string = gv_arena_strdup(&ex->vm, v.string);
1087 }
1088 if (assoc)
1089 assoc->value = v;
1090 else
1092 }
1093 else
1094 {
1095 if (x->data.variable.index)
1096 eval(ex, x->data.variable.index, env);
1097 if (x->data.variable.dyna) {
1098 Extype_t locv = getdyn(ex, x->data.variable.dyna, env, &assoc);
1100 }
1101 if (ex->disc->setf(ex, x, x->data.variable.symbol,
1102 x->data.variable.reference, env, v) < 0)
1103 exerror("%s: cannot set value", x->data.variable.symbol->name);
1104 }
1105 if (exnode->subop == PRE)
1106 r = v;
1107 return r;
1108 case DYNAMIC:
1109 return getdyn(ex, exnode, env, &assoc);
1110 case SPLIT:
1111 return exsplit(ex, exnode, env);
1112 case TOKENS:
1113 return extokens(ex, exnode, env);
1114 case GSUB:
1115 return exsub(ex, exnode, env, /* global = */ true);
1116 case SUB:
1117 return exsub(ex, exnode, env, /* global = */ false);
1118 case SUBSTR:
1119 return exsubstr(ex, exnode, env);
1120 case SRAND:
1121 v.integer = seed;
1122 if (exnode->binary) {
1123 seed = (long)eval(ex, x, env).integer;
1124 } else
1125 seed = (long)time(0);
1126 srand48(seed);
1127 return v;
1128 case RAND:
1129 v.floating = drand48();
1130 return v;
1131 case EXIT:
1132 v = eval(ex, x, env);
1133 if (ex->disc->exitf)
1134 ex->disc->exitf(env, (int)v.integer);
1135 else
1136 graphviz_exit((int)v.integer);
1137 UNREACHABLE();
1138 case IF:
1139 v = eval(ex, x, env);
1140 if (v.integer)
1141 eval(ex, exnode->data.operand.right->data.operand.left, env);
1142 else
1143 eval(ex, exnode->data.operand.right->data.operand.right, env);
1144 v.integer = 1;
1145 return v;
1146 case FOR:
1147 case WHILE:
1148 exnode = exnode->data.operand.right;
1149 for (;;)
1150 {
1151 r = eval(ex, x, env);
1152 if (!r.integer)
1153 {
1154 v.integer = 1;
1155 return v;
1156 }
1157 if (exnode->data.operand.right)
1158 {
1159 eval(ex, exnode->data.operand.right, env);
1160 if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE))
1161 {
1162 v.integer = 0;
1163 return v;
1164 }
1165 }
1166 if (exnode->data.operand.left)
1167 eval(ex, exnode->data.operand.left, env);
1168 }
1169 UNREACHABLE();
1170 case SWITCH:
1171 v = eval(ex, x, env);
1172 i.integer = x->type;
1173 r.integer = 0;
1174 x = exnode->data.operand.right;
1175 a = x->data.select.statement;
1176 n = 0;
1177 while ((x = x->data.select.next))
1178 {
1179 if (!(t = x->data.select.constant))
1180 n = 1;
1181 else
1182 for (; *t; t++)
1183 {
1184 switch ((int)i.integer)
1185 {
1186 case INTEGER:
1187 case UNSIGNED:
1188 if ((*t)->integer == v.integer)
1189 break;
1190 continue;
1191 case STRING:
1192 if (strmatch((*t)->string, v.string))
1193 break;
1194 continue;
1195 case FLOATING:
1196 if ((*t)->floating == v.floating)
1197 break;
1198 continue;
1199 }
1200 n = 1;
1201 break;
1202 }
1203 if (n)
1204 {
1205 if (!x->data.select.statement)
1206 {
1207 r.integer = 1;
1208 break;
1209 }
1210 r = eval(ex, x->data.select.statement, env);
1211 if (ex->loopcount > 0)
1212 {
1213 ex->loopcount--;
1214 break;
1215 }
1216 }
1217 }
1218 if (!n && a)
1219 {
1220 r = eval(ex, a, env);
1221 if (ex->loopcount > 0)
1222 ex->loopcount--;
1223 }
1224 return r;
1225 case ITERATE:
1226 v.integer = 0;
1227 if (exnode->data.generate.array->op == DYNAMIC)
1228 {
1229 n = exnode->data.generate.index->type == STRING;
1230 for (assoc = dtfirst(exnode->data.generate.array->data.variable.symbol->local); assoc; assoc = dtnext(exnode->data.generate.array->data.variable.symbol->local, assoc))
1231 {
1232 v.integer++;
1233 if (n)
1234 exnode->data.generate.index->value->data.constant.value.string = assoc->name;
1235 else
1236 exnode->data.generate.index->value->data.constant.value = assoc->key;
1237 eval(ex, exnode->data.generate.statement, env);
1238 if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE))
1239 {
1240 v.integer = 0;
1241 break;
1242 }
1243 }
1244 }
1245 else
1246 {
1247 r = ex->disc->getf(ex, exnode, exnode->data.generate.array->data.variable.symbol,
1248 exnode->data.generate.array->data.variable.reference, env,
1249 0, ex->disc);
1250 for (v.integer = 0; v.integer < r.integer; v.integer++)
1251 {
1252 exnode->data.generate.index->value->data.constant.value.integer = v.integer;
1253 eval(ex, exnode->data.generate.statement, env);
1254 if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE))
1255 {
1256 v.integer = 0;
1257 break;
1258 }
1259 }
1260 }
1261 return v;
1262 case ITERATOR:
1263 v.integer = 0;
1264 if (exnode->data.generate.array->op == DYNAMIC) {
1265 n = exnode->data.generate.index->type == STRING;
1266 for (assoc = dtlast(exnode->data.generate.array->
1267 data.variable.symbol->local); assoc;
1268 assoc = dtprev(exnode->data.generate.array->data.variable.symbol->local,
1269 assoc)) {
1270 v.integer++;
1271 if (n)
1272 exnode->data.generate.index->value->data.constant.value.string = assoc->name;
1273 else
1274 exnode->data.generate.index->value->data.constant.value = assoc->key;
1275 eval(ex, exnode->data.generate.statement, env);
1276 if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE)) {
1277 v.integer = 0;
1278 break;
1279 }
1280 }
1281 } else {
1282 r = ex->disc->getf(ex, exnode, exnode->data.generate.array->data.variable.symbol,
1283 exnode->data.generate.array->data.variable.reference, env,
1284 0, ex->disc);
1285 for (v.integer = r.integer-1; 0 <= v.integer; v.integer--) {
1286 exnode->data.generate.index->value->data.constant.value.integer = v.integer;
1287 eval(ex, exnode->data.generate.statement, env);
1288 if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE)) {
1289 v.integer = 0;
1290 break;
1291 }
1292 }
1293 }
1294 return v;
1295 case '#':
1296 if (exnode->data.variable.symbol->index > 0) {
1297 if (ex->disc->lengthf != NULL) {
1298 v = ex->disc->lengthf(exnode->data.variable.symbol, ex->disc);
1299 } else {
1300 exerror("%s: cannot get length", x->data.variable.symbol->name);
1301 v.integer = 0;
1302 }
1303 } else {
1304 v.integer = dtsize(exnode->data.variable.symbol->local);
1305 }
1306 return v;
1307 case IN_OP:
1308 v.integer = evaldyn (ex, exnode, env, 0);
1309 return v;
1310 case UNSET:
1311 if (exnode->data.variable.index) {
1312 v.integer = evaldyn (ex, exnode, env, 1);
1313 }
1314 else {
1315 dtclear(exnode->data.variable.symbol->local);
1316 v.integer = 0;
1317 }
1318 return v;
1319 case CALL:
1320 x = exnode->data.call.args;
1321 for (n = 0, a = exnode->data.call.procedure->value->data.procedure.args; a && x; a = a->data.operand.right)
1322 {
1323 if (n < (int)elementsof(args))
1324 {
1326 args[n++] = eval(ex, x->data.operand.left, env);
1327 }
1328 else
1329 a->data.operand.left->data.variable.symbol->value->data.constant.value = eval(ex, x->data.operand.left, env);
1330 x = x->data.operand.right;
1331 }
1332 for (n = 0, a = exnode->data.call.procedure->value->data.procedure.args;
1333 a && n < (int)elementsof(save); a = a->data.operand.right)
1335 if (x)
1336 exerror("too many actual args");
1337 else if (a)
1338 exerror("not enough actual args");
1339 v = exeval(ex, exnode->data.call.procedure->value->data.procedure.body, env);
1340 for (n = 0, a = exnode->data.call.procedure->value->data.procedure.args;
1341 a && n < (int)elementsof(save); a = a->data.operand.right)
1343 return v;
1344 case ARRAY:
1345 n = 0;
1346 for (x = exnode->data.operand.right; x && n < (int)elementsof(args);
1347 x = x->data.operand.right)
1348 args[n++] = eval(ex, x->data.operand.left, env);
1349 return ex->disc->getf(ex, exnode->data.operand.left,
1351 exnode->data.operand.left->data.variable.reference, args,
1352 EX_ARRAY, ex->disc);
1353 case FUNCTION:
1354 n = 0;
1355 args[n++].string = env;
1356 for (x = exnode->data.operand.right; x && n < (int)elementsof(args);
1357 x = x->data.operand.right)
1358 args[n++] = eval(ex, x->data.operand.left, env);
1359 return ex->disc->getf(ex, exnode->data.operand.left,
1362 args+1, EX_CALL, ex->disc);
1363 case ID:
1364 if (exnode->data.variable.index)
1365 i = eval(ex, exnode->data.variable.index, env);
1366 else
1367 i.integer = EX_SCALAR;
1368 if (exnode->data.variable.dyna) {
1369 Extype_t locv = getdyn(ex, exnode->data.variable.dyna, env, &assoc);
1371 }
1372 return ex->disc->getf(ex, exnode, exnode->data.variable.symbol,
1373 exnode->data.variable.reference, env, (int)i.integer,
1374 ex->disc);
1375 case INC:
1376 n = 1;
1377 goto add;
1378 case PRINT:
1379 v.integer = prints(ex, exnode, env, stdout);
1380 return v;
1381 case PRINTF:
1382 v.integer = print(ex, exnode, env, NULL);
1383 return v;
1384 case RETURN:
1385 ex->loopret = eval(ex, x, env);
1386 ex->loopcount = 32767;
1387 ex->loopop = exnode->op;
1388 return ex->loopret;
1389 case SCANF:
1390 case SSCANF:
1391 v.integer = scan(ex, exnode, env, NULL);
1392 return v;
1393 case SPRINTF: {
1394 FILE *buffer = tmpfile();
1395 if (buffer == NULL) {
1396 fprintf(stderr, "out of memory\n");
1397 graphviz_exit(EXIT_FAILURE);
1398 }
1399 print(ex, exnode, env, buffer);
1400 const int64_t size = gv_ftell(buffer);
1401 if (size < 0 || fseek(buffer, 0, SEEK_SET) < 0) {
1402 fclose(buffer);
1403 fprintf(stderr, "failed to read back temporary file\n");
1404 graphviz_exit(EXIT_FAILURE);
1405 }
1406 v.string = gv_arena_alloc(&ex->ve, 1, (size_t)size + 1);
1407 if (fread(v.string, (size_t)size, 1, buffer) < 1) {
1408 fprintf(stderr, "failed to read back temporary file\n");
1409 graphviz_exit(EXIT_FAILURE);
1410 }
1411 fclose(buffer);
1412 return v;
1413 }
1414 case '=':
1415 v = eval(ex, exnode->data.operand.right, env);
1416 if (exnode->subop != '=')
1417 {
1418 r = v;
1419 if (x->op == DYNAMIC)
1420 v = getdyn(ex, x, env, &assoc);
1421 else
1422 {
1423 if (x->data.variable.index)
1424 v = eval(ex, x->data.variable.index, env);
1425 else
1426 v.integer = EX_SCALAR;
1427 if (x->data.variable.dyna) {
1428 Extype_t locv;
1429 locv = getdyn(ex, x->data.variable.dyna, env, &assoc);
1430 x->data.variable.dyna->data.variable.dyna->data.constant.value = locv;
1431 }
1432 v = ex->disc->getf(ex, x, x->data.variable.symbol,
1433 x->data.variable.reference, env, (int)v.integer,
1434 ex->disc);
1435 }
1436 switch (x->type)
1437 {
1438 case FLOATING:
1439 switch (exnode->subop)
1440 {
1441 case '+':
1442 v.floating += r.floating;
1443 break;
1444 case '-':
1445 v.floating -= r.floating;
1446 break;
1447 case '*':
1448 v.floating *= r.floating;
1449 break;
1450 case '/':
1451 if (r.floating == 0.0)
1452 exerror("floating divide by 0");
1453 else
1454 v.floating /= r.floating;
1455 break;
1456 case '%': {
1457 const double rounded = round(r.floating);
1458 if (LLONG_MAX < (INT64_C(1) << 53) &&
1459 (rounded > (double)LLONG_MAX || rounded < (double)LLONG_MIN)) {
1460 exerror("floating modulus out of range");
1461 }
1462 if ((long long)rounded == 0)
1463 exerror("floating 0 modulus");
1464 else
1465 v.floating = (long long)v.floating % (long long)rounded;
1466 break;
1467 }
1468 case '&':
1469 v.floating = (long long)v.floating & (long long)r.floating;
1470 break;
1471 case '|':
1472 v.floating = (long long)v.floating | (long long)r.floating;
1473 break;
1474 case '^':
1475 v.floating = (long long)v.floating ^ (long long)r.floating;
1476 break;
1477 case LSH:
1478 v.floating = (long long)v.floating << (long long)r.floating;
1479 break;
1480 case RSH:
1481#ifdef _WIN32
1482 v.floating = (long long)((unsigned long long)v.floating >> (long long)r.floating);
1483#else
1484 v.floating = (unsigned long long)v.floating >> (long long)r.floating;
1485#endif
1486 break;
1487 default:
1488 goto huh;
1489 }
1490 break;
1491 case INTEGER:
1492 case UNSIGNED:
1493 switch (exnode->subop)
1494 {
1495 case '+':
1496 v.integer += r.integer;
1497 break;
1498 case '-':
1499 v.integer -= r.integer;
1500 break;
1501 case '*':
1502 v.integer *= r.integer;
1503 break;
1504 case '/':
1505 if (r.integer == 0)
1506 exerror("integer divide by 0");
1507 else
1508 v.integer /= r.integer;
1509 break;
1510 case '%':
1511 if (r.integer == 0)
1512 exerror("integer 0 modulus");
1513 else
1514 v.integer %= r.integer;
1515 break;
1516 case '&':
1517 v.integer &= r.integer;
1518 break;
1519 case '|':
1520 v.integer |= r.integer;
1521 break;
1522 case '^':
1523 v.integer ^= r.integer;
1524 break;
1525 case LSH:
1526 v.integer <<= r.integer;
1527 break;
1528 case RSH:
1529 v.integer = (unsigned long long)v.integer >> r.integer;
1530 break;
1531 default:
1532 goto huh;
1533 }
1534 break;
1535 case STRING:
1536 switch (exnode->subop)
1537 {
1538 case '+':
1539 v.string = str_add(ex, v.string, r.string);
1540 break;
1541 case '|':
1542 v.string = str_ior(ex, v.string, r.string);
1543 break;
1544 case '&':
1545 v.string = str_and(ex, v.string, r.string);
1546 break;
1547 case '^':
1548 v.string = str_xor(ex, v.string, r.string);
1549 break;
1550 case '%':
1551 v.string = str_mod(ex, v.string, r.string);
1552 break;
1553 case '*':
1554 v.string = str_mpy(ex, v.string, r.string);
1555 break;
1556 default:
1557 goto huh;
1558 }
1559 break;
1560 default:
1561 goto huh;
1562 }
1563 }
1564 else if (x->op == DYNAMIC)
1565 getdyn(ex, x, env, &assoc);
1566 else
1567 assoc = 0;
1568 r = v;
1569 goto set;
1570 case ';':
1571 case ',':
1572 v = eval(ex, x, env);
1573 while ((exnode = exnode->data.operand.right) && (exnode->op == ';' || exnode->op == ','))
1574 {
1575 v = eval(ex, exnode->data.operand.left, env);
1576 if (ex->loopcount)
1577 return v;
1578 }
1579 return exnode ? eval(ex, exnode, env) : v;
1580 case '?':
1581 v = eval(ex, x, env);
1582 return v.integer ? eval(ex, exnode->data.operand.right->data.operand.left, env) : eval(ex, exnode->data.operand.right->data.operand.right, env);
1583 case AND:
1584 v = eval(ex, x, env);
1585 return v.integer ? eval(ex, exnode->data.operand.right, env) : v;
1586 case OR:
1587 v = eval(ex, x, env);
1588 return v.integer ? v : eval(ex, exnode->data.operand.right, env);
1589 }
1590 v = eval(ex, x, env);
1591 if ((x = exnode->data.operand.right)) {
1592 r = eval(ex, x, env);
1593 if (!BUILTIN(x->type) && exnode->binary) {
1594 tmp = *exnode->data.operand.left;
1595 tmp.data.constant.value = v;
1596 rtmp = *x;
1597 rtmp.data.constant.value = r;
1598 if (!ex->disc->binaryf(&tmp, exnode, &rtmp, 0))
1599 return tmp.data.constant.value;
1600 }
1601 }
1602 switch (exnode->data.operand.left->type)
1603 {
1604 case FLOATING:
1605 switch (exnode->op)
1606 {
1607 case F2I:
1608 v.integer = v.floating;
1609 return v;
1610 case F2S:
1611 tmp = *exnode->data.operand.left;
1612 tmp.data.constant.value = v;
1613 if (exnode->data.operand.left->op != DYNAMIC && exnode->data.operand.left->op != ID)
1614 {
1615 tmp.data.constant.value.string = exprintf(&ex->ve, "%g", v.floating);
1616 }
1617 else if (ex->disc->convertf(&tmp, STRING, 0)) {
1618 tmp.data.constant.value.string = exprintf(&ex->ve, "%g", v.floating);
1619 }
1620 tmp.type = STRING;
1621 return tmp.data.constant.value;
1622 case F2X:
1623 tmp = *exnode->data.operand.left;
1624 tmp.data.constant.value = v;
1625 if (ex->disc->convertf(&tmp, exnode->type, 0))
1626 exerror("%s: cannot convert floating value to external", tmp.data.variable.symbol->name);
1627 tmp.type = exnode->type;
1628 return tmp.data.constant.value;
1629 case '!':
1630 v.floating = !(long long)v.floating;
1631 return v;
1632 case '~':
1633 v.floating = ~(long long)v.floating;
1634 return v;
1635 case '-':
1636 if (x)
1637 v.floating -= r.floating;
1638 else
1639 v.floating = -v.floating;
1640 return v;
1641 case '+':
1642 v.floating += r.floating;
1643 return v;
1644 case '&':
1645 v.floating = (long long)v.floating & (long long)r.floating;
1646 return v;
1647 case '|':
1648 v.floating = (long long)v.floating | (long long)r.floating;
1649 return v;
1650 case '^':
1651 v.floating = (long long)v.floating ^ (long long)r.floating;
1652 return v;
1653 case '*':
1654 v.floating *= r.floating;
1655 return v;
1656 case '/':
1657 if (r.floating == 0.0)
1658 exerror("floating divide by 0");
1659 else
1660 v.floating /= r.floating;
1661 return v;
1662 case '%':
1663 if ((r.integer = r.floating) == 0)
1664 exerror("floating 0 modulus");
1665 else
1666 v.floating = (long long)v.floating % r.integer;
1667 return v;
1668 case '<':
1669 v.integer = v.floating < r.floating;
1670 return v;
1671 case LE:
1672 v.integer = v.floating <= r.floating;
1673 return v;
1674 case EQ:
1675 v.integer = v.floating == r.floating;
1676 return v;
1677 case NE:
1678 v.integer = v.floating != r.floating;
1679 return v;
1680 case GE:
1681 v.integer = v.floating >= r.floating;
1682 return v;
1683 case '>':
1684 v.integer = v.floating > r.floating;
1685 return v;
1686 case LSH:
1687 v.integer = (long long)((unsigned long long)v.floating << (long long)r.floating);
1688 return v;
1689 case RSH:
1690 v.integer = (long long)((unsigned long long)v.floating >> (long long)r.floating);
1691 return v;
1692 }
1693 break;
1694 default:
1695 switch (exnode->op)
1696 {
1697 case X2F:
1698 xConvert(ex, exnode, FLOATING, v, &tmp);
1699 return tmp.data.constant.value;
1700 case X2I:
1701 xConvert(ex, exnode, INTEGER, v, &tmp);
1702 return tmp.data.constant.value;
1703 case X2S:
1704 xConvert(ex, exnode, STRING, v, &tmp);
1705 return tmp.data.constant.value;
1706 case X2X:
1707 xConvert(ex, exnode, exnode->type, v, &tmp);
1708 return tmp.data.constant.value;
1709 case XPRINT:
1710 xPrint(ex, exnode, v, &tmp);
1711 return tmp.data.constant.value;
1712 default:
1713 tmp = *exnode->data.operand.left;
1714 tmp.data.constant.value = v;
1715 if (x) {
1716 rtmp = *x;
1717 rtmp.data.constant.value = r;
1718 rp = &rtmp;
1719 } else
1720 rp = 0;
1721 if (!ex->disc->binaryf(&tmp, exnode, rp, 0))
1722 return tmp.data.constant.value;
1723 }
1724 goto integer;
1725 case UNSIGNED:
1726 switch (exnode->op)
1727 {
1728 case '<':
1729 v.integer = (unsigned long long)v.integer < (unsigned long long)r.integer;
1730 return v;
1731 case LE:
1732 v.integer = (unsigned long long)v.integer <= (unsigned long long)r.integer;
1733 return v;
1734 case GE:
1735 v.integer = (unsigned long long)v.integer >= (unsigned long long)r.integer;
1736 return v;
1737 case '>':
1738 v.integer = (unsigned long long)v.integer > (unsigned long long)r.integer;
1739 return v;
1740 }
1741 /*FALLTHROUGH*/
1742 case INTEGER:
1743 integer:
1744 switch (exnode->op)
1745 {
1746 case I2F:
1747#ifdef _WIN32
1748 v.floating = v.integer;
1749#else
1750 if (exnode->type == UNSIGNED)
1751 v.floating = (unsigned long long)v.integer;
1752 else
1753 v.floating = v.integer;
1754#endif
1755 return v;
1756 case I2S:
1757 tmp = *exnode->data.operand.left;
1758 tmp.data.constant.value = v;
1759 if (exnode->data.operand.left->op != DYNAMIC && exnode->data.operand.left->op != ID)
1760 {
1761 char *str;
1762 if (exnode->data.operand.left->type == UNSIGNED)
1763 str = exprintf(&ex->ve, "%llu", (unsigned long long)v.integer);
1764 else
1765 str = exprintf(&ex->ve, "%lld", v.integer);
1767 }
1768 else if (ex->disc->convertf(&tmp, STRING, 0)) {
1769 char *str = NULL;
1770 if (exnode->data.operand.left->type == UNSIGNED)
1771 str = exprintf(&ex->ve, "%llu", (unsigned long long)v.integer);
1772 else
1773 str = exprintf(&ex->ve, "%lld", v.integer);
1775 }
1776 tmp.type = STRING;
1777 return tmp.data.constant.value;
1778 case I2X:
1779 tmp = *exnode->data.operand.left;
1780 tmp.data.constant.value = v;
1781 if (ex->disc->convertf(&tmp, exnode->type, 0))
1782 exerror("%s: cannot convert integer value to external", tmp.data.variable.symbol->name);
1783 tmp.type = exnode->type;
1784 return tmp.data.constant.value;
1785 case '!':
1786 v.integer = !v.integer;
1787 return v;
1788 case '~':
1789 v.integer = ~v.integer;
1790 return v;
1791 case '-':
1792 if (x)
1793 v.integer -= r.integer;
1794 else
1795 v.integer = -v.integer;
1796 return v;
1797 case '+':
1798 v.integer += r.integer;
1799 return v;
1800 case '&':
1801 v.integer &= r.integer;
1802 return v;
1803 case '|':
1804 v.integer |= r.integer;
1805 return v;
1806 case '^':
1807 v.integer ^= r.integer;
1808 return v;
1809 case '*':
1810 v.integer *= r.integer;
1811 return v;
1812 case '/':
1813 if (r.integer == 0)
1814 exerror("integer divide by 0");
1815 else
1816 v.integer /= r.integer;
1817 return v;
1818 case '%':
1819 if (r.integer == 0)
1820 exerror("integer 0 modulus");
1821 else
1822 v.integer %= r.integer;
1823 return v;
1824 case EQ:
1825 v.integer = v.integer == r.integer;
1826 return v;
1827 case NE:
1828 v.integer = v.integer != r.integer;
1829 return v;
1830 case LSH:
1831 v.integer = v.integer << r.integer;
1832 return v;
1833 case RSH:
1834 v.integer = (unsigned long long)v.integer >> r.integer;
1835 return v;
1836 case '<':
1837 v.integer = v.integer < r.integer;
1838 return v;
1839 case LE:
1840 v.integer = v.integer <= r.integer;
1841 return v;
1842 case GE:
1843 v.integer = v.integer >= r.integer;
1844 return v;
1845 case '>':
1846 v.integer = v.integer > r.integer;
1847 return v;
1848 }
1849 break;
1850 case STRING:
1851 switch (exnode->op)
1852 {
1853 case S2B:
1854 v.integer = *v.string != 0;
1855 return v;
1856 case S2F:
1857 tmp = *exnode->data.operand.left;
1858 tmp.data.constant.value = v;
1859 if (ex->disc->convertf(&tmp, FLOATING, 0))
1860 {
1861 tmp.data.constant.value.floating = strtod(v.string, &e);
1862 if (*e)
1863 tmp.data.constant.value.floating = *v.string != 0;
1864 }
1865 tmp.type = FLOATING;
1866 return tmp.data.constant.value;
1867 case S2I:
1868 tmp = *exnode->data.operand.left;
1869 tmp.data.constant.value = v;
1870 if (ex->disc->convertf(&tmp, INTEGER, 0))
1871 {
1872 if (v.string) {
1873 tmp.data.constant.value.integer = strtoll(v.string, &e, 0);
1874 if (*e)
1875 tmp.data.constant.value.integer = *v.string != 0;
1876 }
1877 else
1878 tmp.data.constant.value.integer = 0;
1879 }
1880 tmp.type = INTEGER;
1881 return tmp.data.constant.value;
1882 case S2X:
1883 tmp = *exnode->data.operand.left;
1884 tmp.data.constant.value = v;
1885 if (ex->disc->convertf(&tmp, exnode->type, 0))
1886 exerror("%s: cannot convert string value to external", tmp.data.variable.symbol->name);
1887 tmp.type = exnode->type;
1888 return tmp.data.constant.value;
1889 case EQ:
1890 case NE:
1891 v.integer = ((v.string && r.string)
1892 ? strmatch(v.string, r.string)
1893 : (v.string == r.string)) == (exnode->op == EQ);
1894 return v;
1895 case '+':
1896 v.string = str_add(ex, v.string, r.string);
1897 return v;
1898 case '|':
1899 v.string = str_ior(ex, v.string, r.string);
1900 return v;
1901 case '&':
1902 v.string = str_and(ex, v.string, r.string);
1903 return v;
1904 case '^':
1905 v.string = str_xor(ex, v.string, r.string);
1906 return v;
1907 case '%':
1908 v.string = str_mod(ex, v.string, r.string);
1909 return v;
1910 case '*':
1911 v.string = str_mpy(ex, v.string, r.string);
1912 return v;
1913 }
1914 v.integer = strcoll(v.string, r.string);
1915 switch (exnode->op)
1916 {
1917 case '<':
1918 v.integer = v.integer < 0;
1919 return v;
1920 case LE:
1921 v.integer = v.integer <= 0;
1922 return v;
1923 case GE:
1924 v.integer = v.integer >= 0;
1925 return v;
1926 case '>':
1927 v.integer = v.integer > 0;
1928 return v;
1929 }
1930 goto huh;
1931 }
1932 huh:;
1933 char *left = lexname(exnode->data.operand.left->type, -1);
1934 char *op = lexname(exnode->op, exnode->subop);
1935 if (exnode->binary) {
1936 char *right = exnode->data.operand.right
1937 ? lexname(exnode->data.operand.right->type, -1) : NULL;
1938 exerror("operator %s %s %s not implemented", left, op,
1939 right ? right : "UNARY");
1940 free(right);
1941 } else
1942 exerror("operator %s %s not implemented", op, left);
1943 free(op);
1944 free(left);
1945 return exzero(exnode->type);
1946}
1947
1948/*
1949 * evaluate expression expr
1950 */
1951
1952Extype_t exeval(Expr_t *ex, Exnode_t *exnode, void *env) {
1953 Extype_t v = eval(ex, exnode, env);
1954 if (ex->loopcount > 0)
1955 {
1956 ex->loopcount = 0;
1957 if (ex->loopop == RETURN)
1958 return ex->loopret;
1959 }
1960 return v;
1961}
1962
1963/* exstring:
1964 * Generate copy of input string using
1965 * string memory.
1966 */
1967char *exstring(Expr_t * ex, char *s)
1968{
1969 return gv_arena_strdup(&ex->ve, s);
1970}
1971
1972/* exstralloc:
1973 * allocate sz bytes in expression memory.
1974 */
1975void *exstralloc(Expr_t * ex, size_t sz)
1976{
1977 return gv_arena_alloc(&ex->ve, 1, sz);
1978}
Agobj_t * copy(Agraph_t *g, Agobj_t *obj)
Definition actions.c:139
Dynamically expanding string buffers.
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:97
static size_t agxbput_n(agxbuf *xb, const char *s, size_t ssz)
append string s of length ssz into xb
Definition agxbuf.h:268
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 char * gv_strdup(const char *original)
Definition alloc.h:101
void * gv_arena_alloc(arena_t *arena, size_t alignment, size_t size)
Definition arena.c:120
char * gv_arena_strdup(arena_t *arena, const char *s)
Definition arena.c:138
void gv_arena_free(arena_t *arena, void *ptr, size_t size)
Definition arena.c:151
Region-based memory allocator.
#define ARENA_NEW(arena, type)
Definition arena.h:55
char * fmtquote(const char *, const char *, const char *)
quote string as with qb...qe
Definition fmtesc.c:28
#define elementsof(x)
Definition ast.h:33
#define STR_LEFT
Definition ast.h:26
#define STR_RIGHT
Definition ast.h:27
int strmatch(char *, char *)
Definition strmatch.c:556
int strgrpmatch(char *, char *, size_t *, int, int)
Definition strmatch.c:507
#define dtmatch(d, o)
Definition cdt.h:185
#define dtclear(d)
Definition cdt.h:189
CDT_API int dtsize(Dt_t *)
Definition dtsize.c:14
#define dtinsert(d, o)
Definition cdt.h:186
#define dtprev(d, o)
Definition cdt.h:183
#define dtlast(d)
Definition cdt.h:182
#define dtdelete(d, o)
Definition cdt.h:187
#define dtnext(d, o)
Definition cdt.h:181
#define dtfirst(d)
Definition cdt.h:180
#define right(i)
Definition closest.c:74
#define sub(h, i)
Definition closest.c:62
double drand48(void)
Definition utils.c:1539
#define left
Definition dthdr.h:12
void exwarn(const char *format,...)
Definition exerror.c:77
void exerror(const char *format,...)
Definition exerror.c:63
static int prints(Expr_t *ex, Exnode_t *exnode, void *env, FILE *sp)
Definition exeval.c:363
static int scformat(void *vp, Sffmt_t *dp)
Definition exeval.c:430
#define TIME_LEN
Definition exeval.c:47
static Extype_t getdyn(Expr_t *ex, Exnode_t *exnode, void *env, Exassoc_t **assoc)
Definition exeval.c:125
static void xConvert(Expr_t *ex, Exnode_t *exnode, long type, Extype_t v, Exnode_t *tmp)
Definition exeval.c:985
static char * str_add(Expr_t *ex, char *l, char *r)
Definition exeval.c:560
static Extype_t exsub(Expr_t *ex, Exnode_t *exnode, void *env, bool global)
Definition exeval.c:871
static char * str_xor(Expr_t *ex, const char *l, const char *r)
Definition exeval.c:646
char * exstring(Expr_t *ex, char *s)
Definition exeval.c:1967
static char * str_and(Expr_t *ex, const char *l, const char *r)
Definition exeval.c:615
static Extype_t eval(Expr_t *, Exnode_t *, void *)
Definition exeval.c:1016
Extype_t exeval(Expr_t *ex, Exnode_t *exnode, void *env)
Definition exeval.c:1952
static char * str_mpy(Expr_t *ex, const char *l, const char *r)
Definition exeval.c:720
static Extype_t exsplit(Expr_t *ex, Exnode_t *exnode, void *env)
Definition exeval.c:787
static void xPrint(Expr_t *ex, Exnode_t *exnode, Extype_t v, Exnode_t *tmp)
Definition exeval.c:1001
static void addItem(Expr_t *ex, Dt_t *arr, Extype_t v, char *tok)
Definition exeval.c:772
static int prformat(void *vp, Sffmt_t *dp)
Definition exeval.c:193
static Extype_t exsubstr(Expr_t *ex, Exnode_t *exnode, void *env)
Definition exeval.c:954
#define FRAME
Definition exeval.c:51
static void replace(agxbuf *s, char *base, char *repl, int ng, size_t *sub)
Definition exeval.c:750
static char * str_mod(Expr_t *ex, const char *l, const char *r)
Definition exeval.c:689
static char * lexname(long op, int subop)
Definition exeval.c:53
static int evaldyn(Expr_t *ex, Exnode_t *exnode, void *env, int delete)
Definition exeval.c:81
static int scan(Expr_t *ex, Exnode_t *exnode, void *env, FILE *sp)
Definition exeval.c:503
static int print(Expr_t *ex, Exnode_t *exnode, void *env, FILE *sp)
Definition exeval.c:380
static char * str_ior(Expr_t *ex, const char *l, const char *r)
Definition exeval.c:572
static Extype_t extokens(Expr_t *ex, Exnode_t *exnode, void *env)
Definition exeval.c:835
void * exstralloc(Expr_t *ex, size_t sz)
Definition exeval.c:1975
static long seed
Definition exeval.c:1014
static NORETURN void graphviz_exit(int status)
Definition exit.h:23
Exstate_t expr
const char * exop(size_t id)
Definition exparse.c:3270
#define UNSIGNED
Definition exparse.h:153
#define CHARACTER
Definition exparse.h:154
#define DYNAMIC
Definition exparse.h:167
#define SCANF
Definition exparse.h:189
#define F2S
Definition exparse.h:201
#define SSCANF
Definition exparse.h:193
#define RSH
Definition exparse.h:222
#define OR
Definition exparse.h:215
#define PRE
Definition exparse.h:182
#define GE
Definition exparse.h:220
#define MINTOKEN
Definition exparse.h:151
#define X2F
Definition exparse.h:210
#define S2X
Definition exparse.h:209
#define WHILE
Definition exparse.h:199
#define ITERATE
Definition exparse.h:173
#define MAXTOKEN
Definition exparse.h:228
#define NE
Definition exparse.h:218
#define SRAND
Definition exparse.h:192
#define S2I
Definition exparse.h:206
#define SUB
Definition exparse.h:194
#define LSH
Definition exparse.h:221
#define FLOATING
Definition exparse.h:155
#define FOR
Definition exparse.h:170
#define I2X
Definition exparse.h:208
#define IN_OP
Definition exparse.h:223
#define SUBSTR
Definition exparse.h:195
#define TOKENS
Definition exparse.h:197
#define ITERATOR
Definition exparse.h:174
#define RAND
Definition exparse.h:187
#define PRINT
Definition exparse.h:183
#define I2F
Definition exparse.h:202
#define SPRINTF
Definition exparse.h:191
#define I2S
Definition exparse.h:203
#define CONSTANT
Definition exparse.h:163
#define LE
Definition exparse.h:219
#define S2B
Definition exparse.h:204
#define CALL
Definition exparse.h:161
#define GSUB
Definition exparse.h:172
#define UNSET
Definition exparse.h:198
#define CONTINUE
Definition exparse.h:164
#define XPRINT
Definition exparse.h:214
#define F2I
Definition exparse.h:200
#define X2S
Definition exparse.h:212
#define SPLIT
Definition exparse.h:190
#define EQ
Definition exparse.h:217
#define BREAK
Definition exparse.h:160
#define S2F
Definition exparse.h:205
#define IF
Definition exparse.h:176
#define SWITCH
Definition exparse.h:196
#define AND
Definition exparse.h:216
#define X2X
Definition exparse.h:213
#define EXIT
Definition exparse.h:169
#define F2X
Definition exparse.h:207
#define X2I
Definition exparse.h:211
#define PRINTF
Definition exparse.h:184
#define FUNCTION
Definition exparse.h:171
#define ARRAY
Definition exparse.h:159
#define INC
Definition exparse.h:225
#define DEC
Definition exparse.h:226
expr procedure type
Definition exparse.y:208
Exnode_t * excast(Expr_t *, Exnode_t *, long, Exnode_t *, int)
#define EX_CALL
Definition expr.h:48
#define BUILTIN(t)
Definition expr.h:58
static char * exprintf(arena_t *vm, const char *fmt,...)
Definition expr.h:275
#define EX_ARRAY
Definition expr.h:47
char * extypename(Expr_t *p, long)
#define EX_SCALAR
Definition expr.h:49
Extype_t exzero(long int)
Definition exzero.c:26
static int flags
Definition gc.c:63
static double len(glCompPoint p)
Definition glutils.c:138
void * malloc(YYSIZE_T)
void free(void *)
#define ID
Definition gmlparse.h:134
#define STRING
Definition gmlparse.h:133
#define INTEGER
Definition gmlparse.h:131
node NULL
Definition grammar.y:181
replacements for ctype.h functions
static void gv_tolower_str(char *s)
Definition gv_ctype.h:87
static bool gv_islower(int c)
Definition gv_ctype.h:25
static bool gv_isupper(int c)
Definition gv_ctype.h:27
static bool gv_isalnum(int c)
Definition gv_ctype.h:43
static void gv_toupper_str(char *s)
Definition gv_ctype.h:99
static bool gv_isdigit(int c)
Definition gv_ctype.h:41
static bool gv_isalpha(int c)
Definition gv_ctype.h:29
Abstraction over ftell
static int64_t gv_ftell(FILE *stream)
ftell, accounting for platform limitations
Definition gv_ftell.h:12
agxbput(xb, staging)
GVIO_API const char * format
Definition gvio.h:51
textitem scanner parser str
Definition htmlparse.y:218
static Ppoint_t add(Ppoint_t, Ppoint_t)
Definition route.c:431
int sfprint(FILE *, Sffmt_t *format)
Definition sfprint.c:38
#define SFFMT_VALUE
Definition sfio.h:62
int sfvscanf(FILE *, Sffmt_t *format)
Definition sfvscanf.c:70
#define RETURN(v)
Definition strmatch.c:146
Extype_t key
Definition exlib.h:146
Extype_t value
Definition exlib.h:147
char name[1]
Definition exlib.h:148
long index_type
Definition expr.h:96
long type
Definition expr.h:95
char name[EX_NAMELEN]
Definition expr.h:99
long index
Definition expr.h:94
void * local
user defined local stuff
Definition expr.h:98
Exnode_t * value
Definition expr.h:97
long op
operator
Definition expr.h:142
long type
value type
Definition expr.h:141
bool binary
data.operand.{left,right} ok
Definition expr.h:143
Exdata_t data
Definition expr.h:144
Definition expr.h:207
arena_t vm
Definition expr.h:211
FILE * file[10]
Definition expr.h:210
char nullstring[1]
Definition exlib.h:162
Extype_t value
Definition exeval.c:184
Sffmt_t fmt
Definition exeval.c:180
Expr_t * expr
Definition exeval.c:181
Exnode_t * actuals
Definition exeval.c:185
void * env
Definition exeval.c:182
Print_t * args
Definition exeval.c:183
struct Exnode_s * param[3]
Definition exlib.h:50
char * format
Definition exlib.h:49
struct Exnode_s * arg
Definition exlib.h:51
struct Print_s * next
Definition exlib.h:48
char * form
Definition sfio.h:34
ssize_t n_str
Definition sfio.h:44
int flags
Definition sfio.h:38
int fmt
Definition sfio.h:36
ssize_t size
Definition sfio.h:37
Sffmtext_f extf
Definition sfio.h:32
const char * t_str
Definition sfio.h:43
Definition cdt.h:98
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 bool strview_str_eq(strview_t a, const char *b)
compare a string reference to a string for equality
Definition strview.h:98
#define srand48
Definition tlayout.c:40
static tok_t tok(const char *input, const char *separators)
begin tokenization of a new string
Definition tokenize.h:43
long long integer
Definition exparse.h:240
double floating
Definition exparse.h:237
char * string
Definition exparse.h:242
Exnode_t * left
Definition expr.h:117
Exnode_t * right
Definition expr.h:118
struct Exdata_u::@63 select
Exid_t * reference
Definition expr.h:113
Exnode_t * next
Definition expr.h:123
Exnode_t * statement
Definition expr.h:122
Exid_t * symbol
Definition expr.h:128
struct Exdata_u::@61 constant
Exnode_t * dyna
Definition expr.h:131
struct Exdata_u::@62 operand
struct Exdata_u::@64 variable
Extype_t value
Definition expr.h:112
Exnode_t * index
Definition expr.h:130
Definition grammar.c:90
#define UNREACHABLE()
Definition unreachable.h:30