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