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