Graphviz 14.1.5~dev.20260409.0840
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 rewind(sp);
541 n = sfvscanf(sp, &fmt.fmt);
542 fclose(sp);
543 } else {
544 n = sfvscanf(sp, &fmt.fmt);
545 }
546 if (fmt.actuals && !*fmt.fmt.form)
547 exerror("scanf: %s: too many arguments", fmt.actuals->data.operand.left->data.variable.symbol->name);
548 return n;
549}
550
551/*
552 * string add
553 */
554
555static char*
556str_add(Expr_t* ex, char* l, char* r)
557{
558 size_t sz = strlen(l) + strlen(r) + 1;
559 char *const s = gv_arena_alloc(&ex->ve, 1, sz);
560 snprintf(s, sz, "%s%s", l, r);
561 return s;
562}
563
564/*
565 * string ior
566 */
567
568static char *str_ior(Expr_t *ex, const char *l, const char *r) {
569
570 // compute how much space the result will occupy
571 size_t len = 1; // 1 for NUL terminator
572 for (const char *p = l; *p != '\0'; ++p) {
573 if (strchr(p + 1, *p) == NULL) {
574 ++len;
575 }
576 }
577 for (const char *p = r; *p != '\0'; ++p) {
578 if (strchr(l, *p) == NULL && strchr(p + 1, *p) == NULL) {
579 ++len;
580 }
581 }
582
583 // allocate a buffer to store this
584 char *const result = gv_arena_alloc(&ex->ve, 1, len);
585
586 // write the result
587 size_t i = 0;
588 for (const char *p = l; *p != '\0'; ++p) {
589 if (strchr(p + 1, *p) == NULL) {
590 assert(i < len && "incorrect preceding length computation");
591 result[i] = *p;
592 ++i;
593 }
594 }
595 for (const char *p = r; *p != '\0'; ++p) {
596 if (strchr(l, *p) == NULL && strchr(p + 1, *p) == NULL) {
597 assert(i < len && "incorrect preceding length computation");
598 result[i] = *p;
599 ++i;
600 }
601 }
602 assert(i + 1 == len && "incorrect preceding length computation");
603
604 return result;
605}
606
607/*
608 * string and
609 */
610
611static char *str_and(Expr_t *ex, const char *l, const char *r) {
612
613 // compute how much space the result will occupy
614 size_t len = 1; // 1 for NUL terminator
615 for (const char *p = l; *p != '\0'; ++p) {
616 if (strchr(r, *p) != NULL && strchr(p + 1, *p) == NULL) {
617 ++len;
618 }
619 }
620
621 // allocate a buffer to store this
622 char *const result = gv_arena_alloc(&ex->ve, 1, len);
623
624 // write the result
625 size_t i = 0;
626 for (const char *p = l; *p != '\0'; ++p) {
627 if (strchr(r, *p) != NULL && strchr(p + 1, *p) == NULL) {
628 assert(i < len && "incorrect preceding length computation");
629 result[i] = *p;
630 ++i;
631 }
632 }
633 assert(i + 1 == len && "incorrect preceding length computation");
634
635 return result;
636}
637
638/*
639 * string xor
640 */
641
642static char *str_xor(Expr_t *ex, const char *l, const char *r) {
643
644 // compute how much space the result will occupy
645 size_t len = 1; // 1 for NUL terminator
646 for (const char *p = l; *p != '\0'; ++p) {
647 if (strchr(r, *p) == NULL && strchr(p + 1, *p) == NULL) {
648 ++len;
649 }
650 }
651 for (const char *p = r; *p != '\0'; ++p) {
652 if (strchr(l, *p) == NULL && strchr(p + 1, *p) == NULL) {
653 ++len;
654 }
655 }
656
657 // allocate a buffer to store this
658 char *const result = gv_arena_alloc(&ex->ve, 1, len);
659
660 // write the result
661 size_t i = 0;
662 for (const char *p = l; *p != '\0'; ++p) {
663 if (strchr(r, *p) == NULL && strchr(p + 1, *p) == NULL) {
664 assert(i < len && "incorrect preceding length computation");
665 result[i] = *p;
666 ++i;
667 }
668 }
669 for (const char *p = r; *p != '\0'; ++p) {
670 if (strchr(l, *p) == NULL && strchr(p + 1, *p) == NULL) {
671 assert(i < len && "incorrect preceding length computation");
672 result[i] = *p;
673 ++i;
674 }
675 }
676 assert(i + 1 == len && "incorrect preceding length computation");
677
678 return result;
679}
680
681/*
682 * string mod
683 */
684
685static char *str_mod(Expr_t *ex, const char *l, const char *r) {
686
687 // compute how much space the result will occupy
688 size_t len = 1; // 1 for NUL terminator
689 for (const char *p = l; *p != '\0'; ++p) {
690 if (strchr(r, *p) == NULL && strchr(p + 1, *p) == NULL) {
691 ++len;
692 }
693 }
694
695 // allocate a buffer to store this
696 char *const result = gv_arena_alloc(&ex->ve, 1, len);
697
698 // write the result
699 size_t i = 0;
700 for (const char *p = l; *p != '\0'; ++p) {
701 if (strchr(r, *p) == NULL && strchr(p + 1, *p) == NULL) {
702 assert(i < len && "incorrect preceding length computation");
703 result[i] = *p;
704 ++i;
705 }
706 }
707 assert(i + 1 == len && "incorrect preceding length computation");
708
709 return result;
710}
711
712/*
713 * string mpy
714 */
715
716static char *str_mpy(Expr_t *ex, const char *l, const char *r) {
717
718 // compute how much space the result will occupy
719 size_t len = strlen(l);
720 {
721 size_t len2 = strlen(r);
722 if (len2 < len) {
723 len = len2;
724 }
725 }
726 ++len; // 1 for NUL terminator
727
728 // allocate a buffer to store this
729 char *const result = gv_arena_alloc(&ex->ve, 1, len);
730
731 // write the result
732 size_t i = 0;
733 for (; l[i] != '\0' && r[i] != '\0'; ++i) {
734 assert(i < len && "incorrect preceding length computation");
735 result[i] = l[i] == r[i] ? l[i] : ' ';
736 }
737 assert(i + 1 == len && "incorrect preceding length computation");
738
739 return result;
740}
741
742/* replace:
743 * Add replacement string.
744 * \digit is replaced with a subgroup match, if any.
745 */
746static void replace(agxbuf *s, char *base, char *repl, int ng, size_t *sub) {
747 char c;
748 int idx;
749
750 while ((c = *repl++)) {
751 if (c == '\\') {
752 if ((c = *repl) && gv_isdigit(c)) {
753 idx = c - '0';
754 if (idx < ng) {
755 const size_t offset = sub[2 * idx];
756 agxbput_n(s, base + offset, sub[2 * idx + 1] - offset);
757 }
758 repl++;
759 } else {
760 agxbputc(s, '\\');
761 }
762 } else {
763 agxbputc(s, c);
764 }
765 }
766}
767
768static void addItem(Expr_t *ex, Dt_t *arr, Extype_t v, char *tok) {
769 Exassoc_t* b;
770
771 if (!(b = dtmatch(arr, &v))) {
772 b = ARENA_NEW(&ex->vm, Exassoc_t);
773 b->key = v;
774 dtinsert(arr, b);
775 }
776 b->value.string = tok;
777}
778
779/* exsplit:
780 * break string into possibly empty fields and store in array
781 * return number of fields
782 */
783static Extype_t exsplit(Expr_t *ex, Exnode_t *exnode, void *env) {
784 Extype_t v;
785 char *str;
786 char *seps;
787 char *tok;
788 size_t sz;
789 Dt_t* arr = exnode->data.split.array->local;
790
791 str = eval(ex, exnode->data.split.string, env).string;
792 if (exnode->data.split.seps)
793 seps = eval(ex, exnode->data.split.seps, env).string;
794 else
795 seps = " \t\n";
796
797 v.integer = 0;
798 while (*str) {
799 sz = strspn (str, seps);
800 if (sz) {
801 if (v.integer == 0) { /* initial separator => empty field */
802 addItem(ex, arr, v, "");
803 v.integer++;
804 }
805 for (size_t i = 1; i < sz; i++) {
806 addItem(ex, arr, v, "");
807 v.integer++;
808 }
809 }
810 str += sz;
811 if (*str == '\0') { /* terminal separator => empty field */
812 addItem(ex, arr, v, "");
813 v.integer++;
814 break;
815 }
816 sz = strcspn (str, seps);
817 tok = gv_arena_alloc(&ex->vm, 1, sz + 1);
818 memcpy(tok, str, sz);
819 addItem(ex, arr, v, tok);
820 v.integer++;
821 str += sz;
822 }
823
824 return v;
825}
826
827/* extoken:
828 * tokenize string and store in array
829 * return number of tokens
830 */
831static Extype_t extokens(Expr_t *ex, Exnode_t *exnode, void *env) {
832 Extype_t v;
833 char *str;
834 char *seps;
835 char *tok;
836 size_t sz;
837 Dt_t* arr = exnode->data.split.array->local;
838
839 str = eval(ex, exnode->data.split.string, env).string;
840 if (exnode->data.split.seps)
841 seps = eval(ex, exnode->data.split.seps, env).string;
842 else
843 seps = " \t\n";
844
845 v.integer = 0;
846 while (*str) {
847 sz = strspn (str, seps);
848 str += sz;
849 if (*str == '\0')
850 break;
851
852 sz = strcspn (str, seps);
853 assert (sz);
854 tok = gv_arena_alloc(&ex->vm, 1, sz + 1);
855 memcpy(tok, str, sz);
856 addItem(ex, arr, v, tok);
857 v.integer++;
858 str += sz;
859 }
860
861 return v;
862}
863
864/* exsub:
865 * return string after pattern substitution
866 */
867static Extype_t exsub(Expr_t *ex, Exnode_t *exnode, void *env, bool global) {
868 char *str;
869 char *pat;
870 char *repl;
871 char *p;
872 char *s;
873 Extype_t v;
874 size_t sub[20];
875 int flags = 0;
876 int ng;
877
878 str = eval(ex, exnode->data.string.base, env).string;
879 pat = eval(ex, exnode->data.string.pat, env).string;
880 if (exnode->data.string.repl)
881 repl = eval(ex, exnode->data.string.repl, env).string;
882 else
883 repl = 0;
884
885 if (!global) {
886 if (*pat == '^') {
887 pat++;
888 flags |= STR_LEFT;
889 }
890 p = pat;
891 while (*p)
892 p++;
893 if (p > pat)
894 p--;
895 if (*p == '$') {
896 if (p > pat && p[-1] == '\\') {
897 *p-- = '\0';
898 *p = '$';
899 } else {
900 flags |= STR_RIGHT;
901 *p = '\0';
902 }
903 }
904 }
905 if (*pat == '\0') {
906 v.string = gv_arena_strdup(&ex->ve, str);
907 return v;
908 }
909
910 ng = strgrpmatch(str, pat, sub, sizeof(sub) / (sizeof(sub[0]) * 2), flags);
911 if (ng == 0) {
912 v.string = gv_arena_strdup(&ex->ve, str);
913 return v;
914 }
915 if (sub[0] == sub[1]) {
916 exwarn("pattern match of empty string - ill-specified pattern \"%s\"?", pat);
917 v.string = gv_arena_strdup(&ex->ve, str);
918 return v;
919 }
920
921 agxbuf buffer = {0};
922
923 agxbput_n(&buffer, str, sub[0]);
924
925 if (repl) {
926 replace(&buffer, str, repl, ng, sub);
927 }
928
929 s = str + sub[1];
930 if (global) {
931 while ((ng = strgrpmatch(s, pat, sub, sizeof(sub) / (sizeof(sub[0]) * 2), flags))) {
932 agxbput_n(&buffer, s, sub[0]);
933 if (repl) {
934 replace(&buffer, s, repl, ng, sub);
935 }
936 s = s + sub[1];
937 }
938 }
939
940 agxbput(&buffer, s);
941
942 v.string = gv_arena_strdup(&ex->ve, agxbuse(&buffer));
943 agxbfree(&buffer);
944 return v;
945}
946
947/* exsubstr:
948 * return substring.
949 */
950static Extype_t exsubstr(Expr_t *ex, Exnode_t *exnode, void *env) {
951 Extype_t s;
952 Extype_t i;
953 Extype_t l;
954 Extype_t v;
955
956 s = eval(ex, exnode->data.string.base, env);
957 const size_t len = strlen(s.string);
958 i = eval(ex, exnode->data.string.pat, env);
959 if (i.integer < 0 || len < (unsigned long long)i.integer)
960 exerror("illegal start index in substr(%s,%lld)", s.string, i.integer);
961 if (exnode->data.string.repl) {
962 l = eval(ex, exnode->data.string.repl, env);
963 if (l.integer < 0 ||
964 len - (unsigned long long)i.integer < (unsigned long long)l.integer)
965 exerror("illegal length in substr(%s,%lld,%lld)",
966 s.string, i.integer, l.integer);
967 } else
968 l.integer = (long long)(len - (unsigned long long)i.integer);
969
970 v.string = gv_arena_alloc(&ex->ve, 1, (size_t)l.integer + 1);
971 if (exnode->data.string.repl) {
972 memcpy(v.string, s.string + i.integer, (size_t)l.integer);
973 } else
974 memcpy(v.string, s.string + i.integer, len - (size_t)i.integer);
975 return v;
976}
977
978/* xConvert:
979 * Convert from external type.
980 */
981static void xConvert(Expr_t *ex, Exnode_t *exnode, long type, Extype_t v,
982 Exnode_t * tmp)
983{
984 *tmp = *exnode->data.operand.left;
985 tmp->data.constant.value = v;
986 if (ex->disc->convertf(tmp, type, 0)) {
987 exerror("%s: cannot convert %s value to %s",
989 extypename(ex, exnode->data.operand.left->type), extypename(ex, type));
990 }
991 tmp->type = type;
992}
993
994/* xPrint:
995 * Generate string representation from value of external type.
996 */
997static void xPrint(Expr_t *ex, Exnode_t *exnode, Extype_t v, Exnode_t *tmp) {
998 *tmp = *exnode->data.operand.left;
999 tmp->data.constant.value = v;
1000 if (ex->disc->stringof(ex, tmp, 0))
1001 exerror("%s: no string representation of %s value",
1003 extypename(ex, exnode->data.operand.left->type));
1004 tmp->type = STRING;
1005}
1006
1007/*
1008 * internal exeval
1009 */
1010static long seed;
1011
1012static Extype_t eval(Expr_t *ex, Exnode_t *exnode, void *env) {
1013 Exnode_t* x;
1014 Exnode_t* a;
1015 Extype_t** t;
1016 int n;
1017 Extype_t v;
1018 Extype_t r = {0};
1019 Extype_t i;
1020 char* e;
1021 Exnode_t tmp;
1022 Exnode_t rtmp;
1023 Exnode_t* rp;
1024 Exassoc_t* assoc;
1025 Extype_t args[FRAME+1];
1026 Extype_t save[FRAME];
1027
1028 if (!exnode || ex->loopcount)
1029 {
1030 v.integer = 1;
1031 return v;
1032 }
1033 x = exnode->data.operand.left;
1034 switch (exnode->op)
1035 {
1036 case BREAK:
1037 case CONTINUE:
1038 v = eval(ex, x, env);
1039 ex->loopcount = v.integer;
1040 ex->loopop = exnode->op;
1041 return v;
1042 case CONSTANT:
1043 return exnode->data.constant.value;
1044 case DEC:
1045 n = -1;
1046 add:
1047 if (x->op == DYNAMIC)
1048 r = getdyn(ex, x, env, &assoc);
1049 else
1050 {
1051 if (x->data.variable.index)
1052 i = eval(ex, x->data.variable.index, env);
1053 else
1054 i.integer = EX_SCALAR;
1055 if (x->data.variable.dyna) {
1056 Extype_t locv;
1057 locv = getdyn(ex, x->data.variable.dyna, env, &assoc);
1059 }
1060 r = ex->disc->getf(ex, x, x->data.variable.symbol,
1061 x->data.variable.reference, env, (int)i.integer,
1062 ex->disc);
1063 }
1064 v = r;
1065 switch (x->type)
1066 {
1067 case FLOATING:
1068 v.floating += n;
1069 break;
1070 case INTEGER:
1071 case UNSIGNED:
1072 v.integer += n;
1073 break;
1074 default:
1075 goto huh;
1076 }
1077 set:
1078 if (x->op == DYNAMIC)
1079 {
1080 if (x->type == STRING)
1081 {
1082 v.string = gv_arena_strdup(&ex->vm, v.string);
1083 }
1084 if (assoc)
1085 assoc->value = v;
1086 else
1088 }
1089 else
1090 {
1091 if (x->data.variable.index)
1092 eval(ex, x->data.variable.index, env);
1093 if (x->data.variable.dyna) {
1094 Extype_t locv = getdyn(ex, x->data.variable.dyna, env, &assoc);
1096 }
1097 if (ex->disc->setf(ex, x, x->data.variable.symbol,
1098 x->data.variable.reference, env, v) < 0)
1099 exerror("%s: cannot set value", x->data.variable.symbol->name);
1100 }
1101 if (exnode->subop == PRE)
1102 r = v;
1103 return r;
1104 case DYNAMIC:
1105 return getdyn(ex, exnode, env, &assoc);
1106 case SPLIT:
1107 return exsplit(ex, exnode, env);
1108 case TOKENS:
1109 return extokens(ex, exnode, env);
1110 case GSUB:
1111 return exsub(ex, exnode, env, /* global = */ true);
1112 case SUB:
1113 return exsub(ex, exnode, env, /* global = */ false);
1114 case SUBSTR:
1115 return exsubstr(ex, exnode, env);
1116 case SRAND:
1117 v.integer = seed;
1118 if (exnode->binary) {
1119 seed = (long)eval(ex, x, env).integer;
1120 } else
1121 seed = (long)time(0);
1122 srand48(seed);
1123 return v;
1124 case RAND:
1125 v.floating = drand48();
1126 return v;
1127 case EXIT:
1128 v = eval(ex, x, env);
1129 if (ex->disc->exitf)
1130 ex->disc->exitf(env, (int)v.integer);
1131 else
1132 graphviz_exit((int)v.integer);
1133 UNREACHABLE();
1134 case IF:
1135 v = eval(ex, x, env);
1136 if (v.integer)
1137 eval(ex, exnode->data.operand.right->data.operand.left, env);
1138 else
1139 eval(ex, exnode->data.operand.right->data.operand.right, env);
1140 v.integer = 1;
1141 return v;
1142 case FOR:
1143 case WHILE:
1144 exnode = exnode->data.operand.right;
1145 for (;;)
1146 {
1147 r = eval(ex, x, env);
1148 if (!r.integer)
1149 {
1150 v.integer = 1;
1151 return v;
1152 }
1153 if (exnode->data.operand.right)
1154 {
1155 eval(ex, exnode->data.operand.right, env);
1156 if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE))
1157 {
1158 v.integer = 0;
1159 return v;
1160 }
1161 }
1162 if (exnode->data.operand.left)
1163 eval(ex, exnode->data.operand.left, env);
1164 }
1165 UNREACHABLE();
1166 case SWITCH:
1167 v = eval(ex, x, env);
1168 i.integer = x->type;
1169 r.integer = 0;
1170 x = exnode->data.operand.right;
1171 a = x->data.select.statement;
1172 n = 0;
1173 while ((x = x->data.select.next))
1174 {
1175 if (!(t = x->data.select.constant))
1176 n = 1;
1177 else
1178 for (; *t; t++)
1179 {
1180 switch ((int)i.integer)
1181 {
1182 case INTEGER:
1183 case UNSIGNED:
1184 if ((*t)->integer == v.integer)
1185 break;
1186 continue;
1187 case STRING:
1188 if (strmatch((*t)->string, v.string))
1189 break;
1190 continue;
1191 case FLOATING:
1192 if ((*t)->floating == v.floating)
1193 break;
1194 continue;
1195 }
1196 n = 1;
1197 break;
1198 }
1199 if (n)
1200 {
1201 if (!x->data.select.statement)
1202 {
1203 r.integer = 1;
1204 break;
1205 }
1206 r = eval(ex, x->data.select.statement, env);
1207 if (ex->loopcount > 0)
1208 {
1209 ex->loopcount--;
1210 break;
1211 }
1212 }
1213 }
1214 if (!n && a)
1215 {
1216 r = eval(ex, a, env);
1217 if (ex->loopcount > 0)
1218 ex->loopcount--;
1219 }
1220 return r;
1221 case ITERATE:
1222 v.integer = 0;
1223 if (exnode->data.generate.array->op == DYNAMIC)
1224 {
1225 n = exnode->data.generate.index->type == STRING;
1226 for (assoc = dtfirst(exnode->data.generate.array->data.variable.symbol->local); assoc; assoc = dtnext(exnode->data.generate.array->data.variable.symbol->local, assoc))
1227 {
1228 v.integer++;
1229 if (n)
1230 exnode->data.generate.index->value->data.constant.value.string = assoc->name;
1231 else
1232 exnode->data.generate.index->value->data.constant.value = assoc->key;
1233 eval(ex, exnode->data.generate.statement, env);
1234 if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE))
1235 {
1236 v.integer = 0;
1237 break;
1238 }
1239 }
1240 }
1241 else
1242 {
1243 r = ex->disc->getf(ex, exnode, exnode->data.generate.array->data.variable.symbol,
1244 exnode->data.generate.array->data.variable.reference, env,
1245 0, ex->disc);
1246 for (v.integer = 0; v.integer < r.integer; v.integer++)
1247 {
1248 exnode->data.generate.index->value->data.constant.value.integer = v.integer;
1249 eval(ex, exnode->data.generate.statement, env);
1250 if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE))
1251 {
1252 v.integer = 0;
1253 break;
1254 }
1255 }
1256 }
1257 return v;
1258 case ITERATOR:
1259 v.integer = 0;
1260 if (exnode->data.generate.array->op == DYNAMIC) {
1261 n = exnode->data.generate.index->type == STRING;
1262 for (assoc = dtlast(exnode->data.generate.array->
1263 data.variable.symbol->local); assoc;
1264 assoc = dtprev(exnode->data.generate.array->data.variable.symbol->local,
1265 assoc)) {
1266 v.integer++;
1267 if (n)
1268 exnode->data.generate.index->value->data.constant.value.string = assoc->name;
1269 else
1270 exnode->data.generate.index->value->data.constant.value = assoc->key;
1271 eval(ex, exnode->data.generate.statement, env);
1272 if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE)) {
1273 v.integer = 0;
1274 break;
1275 }
1276 }
1277 } else {
1278 r = ex->disc->getf(ex, exnode, exnode->data.generate.array->data.variable.symbol,
1279 exnode->data.generate.array->data.variable.reference, env,
1280 0, ex->disc);
1281 for (v.integer = r.integer-1; 0 <= v.integer; v.integer--) {
1282 exnode->data.generate.index->value->data.constant.value.integer = v.integer;
1283 eval(ex, exnode->data.generate.statement, env);
1284 if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE)) {
1285 v.integer = 0;
1286 break;
1287 }
1288 }
1289 }
1290 return v;
1291 case '#':
1292 if (exnode->data.variable.symbol->index > 0) {
1293 if (ex->disc->lengthf != NULL) {
1294 v = ex->disc->lengthf(exnode->data.variable.symbol, ex->disc);
1295 } else {
1296 exerror("%s: cannot get length", x->data.variable.symbol->name);
1297 v.integer = 0;
1298 }
1299 } else {
1300 v.integer = dtsize(exnode->data.variable.symbol->local);
1301 }
1302 return v;
1303 case IN_OP:
1304 v.integer = evaldyn (ex, exnode, env, 0);
1305 return v;
1306 case UNSET:
1307 if (exnode->data.variable.index) {
1308 v.integer = evaldyn (ex, exnode, env, 1);
1309 }
1310 else {
1311 dtclear(exnode->data.variable.symbol->local);
1312 v.integer = 0;
1313 }
1314 return v;
1315 case CALL:
1316 x = exnode->data.call.args;
1317 for (n = 0, a = exnode->data.call.procedure->value->data.procedure.args; a && x; a = a->data.operand.right)
1318 {
1319 if (n < (int)elementsof(args))
1320 {
1322 args[n++] = eval(ex, x->data.operand.left, env);
1323 }
1324 else
1325 a->data.operand.left->data.variable.symbol->value->data.constant.value = eval(ex, x->data.operand.left, env);
1326 x = x->data.operand.right;
1327 }
1328 for (n = 0, a = exnode->data.call.procedure->value->data.procedure.args;
1329 a && n < (int)elementsof(save); a = a->data.operand.right)
1331 if (x)
1332 exerror("too many actual args");
1333 else if (a)
1334 exerror("not enough actual args");
1335 v = exeval(ex, exnode->data.call.procedure->value->data.procedure.body, env);
1336 for (n = 0, a = exnode->data.call.procedure->value->data.procedure.args;
1337 a && n < (int)elementsof(save); a = a->data.operand.right)
1339 return v;
1340 case ARRAY:
1341 n = 0;
1342 for (x = exnode->data.operand.right; x && n < (int)elementsof(args);
1343 x = x->data.operand.right)
1344 args[n++] = eval(ex, x->data.operand.left, env);
1345 return ex->disc->getf(ex, exnode->data.operand.left,
1347 exnode->data.operand.left->data.variable.reference, args,
1348 EX_ARRAY, ex->disc);
1349 case FUNCTION:
1350 n = 0;
1351 args[n++].string = env;
1352 for (x = exnode->data.operand.right; x && n < (int)elementsof(args);
1353 x = x->data.operand.right)
1354 args[n++] = eval(ex, x->data.operand.left, env);
1355 return ex->disc->getf(ex, exnode->data.operand.left,
1358 args+1, EX_CALL, ex->disc);
1359 case ID:
1360 if (exnode->data.variable.index)
1361 i = eval(ex, exnode->data.variable.index, env);
1362 else
1363 i.integer = EX_SCALAR;
1364 if (exnode->data.variable.dyna) {
1365 Extype_t locv = getdyn(ex, exnode->data.variable.dyna, env, &assoc);
1367 }
1368 return ex->disc->getf(ex, exnode, exnode->data.variable.symbol,
1369 exnode->data.variable.reference, env, (int)i.integer,
1370 ex->disc);
1371 case INC:
1372 n = 1;
1373 goto add;
1374 case PRINT:
1375 v.integer = prints(ex, exnode, env, stdout);
1376 return v;
1377 case PRINTF:
1378 v.integer = print(ex, exnode, env, NULL);
1379 return v;
1380 case RETURN:
1381 ex->loopret = eval(ex, x, env);
1382 ex->loopcount = 32767;
1383 ex->loopop = exnode->op;
1384 return ex->loopret;
1385 case SCANF:
1386 case SSCANF:
1387 v.integer = scan(ex, exnode, env, NULL);
1388 return v;
1389 case SPRINTF: {
1390 FILE *buffer = tmpfile();
1391 if (buffer == NULL) {
1392 fprintf(stderr, "out of memory\n");
1393 graphviz_exit(EXIT_FAILURE);
1394 }
1395 print(ex, exnode, env, buffer);
1396 const int64_t size = gv_ftell(buffer);
1397 if (size < 0) {
1398 fclose(buffer);
1399 fprintf(stderr, "failed to read back temporary file\n");
1400 graphviz_exit(EXIT_FAILURE);
1401 }
1402 rewind(buffer);
1403 v.string = gv_arena_alloc(&ex->ve, 1, (size_t)size + 1);
1404 if (fread(v.string, (size_t)size, 1, buffer) < 1) {
1405 fprintf(stderr, "failed to read back temporary file\n");
1406 graphviz_exit(EXIT_FAILURE);
1407 }
1408 fclose(buffer);
1409 return v;
1410 }
1411 case '=':
1412 v = eval(ex, exnode->data.operand.right, env);
1413 if (exnode->subop != '=')
1414 {
1415 r = v;
1416 if (x->op == DYNAMIC)
1417 v = getdyn(ex, x, env, &assoc);
1418 else
1419 {
1420 if (x->data.variable.index)
1421 v = eval(ex, x->data.variable.index, env);
1422 else
1423 v.integer = EX_SCALAR;
1424 if (x->data.variable.dyna) {
1425 Extype_t locv;
1426 locv = getdyn(ex, x->data.variable.dyna, env, &assoc);
1427 x->data.variable.dyna->data.variable.dyna->data.constant.value = locv;
1428 }
1429 v = ex->disc->getf(ex, x, x->data.variable.symbol,
1430 x->data.variable.reference, env, (int)v.integer,
1431 ex->disc);
1432 }
1433 switch (x->type)
1434 {
1435 case FLOATING:
1436 switch (exnode->subop)
1437 {
1438 case '+':
1439 v.floating += r.floating;
1440 break;
1441 case '-':
1442 v.floating -= r.floating;
1443 break;
1444 case '*':
1445 v.floating *= r.floating;
1446 break;
1447 case '/':
1448 if (r.floating == 0.0)
1449 exerror("floating divide by 0");
1450 else
1451 v.floating /= r.floating;
1452 break;
1453 case '%': {
1454 const double rounded = round(r.floating);
1455 if (LLONG_MAX < (INT64_C(1) << 53) &&
1456 (rounded > (double)LLONG_MAX || rounded < (double)LLONG_MIN)) {
1457 exerror("floating modulus out of range");
1458 }
1459 if ((long long)rounded == 0)
1460 exerror("floating 0 modulus");
1461 else
1462 v.floating = (long long)v.floating % (long long)rounded;
1463 break;
1464 }
1465 case '&':
1466 v.floating = (long long)v.floating & (long long)r.floating;
1467 break;
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 LSH:
1475 v.floating = (long long)v.floating << (long long)r.floating;
1476 break;
1477 case RSH:
1478#ifdef _WIN32
1479 v.floating = (long long)((unsigned long long)v.floating >> (long long)r.floating);
1480#else
1481 v.floating = (unsigned long long)v.floating >> (long long)r.floating;
1482#endif
1483 break;
1484 default:
1485 goto huh;
1486 }
1487 break;
1488 case INTEGER:
1489 case UNSIGNED:
1490 switch (exnode->subop)
1491 {
1492 case '+':
1493 v.integer += r.integer;
1494 break;
1495 case '-':
1496 v.integer -= r.integer;
1497 break;
1498 case '*':
1499 v.integer *= r.integer;
1500 break;
1501 case '/':
1502 if (r.integer == 0)
1503 exerror("integer divide by 0");
1504 else
1505 v.integer /= r.integer;
1506 break;
1507 case '%':
1508 if (r.integer == 0)
1509 exerror("integer 0 modulus");
1510 else
1511 v.integer %= r.integer;
1512 break;
1513 case '&':
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 LSH:
1523 v.integer <<= r.integer;
1524 break;
1525 case RSH:
1526 v.integer = (unsigned long long)v.integer >> r.integer;
1527 break;
1528 default:
1529 goto huh;
1530 }
1531 break;
1532 case STRING:
1533 switch (exnode->subop)
1534 {
1535 case '+':
1536 v.string = str_add(ex, v.string, r.string);
1537 break;
1538 case '|':
1539 v.string = str_ior(ex, v.string, r.string);
1540 break;
1541 case '&':
1542 v.string = str_and(ex, v.string, r.string);
1543 break;
1544 case '^':
1545 v.string = str_xor(ex, v.string, r.string);
1546 break;
1547 case '%':
1548 v.string = str_mod(ex, v.string, r.string);
1549 break;
1550 case '*':
1551 v.string = str_mpy(ex, v.string, r.string);
1552 break;
1553 default:
1554 goto huh;
1555 }
1556 break;
1557 default:
1558 goto huh;
1559 }
1560 }
1561 else if (x->op == DYNAMIC)
1562 getdyn(ex, x, env, &assoc);
1563 else
1564 assoc = 0;
1565 r = v;
1566 goto set;
1567 case ';':
1568 case ',':
1569 v = eval(ex, x, env);
1570 while ((exnode = exnode->data.operand.right) && (exnode->op == ';' || exnode->op == ','))
1571 {
1572 v = eval(ex, exnode->data.operand.left, env);
1573 if (ex->loopcount)
1574 return v;
1575 }
1576 return exnode ? eval(ex, exnode, env) : v;
1577 case '?':
1578 v = eval(ex, x, env);
1579 return v.integer ? eval(ex, exnode->data.operand.right->data.operand.left, env) : eval(ex, exnode->data.operand.right->data.operand.right, env);
1580 case AND:
1581 v = eval(ex, x, env);
1582 return v.integer ? eval(ex, exnode->data.operand.right, env) : v;
1583 case OR:
1584 v = eval(ex, x, env);
1585 return v.integer ? v : eval(ex, exnode->data.operand.right, env);
1586 }
1587 v = eval(ex, x, env);
1588 if ((x = exnode->data.operand.right)) {
1589 r = eval(ex, x, env);
1590 if (!BUILTIN(x->type) && exnode->binary) {
1591 tmp = *exnode->data.operand.left;
1592 tmp.data.constant.value = v;
1593 rtmp = *x;
1594 rtmp.data.constant.value = r;
1595 if (!ex->disc->binaryf(&tmp, exnode, &rtmp, 0))
1596 return tmp.data.constant.value;
1597 }
1598 }
1599 switch (exnode->data.operand.left->type)
1600 {
1601 case FLOATING:
1602 switch (exnode->op)
1603 {
1604 case F2I:
1605 v.integer = v.floating;
1606 return v;
1607 case F2S:
1608 tmp = *exnode->data.operand.left;
1609 tmp.data.constant.value = v;
1610 if (exnode->data.operand.left->op != DYNAMIC && exnode->data.operand.left->op != ID)
1611 {
1612 tmp.data.constant.value.string = exprintf(&ex->ve, "%g", v.floating);
1613 }
1614 else if (ex->disc->convertf(&tmp, STRING, 0)) {
1615 tmp.data.constant.value.string = exprintf(&ex->ve, "%g", v.floating);
1616 }
1617 tmp.type = STRING;
1618 return tmp.data.constant.value;
1619 case F2X:
1620 tmp = *exnode->data.operand.left;
1621 tmp.data.constant.value = v;
1622 if (ex->disc->convertf(&tmp, exnode->type, 0))
1623 exerror("%s: cannot convert floating value to external", tmp.data.variable.symbol->name);
1624 tmp.type = exnode->type;
1625 return tmp.data.constant.value;
1626 case '!':
1627 v.floating = !(long long)v.floating;
1628 return v;
1629 case '~':
1630 v.floating = ~(long long)v.floating;
1631 return v;
1632 case '-':
1633 if (x)
1634 v.floating -= r.floating;
1635 else
1636 v.floating = -v.floating;
1637 return v;
1638 case '+':
1639 v.floating += r.floating;
1640 return v;
1641 case '&':
1642 v.floating = (long long)v.floating & (long long)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 *= r.floating;
1652 return v;
1653 case '/':
1654 if (r.floating == 0.0)
1655 exerror("floating divide by 0");
1656 else
1657 v.floating /= r.floating;
1658 return v;
1659 case '%':
1660 if ((r.integer = r.floating) == 0)
1661 exerror("floating 0 modulus");
1662 else
1663 v.floating = (long long)v.floating % r.integer;
1664 return v;
1665 case '<':
1666 v.integer = v.floating < r.floating;
1667 return v;
1668 case LE:
1669 v.integer = v.floating <= r.floating;
1670 return v;
1671 case EQ:
1672 v.integer = v.floating == r.floating;
1673 return v;
1674 case NE:
1675 v.integer = v.floating != r.floating;
1676 return v;
1677 case GE:
1678 v.integer = v.floating >= r.floating;
1679 return v;
1680 case '>':
1681 v.integer = v.floating > r.floating;
1682 return v;
1683 case LSH:
1684 v.integer = (long long)((unsigned long long)v.floating << (long long)r.floating);
1685 return v;
1686 case RSH:
1687 v.integer = (long long)((unsigned long long)v.floating >> (long long)r.floating);
1688 return v;
1689 }
1690 break;
1691 default:
1692 switch (exnode->op)
1693 {
1694 case X2F:
1695 xConvert(ex, exnode, FLOATING, v, &tmp);
1696 return tmp.data.constant.value;
1697 case X2I:
1698 xConvert(ex, exnode, INTEGER, v, &tmp);
1699 return tmp.data.constant.value;
1700 case X2S:
1701 xConvert(ex, exnode, STRING, v, &tmp);
1702 return tmp.data.constant.value;
1703 case X2X:
1704 xConvert(ex, exnode, exnode->type, v, &tmp);
1705 return tmp.data.constant.value;
1706 case XPRINT:
1707 xPrint(ex, exnode, v, &tmp);
1708 return tmp.data.constant.value;
1709 default:
1710 tmp = *exnode->data.operand.left;
1711 tmp.data.constant.value = v;
1712 if (x) {
1713 rtmp = *x;
1714 rtmp.data.constant.value = r;
1715 rp = &rtmp;
1716 } else
1717 rp = 0;
1718 if (!ex->disc->binaryf(&tmp, exnode, rp, 0))
1719 return tmp.data.constant.value;
1720 }
1721 goto integer;
1722 case UNSIGNED:
1723 switch (exnode->op)
1724 {
1725 case '<':
1726 v.integer = (unsigned long long)v.integer < (unsigned long long)r.integer;
1727 return v;
1728 case LE:
1729 v.integer = (unsigned long long)v.integer <= (unsigned long long)r.integer;
1730 return v;
1731 case GE:
1732 v.integer = (unsigned long long)v.integer >= (unsigned long long)r.integer;
1733 return v;
1734 case '>':
1735 v.integer = (unsigned long long)v.integer > (unsigned long long)r.integer;
1736 return v;
1737 }
1738 /*FALLTHROUGH*/
1739 case INTEGER:
1740 integer:
1741 switch (exnode->op)
1742 {
1743 case I2F:
1744#ifdef _WIN32
1745 v.floating = v.integer;
1746#else
1747 if (exnode->type == UNSIGNED)
1748 v.floating = (unsigned long long)v.integer;
1749 else
1750 v.floating = v.integer;
1751#endif
1752 return v;
1753 case I2S:
1754 tmp = *exnode->data.operand.left;
1755 tmp.data.constant.value = v;
1756 if (exnode->data.operand.left->op != DYNAMIC && exnode->data.operand.left->op != ID)
1757 {
1758 char *str;
1759 if (exnode->data.operand.left->type == UNSIGNED)
1760 str = exprintf(&ex->ve, "%llu", (unsigned long long)v.integer);
1761 else
1762 str = exprintf(&ex->ve, "%lld", v.integer);
1764 }
1765 else if (ex->disc->convertf(&tmp, STRING, 0)) {
1766 char *str = NULL;
1767 if (exnode->data.operand.left->type == UNSIGNED)
1768 str = exprintf(&ex->ve, "%llu", (unsigned long long)v.integer);
1769 else
1770 str = exprintf(&ex->ve, "%lld", v.integer);
1772 }
1773 tmp.type = STRING;
1774 return tmp.data.constant.value;
1775 case I2X:
1776 tmp = *exnode->data.operand.left;
1777 tmp.data.constant.value = v;
1778 if (ex->disc->convertf(&tmp, exnode->type, 0))
1779 exerror("%s: cannot convert integer value to external", tmp.data.variable.symbol->name);
1780 tmp.type = exnode->type;
1781 return tmp.data.constant.value;
1782 case '!':
1783 v.integer = !v.integer;
1784 return v;
1785 case '~':
1786 v.integer = ~v.integer;
1787 return v;
1788 case '-':
1789 if (x)
1790 v.integer -= r.integer;
1791 else
1792 v.integer = -v.integer;
1793 return v;
1794 case '+':
1795 v.integer += r.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 if (r.integer == 0)
1811 exerror("integer divide by 0");
1812 else
1813 v.integer /= r.integer;
1814 return v;
1815 case '%':
1816 if (r.integer == 0)
1817 exerror("integer 0 modulus");
1818 else
1819 v.integer %= r.integer;
1820 return v;
1821 case EQ:
1822 v.integer = v.integer == r.integer;
1823 return v;
1824 case NE:
1825 v.integer = v.integer != r.integer;
1826 return v;
1827 case LSH:
1828 v.integer = v.integer << r.integer;
1829 return v;
1830 case RSH:
1831 v.integer = (unsigned long long)v.integer >> r.integer;
1832 return v;
1833 case '<':
1834 v.integer = v.integer < r.integer;
1835 return v;
1836 case LE:
1837 v.integer = v.integer <= r.integer;
1838 return v;
1839 case GE:
1840 v.integer = v.integer >= r.integer;
1841 return v;
1842 case '>':
1843 v.integer = v.integer > r.integer;
1844 return v;
1845 }
1846 break;
1847 case STRING:
1848 switch (exnode->op)
1849 {
1850 case S2B:
1851 v.integer = *v.string != 0;
1852 return v;
1853 case S2F:
1854 tmp = *exnode->data.operand.left;
1855 tmp.data.constant.value = v;
1856 if (ex->disc->convertf(&tmp, FLOATING, 0))
1857 {
1858 tmp.data.constant.value.floating = strtod(v.string, &e);
1859 if (*e)
1860 tmp.data.constant.value.floating = *v.string != 0;
1861 }
1862 tmp.type = FLOATING;
1863 return tmp.data.constant.value;
1864 case S2I:
1865 tmp = *exnode->data.operand.left;
1866 tmp.data.constant.value = v;
1867 if (ex->disc->convertf(&tmp, INTEGER, 0))
1868 {
1869 if (v.string) {
1870 tmp.data.constant.value.integer = strtoll(v.string, &e, 0);
1871 if (*e)
1872 tmp.data.constant.value.integer = *v.string != 0;
1873 }
1874 else
1875 tmp.data.constant.value.integer = 0;
1876 }
1877 tmp.type = INTEGER;
1878 return tmp.data.constant.value;
1879 case S2X:
1880 tmp = *exnode->data.operand.left;
1881 tmp.data.constant.value = v;
1882 if (ex->disc->convertf(&tmp, exnode->type, 0))
1883 exerror("%s: cannot convert string value to external", tmp.data.variable.symbol->name);
1884 tmp.type = exnode->type;
1885 return tmp.data.constant.value;
1886 case EQ:
1887 case NE:
1888 v.integer = ((v.string && r.string)
1889 ? strmatch(v.string, r.string)
1890 : (v.string == r.string)) == (exnode->op == EQ);
1891 return v;
1892 case '+':
1893 v.string = str_add(ex, v.string, r.string);
1894 return v;
1895 case '|':
1896 v.string = str_ior(ex, v.string, r.string);
1897 return v;
1898 case '&':
1899 v.string = str_and(ex, v.string, r.string);
1900 return v;
1901 case '^':
1902 v.string = str_xor(ex, v.string, r.string);
1903 return v;
1904 case '%':
1905 v.string = str_mod(ex, v.string, r.string);
1906 return v;
1907 case '*':
1908 v.string = str_mpy(ex, v.string, r.string);
1909 return v;
1910 }
1911 v.integer = strcoll(v.string, r.string);
1912 switch (exnode->op)
1913 {
1914 case '<':
1915 v.integer = v.integer < 0;
1916 return v;
1917 case LE:
1918 v.integer = v.integer <= 0;
1919 return v;
1920 case GE:
1921 v.integer = v.integer >= 0;
1922 return v;
1923 case '>':
1924 v.integer = v.integer > 0;
1925 return v;
1926 }
1927 goto huh;
1928 }
1929 huh:;
1930 char *left = lexname(exnode->data.operand.left->type, -1);
1931 char *op = lexname(exnode->op, exnode->subop);
1932 if (exnode->binary) {
1933 char *right = exnode->data.operand.right
1934 ? lexname(exnode->data.operand.right->type, -1) : NULL;
1935 exerror("operator %s %s %s not implemented", left, op,
1936 right ? right : "UNARY");
1937 free(right);
1938 } else
1939 exerror("operator %s %s not implemented", op, left);
1940 free(op);
1941 free(left);
1942 return exzero(exnode->type);
1943}
1944
1945/*
1946 * evaluate expression expr
1947 */
1948
1949Extype_t exeval(Expr_t *ex, Exnode_t *exnode, void *env) {
1950 Extype_t v = eval(ex, exnode, env);
1951 if (ex->loopcount > 0)
1952 {
1953 ex->loopcount = 0;
1954 if (ex->loopop == RETURN)
1955 return ex->loopret;
1956 }
1957 return v;
1958}
1959
1960/* exstring:
1961 * Generate copy of input string using
1962 * string memory.
1963 */
1964char *exstring(Expr_t * ex, char *s)
1965{
1966 return gv_arena_strdup(&ex->ve, s);
1967}
1968
1969/* exstralloc:
1970 * allocate sz bytes in expression memory.
1971 */
1972void *exstralloc(Expr_t * ex, size_t sz)
1973{
1974 return gv_arena_alloc(&ex->ve, 1, sz);
1975}
Agobj_t * copy(Agraph_t *g, Agobj_t *obj)
Definition actions.c:147
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:1550
#define left
Definition dthdr.h:12
void exwarn(const char *format,...)
Definition exerror.c:81
void exerror(const char *format,...)
Definition exerror.c:64
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:981
static char * str_add(Expr_t *ex, char *l, char *r)
Definition exeval.c:556
static Extype_t exsub(Expr_t *ex, Exnode_t *exnode, void *env, bool global)
Definition exeval.c:867
static char * str_xor(Expr_t *ex, const char *l, const char *r)
Definition exeval.c:642
char * exstring(Expr_t *ex, char *s)
Definition exeval.c:1964
static char * str_and(Expr_t *ex, const char *l, const char *r)
Definition exeval.c:611
static Extype_t eval(Expr_t *, Exnode_t *, void *)
Definition exeval.c:1012
Extype_t exeval(Expr_t *ex, Exnode_t *exnode, void *env)
Definition exeval.c:1949
static char * str_mpy(Expr_t *ex, const char *l, const char *r)
Definition exeval.c:716
static Extype_t exsplit(Expr_t *ex, Exnode_t *exnode, void *env)
Definition exeval.c:783
static void xPrint(Expr_t *ex, Exnode_t *exnode, Extype_t v, Exnode_t *tmp)
Definition exeval.c:997
static void addItem(Expr_t *ex, Dt_t *arr, Extype_t v, char *tok)
Definition exeval.c:768
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:950
#define FRAME
Definition exeval.c:51
static void replace(agxbuf *s, char *base, char *repl, int ng, size_t *sub)
Definition exeval.c:746
static char * str_mod(Expr_t *ex, const char *l, const char *r)
Definition exeval.c:685
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:568
static Extype_t extokens(Expr_t *ex, Exnode_t *exnode, void *env)
Definition exeval.c:831
void * exstralloc(Expr_t *ex, size_t sz)
Definition exeval.c:1972
static long seed
Definition exeval.c:1010
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:281
#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:148
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:150
Definition expr.h:212
arena_t vm
Definition expr.h:216
FILE * file[10]
Definition expr.h:215
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: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