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