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