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