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