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