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