Graphviz 12.0.1~dev.20240716.0800
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 <cgraph/alloc.h>
19#include <cgraph/agxbuf.h>
20#include <cgraph/strview.h>
21#include <cgraph/exit.h>
22#include <cgraph/gv_ctype.h>
23#include <cgraph/unreachable.h>
24#include <expr/exlib.h>
25#include <expr/exop.h>
26#include <inttypes.h>
27#include <stdbool.h>
28#include <stdint.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <assert.h>
33#include <time.h>
34#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];
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 {
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 = calloc(1, sizeof(Exassoc_t))))
128 exnospace();
129 b->key = v;
130 dtinsert(exnode->data.variable.symbol->local, b);
131 }
132 } else {
133 const long type = exnode->data.variable.index->type;
134 if (type != STRING) {
135 if (!BUILTIN(type)) {
136 key = ex->disc->keyf(v, type);
137 } else
138 key.integer = v.integer;
139 snprintf(buf, sizeof(buf), "%llx", (unsigned long long)key.integer);
140 keyname = buf;
141 } else
142 keyname = v.string;
143 if (!(b = dtmatch(exnode->data.variable.symbol->local, keyname)))
144 {
145 if (!(b = calloc(1, sizeof(Exassoc_t) + strlen(keyname))))
146 exnospace();
147 strcpy(b->name, keyname);
148 b->key = v;
149 dtinsert(exnode->data.variable.symbol->local, b);
150 }
151 }
152 *assoc = b;
153 if (b)
154 {
155 if (exnode->data.variable.symbol->type == STRING && !b->value.string)
156 b->value = exzero(exnode->data.variable.symbol->type);
157 return b->value;
158 }
159 v = exzero(exnode->data.variable.symbol->type);
160 return v;
161 }
162 *assoc = 0;
163 return exnode->data.variable.symbol->value->data.constant.value;
164}
165
175
176/*
177 * printf %! extension function
178 */
179
180static int
181prformat(void* vp, Sffmt_t* dp)
182{
183 Fmt_t* fmt = (Fmt_t*)dp;
184 Exnode_t* node;
185 char* s;
186 long to = 0;
187 time_t tm;
188 struct tm *stm;
189
190 dp->flags |= SFFMT_VALUE;
191 if (fmt->args)
192 {
193 if ((node = dp->fmt == '*' ? fmt->args->param[dp->size] : fmt->args->arg))
194 fmt->value = exeval(fmt->expr, node, fmt->env);
195 else
196 fmt->value.integer = 0;
197 to = fmt->args->arg->type;
198 }
199 else if (!(fmt->actuals = fmt->actuals->data.operand.right))
200 exerror("printf: not enough arguments");
201 else
202 {
203 node = fmt->actuals->data.operand.left;
204 const long from = node->type;
205 switch (dp->fmt)
206 {
207 case 'f':
208 case 'g':
209 to = FLOATING;
210 break;
211 case 's':
212 to = STRING;
213 break;
214 default:
215 switch (from)
216 {
217 case INTEGER:
218 case UNSIGNED:
219 to = from;
220 break;
221 default:
222 to = INTEGER;
223 break;
224 }
225 break;
226 }
227 if (to == from)
228 fmt->value = exeval(fmt->expr, node, fmt->env);
229 else
230 {
231 node = excast(fmt->expr, node, to, NULL, 0);
232 fmt->value = exeval(fmt->expr, node, fmt->env);
233 node->data.operand.left = 0;
234 vmfree(fmt->expr->vm, node);
235 if (to == STRING)
236 {
237 if (fmt->value.string)
238 {
239 char *const copy = vmstrdup(fmt->expr->vm, fmt->value.string);
240 if (copy == NULL) {
241 exerror("printf: out of memory");
242 }
243 vmfree(fmt->expr->vm, fmt->value.string);
244 fmt->value.string = copy;
245 }
246 if (!fmt->value.string)
247 fmt->value.string = "";
248 }
249 }
250 }
251 switch (to)
252 {
253 case STRING:
254 *(char**)vp = fmt->value.string;
255 fmt->fmt.size = -1;
256 break;
257 case FLOATING:
258 *(double*)vp = fmt->value.floating;
259 fmt->fmt.size = sizeof(double);
260 break;
261 default:
262 *(long long *)vp = fmt->value.integer;
263 dp->size = sizeof(long long);
264 break;
265 }
266 strview_t txt = {0};
267 if (dp->n_str > 0)
268 {
269 txt = (strview_t){.data = dp->t_str, .size = (size_t)dp->n_str};
270 }
271 switch (dp->fmt)
272 {
273 case 'q':
274 case 'Q': {
275 s = *(char**)vp;
276 char *quoted = fmtquote(s, "$'", "'");
277 *(char**)vp = vmstrdup(fmt->expr->vm, quoted);
278 free(quoted);
279 if (*(char**)vp == NULL) {
280 exerror("printf: out of memory");
281 }
282 dp->fmt = 's';
283 dp->size = -1;
284 break;
285 }
286 case 'S':
287 dp->flags &= ~SFFMT_LONG;
288 s = *(char**)vp;
289 if (txt.data != NULL)
290 {
291 if (strview_str_eq(txt, "identifier"))
292 {
293 if (*s && !gv_isalpha(*s))
294 *s++ = '_';
295 for (; *s; s++)
296 if (!gv_isalnum(*s))
297 *s = '_';
298 }
299 else if (strview_str_eq(txt, "invert"))
300 {
301 for (; *s; s++)
302 if (gv_isupper(*s))
303 *s = (char)tolower(*s);
304 else if (gv_islower(*s))
305 *s = (char)toupper(*s);
306 }
307 else if (strview_str_eq(txt, "lower"))
308 {
310 }
311 else if (strview_str_eq(txt, "upper"))
312 {
314 }
315 else if (strview_str_eq(txt, "variable"))
316 {
317 for (; *s; s++)
318 if (!gv_isalnum(*s) && *s != '_')
319 *s = '.';
320 }
321 }
322 dp->fmt = 's';
323 dp->size = -1;
324 break;
325 case 't':
326 case 'T':
327 if ((tm = *(long long *)vp) == -1)
328 tm = time(NULL);
329 if (txt.data == NULL) {
330 exerror("printf: no time format provided");
331 } else {
332 s = vmalloc(fmt->expr->vm, TIME_LEN);
333 stm = localtime(&tm);
334 char *format = malloc(sizeof(char) * (txt.size + 1));
335 if (s == NULL || format == NULL) {
336 vmfree(fmt->expr->vm, s);
337 exerror("printf: out of memory");
338 } else {
339 strncpy(format, txt.data, txt.size);
340 format[txt.size] = '\0';
341 strftime(s, TIME_LEN, format, stm);
342 *(char **)vp = s;
343 }
344 free(format);
345 }
346 dp->fmt = 's';
347 dp->size = -1;
348 break;
349 }
350 return 0;
351}
352
353/*
354 * print a list of strings
355 */
356static int prints(Expr_t *ex, Exnode_t *exnode, void *env, FILE *sp) {
357 Extype_t v;
358 Exnode_t *args;
359
360 args = exnode->data.operand.left;
361 while (args) {
362 v = eval(ex, args->data.operand.left, env);
363 fputs(v.string, sp);
364 args = args->data.operand.right;
365 }
366 putc('\n', sp);
367 return 0;
368}
369
370/*
371 * do printf
372 */
373static int print(Expr_t *ex, Exnode_t *exnode, void *env, FILE *sp) {
374 Print_t* x;
375 Extype_t v;
376 Fmt_t fmt;
377
378 if (!sp)
379 {
380 v = eval(ex, exnode->data.print.descriptor, env);
381 if (v.integer < 0 || v.integer >= (long long)elementsof(ex->file) ||
382 (!(sp = ex->file[v.integer]) &&
383 !(sp = ex->file[v.integer] = tmpfile())))
384 {
385 exerror("printf: %lld: invalid descriptor", v.integer);
386 return -1;
387 }
388 }
389 memset(&fmt, 0, sizeof(fmt));
390 fmt.fmt.extf = prformat;
391 fmt.expr = ex;
392 fmt.env = env;
393 x = exnode->data.print.args;
394 if (x->format)
395 do
396 {
397 if (x->arg)
398 {
399 fmt.fmt.form = x->format;
400 fmt.args = x;
401 sfprint(sp, &fmt.fmt);
402 }
403 else
404 fputs(x->format, sp);
405 } while ((x = x->next));
406 else
407 {
408 v = eval(ex, x->arg->data.operand.left, env);
409 fmt.fmt.form = v.string;
410 fmt.actuals = x->arg;
411 sfprint(sp, &fmt.fmt);
412 if (fmt.actuals->data.operand.right)
413 exerror("(s)printf: \"%s\": too many arguments", fmt.fmt.form);
414 }
415 return 0;
416}
417
418/*
419 * scanf %! extension function
420 */
421
422static int
423scformat(void* vp, Sffmt_t* dp)
424{
425 Fmt_t* fmt = (Fmt_t*)dp;
426 Exnode_t* node;
427
428 if (!fmt->actuals)
429 {
430 exerror("scanf: not enough arguments");
431 return -1;
432 }
433 node = fmt->actuals->data.operand.left;
434 switch (dp->fmt)
435 {
436 case 'f':
437 case 'g':
438 if (node->type != FLOATING)
439 {
440 exerror("scanf: %s: floating variable address argument expected", node->data.variable.symbol->name);
441 return -1;
442 }
443 fmt->fmt.size = sizeof(double);
444 *(void**)vp = &node->data.variable.symbol->value->data.constant.value;
445 break;
446 case 's':
447 case '[': {
448 if (node->type != STRING)
449 {
450 exerror("scanf: %s: string variable address argument expected", node->data.variable.symbol->name);
451 return -1;
452 }
453 if (node->data.variable.symbol->value->data.constant.value.string == expr.nullstring)
454 node->data.variable.symbol->value->data.constant.value.string = 0;
455 fmt->fmt.size = 1024;
456 char *s = node->data.variable.symbol->value->data.constant.value.string;
457 vmfree(fmt->expr->vm, s);
458 s = vmalloc(fmt->expr->vm, sizeof(char) * (size_t)fmt->fmt.size);
459 memset(s, 0, sizeof(char) * (size_t)fmt->fmt.size);
460 *(void**)vp = s;
461 node->data.variable.symbol->value->data.constant.value.string = s;
462 break;
463 }
464 case 'c':
465 if (node->type != CHARACTER) {
466 exerror("scanf: %s: char variable address argument expected", node->data.variable.symbol->name);
467 return -1;
468 }
469 fmt->fmt.size = sizeof(long long);
470 *((void **) vp) = &node->data.variable.symbol->value->data.constant.value;
471 break;
472 default:
473 if (node->type != INTEGER && node->type != UNSIGNED)
474 {
475 exerror("scanf: %s: integer variable address argument expected", node->data.variable.symbol->name);
476 return -1;
477 }
478 dp->size = sizeof(long long);
479 *(void**)vp = &node->data.variable.symbol->value->data.constant.value;
480 break;
481 }
482 fmt->actuals = fmt->actuals->data.operand.right;
483 dp->flags |= SFFMT_VALUE;
484 return 0;
485}
486
487/*
488 * do scanf
489 */
490
491static int scan(Expr_t *ex, Exnode_t *exnode, void *env, FILE *sp) {
492 Extype_t v;
493 Extype_t u;
494 Fmt_t fmt;
495 int n;
496
497 if (!sp)
498 {
499 if (exnode->data.scan.descriptor)
500 {
501 v = eval(ex, exnode->data.scan.descriptor, env);
502 if (exnode->data.scan.descriptor->type == STRING)
503 goto get;
504 }
505 else
506 v.integer = 0;
507 if (v.integer < 0 || v.integer >= (long long)elementsof(ex->file) || (!(sp = ex->file[v.integer]) && !(sp = ex->file[v.integer] = tmpfile())))
508 {
509 exerror("scanf: %lld: invalid descriptor", v.integer);
510 return 0;
511 }
512 }
513 get:
514 memset(&fmt, 0, sizeof(fmt));
515 fmt.fmt.extf = scformat;
516 fmt.expr = ex;
517 fmt.env = env;
518 u = eval(ex, exnode->data.scan.format, env);
519 fmt.fmt.form = u.string;
520 fmt.actuals = exnode->data.scan.args;
521 if (sp == NULL) {
522 sp = tmpfile();
523 if (sp == NULL) {
524 exerror("scanf: failed to open temporary file");
525 return 0;
526 }
527 fputs(v.string, sp);
528 rewind(sp);
529 n = sfvscanf(sp, &fmt.fmt);
530 fclose(sp);
531 } else {
532 n = sfvscanf(sp, &fmt.fmt);
533 }
534 if (fmt.actuals && !*fmt.fmt.form)
535 exerror("scanf: %s: too many arguments", fmt.actuals->data.operand.left->data.variable.symbol->name);
536 return n;
537}
538
539/*
540 * string add
541 */
542
543static char*
544str_add(Expr_t* ex, char* l, char* r)
545{
546 size_t sz = strlen(l) + strlen(r) + 1;
547 char *s = vmalloc(ex->ve, sz);
548 if (s == NULL) {
549 return exnospace();
550 }
551 snprintf(s, sz, "%s%s", l, r);
552 return s;
553}
554
555/*
556 * string ior
557 */
558
559static char *str_ior(Expr_t *ex, const char *l, const char *r) {
560
561 // compute how much space the result will occupy
562 size_t len = 1; // 1 for NUL terminator
563 for (const char *p = l; *p != '\0'; ++p) {
564 if (strchr(p + 1, *p) == NULL) {
565 ++len;
566 }
567 }
568 for (const char *p = r; *p != '\0'; ++p) {
569 if (strchr(l, *p) == NULL && strchr(p + 1, *p) == NULL) {
570 ++len;
571 }
572 }
573
574 // allocate a buffer to store this
575 char *result = vmalloc(ex->ve, len);
576 if (result == NULL) {
577 return exnospace();
578 }
579
580 // write the result
581 size_t i = 0;
582 for (const char *p = l; *p != '\0'; ++p) {
583 if (strchr(p + 1, *p) == NULL) {
584 assert(i < len && "incorrect preceding length computation");
585 result[i] = *p;
586 ++i;
587 }
588 }
589 for (const char *p = r; *p != '\0'; ++p) {
590 if (strchr(l, *p) == NULL && strchr(p + 1, *p) == NULL) {
591 assert(i < len && "incorrect preceding length computation");
592 result[i] = *p;
593 ++i;
594 }
595 }
596 assert(i + 1 == len && "incorrect preceding length computation");
597 result[i] = '\0';
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 *result = vmalloc(ex->ve, len);
618 if (result == NULL) {
619 return exnospace();
620 }
621
622 // write the result
623 size_t i = 0;
624 for (const char *p = l; *p != '\0'; ++p) {
625 if (strchr(r, *p) != NULL && strchr(p + 1, *p) == NULL) {
626 assert(i < len && "incorrect preceding length computation");
627 result[i] = *p;
628 ++i;
629 }
630 }
631 assert(i + 1 == len && "incorrect preceding length computation");
632 result[i] = '\0';
633
634 return result;
635}
636
637/*
638 * string xor
639 */
640
641static char *str_xor(Expr_t *ex, const char *l, const char *r) {
642
643 // compute how much space the result will occupy
644 size_t len = 1; // 1 for NUL terminator
645 for (const char *p = l; *p != '\0'; ++p) {
646 if (strchr(r, *p) == NULL && strchr(p + 1, *p) == NULL) {
647 ++len;
648 }
649 }
650 for (const char *p = r; *p != '\0'; ++p) {
651 if (strchr(l, *p) == NULL && strchr(p + 1, *p) == NULL) {
652 ++len;
653 }
654 }
655
656 // allocate a buffer to store this
657 char *result = vmalloc(ex->ve, len);
658 if (result == NULL) {
659 return exnospace();
660 }
661
662 // write the result
663 size_t i = 0;
664 for (const char *p = l; *p != '\0'; ++p) {
665 if (strchr(r, *p) == NULL && strchr(p + 1, *p) == NULL) {
666 assert(i < len && "incorrect preceding length computation");
667 result[i] = *p;
668 ++i;
669 }
670 }
671 for (const char *p = r; *p != '\0'; ++p) {
672 if (strchr(l, *p) == NULL && strchr(p + 1, *p) == NULL) {
673 assert(i < len && "incorrect preceding length computation");
674 result[i] = *p;
675 ++i;
676 }
677 }
678 assert(i + 1 == len && "incorrect preceding length computation");
679 result[i] = '\0';
680
681 return result;
682}
683
684/*
685 * string mod
686 */
687
688static char *str_mod(Expr_t *ex, const char *l, const char *r) {
689
690 // compute how much space the result will occupy
691 size_t len = 1; // 1 for NUL terminator
692 for (const char *p = l; *p != '\0'; ++p) {
693 if (strchr(r, *p) == NULL && strchr(p + 1, *p) == NULL) {
694 ++len;
695 }
696 }
697
698 // allocate a buffer to store this
699 char *result = vmalloc(ex->ve, len);
700 if (result == NULL) {
701 return exnospace();
702 }
703
704 // write the result
705 size_t i = 0;
706 for (const char *p = l; *p != '\0'; ++p) {
707 if (strchr(r, *p) == NULL && strchr(p + 1, *p) == NULL) {
708 assert(i < len && "incorrect preceding length computation");
709 result[i] = *p;
710 ++i;
711 }
712 }
713 assert(i + 1 == len && "incorrect preceding length computation");
714 result[i] = '\0';
715
716 return result;
717}
718
719/*
720 * string mpy
721 */
722
723static char *str_mpy(Expr_t *ex, const char *l, const char *r) {
724
725 // compute how much space the result will occupy
726 size_t len = strlen(l);
727 {
728 size_t len2 = strlen(r);
729 if (len2 < len) {
730 len = len2;
731 }
732 }
733 ++len; // 1 for NUL terminator
734
735 // allocate a buffer to store this
736 char *result = vmalloc(ex->ve, len);
737 if (result == NULL) {
738 return exnospace();
739 }
740
741 // write the result
742 size_t i = 0;
743 for (; l[i] != '\0' && r[i] != '\0'; ++i) {
744 assert(i < len && "incorrect preceding length computation");
745 result[i] = l[i] == r[i] ? l[i] : ' ';
746 }
747 assert(i + 1 == len && "incorrect preceding length computation");
748 result[i] = '\0';
749
750 return result;
751}
752
753/* replace:
754 * Add replacement string.
755 * \digit is replaced with a subgroup match, if any.
756 */
757static void replace(agxbuf *s, char *base, char *repl, int ng, size_t *sub) {
758 char c;
759 int idx;
760
761 while ((c = *repl++)) {
762 if (c == '\\') {
763 if ((c = *repl) && gv_isdigit(c)) {
764 idx = c - '0';
765 if (idx < ng) {
766 const size_t offset = sub[2 * idx];
767 agxbput_n(s, base + offset, sub[2 * idx + 1] - offset);
768 }
769 repl++;
770 } else {
771 agxbputc(s, '\\');
772 }
773 } else {
774 agxbputc(s, c);
775 }
776 }
777}
778
779static void
780addItem (Dt_t* arr, Extype_t v, char* tok)
781{
782 Exassoc_t* b;
783
784 if (!(b = dtmatch(arr, &v))) {
785 if (!(b = calloc(1, sizeof(Exassoc_t))))
786 exerror("out of space [assoc]");
787 b->key = v;
788 dtinsert(arr, b);
789 }
790 b->value.string = tok;
791}
792
793/* exsplit:
794 * break string into possibly empty fields and store in array
795 * return number of fields
796 */
797static Extype_t exsplit(Expr_t *ex, Exnode_t *exnode, void *env) {
798 Extype_t v;
799 char *str;
800 char *seps;
801 char *tok;
802 size_t sz;
803 Dt_t* arr = exnode->data.split.array->local;
804
805 str = eval(ex, exnode->data.split.string, env).string;
806 if (exnode->data.split.seps)
807 seps = eval(ex, exnode->data.split.seps, env).string;
808 else
809 seps = " \t\n";
810
811 v.integer = 0;
812 while (*str) {
813 sz = strspn (str, seps);
814 if (sz) {
815 if (v.integer == 0) { /* initial separator => empty field */
816 addItem (arr, v, "");
817 v.integer++;
818 }
819 for (size_t i = 1; i < sz; i++) {
820 addItem (arr, v, "");
821 v.integer++;
822 }
823 }
824 str += sz;
825 if (*str == '\0') { /* terminal separator => empty field */
826 addItem (arr, v, "");
827 v.integer++;
828 break;
829 }
830 sz = strcspn (str, seps);
831 tok = vmalloc(ex->vm, sz + 1);
832 if (tok == NULL) {
833 tok = exnospace();
834 } else {
835 memcpy(tok, str, sz);
836 tok[sz] = '\0';
837 }
838 addItem (arr, v, tok);
839 v.integer++;
840 str += sz;
841 }
842
843 return v;
844}
845
846/* extoken:
847 * tokenize string and store in array
848 * return number of tokens
849 */
850static Extype_t extokens(Expr_t *ex, Exnode_t *exnode, void *env) {
851 Extype_t v;
852 char *str;
853 char *seps;
854 char *tok;
855 size_t sz;
856 Dt_t* arr = exnode->data.split.array->local;
857
858 str = eval(ex, exnode->data.split.string, env).string;
859 if (exnode->data.split.seps)
860 seps = eval(ex, exnode->data.split.seps, env).string;
861 else
862 seps = " \t\n";
863
864 v.integer = 0;
865 while (*str) {
866 sz = strspn (str, seps);
867 str += sz;
868 if (*str == '\0')
869 break;
870
871 sz = strcspn (str, seps);
872 assert (sz);
873 tok = vmalloc(ex->vm, sz + 1);
874 if (tok == NULL) {
875 tok = exnospace();
876 } else {
877 memcpy(tok, str, sz);
878 tok[sz] = '\0';
879 }
880 addItem (arr, v, tok);
881 v.integer++;
882 str += sz;
883 }
884
885 return v;
886}
887
888/* exsub:
889 * return string after pattern substitution
890 */
891static Extype_t exsub(Expr_t *ex, Exnode_t *exnode, void *env, bool global) {
892 char *str;
893 char *pat;
894 char *repl;
895 char *p;
896 char *s;
897 Extype_t v;
898 size_t sub[20];
899 int flags = 0;
900 int ng;
901
902 str = eval(ex, exnode->data.string.base, env).string;
903 pat = eval(ex, exnode->data.string.pat, env).string;
904 if (exnode->data.string.repl)
905 repl = eval(ex, exnode->data.string.repl, env).string;
906 else
907 repl = 0;
908
909 if (!global) {
910 if (*pat == '^') {
911 pat++;
912 flags |= STR_LEFT;
913 }
914 p = pat;
915 while (*p)
916 p++;
917 if (p > pat)
918 p--;
919 if (*p == '$') {
920 if (p > pat && p[-1] == '\\') {
921 *p-- = '\0';
922 *p = '$';
923 } else {
924 flags |= STR_RIGHT;
925 *p = '\0';
926 }
927 }
928 }
929 if (*pat == '\0') {
930 v.string = vmstrdup(ex->ve, str);
931 return v;
932 }
933
934 ng = strgrpmatch(str, pat, sub, sizeof(sub) / (sizeof(sub[0]) * 2), flags);
935 if (ng == 0) {
936 v.string = vmstrdup(ex->ve, str);
937 return v;
938 }
939 if (sub[0] == sub[1]) {
940 exwarn("pattern match of empty string - ill-specified pattern \"%s\"?", pat);
941 v.string = vmstrdup(ex->ve, str);
942 return v;
943 }
944
945 agxbuf buffer = {0};
946
947 agxbput_n(&buffer, str, sub[0]);
948
949 if (repl) {
950 replace(&buffer, str, repl, ng, sub);
951 }
952
953 s = str + sub[1];
954 if (global) {
955 while ((ng = strgrpmatch(s, pat, sub, sizeof(sub) / (sizeof(sub[0]) * 2), flags))) {
956 agxbput_n(&buffer, s, sub[0]);
957 if (repl) {
958 replace(&buffer, s, repl, ng, sub);
959 }
960 s = s + sub[1];
961 }
962 }
963
964 agxbput(&buffer, s);
965
966 v.string = vmstrdup(ex->ve, agxbuse(&buffer));
967 agxbfree(&buffer);
968 return v;
969}
970
971/* exsubstr:
972 * return substring.
973 */
974static Extype_t exsubstr(Expr_t *ex, Exnode_t *exnode, void *env) {
975 Extype_t s;
976 Extype_t i;
977 Extype_t l;
978 Extype_t v;
979 int len;
980
981 s = eval(ex, exnode->data.string.base, env);
982 len = strlen(s.string);
983 i = eval(ex, exnode->data.string.pat, env);
984 if (i.integer < 0 || len < i.integer)
985 exerror("illegal start index in substr(%s,%lld)", s.string, i.integer);
986 if (exnode->data.string.repl) {
987 l = eval(ex, exnode->data.string.repl, env);
988 if (l.integer < 0 || len - i.integer < l.integer)
989 exerror("illegal length in substr(%s,%lld,%lld)",
990 s.string, i.integer, l.integer);
991 } else
992 l.integer = len - i.integer;
993
994 v.string = vmalloc(ex->ve, l.integer + 1);
995 if (exnode->data.string.repl) {
996 strncpy(v.string, s.string + i.integer, l.integer);
997 v.string[l.integer] = '\0';
998 } else
999 strcpy(v.string, s.string + i.integer);
1000 return v;
1001}
1002
1003/* xConvert:
1004 * Convert from external type.
1005 */
1006static void xConvert(Expr_t *ex, Exnode_t *exnode, long type, Extype_t v,
1007 Exnode_t * tmp)
1008{
1009 *tmp = *exnode->data.operand.left;
1010 tmp->data.constant.value = v;
1011 if (ex->disc->convertf(tmp, type, 0)) {
1012 exerror("%s: cannot convert %s value to %s",
1014 extypename(ex, exnode->data.operand.left->type), extypename(ex, type));
1015 }
1016 tmp->type = type;
1017}
1018
1019/* xPrint:
1020 * Generate string representation from value of external type.
1021 */
1022static void xPrint(Expr_t *ex, Exnode_t *exnode, Extype_t v, Exnode_t *tmp) {
1023 *tmp = *exnode->data.operand.left;
1024 tmp->data.constant.value = v;
1025 if (ex->disc->stringof(ex, tmp, 0))
1026 exerror("%s: no string representation of %s value",
1028 extypename(ex, exnode->data.operand.left->type));
1029 tmp->type = STRING;
1030}
1031
1032/*
1033 * internal exeval
1034 */
1035static long seed;
1036
1037static Extype_t eval(Expr_t *ex, Exnode_t *exnode, void *env) {
1038 Exnode_t* x;
1039 Exnode_t* a;
1040 Extype_t** t;
1041 int n;
1042 Extype_t v;
1043 Extype_t r = {0};
1044 Extype_t i;
1045 char* e;
1046 Exnode_t tmp;
1047 Exnode_t rtmp;
1048 Exnode_t* rp;
1049 Exassoc_t* assoc;
1050 Extype_t args[FRAME+1];
1051 Extype_t save[FRAME];
1052
1053 if (!exnode || ex->loopcount)
1054 {
1055 v.integer = 1;
1056 return v;
1057 }
1058 x = exnode->data.operand.left;
1059 switch (exnode->op)
1060 {
1061 case BREAK:
1062 case CONTINUE:
1063 v = eval(ex, x, env);
1064 ex->loopcount = v.integer;
1065 ex->loopop = exnode->op;
1066 return v;
1067 case CONSTANT:
1068 return exnode->data.constant.value;
1069 case DEC:
1070 n = -1;
1071 add:
1072 if (x->op == DYNAMIC)
1073 r = getdyn(ex, x, env, &assoc);
1074 else
1075 {
1076 if (x->data.variable.index)
1077 i = eval(ex, x->data.variable.index, env);
1078 else
1079 i.integer = EX_SCALAR;
1080 if (x->data.variable.dyna) {
1081 Extype_t locv;
1082 locv = getdyn(ex, x->data.variable.dyna, env, &assoc);
1084 }
1085 r = ex->disc->getf(ex, x, x->data.variable.symbol,
1086 x->data.variable.reference, env, (int)i.integer,
1087 ex->disc);
1088 }
1089 v = r;
1090 switch (x->type)
1091 {
1092 case FLOATING:
1093 v.floating += n;
1094 break;
1095 case INTEGER:
1096 case UNSIGNED:
1097 v.integer += n;
1098 break;
1099 default:
1100 goto huh;
1101 }
1102 set:
1103 if (x->op == DYNAMIC)
1104 {
1105 if (x->type == STRING)
1106 {
1107 v.string = vmstrdup(ex->vm, v.string);
1108 if ((e = assoc ? assoc->value.string : x->data.variable.symbol->value->data.constant.value.string))
1109 vmfree(ex->vm, e);
1110 }
1111 if (assoc)
1112 assoc->value = v;
1113 else
1115 }
1116 else
1117 {
1118 if (x->data.variable.index)
1119 i = eval(ex, x->data.variable.index, env);
1120 else
1121 i.integer = EX_SCALAR;
1122 if (x->data.variable.dyna) {
1123 Extype_t locv;
1124 locv = getdyn(ex, x->data.variable.dyna, env, &assoc);
1126 }
1127 if (ex->disc->setf(ex, x, x->data.variable.symbol,
1128 x->data.variable.reference, env, v) < 0)
1129 exerror("%s: cannot set value", x->data.variable.symbol->name);
1130 }
1131 if (exnode->subop == PRE)
1132 r = v;
1133 return r;
1134 case DYNAMIC:
1135 return getdyn(ex, exnode, env, &assoc);
1136 case SPLIT:
1137 return exsplit(ex, exnode, env);
1138 case TOKENS:
1139 return extokens(ex, exnode, env);
1140 case GSUB:
1141 return exsub(ex, exnode, env, /* global = */ true);
1142 case SUB:
1143 return exsub(ex, exnode, env, /* global = */ false);
1144 case SUBSTR:
1145 return exsubstr(ex, exnode, env);
1146 case SRAND:
1147 v.integer = seed;
1148 if (exnode->binary) {
1149 seed = (long)eval(ex, x, env).integer;
1150 } else
1151 seed = (long)time(0);
1152 srand48(seed);
1153 return v;
1154 case RAND:
1155 v.floating = drand48();
1156 return v;
1157 case EXIT:
1158 v = eval(ex, x, env);
1159 if (ex->disc->exitf)
1160 ex->disc->exitf(ex, env, (int)v.integer);
1161 else
1162 graphviz_exit((int)v.integer);
1163 UNREACHABLE();
1164 case IF:
1165 v = eval(ex, x, env);
1166 if (v.integer)
1167 eval(ex, exnode->data.operand.right->data.operand.left, env);
1168 else
1169 eval(ex, exnode->data.operand.right->data.operand.right, env);
1170 v.integer = 1;
1171 return v;
1172 case FOR:
1173 case WHILE:
1174 exnode = exnode->data.operand.right;
1175 for (;;)
1176 {
1177 r = eval(ex, x, env);
1178 if (!r.integer)
1179 {
1180 v.integer = 1;
1181 return v;
1182 }
1183 if (exnode->data.operand.right)
1184 {
1185 eval(ex, exnode->data.operand.right, env);
1186 if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE))
1187 {
1188 v.integer = 0;
1189 return v;
1190 }
1191 }
1192 if (exnode->data.operand.left)
1193 eval(ex, exnode->data.operand.left, env);
1194 }
1195 /*NOTREACHED*/
1196 case SWITCH:
1197 v = eval(ex, x, env);
1198 i.integer = x->type;
1199 r.integer = 0;
1200 x = exnode->data.operand.right;
1201 a = x->data.select.statement;
1202 n = 0;
1203 while ((x = x->data.select.next))
1204 {
1205 if (!(t = x->data.select.constant))
1206 n = 1;
1207 else
1208 for (; *t; t++)
1209 {
1210 switch ((int)i.integer)
1211 {
1212 case INTEGER:
1213 case UNSIGNED:
1214 if ((*t)->integer == v.integer)
1215 break;
1216 continue;
1217 case STRING:
1218 if (strmatch((*t)->string, v.string))
1219 break;
1220 continue;
1221 case FLOATING:
1222 if ((*t)->floating == v.floating)
1223 break;
1224 continue;
1225 }
1226 n = 1;
1227 break;
1228 }
1229 if (n)
1230 {
1231 if (!x->data.select.statement)
1232 {
1233 r.integer = 1;
1234 break;
1235 }
1236 r = eval(ex, x->data.select.statement, env);
1237 if (ex->loopcount > 0)
1238 {
1239 ex->loopcount--;
1240 break;
1241 }
1242 }
1243 }
1244 if (!n && a)
1245 {
1246 r = eval(ex, a, env);
1247 if (ex->loopcount > 0)
1248 ex->loopcount--;
1249 }
1250 return r;
1251 case ITERATE:
1252 v.integer = 0;
1253 if (exnode->data.generate.array->op == DYNAMIC)
1254 {
1255 n = exnode->data.generate.index->type == STRING;
1256 for (assoc = dtfirst(exnode->data.generate.array->data.variable.symbol->local); assoc; assoc = dtnext(exnode->data.generate.array->data.variable.symbol->local, assoc))
1257 {
1258 v.integer++;
1259 if (n)
1260 exnode->data.generate.index->value->data.constant.value.string = assoc->name;
1261 else
1262 exnode->data.generate.index->value->data.constant.value = assoc->key;
1263 eval(ex, exnode->data.generate.statement, env);
1264 if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE))
1265 {
1266 v.integer = 0;
1267 break;
1268 }
1269 }
1270 }
1271 else
1272 {
1273 r = ex->disc->getf(ex, exnode, exnode->data.generate.array->data.variable.symbol,
1274 exnode->data.generate.array->data.variable.reference, env,
1275 0, ex->disc);
1276 for (v.integer = 0; v.integer < r.integer; v.integer++)
1277 {
1278 exnode->data.generate.index->value->data.constant.value.integer = v.integer;
1279 eval(ex, exnode->data.generate.statement, env);
1280 if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE))
1281 {
1282 v.integer = 0;
1283 break;
1284 }
1285 }
1286 }
1287 return v;
1288 case ITERATER:
1289 v.integer = 0;
1290 if (exnode->data.generate.array->op == DYNAMIC) {
1291 n = exnode->data.generate.index->type == STRING;
1292 for (assoc = dtlast(exnode->data.generate.array->
1293 data.variable.symbol->local); assoc;
1294 assoc = dtprev(exnode->data.generate.array->data.variable.symbol->local,
1295 assoc)) {
1296 v.integer++;
1297 if (n)
1298 exnode->data.generate.index->value->data.constant.value.string = assoc->name;
1299 else
1300 exnode->data.generate.index->value->data.constant.value = assoc->key;
1301 eval(ex, exnode->data.generate.statement, env);
1302 if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE)) {
1303 v.integer = 0;
1304 break;
1305 }
1306 }
1307 } else {
1308 r = ex->disc->getf(ex, exnode, exnode->data.generate.array->data.variable.symbol,
1309 exnode->data.generate.array->data.variable.reference, env,
1310 0, ex->disc);
1311 for (v.integer = r.integer-1; 0 <= v.integer; v.integer--) {
1312 exnode->data.generate.index->value->data.constant.value.integer = v.integer;
1313 eval(ex, exnode->data.generate.statement, env);
1314 if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE)) {
1315 v.integer = 0;
1316 break;
1317 }
1318 }
1319 }
1320 return v;
1321 case '#':
1322 v.integer = dtsize(exnode->data.variable.symbol->local);
1323 return v;
1324 case IN_OP:
1325 v.integer = evaldyn (ex, exnode, env, 0);
1326 return v;
1327 case UNSET:
1328 if (exnode->data.variable.index) {
1329 v.integer = evaldyn (ex, exnode, env, 1);
1330 }
1331 else {
1332 dtclear(exnode->data.variable.symbol->local);
1333 v.integer = 0;
1334 }
1335 return v;
1336 case CALL:
1337 x = exnode->data.call.args;
1338 for (n = 0, a = exnode->data.call.procedure->value->data.procedure.args; a && x; a = a->data.operand.right)
1339 {
1340 if (n < (int)elementsof(args))
1341 {
1343 args[n++] = eval(ex, x->data.operand.left, env);
1344 }
1345 else
1346 a->data.operand.left->data.variable.symbol->value->data.constant.value = eval(ex, x->data.operand.left, env);
1347 x = x->data.operand.right;
1348 }
1349 for (n = 0, a = exnode->data.call.procedure->value->data.procedure.args;
1350 a && n < (int)elementsof(save); a = a->data.operand.right)
1352 if (x)
1353 exerror("too many actual args");
1354 else if (a)
1355 exerror("not enough actual args");
1356 v = exeval(ex, exnode->data.call.procedure->value->data.procedure.body, env);
1357 for (n = 0, a = exnode->data.call.procedure->value->data.procedure.args;
1358 a && n < (int)elementsof(save); a = a->data.operand.right)
1360 return v;
1361 case ARRAY:
1362 n = 0;
1363 for (x = exnode->data.operand.right; x && n < (int)elementsof(args);
1364 x = x->data.operand.right)
1365 args[n++] = eval(ex, x->data.operand.left, env);
1366 return ex->disc->getf(ex, exnode->data.operand.left,
1368 exnode->data.operand.left->data.variable.reference, args,
1369 EX_ARRAY, ex->disc);
1370 case FUNCTION:
1371 n = 0;
1372 args[n++].string = env;
1373 for (x = exnode->data.operand.right; x && n < (int)elementsof(args);
1374 x = x->data.operand.right)
1375 args[n++] = eval(ex, x->data.operand.left, env);
1376 return ex->disc->getf(ex, exnode->data.operand.left,
1379 args+1, EX_CALL, ex->disc);
1380 case ID:
1381 if (exnode->data.variable.index)
1382 i = eval(ex, exnode->data.variable.index, env);
1383 else
1384 i.integer = EX_SCALAR;
1385 if (exnode->data.variable.dyna) {
1386 Extype_t locv;
1387 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:77
static size_t agxbput(agxbuf *xb, const char *s)
append string s into xb
Definition agxbuf.h:249
static size_t agxbput_n(agxbuf *xb, const char *s, size_t ssz)
append string s of length ssz into xb
Definition agxbuf.h:229
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:213
static int agxbputc(agxbuf *xb, char c)
add character to buffer
Definition agxbuf.h:256
static char * agxbuse(agxbuf *xb)
Definition agxbuf.h:286
static char * agxbdisown(agxbuf *xb)
Definition agxbuf.h:299
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:192
#define dtclear(d)
Definition cdt.h:196
CDT_API int dtsize(Dt_t *)
Definition dtsize.c:12
#define dtinsert(d, o)
Definition cdt.h:193
#define dtprev(d, o)
Definition cdt.h:190
#define dtlast(d)
Definition cdt.h:189
#define dtdelete(d, o)
Definition cdt.h:194
#define dtnext(d, o)
Definition cdt.h:188
#define dtfirst(d)
Definition cdt.h:187
#define right(i)
Definition closest.c:77
#define sub(h, i)
Definition closest.c:65
double drand48(void)
Definition utils.c:1570
#define left
Definition dthdr.h:12
static int global(void *object, void *handle)
Definition excc.c:650
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:356
static int scformat(void *vp, Sffmt_t *dp)
Definition exeval.c:423
#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:1006
static char * str_add(Expr_t *ex, char *l, char *r)
Definition exeval.c:544
static Extype_t exsub(Expr_t *ex, Exnode_t *exnode, void *env, bool global)
Definition exeval.c:891
static char * str_xor(Expr_t *ex, const char *l, const char *r)
Definition exeval.c:641
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:606
static Extype_t eval(Expr_t *, Exnode_t *, void *)
Definition exeval.c:1037
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:723
static Extype_t exsplit(Expr_t *ex, Exnode_t *exnode, void *env)
Definition exeval.c:797
static void xPrint(Expr_t *ex, Exnode_t *exnode, Extype_t v, Exnode_t *tmp)
Definition exeval.c:1022
static void addItem(Dt_t *arr, Extype_t v, char *tok)
Definition exeval.c:780
static int prformat(void *vp, Sffmt_t *dp)
Definition exeval.c:181
static Extype_t exsubstr(Expr_t *ex, Exnode_t *exnode, void *env)
Definition exeval.c:974
#define FRAME
Definition exeval.c:43
static void replace(agxbuf *s, char *base, char *repl, int ng, size_t *sub)
Definition exeval.c:757
static char * str_mod(Expr_t *ex, const char *l, const char *r)
Definition exeval.c:688
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:491
static int print(Expr_t *ex, Exnode_t *exnode, void *env, FILE *sp)
Definition exeval.c:373
static char * str_ior(Expr_t *ex, const char *l, const char *r)
Definition exeval.c:559
static Extype_t extokens(Expr_t *ex, Exnode_t *exnode, void *env)
Definition exeval.c:850
void * exstralloc(Expr_t *ex, size_t sz)
Definition exeval.c:2008
static long seed
Definition exeval.c:1035
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:3615
#define UNSIGNED
Definition exparse.c:237
#define CHARACTER
Definition exparse.c:238
#define DYNAMIC
Definition exparse.c:252
#define SCANF
Definition exparse.c:274
#define F2S
Definition exparse.c:286
#define SSCANF
Definition exparse.c:278
#define RSH
Definition exparse.c:307
#define OR
Definition exparse.c:300
#define PRE
Definition exparse.c:267
#define GE
Definition exparse.c:305
#define MINTOKEN
Definition exparse.c:235
#define ITERATER
Definition exparse.c:259
#define X2F
Definition exparse.c:295
#define S2X
Definition exparse.c:294
#define WHILE
Definition exparse.c:284
#define ITERATE
Definition exparse.c:258
#define MAXTOKEN
Definition exparse.c:313
#define NE
Definition exparse.c:303
#define SRAND
Definition exparse.c:277
#define S2I
Definition exparse.c:291
#define SUB
Definition exparse.c:279
#define LSH
Definition exparse.c:306
#define FLOATING
Definition exparse.c:239
#define FOR
Definition exparse.c:255
#define I2X
Definition exparse.c:293
#define IN_OP
Definition exparse.c:308
#define SUBSTR
Definition exparse.c:280
#define TOKENS
Definition exparse.c:282
#define RAND
Definition exparse.c:272
#define PRINT
Definition exparse.c:268
#define I2F
Definition exparse.c:287
#define SPRINTF
Definition exparse.c:276
#define I2S
Definition exparse.c:288
#define CONSTANT
Definition exparse.c:248
#define LE
Definition exparse.c:304
#define S2B
Definition exparse.c:289
#define CALL
Definition exparse.c:246
#define GSUB
Definition exparse.c:257
#define UNSET
Definition exparse.c:283
#define CONTINUE
Definition exparse.c:249
#define XPRINT
Definition exparse.c:299
#define F2I
Definition exparse.c:285
#define X2S
Definition exparse.c:297
#define EQ
Definition exparse.c:302
#define BREAK
Definition exparse.c:245
#define S2F
Definition exparse.c:290
#define IF
Definition exparse.c:261
#define SWITCH
Definition exparse.c:281
#define AND
Definition exparse.c:301
#define X2X
Definition exparse.c:298
#define EXIT
Definition exparse.c:254
#define F2X
Definition exparse.c:292
#define X2I
Definition exparse.c:296
#define PRINTF
Definition exparse.c:269
#define FUNCTION
Definition exparse.c:256
#define ARRAY
Definition exparse.c:244
#define INC
Definition exparse.c:310
#define DEC
Definition exparse.c:311
disc key
Definition exparse.y:214
expr procedure type
Definition exparse.y:211
Exnode_t * excast(Expr_t *, Exnode_t *, long, Exnode_t *, int)
static char * exprintf(Vmalloc_t *vm, const char *fmt,...)
Definition expr.h:271
#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:415
void * malloc(YYSIZE_T)
#define STRING
Definition gmlparse.c:414
#define INTEGER
Definition gmlparse.c:412
void free(void *)
node NULL
Definition grammar.y:149
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:5915
GVIO_API const char * format
Definition gvio.h:51
agxbuf * str
Definition htmlparse.c:97
#define SPLIT(x, n, s)
Definition htmltable.c:1273
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:65
int sfvscanf(FILE *, Sffmt_t *format)
Definition sfvscanf.c:68
#define RETURN(v)
Definition strmatch.c:144
char name[1]
Definition exlib.h:148
Extype_t key
Definition exlib.h:146
Extype_t value
Definition exlib.h:147
long index_type
Definition expr.h:98
long type
Definition expr.h:97
char name[EX_NAMELEN]
Definition expr.h:103
void * local
user defined local stuff
Definition expr.h:101
Exnode_t * value
Definition expr.h:100
long long(* integer)(char **)
INTEGER|UNSIGNED return value.
Definition expr.h:159
char *(* string)(char **)
Definition expr.h:160
int op
Definition expr.h:153
double(* floating)(char **)
Definition expr.h:158
long type
value type
Definition expr.h:152
union Exnode_s::@91 compiled
int binary
Definition expr.h:154
Exdata_t data
Definition expr.h:162
Definition expr.h:202
FILE * file[10]
Definition expr.h:205
Vmalloc_t * vm
Definition expr.h:206
char nullstring[1]
Definition exlib.h:164
Extype_t value
Definition exeval.c:172
Sffmt_t fmt
Definition exeval.c:168
Expr_t * expr
Definition exeval.c:169
Exnode_t * actuals
Definition exeval.c:173
void * env
Definition exeval.c:170
Print_t * args
Definition exeval.c:171
struct Exnode_s * param[3]
Definition exlib.h:48
char * format
Definition exlib.h:47
struct Exnode_s * arg
Definition exlib.h:49
struct Print_s * next
Definition exlib.h:46
Definition cdt.h:104
char * form
Definition sfio.h:37
ssize_t n_str
Definition sfio.h:47
int flags
Definition sfio.h:41
int fmt
Definition sfio.h:39
ssize_t size
Definition sfio.h:40
Sffmtext_f extf
Definition sfio.h:35
const char * t_str
Definition sfio.h:46
Definition legal.c:50
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:45
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:327
long long integer
Definition exparse.c:325
double floating
Definition exparse.c:322
struct Exdata_u::@87 constant
Exnode_t * left
Definition expr.h:124
Exnode_t * right
Definition expr.h:125
Exid_t * reference
Definition expr.h:119
Exnode_t * next
Definition expr.h:132
struct Exdata_u::@88 operand
Exnode_t * statement
Definition expr.h:131
Exid_t * symbol
Definition expr.h:138
Exnode_t * dyna
Definition expr.h:141
struct Exdata_u::@89 select
Extype_t value
Definition expr.h:118
Exnode_t * index
Definition expr.h:140
struct Exdata_u::@90 variable
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