Graphviz 13.0.0~dev.20250210.0415
Loading...
Searching...
No Matches
exgram.h
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#ifdef __cplusplus
12extern "C" {
13#endif
14
15
16/*
17 * grammar support routines
18 * stuffed in a header so exparse.y can work
19 * with both yacc and bison
20 */
21
22#if !defined(_EXGRAM_H) && ( defined(MINTOKEN) || defined(YYTOKENTYPE) )
23#define _EXGRAM_H
24
25#include <expr/exlib.h>
26#include <stdbool.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <util/agxbuf.h>
30#include <util/gv_ctype.h>
31
32#define ex_lex() extoken_fn(expr.program)
33
34#define ALLOCATE(p,x) exalloc(p,sizeof(x))
35
36static int a2t[] = { 0, FLOATING, INTEGER, STRING };
37
39
40static int T(long t) {
41 if (expr.program->disc->types)
42 return expr.program->disc->types[t & TMASK];
43 else
44 return a2t[t & TMASK];
45}
46
47/*
48 * allocate and initialize a new expression node in the current program
49 */
50
51Exnode_t *exnewnode(Expr_t *p, long op, bool binary, long type, Exnode_t *left,
52 Exnode_t *right) {
53 Exnode_t* x;
54
55 x = ALLOCATE(p, Exnode_t);
56 *x = (Exnode_t){0};
57 x->op = op;
58 x->type = type;
59 x->binary = binary;
60 x->data.operand.left = left;
62 return x;
63}
64
65/*
66 * free node x and its children
67 */
68
69void
71{
72 Print_t* pr;
73 Exref_t* r;
74 Print_t* pn;
75 Exref_t* rn;
76
77 switch (x->op)
78 {
79 case CALL:
80 if (x->data.call.args)
81 exfreenode(p, x->data.call.args);
82 break;
83 case CONSTANT:
84 break;
85 case DEFAULT:
86 if (x->data.select.next)
88 break;
89 case DYNAMIC:
90 if (x->data.variable.index)
92 if (x->data.variable.symbol->local)
93 {
96 }
97 break;
98 case '#':
99 if (x->data.variable.symbol->local) {
102 }
103 break;
104// case IN_OP:
105 case UNSET:
106 if (x->data.variable.index)
108 if (x->data.variable.symbol->local) {
111 }
112 break;
113 case ITERATE:
114 case ITERATOR:
115 if (x->data.generate.statement)
116 exfreenode(p, x->data.generate.statement);
117 break;
118 case ID:
119 rn = x->data.variable.reference;
120 while ((r = rn))
121 {
122 rn = r->next;
123 vmfree(p->vm, r);
124 }
125 if (x->data.variable.index)
127 break;
128 case GSUB:
129 case SUB:
130 case SUBSTR:
131 exfreenode(p, x->data.string.base);
132 exfreenode(p, x->data.string.pat);
133 if (x->data.string.repl)
134 exfreenode(p, x->data.string.repl);
135 break;
136 case TOKENS:
137 case SPLIT:
138 if (x->data.split.seps)
139 exfreenode(p, x->data.split.seps);
140 exfreenode(p, x->data.split.string);
141 if (x->data.split.array->local) {
142 dtclose(x->data.split.array->local);
143 x->data.split.array->local = NULL;
144 }
145 break;
146 case PRINT:
148 break;
149 case PRINTF:
150 case SPRINTF:
151 if (x->data.print.descriptor)
152 exfreenode(p, x->data.print.descriptor);
153 pn = x->data.print.args;
154 while ((pr = pn))
155 {
156 size_t i;
157 for (i = 0; i < elementsof(pr->param) && pr->param[i]; i++)
158 exfreenode(p, pr->param[i]);
159 if (pr->arg)
160 exfreenode(p, pr->arg);
161 pn = pr->next;
162 vmfree(p->vm, pr);
163 }
164 break;
165 case PROCEDURE:
166 if (x->data.procedure.args)
167 exfreenode(p, x->data.procedure.args);
168 if (x->data.procedure.body)
169 exfreenode(p, x->data.procedure.body);
170 break;
171 default:
172 if (x->data.operand.left)
174 if (x->data.operand.right)
176 break;
177 }
178 vmfree(p->vm, x);
179}
180
181/* extract:
182 * Given an argument list, extract first argument,
183 * check its type, reset argument list, and
184 * return first argument.
185 * Return 0 on failure.
186 */
187static Exnode_t *extract(Expr_t * p, Exnode_t ** argp, int type) {
188 Exnode_t *args = *argp;
189 Exnode_t *left;
190
191 if (!args || (type != args->data.operand.left->type))
192 return 0;
193 *argp = args->data.operand.right;
194 left = args->data.operand.left;
195 args->data.operand.left = args->data.operand.right = 0;
196 exfreenode(p, args);
197 return left;
198}
199
200/* exnewsplit:
201 * Generate split/tokens node.
202 * Fifth argument is optional.
203 */
204static Exnode_t *exnewsplit(Expr_t *p, long op, Exid_t *dyn, Exnode_t *s,
205 Exnode_t *seps) {
206 Exnode_t *ss = 0;
207
208 if (dyn->local == NULL)
209 exerror("cannot use non-array %s in %s", dyn->name, exopname(op));
210 if ((dyn->index_type > 0) && (dyn->index_type != INTEGER))
211 exerror("in %s, array %s must have integer index type, not %s",
212 exopname(op), dyn->name, extypename(p, s->type));
213 if (dyn->type != STRING)
214 exerror("in %s, array %s entries must have string type, not %s",
215 exopname(op), dyn->name, extypename(p, s->type));
216 if (s->type != STRING)
217 exerror("first argument to %s must have string type, not %s",
218 exopname(op), extypename(p, s->type));
219 if (seps && (seps->type != STRING))
220 exerror("third argument to %s must have string type, not %s",
221 exopname(op), extypename(p, seps->type));
222 ss = exnewnode(p, op, false, INTEGER, NULL, NULL);
223 ss->data.split.array = dyn;
224 ss->data.split.string = s;
225 ss->data.split.seps = seps;
226 return ss;
227}
228
229/* exnewsub:
230 * Generate sub node.
231 * Third argument is optional.
232 */
233static Exnode_t *exnewsub(Expr_t * p, Exnode_t * args, int op) {
234 Exnode_t *base;
235 Exnode_t *pat;
236 Exnode_t *repl;
237 Exnode_t *ss = 0;
238
239 base = extract(p, &args, STRING);
240 if (!base)
241 exerror("invalid first argument to sub operator");
242 pat = extract(p, &args, STRING);
243 if (!pat)
244 exerror("invalid second argument to sub operator");
245 if (args) {
246 repl = extract(p, &args, STRING);
247 if (!repl)
248 exerror("invalid third argument to sub operator");
249 } else
250 repl = 0;
251 if (args)
252 exerror("too many arguments to sub operator");
253 ss = exnewnode(p, op, false, STRING, NULL, NULL);
254 ss->data.string.base = base;
255 ss->data.string.pat = pat;
256 ss->data.string.repl = repl;
257 return ss;
258}
259
260/* exnewsubstr:
261 * Generate substr node.
262 */
263static Exnode_t *exnewsubstr(Expr_t * p, Exnode_t * args) {
264 Exnode_t *base;
265 Exnode_t *pat;
266 Exnode_t *repl;
267 Exnode_t *ss = 0;
268
269 base = extract(p, &args, STRING);
270 if (!base)
271 exerror("invalid first argument to substr operator");
272 pat = extract(p, &args, INTEGER);
273 if (!pat)
274 exerror("invalid second argument to substr operator");
275 if (args) {
276 repl = extract(p, &args, INTEGER);
277 if (!repl)
278 exerror("invalid third argument to substr operator");
279 } else
280 repl = 0;
281 if (args)
282 exerror("too many arguments to substr operator");
283 ss = exnewnode(p, SUBSTR, false, STRING, NULL, NULL);
284 ss->data.string.base = base;
285 ss->data.string.pat = pat;
286 ss->data.string.repl = repl;
287 return ss;
288}
289
290/*
291 * cast x to type
292 */
293
294static char* typename[] =
295{
296 "external", "integer", "unsigned", "char", "float", "string"
297};
298
299static int typecast[6][6] =
300{
301 {X2X, X2I, X2I, X2I, X2F, X2S},
302 {I2X, 0, 0, 0, I2F, I2S},
303 {I2X, 0, 0, 0, I2F, I2S},
304 {I2X, 0, 0, 0, I2F, I2S},
305 {F2X, F2I, F2I, F2I, 0, F2S},
306 {S2X, S2I, S2I, S2I, S2F, 0},
307};
308
309#define TYPEINDEX(t) (((t)>=INTEGER&&(t)<=STRING)?((t)-INTEGER+1):0)
310#define TYPENAME(t) typename[TYPEINDEX(t)]
311#define TYPECAST(f,t) typecast[TYPEINDEX(f)][TYPEINDEX(t)]
312
313#define EXTERNAL(t) ((t)>=F2X)
314
315char *extypename(Expr_t *p, long type) {
316 if (BUILTIN(type))
317 return TYPENAME(type);
318 return p->disc->typename(type);
319}
320
321/* exstringOf:
322 * Cast x to type STRING
323 * Assume x->type != STRING
324 */
325static Exnode_t *exstringOf(Expr_t * p, Exnode_t * x) {
326 const long type = x->type;
327 int cvt = 0;
328
329 if (!type) {
330 x->type = STRING;
331 return x;
332 }
333 if (!BUILTIN(type) && !p->disc->stringof)
334 exerror("cannot convert %s to STRING", extypename(p, type));
335 if (x->op != CONSTANT) {
336 if (!BUILTIN(type)) {
337 if (p->disc->stringof(p, x, 1) < 0) {
338 exerror("cannot convert %s to STRING",
339 extypename(p, type));
340 }
341 cvt = XPRINT;
342 } else if (TYPEINDEX(type) != 0) {
343 cvt = TYPECAST(type, STRING);
344 }
345 x = exnewnode(p, cvt, false, STRING, x, 0);
346 } else if (!BUILTIN(type)) {
347 if (p->disc->stringof(p, x, 0) < 0)
348 exerror("cannot convert constant %s to STRING",
349 extypename(p, x->type));
350 } else
351 switch (type) {
352 case FLOATING:
354 exprintf(p->vm, "%g", x->data.constant.value.floating);
355 break;
356 case INTEGER:
358 exprintf(p->vm, "%lld", x->data.constant.value.integer);
359 break;
360 default:
361 exerror("internal error: %ld: unknown type", type);
362 break;
363 }
364 x->type = STRING;
365 return x;
366}
367
368/* exprint:
369 * Generate argument list of strings.
370 */
371static Exnode_t *exprint(Expr_t * p, Exid_t * ex, Exnode_t * args) {
372 Exnode_t *arg = args;
373 Exnode_t *pr;
374
375 while (arg) {
376 if (arg->data.operand.left->type != STRING)
377 arg->data.operand.left =
378 exstringOf(p, arg->data.operand.left);
379 arg = arg->data.operand.right;
380 }
381 pr = exnewnode(p, ex->index, true, ex->type, args, NULL);
382 return pr;
383}
384
385/* makeVar:
386 *
387 * Create variable from s[idx].refs
388 * If s is DYNAMIC, refs is non-empty and dyna represents s[idx].
389 * The rightmost element in s[idx].refs becomes the dominant symbol,
390 * and the prefix gets stored in refs. (This format is used to simplify
391 * the yacc parser.)
392 */
393static Exnode_t *makeVar(Expr_t * prog, Exid_t * s, Exnode_t * idx,
394 Exnode_t * dyna, Exref_t * refs) {
395 Exnode_t *nn;
396 Exid_t *sym;
397
398 /* parse components */
399 if (refs) {
400 if (refs->next) {
401 sym = refs->next->symbol;
402 refs->next->symbol = refs->symbol;
403 } else
404 sym = refs->symbol;
405 refs->symbol = s;
406 refs->index = idx;
407 } else
408 sym = s;
409
410 const long kind = sym->type ? sym->type : STRING;
411
412 nn = exnewnode(prog, ID, false, kind, NULL, NULL);
413 nn->data.variable.symbol = sym;
414 nn->data.variable.reference = refs;
415 nn->data.variable.index = 0;
416 nn->data.variable.dyna = dyna;
417 if (!prog->disc->getf)
418 exerror("%s: identifier references not supported", sym->name);
419 else if (expr.program->disc->reff)
420 expr.program->disc->reff(prog, nn, nn->data.variable.symbol, refs);
421
422 return nn;
423}
424
425/* exnoncast:
426 * Return first non-cast node.
427 */
429 while (x && (x->op >= F2I) && (x->op <= X2X))
430 x = x->data.operand.left;
431 return x;
432}
433
434Exnode_t *excast(Expr_t *p, Exnode_t *x, long type, Exnode_t *xref, int arg) {
435 int t2t;
436 char* s;
437 char* e;
438
439 if (x && x->type != type && type && type != VOIDTYPE)
440 {
441 if (!x->type)
442 {
443 x->type = type;
444 return x;
445 }
446 if (!(t2t = TYPECAST(x->type, type)))
447 return x;
448 if (EXTERNAL(t2t) && !p->disc->convertf)
449 exerror("cannot convert %s to %s", extypename(p, x->type), extypename(p, type));
450 if (x->op != CONSTANT) {
451 Exid_t *sym = (xref ? xref->data.variable.symbol : NULL);
452 if (EXTERNAL(t2t)) {
453 if (p->disc->convertf(x, type, 1) < 0) {
454 if (xref) {
455 if ((sym->lex == FUNCTION) && arg)
456 exerror ("%s: cannot use value of type %s as argument %d in function %s",
457 sym->name, extypename(p, x->type),
458 arg, sym->name);
459 else
460 exerror("%s: cannot convert %s to %s",
461 xref->data.variable.symbol->name,
462 extypename(p, x->type),
463 extypename(p, type));
464 } else {
465 exerror("cannot convert %s to %s",
466 extypename(p, x->type), extypename(p, type));
467 }
468 }
469 }
470 x = exnewnode(p, t2t, false, type, x, xref);
471 }
472 else switch (t2t)
473 {
474 case F2X:
475 case I2X:
476 case S2X:
477 case X2F:
478 case X2I:
479 case X2S:
480 case X2X:
481 if (xref && xref->op == ID)
482 {
483 if (p->disc->convertf(x, type, arg) < 0)
484 exerror("%s: cannot cast constant %s to %s", xref->data.variable.symbol->name, extypename(p, x->type), extypename(p, type));
485 }
486 else if (p->disc->convertf(x, type, arg) < 0)
487 exerror("cannot cast constant %s to %s", extypename(p, x->type), extypename(p, type));
488 break;
489 case F2I:
491 break;
492 case F2S:
494 exprintf(p->vm, "%g", x->data.constant.value.floating);
495 break;
496 case I2F:
498 break;
499 case I2S:
501 exprintf(p->vm, "%lld", x->data.constant.value.integer);
502 break;
503 case S2F:
505 x->data.constant.value.floating = strtod(s, &e);
506 if (*e)
507 x->data.constant.value.floating = (*s != 0);
508 break;
509 case S2I:
511 x->data.constant.value.integer = strtoll(s, &e, 0);
512 if (*e)
513 x->data.constant.value.integer = (*s != 0);
514 break;
515 default:
516 exerror("internal error: %d: unknown cast op", t2t);
517 break;
518 }
519 x->type = type;
520 }
521 return x;
522}
523
524/*
525 * check function call arg types and count
526 * return function identifier node
527 */
528
529static Exnode_t*
530call(Exref_t* ref, Exid_t* fun, Exnode_t* args)
531{
532 int type;
533 Exnode_t* x;
534 int num;
535
536 x = exnewnode(expr.program, ID, false, 0, NULL, NULL);
537 long t = fun->type;
538 x->data.variable.symbol = fun;
540 num = 0;
541 N(t);
542 while ((type = T(t)))
543 {
544 if (!args)
545 {
546 exerror("%s: not enough args", fun->name);
547 return args;
548 }
549 num++;
550 if (type != args->data.operand.left->type)
551 args->data.operand.left = excast(expr.program, args->data.operand.left, type, NULL, num);
552 args = args->data.operand.right;
553 N(t);
554 }
555 if (args)
556 exerror("%s: too many args", fun->name);
557 return x;
558}
559
560/*
561 * precompile a printf/scanf call
562 */
563
564static Print_t*
565preprint(Exnode_t* args)
566{
567 Print_t* x;
568 char* s;
569 char c;
570 int t;
571 int i;
572 int n;
573 char* e;
574 char* f;
575 Print_t* p = 0;
576 Print_t* q;
577
578 if (!args || args->data.operand.left->type != STRING)
579 exerror("format string argument expected");
580 if (args->data.operand.left->op != CONSTANT)
581 {
582 x = ALLOCATE(expr.program, Print_t);
583 *x = (Print_t){0};
584 x->arg = args;
585 return x;
586 }
588 args = args->data.operand.right;
589 for (s = f; *s; s++)
590 {
591 agxbputc(&expr.program->tmp, *s);
592 if (*s == '%')
593 {
594 if (!*++s)
595 exerror("%s: trailing %% in format", f);
596 if (*s != '%')
597 break;
598 if (args)
599 agxbputc(&expr.program->tmp, '%');
600 }
601 }
602 x = 0;
603 for (;;)
604 {
605 q = ALLOCATE(expr.program, Print_t);
606 if (x)
607 x->next = q;
608 else
609 p = q;
610 x = q;
611 *x = (Print_t){0};
612 if (*s)
613 {
614 i = 0;
615 t = INTEGER;
616 for (;;)
617 {
618 switch (c = *s++)
619 {
620 case 0:
621 exerror("unterminated %%... in format");
622 goto done;
623 case '*':
624 if (i >= (int)elementsof(x->param))
625 {
626 *s = 0;
627 exerror("format %s has too many * arguments", f);
628 goto done;
629 }
630 if (!args)
631 {
632 *s = 0;
633 exerror("format %s * argument expected", f);
634 goto done;
635 }
636 x->param[i++] = args->data.operand.left;
637 args = args->data.operand.right;
638 break;
639 case '(':
640 n = 1;
641 for (;;)
642 {
643 agxbputc(&expr.program->tmp, c);
644 switch (c = *s++)
645 {
646 case 0:
647 s--;
648 break;
649 case '(':
650 n++;
651 continue;
652 case ')':
653 if (--n <= 0)
654 break;
655 continue;
656 default:
657 continue;
658 }
659 break;
660 }
661 break;
662 case 'c':
663 case 'd':
664 goto specified;
665 case 'e':
666 case 'f':
667 case 'g':
668 t = FLOATING;
669 goto specified;
670 case 'h':
671 exerror("short formats not supported");
672 goto done;
673 case 'l':
674 t = INTEGER;
675 break;
676 case 'o':
677 case 'u':
678 case 'x':
679 case 'T':
680 t = UNSIGNED;
681 goto specified;
682 case 's':
683 case 'S':
684 t = STRING;
685 goto specified;
686 default:
687 if (gv_isalpha(c))
688 goto specified;
689 break;
690 }
691 agxbputc(&expr.program->tmp, c);
692 }
693 specified:
694 agxbputc(&expr.program->tmp, c);
695 for (e = s; *s; s++)
696 {
697 if (*s == '%')
698 {
699 if (!*++s)
700 {
701 *e = 0;
702 exerror("%s: trailing %% in format", f);
703 goto done;
704 }
705 if (*s != '%')
706 {
707 s--;
708 break;
709 }
710 }
711 agxbputc(&expr.program->tmp, *s);
712 }
713 if (!args)
714 {
715 *e = 0;
716 exerror("%s format argument expected", f);
717 goto done;
718 }
719 x->arg = args->data.operand.left;
720 switch (t)
721 {
722 case FLOATING:
723 if (x->arg->type != FLOATING)
725 x->arg->type == STRING ? S2F : INTEGRAL(x->arg->type) ? I2F : X2F,
726 false, FLOATING, x->arg,
727 x->arg->op == ID ? x->arg : NULL);
728 break;
729 case INTEGER:
730 case UNSIGNED:
731 if (!INTEGRAL(x->arg->type))
733 x->arg->type == STRING ? S2I : x->arg->type == FLOATING ? F2I : X2I,
734 false, INTEGER, x->arg,
735 x->arg->op == ID ? x->arg : NULL);
736 x->arg->type = t;
737 break;
738 case STRING:
739 if (x->arg->type != STRING)
740 {
741 if (x->arg->op == CONSTANT && x->arg->data.constant.reference && expr.program->disc->convertf)
742 {
743 if (expr.program->disc->convertf(x->arg, STRING, 0) < 0)
744 exerror("cannot convert string format argument");
746 }
747 else if (!expr.program->disc->convertf || (x->arg->op != ID && x->arg->op != DYNAMIC && x->arg->op != F2X && x->arg->op != I2X && x->arg->op != S2X))
748 exerror("string format argument expected");
749 else
751 x->arg->type == FLOATING ? F2S : INTEGRAL(x->arg->type) ? I2S : X2S,
752 false, STRING, x->arg,
753 x->arg->op == ID ? x->arg : NULL);
754 }
755 break;
756 }
757 args = args->data.operand.right;
758 }
760 if (x->format == NULL) {
761 x->format = exnospace();
762 }
763 if (!*s)
764 break;
765 f = s;
766 }
767 if (args)
768 exerror("too many format arguments");
769 done:
770 agxbclear(&expr.program->tmp);
771 return p;
772}
773
774/*
775 * push a new input stream and program
776 */
777
778int expush(Expr_t *p, const char *name, int line, FILE *fp) {
779 Exinput_t* in;
780
781 if (!(in = calloc(1, sizeof(Exinput_t))))
782 {
783 exnospace();
784 return -1;
785 }
786 if (!p->input)
787 p->input = &expr.null;
788 if ((in->fp = fp))
789 in->close = 0;
790 else if (name)
791 {
792 if (!(in->fp = fopen(name, "r")))
793 {
794 exerror("%s: file not found", name);
795 }
796 else
797 {
798 name = vmstrdup(p->vm, name);
799 in->close = 1;
800 }
801 }
802 if (!(in->next = p->input)->next)
803 {
804 p->errors = 0;
805 if (line >= 0)
806 error_info.line = line;
807 }
808 else if (line >= 0)
809 error_info.line = line;
810 setcontext(p);
811 p->eof = 0;
812 p->input = in;
813 in->file = error_info.file;
814 if (line >= 0)
815 error_info.file = (char*)name;
816 in->line = error_info.line;
817 in->nesting = 0;
818 in->unit = !name && !line;
819 p->program = expr.program;
820 expr.program = p;
821 return 0;
822}
823
824/*
825 * pop the current input stream
826 */
827
828int
829expop(Expr_t* p)
830{
831 int c;
832 Exinput_t* in;
833
834 if (!(in = p->input) || !in->next || in->unit)
835 return -1;
836 if (in->nesting)
837 exerror("unbalanced quote or nesting construct");
838 error_info.file = in->file;
839 if (in->next->next)
840 error_info.line = in->line;
841 else
842 {
843 if (p->errors && in->fp && p->linep != p->line)
844 while ((c = getc(in->fp)) != EOF)
845 if (c == '\n')
846 {
848 break;
849 }
850 error_info.line = in->line;
851 }
852 if (in->fp && in->close)
853 fclose(in->fp);
854 free(in->pushback);
855 p->input = in->next;
856 free(in);
857 setcontext(p);
858 if (p->program)
859 expr.program = p->program;
860 return 0;
861}
862
863/*
864 * clear global state of stale pointers
865 */
866
867void exinit(void) { expr = (Exstate_t){0}; }
868
869int excomp(Expr_t *p, const char *name, int line, FILE *fp, char *prefix) {
870 int eof;
871
872 eof = p->eof;
873 if (expush(p, name, line, fp))
874 return -1;
875 p->input->unit = line >= 0;
876 // insert prefix as pre-loaded pushback
877 p->input->pushback = p->input->pp = prefix;
878 ex_parse();
879 p->input->unit = 0;
880 expop(p);
881 p->eof = eof;
882 return 0;
883}
884
885/*
886 * free the program p
887 */
888
889void exclose(Expr_t *p) {
890 Exinput_t* in;
891
892 if (p)
893 {
894 size_t i;
895 for (i = 3; i < elementsof(p->file); i++)
896 if (p->file[i])
897 fclose(p->file[i]);
898 if (p->symbols)
899 dtclose(p->symbols);
900 if (p->vm)
901 vmclose(p->vm);
902 if (p->ve)
903 vmclose(p->ve);
904 agxbfree(&p->tmp);
905 while ((in = p->input))
906 {
907 free(in->pushback);
908 if (in->fp && in->close)
909 fclose(in->fp);
910 if ((p->input = in->next))
911 free(in);
912 }
913 free(p);
914 }
915}
916
917/* checkBinary:
918 * See if application wants to allow the given expression
919 * combination. l and r give the operands; the operator
920 * is given by ex. r may be NULL.
921 */
922static void
923checkBinary(Expr_t * p, Exnode_t * l, Exnode_t * ex, Exnode_t * r)
924{
925 if (p->disc->binaryf(l, ex, r, 1) < 0) {
926 if (r)
927 exerror
928 ("cannot apply operator %s to expressions of types %s and %s",
929 exopname(ex->op), extypename(p, l->type),
930 extypename(p, r->type));
931 else
932 exerror
933 ("cannot apply operator %s to expression of type %s",
934 exopname(ex->op), extypename(p, l->type));
935 }
936}
937
938/* checkName:
939 * We allow parser to accept any name in a declaration, in
940 * order to check that the name is undeclared and give a better
941 * error message if it isn't.
942 */
943static void checkName(const Exid_t *id) {
944 switch (id->lex) {
945 case DYNAMIC:
946 exerror("Variable \"%s\" already declared", id->name);
947 break;
948 case FUNCTION:
949 exerror("Name \"%s\" already used as a function", id->name);
950 break;
951 case ID:
952 exerror("Name \"%s\" already used as a keyword", id->name);
953 break;
954 case NAME:
955 break;
956 default:
958 "Unexpected token \"%s\" as name in dcl_item", id->name);
959 break;
960 }
961}
962
963static int cmpKey(void *k1, void *k2) {
964 const Extype_t *key1 = k1;
965 const Extype_t *key2 = k2;
966 if (key1->integer < key2->integer)
967 return -1;
968 else if (key1->integer > key2->integer)
969 return 1;
970 else
971 return 0;
972}
973
974int
976{
977 return n->op == '=' && n->subop == '=';
978}
979
980#endif
981
982#ifdef __cplusplus
983}
984#endif
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:78
static void agxbclear(agxbuf *xb)
resets pointer to data
Definition agxbuf.h:294
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
#define elementsof(x)
Definition ast.h:33
#define N(n)
Definition bcomps.c:58
CDT_API int dtclose(Dt_t *)
Definition dtclose.c:8
#define right(i)
Definition closest.c:79
@ EXTERNAL
Definition ccomps.c:61
static int binary(Exnode_t *l, Exnode_t *ex, Exnode_t *r, int arg)
Definition compile.c:1830
static int a2t[]
Definition compile.c:2160
#define left
Definition dthdr.h:12
Error_info_t error_info
Definition error.c:23
#define ERROR_PANIC
Definition error.h:38
char * exopname(long op)
Definition excc.c:41
void exerror(const char *format,...)
Definition exerror.c:62
struct Print_s Print_t
Exstate_t expr
int ex_parse(void)
#define setcontext(p)
Definition exlib.h:127
char * exnospace(void)
Definition exnospace.c:25
#define UNSIGNED
Definition exparse.c:237
#define DYNAMIC
Definition exparse.c:251
#define F2S
Definition exparse.c:285
#define DEFAULT
Definition exparse.c:250
#define X2F
Definition exparse.c:294
#define S2X
Definition exparse.c:293
#define ITERATE
Definition exparse.c:257
#define S2I
Definition exparse.c:290
#define SUB
Definition exparse.c:278
#define FLOATING
Definition exparse.c:239
#define I2X
Definition exparse.c:292
#define SUBSTR
Definition exparse.c:279
#define TOKENS
Definition exparse.c:281
#define ITERATOR
Definition exparse.c:258
#define VOIDTYPE
Definition exparse.c:241
#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 CALL
Definition exparse.c:245
#define GSUB
Definition exparse.c:256
#define UNSET
Definition exparse.c:282
#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 S2F
Definition exparse.c:289
#define PROCEDURE
Definition exparse.c:269
#define X2X
Definition exparse.c:297
#define F2X
Definition exparse.c:291
#define X2I
Definition exparse.c:295
#define PRINTF
Definition exparse.c:268
#define FUNCTION
Definition exparse.c:255
expr procedure type
Definition exparse.y:206
int exisAssign(Exnode_t *)
Exnode_t * exnoncast(Exnode_t *)
Exnode_t * excast(Expr_t *, Exnode_t *, long, Exnode_t *, int)
static char * exprintf(Vmalloc_t *vm, const char *fmt,...)
Definition expr.h:267
struct Exnode_s Exnode_t
Definition expr.h:85
int expop(Expr_t *)
#define BUILTIN(t)
Definition expr.h:58
void exinit(void)
Exnode_t * exnewnode(Expr_t *, long, bool, long, Exnode_t *, Exnode_t *)
void exfreenode(Expr_t *, Exnode_t *)
void exclose(Expr_t *)
char * extypename(Expr_t *p, long)
#define INTEGRAL(t)
Definition expr.h:57
int expush(Expr_t *, const char *, int, FILE *)
int excomp(Expr_t *p, const char *name, int line, FILE *fp, char *prefix)
#define TMASK
Definition expr.h:75
#define NAME
Definition gmlparse.c:377
#define ID
Definition gmlparse.c:376
#define STRING
Definition gmlparse.c:375
#define INTEGER
Definition gmlparse.c:373
void free(void *)
require define api prefix
Definition gmlparse.y:17
node NULL
Definition grammar.y:163
static uint64_t id
Definition gv2gml.c:42
replacements for ctype.h functions
static bool gv_isalpha(int c)
Definition gv_ctype.h:29
table Syntax error
Definition htmlparse.y:294
void ref(Site *v)
Definition site.c:59
char * file
Definition error.h:30
int line
Definition error.h:27
Definition expr.h:93
long index_type
Definition expr.h:98
long type
Definition expr.h:97
long lex
Definition expr.h:95
char name[EX_NAMELEN]
Definition expr.h:101
long index
Definition expr.h:96
void * local
user defined local stuff
Definition expr.h:100
int nesting
Definition exlib.h:38
char * file
Definition exlib.h:35
int line
Definition exlib.h:37
char * pushback
Definition exlib.h:41
int unit
Definition exlib.h:40
struct Exinput_s * next
Definition exlib.h:33
int close
Definition exlib.h:34
FILE * fp
Definition exlib.h:36
long op
operator
Definition expr.h:150
long type
value type
Definition expr.h:149
bool binary
data.operand.{left,right} ok
Definition expr.h:151
Exdata_t data
Definition expr.h:158
Definition expr.h:198
Dt_t * symbols
Definition expr.h:200
FILE * file[10]
Definition expr.h:201
Vmalloc_t * vm
Definition expr.h:202
Exid_t * symbol
Definition expr.h:107
Exref_t * next
Definition expr.h:106
Exnode_t * index
Definition expr.h:108
Expr_t * program
Definition exlib.h:156
Exinput_t null
Definition exlib.h:155
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
static mytime_t T
Definition timing.c:41
char * string
Definition exparse.c:326
long long integer
Definition exparse.c:324
double floating
Definition exparse.c:321
struct Exdata_u::@87 variable
Exnode_t * left
Definition expr.h:122
struct Exdata_u::@84 constant
Exnode_t * right
Definition expr.h:123
Exid_t * reference
Definition expr.h:117
Exnode_t * next
Definition expr.h:129
Exnode_t * statement
Definition expr.h:128
Exid_t * symbol
Definition expr.h:135
struct Exdata_u::@85 operand
struct Exdata_u::@86 select
Exnode_t * dyna
Definition expr.h:138
Extype_t value
Definition expr.h:116
Exnode_t * index
Definition expr.h:137
Definition grammar.c:93
void vmfree(Vmalloc_t *vm, void *data)
Definition vmalloc.c:57
char * vmstrdup(Vmalloc_t *, const char *)
Definition vmstrdup.c:19
void vmclose(Vmalloc_t *)
Definition vmclose.c:18