Graphviz 13.0.0~dev.20241220.2304
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/* exstringOf:
286 * Cast x to type STRING
287 * Assume x->type != STRING
288 */
289static Exnode_t *exstringOf(Expr_t * p, Exnode_t * x) {
290 const long type = x->type;
291 int cvt = 0;
292
293 if (!type) {
294 x->type = STRING;
295 return x;
296 }
297 if (!BUILTIN(type) && !p->disc->stringof)
298 exerror("cannot convert %s to STRING", extypename(p, type));
299 if (x->op != CONSTANT) {
300 if (!BUILTIN(type)) {
301 if (p->disc->stringof(p, x, 1) < 0) {
302 exerror("cannot convert %s to STRING",
303 extypename(p, type));
304 }
305 cvt = XPRINT;
306 } else
307 switch (type) {
308 case FLOATING:
309 cvt = F2S;
310 break;
311 case INTEGER:
312 cvt = I2S;
313 break;
314 }
315 x = exnewnode(p, cvt, false, STRING, x, 0);
316 } else if (!BUILTIN(type)) {
317 if (p->disc->stringof(p, x, 0) < 0)
318 exerror("cannot convert constant %s to STRING",
319 extypename(p, x->type));
320 } else
321 switch (type) {
322 case FLOATING:
324 exprintf(p->vm, "%g", x->data.constant.value.floating);
325 break;
326 case INTEGER:
328 exprintf(p->vm, "%lld", x->data.constant.value.integer);
329 break;
330 default:
331 exerror("internal error: %ld: unknown type", type);
332 break;
333 }
334 x->type = STRING;
335 return x;
336}
337
338/* exprint:
339 * Generate argument list of strings.
340 */
341static Exnode_t *exprint(Expr_t * p, Exid_t * ex, Exnode_t * args) {
342 Exnode_t *arg = args;
343 Exnode_t *pr;
344
345 while (arg) {
346 if (arg->data.operand.left->type != STRING)
347 arg->data.operand.left =
348 exstringOf(p, arg->data.operand.left);
349 arg = arg->data.operand.right;
350 }
351 pr = exnewnode(p, ex->index, true, ex->type, args, NULL);
352 return pr;
353}
354
355/* makeVar:
356 *
357 * Create variable from s[idx].refs
358 * If s is DYNAMIC, refs is non-empty and dyna represents s[idx].
359 * The rightmost element in s[idx].refs becomes the dominant symbol,
360 * and the prefix gets stored in refs. (This format is used to simplify
361 * the yacc parser.)
362 */
363static Exnode_t *makeVar(Expr_t * prog, Exid_t * s, Exnode_t * idx,
364 Exnode_t * dyna, Exref_t * refs) {
365 Exnode_t *nn;
366 Exid_t *sym;
367
368 /* parse components */
369 if (refs) {
370 if (refs->next) {
371 sym = refs->next->symbol;
372 refs->next->symbol = refs->symbol;
373 } else
374 sym = refs->symbol;
375 refs->symbol = s;
376 refs->index = idx;
377 } else
378 sym = s;
379
380 const long kind = sym->type ? sym->type : STRING;
381
382 nn = exnewnode(prog, ID, false, kind, NULL, NULL);
383 nn->data.variable.symbol = sym;
384 nn->data.variable.reference = refs;
385 nn->data.variable.index = 0;
386 nn->data.variable.dyna = dyna;
387 if (!prog->disc->getf)
388 exerror("%s: identifier references not supported", sym->name);
389 else if (expr.program->disc->reff)
390 expr.program->disc->reff(prog, nn, nn->data.variable.symbol, refs);
391
392 return nn;
393}
394
395/*
396 * cast x to type
397 */
398
399static char* typename[] =
400{
401 "external", "integer", "unsigned", "char", "float", "string"
402};
403
404static int typecast[6][6] =
405{
406 {X2X, X2I, X2I, X2I, X2F, X2S},
407 {I2X, 0, 0, 0, I2F, I2S},
408 {I2X, 0, 0, 0, I2F, I2S},
409 {I2X, 0, 0, 0, I2F, I2S},
410 {F2X, F2I, F2I, F2I, 0, F2S},
411 {S2X, S2I, S2I, S2I, S2F, 0},
412};
413
414#define TYPEINDEX(t) (((t)>=INTEGER&&(t)<=STRING)?((t)-INTEGER+1):0)
415#define TYPENAME(t) typename[TYPEINDEX(t)]
416#define TYPECAST(f,t) typecast[TYPEINDEX(f)][TYPEINDEX(t)]
417
418#define EXTERNAL(t) ((t)>=F2X)
419
420char *extypename(Expr_t *p, long type) {
421 if (BUILTIN(type))
422 return TYPENAME(type);
423 return p->disc->typename(type);
424}
425
426/* exnoncast:
427 * Return first non-cast node.
428 */
430 while (x && (x->op >= F2I) && (x->op <= X2X))
431 x = x->data.operand.left;
432 return x;
433}
434
435Exnode_t *excast(Expr_t *p, Exnode_t *x, long type, Exnode_t *xref, int arg) {
436 int t2t;
437 char* s;
438 char* e;
439
440 if (x && x->type != type && type && type != VOIDTYPE)
441 {
442 if (!x->type)
443 {
444 x->type = type;
445 return x;
446 }
447 if (!(t2t = TYPECAST(x->type, type)))
448 return x;
449 if (EXTERNAL(t2t) && !p->disc->convertf)
450 exerror("cannot convert %s to %s", extypename(p, x->type), extypename(p, type));
451 if (x->op != CONSTANT) {
452 Exid_t *sym = (xref ? xref->data.variable.symbol : NULL);
453 if (EXTERNAL(t2t)) {
454 if (p->disc->convertf(x, type, 1) < 0) {
455 if (xref) {
456 if ((sym->lex == FUNCTION) && arg)
457 exerror ("%s: cannot use value of type %s as argument %d in function %s",
458 sym->name, extypename(p, x->type),
459 arg, sym->name);
460 else
461 exerror("%s: cannot convert %s to %s",
462 xref->data.variable.symbol->name,
463 extypename(p, x->type),
464 extypename(p, type));
465 } else {
466 exerror("cannot convert %s to %s",
467 extypename(p, x->type), extypename(p, type));
468 }
469 }
470 }
471 x = exnewnode(p, t2t, false, type, x, xref);
472 }
473 else switch (t2t)
474 {
475 case F2X:
476 case I2X:
477 case S2X:
478 case X2F:
479 case X2I:
480 case X2S:
481 case X2X:
482 if (xref && xref->op == ID)
483 {
484 if (p->disc->convertf(x, type, arg) < 0)
485 exerror("%s: cannot cast constant %s to %s", xref->data.variable.symbol->name, extypename(p, x->type), extypename(p, type));
486 }
487 else if (p->disc->convertf(x, type, arg) < 0)
488 exerror("cannot cast constant %s to %s", extypename(p, x->type), extypename(p, type));
489 break;
490 case F2I:
492 break;
493 case F2S:
495 exprintf(p->vm, "%g", x->data.constant.value.floating);
496 break;
497 case I2F:
499 break;
500 case I2S:
502 exprintf(p->vm, "%lld", x->data.constant.value.integer);
503 break;
504 case S2F:
506 x->data.constant.value.floating = strtod(s, &e);
507 if (*e)
508 x->data.constant.value.floating = (*s != 0);
509 break;
510 case S2I:
512 x->data.constant.value.integer = strtoll(s, &e, 0);
513 if (*e)
514 x->data.constant.value.integer = (*s != 0);
515 break;
516 default:
517 exerror("internal error: %d: unknown cast op", t2t);
518 break;
519 }
520 x->type = type;
521 }
522 return x;
523}
524
525/*
526 * check function call arg types and count
527 * return function identifier node
528 */
529
530static Exnode_t*
531call(Exref_t* ref, Exid_t* fun, Exnode_t* args)
532{
533 int type;
534 Exnode_t* x;
535 int num;
536
537 x = exnewnode(expr.program, ID, false, 0, NULL, NULL);
538 long t = fun->type;
539 x->data.variable.symbol = fun;
541 num = 0;
542 N(t);
543 while ((type = T(t)))
544 {
545 if (!args)
546 {
547 exerror("%s: not enough args", fun->name);
548 return args;
549 }
550 num++;
551 if (type != args->data.operand.left->type)
552 args->data.operand.left = excast(expr.program, args->data.operand.left, type, NULL, num);
553 args = args->data.operand.right;
554 N(t);
555 }
556 if (args)
557 exerror("%s: too many args", fun->name);
558 return x;
559}
560
561/*
562 * precompile a printf/scanf call
563 */
564
565static Print_t*
566preprint(Exnode_t* args)
567{
568 Print_t* x;
569 char* s;
570 char c;
571 int t;
572 int i;
573 int n;
574 char* e;
575 char* f;
576 Print_t* p = 0;
577 Print_t* q;
578
579 if (!args || args->data.operand.left->type != STRING)
580 exerror("format string argument expected");
581 if (args->data.operand.left->op != CONSTANT)
582 {
583 x = ALLOCATE(expr.program, Print_t);
584 *x = (Print_t){0};
585 x->arg = args;
586 return x;
587 }
589 args = args->data.operand.right;
590 for (s = f; *s; s++)
591 {
592 agxbputc(&expr.program->tmp, *s);
593 if (*s == '%')
594 {
595 if (!*++s)
596 exerror("%s: trailing %% in format", f);
597 if (*s != '%')
598 break;
599 if (args)
600 agxbputc(&expr.program->tmp, '%');
601 }
602 }
603 x = 0;
604 for (;;)
605 {
606 q = ALLOCATE(expr.program, Print_t);
607 if (x)
608 x->next = q;
609 else
610 p = q;
611 x = q;
612 *x = (Print_t){0};
613 if (*s)
614 {
615 i = 0;
616 t = INTEGER;
617 for (;;)
618 {
619 switch (c = *s++)
620 {
621 case 0:
622 exerror("unterminated %%... in format");
623 goto done;
624 case '*':
625 if (i >= (int)elementsof(x->param))
626 {
627 *s = 0;
628 exerror("format %s has too many * arguments", f);
629 goto done;
630 }
631 if (!args)
632 {
633 *s = 0;
634 exerror("format %s * argument expected", f);
635 goto done;
636 }
637 x->param[i++] = args->data.operand.left;
638 args = args->data.operand.right;
639 break;
640 case '(':
641 n = 1;
642 for (;;)
643 {
644 agxbputc(&expr.program->tmp, c);
645 switch (c = *s++)
646 {
647 case 0:
648 s--;
649 break;
650 case '(':
651 n++;
652 continue;
653 case ')':
654 if (--n <= 0)
655 break;
656 continue;
657 default:
658 continue;
659 }
660 break;
661 }
662 break;
663 case 'c':
664 case 'd':
665 goto specified;
666 case 'e':
667 case 'f':
668 case 'g':
669 t = FLOATING;
670 goto specified;
671 case 'h':
672 exerror("short formats not supported");
673 goto done;
674 case 'l':
675 t = INTEGER;
676 break;
677 case 'o':
678 case 'u':
679 case 'x':
680 case 'T':
681 t = UNSIGNED;
682 goto specified;
683 case 's':
684 case 'S':
685 t = STRING;
686 goto specified;
687 default:
688 if (gv_isalpha(c))
689 goto specified;
690 break;
691 }
692 agxbputc(&expr.program->tmp, c);
693 }
694 specified:
695 agxbputc(&expr.program->tmp, c);
696 for (e = s; *s; s++)
697 {
698 if (*s == '%')
699 {
700 if (!*++s)
701 {
702 *e = 0;
703 exerror("%s: trailing %% in format", f);
704 goto done;
705 }
706 if (*s != '%')
707 {
708 s--;
709 break;
710 }
711 }
712 agxbputc(&expr.program->tmp, *s);
713 }
714 if (!args)
715 {
716 *e = 0;
717 exerror("%s format argument expected", f);
718 goto done;
719 }
720 x->arg = args->data.operand.left;
721 switch (t)
722 {
723 case FLOATING:
724 if (x->arg->type != FLOATING)
726 x->arg->type == STRING ? S2F : INTEGRAL(x->arg->type) ? I2F : X2F,
727 false, FLOATING, x->arg,
728 x->arg->op == ID ? x->arg : NULL);
729 break;
730 case INTEGER:
731 case UNSIGNED:
732 if (!INTEGRAL(x->arg->type))
734 x->arg->type == STRING ? S2I : x->arg->type == FLOATING ? F2I : X2I,
735 false, INTEGER, x->arg,
736 x->arg->op == ID ? x->arg : NULL);
737 x->arg->type = t;
738 break;
739 case STRING:
740 if (x->arg->type != STRING)
741 {
742 if (x->arg->op == CONSTANT && x->arg->data.constant.reference && expr.program->disc->convertf)
743 {
744 if (expr.program->disc->convertf(x->arg, STRING, 0) < 0)
745 exerror("cannot convert string format argument");
747 }
748 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))
749 exerror("string format argument expected");
750 else
752 x->arg->type == FLOATING ? F2S : INTEGRAL(x->arg->type) ? I2S : X2S,
753 false, STRING, x->arg,
754 x->arg->op == ID ? x->arg : NULL);
755 }
756 break;
757 }
758 args = args->data.operand.right;
759 }
761 if (x->format == NULL) {
762 x->format = exnospace();
763 }
764 if (!*s)
765 break;
766 f = s;
767 }
768 if (args)
769 exerror("too many format arguments");
770 done:
771 agxbclear(&expr.program->tmp);
772 return p;
773}
774
775/*
776 * push a new input stream and program
777 */
778
779int expush(Expr_t *p, const char *name, int line, FILE *fp) {
780 Exinput_t* in;
781
782 if (!(in = calloc(1, sizeof(Exinput_t))))
783 {
784 exnospace();
785 return -1;
786 }
787 if (!p->input)
788 p->input = &expr.null;
789 if ((in->fp = fp))
790 in->close = 0;
791 else if (name)
792 {
793 if (!(in->fp = fopen(name, "r")))
794 {
795 exerror("%s: file not found", name);
796 }
797 else
798 {
799 name = vmstrdup(p->vm, name);
800 in->close = 1;
801 }
802 }
803 if (!(in->next = p->input)->next)
804 {
805 p->errors = 0;
806 if (line >= 0)
807 error_info.line = line;
808 }
809 else if (line >= 0)
810 error_info.line = line;
811 setcontext(p);
812 p->eof = 0;
813 p->input = in;
814 in->file = error_info.file;
815 if (line >= 0)
816 error_info.file = (char*)name;
817 in->line = error_info.line;
818 in->nesting = 0;
819 in->unit = !name && !line;
820 p->program = expr.program;
821 expr.program = p;
822 return 0;
823}
824
825/*
826 * pop the current input stream
827 */
828
829int
830expop(Expr_t* p)
831{
832 int c;
833 Exinput_t* in;
834
835 if (!(in = p->input) || !in->next || in->unit)
836 return -1;
837 if (in->nesting)
838 exerror("unbalanced quote or nesting construct");
839 error_info.file = in->file;
840 if (in->next->next)
841 error_info.line = in->line;
842 else
843 {
844 if (p->errors && in->fp && p->linep != p->line)
845 while ((c = getc(in->fp)) != EOF)
846 if (c == '\n')
847 {
849 break;
850 }
851 error_info.line = in->line;
852 }
853 if (in->fp && in->close)
854 fclose(in->fp);
855 free(in->pushback);
856 p->input = in->next;
857 free(in);
858 setcontext(p);
859 if (p->program)
860 expr.program = p->program;
861 return 0;
862}
863
864/*
865 * clear global state of stale pointers
866 */
867
868void exinit(void) { expr = (Exstate_t){0}; }
869
870int excomp(Expr_t *p, const char *name, int line, FILE *fp, char *prefix) {
871 int eof;
872
873 eof = p->eof;
874 if (expush(p, name, line, fp))
875 return -1;
876 p->input->unit = line >= 0;
877 // insert prefix as pre-loaded pushback
878 p->input->pushback = p->input->pp = prefix;
879 ex_parse();
880 p->input->unit = 0;
881 expop(p);
882 p->eof = eof;
883 return 0;
884}
885
886/*
887 * free the program p
888 */
889
890void
891exclose(Expr_t* p, int all)
892{
893 Exinput_t* in;
894
895 if (p)
896 {
897 if (all)
898 {
899 size_t i;
900 for (i = 3; i < elementsof(p->file); i++)
901 if (p->file[i])
902 fclose(p->file[i]);
903 if (p->vm)
904 vmclose(p->vm);
905 if (p->ve)
906 vmclose(p->ve);
907 if (p->symbols)
908 dtclose(p->symbols);
909 agxbfree(&p->tmp);
910 while ((in = p->input))
911 {
912 free(in->pushback);
913 if (in->fp && in->close)
914 fclose(in->fp);
915 if ((p->input = in->next))
916 free(in);
917 }
918 free(p);
919 }
920 else
921 {
922 vmclear(p->ve);
923 p->main.value = 0;
924 }
925 }
926}
927
928/* checkBinary:
929 * See if application wants to allow the given expression
930 * combination. l and r give the operands; the operator
931 * is given by ex. r may be NULL.
932 */
933static void
934checkBinary(Expr_t * p, Exnode_t * l, Exnode_t * ex, Exnode_t * r)
935{
936 if (p->disc->binaryf(l, ex, r, 1) < 0) {
937 if (r)
938 exerror
939 ("cannot apply operator %s to expressions of types %s and %s",
940 exopname(ex->op), extypename(p, l->type),
941 extypename(p, r->type));
942 else
943 exerror
944 ("cannot apply operator %s to expression of type %s",
945 exopname(ex->op), extypename(p, l->type));
946 }
947}
948
949/* checkName:
950 * We allow parser to accept any name in a declaration, in
951 * order to check that the name is undeclared and give a better
952 * error message if it isn't.
953 */
954static void checkName(Exid_t * id)
955{
956 switch (id->lex) {
957 case DYNAMIC:
958 exerror("Variable \"%s\" already declared", id->name);
959 break;
960 case FUNCTION:
961 exerror("Name \"%s\" already used as a function", id->name);
962 break;
963 case ID:
964 exerror("Name \"%s\" already used as a keyword", id->name);
965 break;
966 case NAME:
967 break;
968 default:
970 "Unexpected token \"%s\" as name in dcl_item", id->name);
971 break;
972 }
973}
974
975static int cmpKey(void *k1, void *k2) {
976 const Extype_t *key1 = k1;
977 const Extype_t *key2 = k2;
978 if (key1->integer < key2->integer)
979 return -1;
980 else if (key1->integer > key2->integer)
981 return 1;
982 else
983 return 0;
984}
985
986int
988{
989 return n->op == '=' && n->subop == '=';
990}
991
992#endif
993
994#ifdef __cplusplus
995}
996#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:1831
static int a2t[]
Definition compile.c:2161
#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