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