Graphviz 12.0.1~dev.20240716.0800
Loading...
Searching...
No Matches
exparse.y
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%require "3.0"
12
13 /* By default, Bison emits a parser using symbols prefixed with "yy". Graphviz
14 * contains multiple Bison-generated parsers, so we alter this prefix to avoid
15 * symbol clashes.
16 */
17%define api.prefix {ex_}
18
19%{
20
21/*
22 * Glenn Fowler
23 * AT&T Research
24 *
25 * expression library grammar and compiler
26 */
27
28#include <assert.h>
29#include <cgraph/gv_ctype.h>
30#include <cgraph/streq.h>
31#include <expr/exop.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <ast/ast.h>
36
37%}
38
39%union
40{
41 struct Exnode_s*expr;
42 double floating;
43 struct Exref_s* reference;
44 struct Exid_s* id;
45 long long integer;
46 int op;
47 char* string;
48}
49
50%start program
51
52%token MINTOKEN
53
54%token INTEGER
55%token UNSIGNED
56%token CHARACTER
57%token FLOATING
58%token STRING
59%token VOIDTYPE
60%token STATIC
61
62%token ADDRESS
63%token ARRAY
64%token BREAK
65%token CALL
66%token CASE
67%token CONSTANT
68%token CONTINUE
69%token DECLARE
70%token DEFAULT
71%token DYNAMIC
72%token ELSE
73%token EXIT
74%token FOR
75%token FUNCTION
76%token GSUB
77%token ITERATE
78%token ITERATER
79%token ID
80%token IF
81%token LABEL
82%token MEMBER
83%token NAME
84%token POS
85%token PRAGMA
86%token PRE
87%token PRINT
88%token PRINTF
89%token PROCEDURE
90%token QUERY
91%token RAND
92%token RETURN
93%token SCANF
94%token SPLIT
95%token SPRINTF
96%token SRAND
97%token SSCANF
98%token SUB
99%token SUBSTR
100%token SWITCH
101%token TOKENS
102%token UNSET
103%token WHILE
104
105%token F2I
106%token F2S
107%token I2F
108%token I2S
109%token S2B
110%token S2F
111%token S2I
112
113%token F2X
114%token I2X
115%token S2X
116%token X2F
117%token X2I
118%token X2S
119%token X2X
120%token XPRINT
121
122%left <op> ','
123%right <op> '='
124%right <op> '?' ':'
125%left <op> OR
126%left <op> AND
127%left <op> '|'
128%left <op> '^'
129%left <op> '&'
130%binary <op> EQ NE
131%binary <op> '<' '>' LE GE
132%left <op> LSH RSH
133%left <op> '+' '-' IN_OP
134%left <op> '*' '/' '%'
135%right <op> '!' '~' '#' UNARY
136%right <op> INC DEC
137%right <op> CAST
138%left <op> '('
139
140%type <expr> statement statement_list arg_list
141%type <expr> else_opt expr_opt expr
142%type <expr> args variable assign
143%type <expr> dcl_list dcl_item index
144%type <expr> initialize switch_item constant
145%type <expr> formals formal_list formal_item
146%type <reference> members
147%type <id> ID LABEL NAME
149%type <id> EXIT PRINT PRINTF QUERY
150%type <id> RAND SRAND
151%type <id> SPRINTF PROCEDURE name dcl_name
152%type <id> GSUB SUB SUBSTR
153%type <id> SPLIT TOKENS splitop
154%type <id> IF WHILE FOR ITERATER
155%type <id> BREAK CONTINUE print member
156%type <id> RETURN DYNAMIC SWITCH UNSET
157%type <id> SCANF SSCANF scan
158%type <floating> FLOATING
159%type <integer> INTEGER UNSIGNED array
160%type <integer> static
161%type <string> STRING
162
163%token MAXTOKEN
164
165 /* ask Bison to generate a table, yytname, containing string representations
166 * of all the above tokens
167 */
168%token-table
169
170%{
171
172#include <expr/exgram.h>
173
174void ex_error(const char *message);
175
176%}
177
178%%
179
180program : statement_list action_list
181 {
182 if ($1) {
183 if (expr.program->main.value)
184 exfreenode(expr.program, expr.program->main.value);
185 if ($1->op == S2B)
186 {
187 Exnode_t* x;
188
189 x = $1;
190 $1 = x->data.operand.left;
191 x->data.operand.left = 0;
193 }
194 expr.program->main.lex = PROCEDURE;
195 expr.program->main.value = exnewnode(expr.program, PROCEDURE, 1, $1->type, NULL, $1);
196 }
197 }
198 ;
199
200action_list : /* empty */
201 | action_list action
202 ;
203
204action : LABEL ':' {
205 Dtdisc_t* disc;
206
208 exerror("no nested function definitions");
209 $1->lex = PROCEDURE;
212 if (!(disc = calloc(1, sizeof(Dtdisc_t))))
213 exnospace();
214 disc->key = offsetof(Exid_t, name);
215 if (expr.assigned && !streq($1->name, "begin"))
216 {
217 if (!(expr.procedure->data.procedure.frame = dtopen(disc, Dtset)) || !dtview(expr.procedure->data.procedure.frame, expr.program->symbols))
218 exnospace();
219 expr.program->symbols = expr.program->frame = expr.procedure->data.procedure.frame;
220 }
222 {
223 expr.procedure = 0;
224 if (expr.program->frame)
225 {
226 expr.program->symbols = expr.program->frame->view;
227 dtview(expr.program->frame, NULL);
228 expr.program->frame = 0;
229 }
230 if ($4 && $4->op == S2B)
231 {
232 Exnode_t* x;
233
234 x = $4;
235 $4 = x->data.operand.left;
236 x->data.operand.left = 0;
238 }
239 $1->value->data.operand.right = excast(expr.program, $4, $1->type, NULL, 0);
240 }
241 ;
242
243statement_list : /* empty */
244 {
245 $$ = 0;
246 }
248 {
249 if (!$1)
250 $$ = $2;
251 else if (!$2)
252 $$ = $1;
253 else if ($1->op == CONSTANT)
254 {
256 $$ = $2;
257 }
258 else $$ = exnewnode(expr.program, ';', 1, $2->type, $1, $2);
259 }
260 ;
261
263 {
264 $$ = $2;
265 }
267 {
268 $$ = ($1 && $1->type == STRING) ? exnewnode(expr.program, S2B, 1, INTEGER, $1, NULL) : $1;
269 }
270 | static {expr.instatic=$1;} DECLARE {expr.declare=$3->type;} dcl_list ';'
271 {
272 $$ = $5;
274 }
275 | IF '(' expr ')' statement else_opt
276 {
277 if (exisAssign ($3))
278 exwarn ("assignment used as boolean in if statement");
279 if ($3->type == STRING)
281 else if (!INTEGRAL($3->type))
283 $$ = exnewnode(expr.program, $1->index, 1, INTEGER, $3, exnewnode(expr.program, ':', 1, $5 ? $5->type : 0, $5, $6));
284 }
285 | FOR '(' variable ')' statement
286 {
288 $$->data.generate.array = $3;
289 if (!$3->data.variable.index || $3->data.variable.index->op != DYNAMIC)
290 exerror("simple index variable expected");
291 $$->data.generate.index = $3->data.variable.index->data.variable.symbol;
292 if ($3->op == ID && $$->data.generate.index->type != INTEGER)
293 exerror("integer index variable expected");
294 exfreenode(expr.program, $3->data.variable.index);
295 $3->data.variable.index = 0;
296 $$->data.generate.statement = $5;
297 }
298 | FOR '(' expr_opt ';' expr_opt ';' expr_opt ')' statement
299 {
300 if (!$5)
301 {
303 $5->data.constant.value.integer = 1;
304 }
305 else if ($5->type == STRING)
307 else if (!INTEGRAL($5->type))
309 $$ = exnewnode(expr.program, $1->index, 1, INTEGER, $5, exnewnode(expr.program, ';', 1, 0, $7, $9));
310 if ($3)
311 $$ = exnewnode(expr.program, ';', 1, INTEGER, $3, $$);
312 }
313 | ITERATER '(' variable ')' statement
314 {
316 $$->data.generate.array = $3;
317 if (!$3->data.variable.index || $3->data.variable.index->op != DYNAMIC)
318 exerror("simple index variable expected");
319 $$->data.generate.index = $3->data.variable.index->data.variable.symbol;
320 if ($3->op == ID && $$->data.generate.index->type != INTEGER)
321 exerror("integer index variable expected");
322 exfreenode(expr.program, $3->data.variable.index);
323 $3->data.variable.index = 0;
324 $$->data.generate.statement = $5;
325 }
326 | UNSET '(' DYNAMIC ')'
327 {
328 if ($3->local == NULL)
329 exerror("cannot apply unset to non-array %s", $3->name);
331 $$->data.variable.symbol = $3;
332 $$->data.variable.index = NULL;
333 }
334 | UNSET '(' DYNAMIC ',' expr ')'
335 {
336 if ($3->local == NULL)
337 exerror("cannot apply unset to non-array %s", $3->name);
338 if (($3->index_type > 0) && ($5->type != $3->index_type))
339 exerror("%s indices must have type %s, not %s",
340 $3->name, extypename(expr.program, $3->index_type),extypename(expr.program, $5->type));
342 $$->data.variable.symbol = $3;
343 $$->data.variable.index = $5;
344 }
345 | WHILE '(' expr ')' statement
346 {
347 if (exisAssign ($3))
348 exwarn ("assignment used as boolean in while statement");
349 if ($3->type == STRING)
351 else if (!INTEGRAL($3->type))
353 $$ = exnewnode(expr.program, $1->index, 1, INTEGER, $3, exnewnode(expr.program, ';', 1, 0, NULL, $5));
354 }
355 | SWITCH '(' expr {expr.declare=$3->type;} ')' '{' switch_list '}'
356 {
357 Switch_t* sw = expr.swstate;
358
359 $$ = exnewnode(expr.program, $1->index, 1, INTEGER, $3, exnewnode(expr.program, DEFAULT, 1, 0, sw->defcase, sw->firstcase));
361 free(sw->base);
362 if (sw != &swstate)
363 free(sw);
364 expr.declare = 0;
365 }
366 | BREAK expr_opt ';'
367 {
368 loopop:
369 if (!$2)
370 {
372 $2->data.constant.value.integer = 1;
373 }
374 else if (!INTEGRAL($2->type))
376 $$ = exnewnode(expr.program, $1->index, 1, INTEGER, $2, NULL);
377 }
378 | CONTINUE expr_opt ';'
379 {
380 goto loopop;
381 }
382 | RETURN expr_opt ';'
383 {
384 if ($2)
385 {
387 exerror("return in void function");
389 }
390 $$ = exnewnode(expr.program, RETURN, 1, $2 ? $2->type : 0, $2, NULL);
391 }
392 ;
393
394switch_list : /* empty */
395 {
396 Switch_t* sw;
397
398 if (expr.swstate)
399 {
400 if (!(sw = calloc(1, sizeof(Switch_t))))
401 {
402 exnospace();
403 sw = &swstate;
404 }
405 sw->prev = expr.swstate;
406 }
407 else
408 sw = &swstate;
409 expr.swstate = sw;
410 sw->type = expr.declare;
411 sw->firstcase = 0;
412 sw->lastcase = 0;
413 sw->defcase = 0;
414 sw->def = 0;
415 size_t n = 8;
416 if (!(sw->base = calloc(n, sizeof(Extype_t*))))
417 {
418 exnospace();
419 n = 0;
420 }
421 sw->cur = sw->base;
422 sw->last = sw->base + n;
423 }
424 | switch_list switch_item
425 ;
426
427switch_item : case_list statement_list
428 {
429 Switch_t* sw = expr.swstate;
430
431 $$ = exnewnode(expr.program, CASE, 1, 0, $2, NULL);
432 if (sw->cur > sw->base)
433 {
434 if (sw->lastcase)
435 sw->lastcase->data.select.next = $$;
436 else
437 sw->firstcase = $$;
438 sw->lastcase = $$;
439 size_t n = (size_t)(sw->cur - sw->base);
440 sw->cur = sw->base;
441 $$->data.select.constant = exalloc(expr.program, (n + 1) * sizeof(Extype_t*));
442 memcpy($$->data.select.constant, sw->base, n * sizeof(Extype_t*));
443 $$->data.select.constant[n] = 0;
444 }
445 else
446 $$->data.select.constant = 0;
447 if (sw->def)
448 {
449 sw->def = 0;
450 if (sw->defcase)
451 exerror("duplicate default in switch");
452 else
453 sw->defcase = $2;
454 }
455 }
456 ;
457
458case_list : case_item
459 | case_list case_item
460 ;
461
462case_item : CASE constant ':'
463 {
464 if (expr.swstate->cur >= expr.swstate->last)
465 {
466 size_t n = (size_t)(expr.swstate->cur - expr.swstate->base);
467 if (!(expr.swstate->base = realloc(expr.swstate->base, sizeof(Extype_t*) * 2 * n)))
468 {
469 exerror("too many case labels for switch");
470 n = 0;
471 }
473 expr.swstate->last = expr.swstate->base + 2 * n;
474 }
475 if (expr.swstate->cur)
476 {
478 *expr.swstate->cur++ = &($2->data.constant.value);
479 }
480 }
481 | DEFAULT ':'
482 {
483 expr.swstate->def = 1;
484 }
485 ;
486
487static : /* empty */
488 {
489 $$ = 0;
490 }
491 | STATIC
492 {
493 $$ = 1;
494 }
495 ;
496
497dcl_list : dcl_item
498 | dcl_list ',' dcl_item
499 {
500 if ($3)
501 $$ = $1 ? exnewnode(expr.program, ',', 1, $3->type, $1, $3) : $3;
502 }
503 ;
504
505dcl_item : dcl_name {checkName ($1); expr.id=$1;} array initialize
506 {
507 $$ = 0;
508 if (!$1->type || expr.declare)
509 $1->type = expr.declare;
510 if ($4 && $4->op == PROCEDURE)
511 {
512 $1->lex = PROCEDURE;
513 $1->type = $4->type;
514 $1->value = $4;
515 }
516 else
517 {
518 $1->lex = DYNAMIC;
519 $1->value = exnewnode(expr.program, 0, 0, 0, NULL, NULL);
520 if ($3 && $1->local == NULL)
521 {
522 Dtdisc_t* disc;
523
524 if (!(disc = calloc(1, sizeof(Dtdisc_t))))
525 exnospace();
526 if ($3 == INTEGER) {
527 disc->key = offsetof(Exassoc_t, key);
528 disc->size = sizeof(Extype_t);
529 disc->comparf = cmpKey;
530 }
531 else
532 disc->key = offsetof(Exassoc_t, name);
533 if (!($1->local = dtopen(disc, Dtoset)))
534 exerror("%s: cannot initialize associative array", $1->name);
535 $1->index_type = $3; /* -1 indicates no typechecking */
536 }
537 if ($4)
538 {
539 if ($4->type != $1->type)
540 {
541 $4->type = $1->type;
542 $4->data.operand.right = excast(expr.program, $4->data.operand.right, $1->type, NULL, 0);
543 }
544 $4->data.operand.left = exnewnode(expr.program, DYNAMIC, 0, $1->type, NULL, NULL);
545 $4->data.operand.left->data.variable.symbol = $1;
546 $$ = $4;
547 }
548 else if (!$3)
549 $1->value->data.value = exzero($1->type);
550 }
551 }
552 ;
553
554dcl_name : NAME
555 | DYNAMIC
556 | ID
557 | FUNCTION
558 ;
559
560name : NAME
561 | DYNAMIC
562 ;
563
564else_opt : /* empty */
565 {
566 $$ = 0;
567 }
569 {
570 $$ = $2;
571 }
572 ;
573
574expr_opt : /* empty */
575 {
576 $$ = 0;
577 }
578 | expr
579 ;
580
581expr : '(' expr ')'
582 {
583 $$ = $2;
584 }
585 | '(' DECLARE ')' expr %prec CAST
586 {
587 $$ = ($4->type == $2->type) ? $4 : excast(expr.program, $4, $2->type, NULL, 0);
588 }
589 | expr '<' expr
590 {
591 long rel;
592
593 relational:
594 rel = INTEGER;
595 goto coerce;
596 binary:
597 rel = 0;
598 coerce:
599 if (!$1->type)
600 {
601 if (!$3->type)
602 $1->type = $3->type = rel ? STRING : INTEGER;
603 else
604 $1->type = $3->type;
605 }
606 else if (!$3->type)
607 $3->type = $1->type;
608 if ($1->type != $3->type)
609 {
610 if ($1->type == STRING)
611 $1 = excast(expr.program, $1, $3->type, $3, 0);
612 else if ($3->type == STRING)
613 $3 = excast(expr.program, $3, $1->type, $1, 0);
614 else if ($1->type == FLOATING)
615 $3 = excast(expr.program, $3, FLOATING, $1, 0);
616 else if ($3->type == FLOATING)
617 $1 = excast(expr.program, $1, FLOATING, $3, 0);
618 }
619 if (!rel)
620 rel = ($1->type == STRING) ? STRING : (($1->type == UNSIGNED) ? UNSIGNED : $3->type);
621 $$ = exnewnode(expr.program, $2, 1, rel, $1, $3);
622 if (!expr.program->errors && $1->op == CONSTANT && $3->op == CONSTANT)
623 {
624 $$->data.constant.value = exeval(expr.program, $$, NULL);
625 /* If a constant string, re-allocate from program heap. This is because the
626 * value was constructed from string operators, which create a value in the
627 * temporary heap, which is cleared when exeval is called again.
628 */
629 if ($$->type == STRING) {
630 $$->data.constant.value.string =
631 vmstrdup(expr.program->vm, $$->data.constant.value.string);
632 }
633 $$->binary = 0;
634 $$->op = CONSTANT;
637 }
638 else if (!BUILTIN($1->type) || !BUILTIN($3->type)) {
639 checkBinary(expr.program, $1, $$, $3);
640 }
641 }
642 | expr '-' expr
643 {
644 goto binary;
645 }
646 | expr '*' expr
647 {
648 goto binary;
649 }
650 | expr '/' expr
651 {
652 goto binary;
653 }
654 | expr '%' expr
655 {
656 goto binary;
657 }
658 | expr LSH expr
659 {
660 goto binary;
661 }
662 | expr RSH expr
663 {
664 goto binary;
665 }
666 | expr '>' expr
667 {
668 goto relational;
669 }
670 | expr LE expr
671 {
672 goto relational;
673 }
674 | expr GE expr
675 {
676 goto relational;
677 }
678 | expr EQ expr
679 {
680 goto relational;
681 }
682 | expr NE expr
683 {
684 goto relational;
685 }
686 | expr '&' expr
687 {
688 goto binary;
689 }
690 | expr '|' expr
691 {
692 goto binary;
693 }
694 | expr '^' expr
695 {
696 goto binary;
697 }
698 | expr '+' expr
699 {
700 goto binary;
701 }
702 | expr AND expr
703 {
704 logical:
705 if ($1->type == STRING)
707 else if (!BUILTIN($1->type))
709 if ($3->type == STRING)
711 else if (!BUILTIN($3->type))
713 goto binary;
714 }
715 | expr OR expr
716 {
717 goto logical;
718 }
719 | expr ',' expr
720 {
721 if ($1->op == CONSTANT)
722 {
724 $$ = $3;
725 }
726 else
727 $$ = exnewnode(expr.program, ',', 1, $3->type, $1, $3);
728 }
729 | expr '?' {expr.nolabel=1;} expr ':' {expr.nolabel=0;} expr
730 {
731 if (!$4->type)
732 {
733 if (!$7->type)
734 $4->type = $7->type = INTEGER;
735 else
736 $4->type = $7->type;
737 }
738 else if (!$7->type)
739 $7->type = $4->type;
740 if ($1->type == STRING)
742 else if (!INTEGRAL($1->type))
744 if ($4->type != $7->type)
745 {
746 if ($4->type == STRING || $7->type == STRING)
747 exerror("if statement string type mismatch");
748 else if ($4->type == FLOATING)
749 $7 = excast(expr.program, $7, FLOATING, NULL, 0);
750 else if ($7->type == FLOATING)
751 $4 = excast(expr.program, $4, FLOATING, NULL, 0);
752 }
753 if ($1->op == CONSTANT)
754 {
755 if ($1->data.constant.value.integer)
756 {
757 $$ = $4;
759 }
760 else
761 {
762 $$ = $7;
764 }
766 }
767 else
768 $$ = exnewnode(expr.program, '?', 1, $4->type, $1, exnewnode(expr.program, ':', 1, $4->type, $4, $7));
769 }
770 | '!' expr
771 {
772 iunary:
773 if ($2->type == STRING)
775 else if (!INTEGRAL($2->type))
777 unary:
778 $$ = exnewnode(expr.program, $1, 1, $2->type == UNSIGNED ? INTEGER : $2->type, $2, NULL);
779 if ($2->op == CONSTANT)
780 {
782 $$->binary = 0;
783 $$->op = CONSTANT;
785 }
786 else if (!BUILTIN($2->type)) {
787 checkBinary(expr.program, $2, $$, 0);
788 }
789 }
790 | '#' DYNAMIC
791 {
792 if ($2->local == NULL)
793 exerror("cannot apply '#' operator to non-array %s", $2->name);
794 $$ = exnewnode(expr.program, '#', 0, INTEGER, NULL, NULL);
795 $$->data.variable.symbol = $2;
796 }
797 | '~' expr
798 {
799 goto iunary;
800 }
801 | '-' expr %prec UNARY
802 {
803 goto unary;
804 }
805 | '+' expr %prec UNARY
806 {
807 $$ = $2;
808 }
809 | '&' variable %prec UNARY
810 {
811 $$ = exnewnode(expr.program, ADDRESS, 0, T($2->type), $2, NULL);
812 }
813 | ARRAY '[' args ']'
814 {
815 $$ = exnewnode(expr.program, ARRAY, 1, T($1->type), call(0, $1, $3), $3);
816 }
817 | FUNCTION '(' args ')'
818 {
819 $$ = exnewnode(expr.program, FUNCTION, 1, T($1->type), call(0, $1, $3), $3);
820 }
821 | GSUB '(' args ')'
822 {
823 $$ = exnewsub (expr.program, $3, GSUB);
824 }
825 | SUB '(' args ')'
826 {
827 $$ = exnewsub (expr.program, $3, SUB);
828 }
829 | SUBSTR '(' args ')'
830 {
831 $$ = exnewsubstr (expr.program, $3);
832 }
833 | splitop '(' expr ',' DYNAMIC ')'
834 {
835 $$ = exnewsplit (expr.program, $1->index, $5, $3, NULL);
836 }
837 | splitop '(' expr ',' DYNAMIC ',' expr ')'
838 {
839 $$ = exnewsplit (expr.program, $1->index, $5, $3, $7);
840 }
841 | EXIT '(' expr ')'
842 {
843 if (!INTEGRAL($3->type))
846 }
847 | RAND '(' ')'
848 {
850 }
851 | SRAND '(' ')'
852 {
854 }
855 | SRAND '(' expr ')'
856 {
857 if (!INTEGRAL($3->type))
860 }
861 | PROCEDURE '(' args ')'
862 {
863 $$ = exnewnode(expr.program, CALL, 1, $1->type, NULL, $3);
864 $$->data.call.procedure = $1;
865 }
866 | PRINT '(' args ')'
867 {
868 $$ = exprint(expr.program, $1, $3);
869 }
870 | print '(' args ')'
871 {
872 $$ = exnewnode(expr.program, $1->index, 0, $1->type, NULL, NULL);
873 if ($3 && $3->data.operand.left->type == INTEGER)
874 {
875 $$->data.print.descriptor = $3->data.operand.left;
876 $3 = $3->data.operand.right;
877 }
878 else
879 switch ($1->index)
880 {
881 case QUERY:
882 $$->data.print.descriptor = exnewnode(expr.program, CONSTANT, 0, INTEGER, NULL, NULL);
883 $$->data.print.descriptor->data.constant.value.integer = 2;
884 break;
885 case PRINTF:
886 $$->data.print.descriptor = exnewnode(expr.program, CONSTANT, 0, INTEGER, NULL, NULL);
887 $$->data.print.descriptor->data.constant.value.integer = 1;
888 break;
889 case SPRINTF:
890 $$->data.print.descriptor = 0;
891 break;
892 }
893 $$->data.print.args = preprint($3);
894 }
895 | scan '(' args ')'
896 {
897 Exnode_t* x;
898
899 $$ = exnewnode(expr.program, $1->index, 0, $1->type, NULL, NULL);
900 if ($3 && $3->data.operand.left->type == INTEGER)
901 {
902 $$->data.scan.descriptor = $3->data.operand.left;
903 $3 = $3->data.operand.right;
904 }
905 else
906 switch ($1->index)
907 {
908 case SCANF:
909 $$->data.scan.descriptor = 0;
910 break;
911 case SSCANF:
912 if ($3 && $3->data.operand.left->type == STRING)
913 {
914 $$->data.scan.descriptor = $3->data.operand.left;
915 $3 = $3->data.operand.right;
916 }
917 else
918 exerror("%s: string argument expected", $1->name);
919 break;
920 }
921 if (!$3 || !$3->data.operand.left || $3->data.operand.left->type != STRING)
922 exerror("%s: format argument expected", $1->name);
923 $$->data.scan.format = $3->data.operand.left;
924 for (x = $$->data.scan.args = $3->data.operand.right; x; x = x->data.operand.right)
925 {
926 if (x->data.operand.left->op != ADDRESS)
927 exerror("%s: address argument expected", $1->name);
929 }
930 }
931 | variable assign
932 {
933 if ($2)
934 {
935 if ($1->op == ID && !expr.program->disc->setf)
936 exerror("%s: variable assignment not supported", $1->data.variable.symbol->name);
937 else
938 {
939 if (!$1->type)
940 $1->type = $2->type;
941 else if ($2->type != $1->type)
942 {
943 $2->type = $1->type;
944 $2->data.operand.right = excast(expr.program, $2->data.operand.right, $1->type, NULL, 0);
945 }
946 $2->data.operand.left = $1;
947 $$ = $2;
948 }
949 }
950 }
951 | INC variable
952 {
953 pre:
954 if ($2->type == STRING)
955 exerror("++ and -- invalid for string variables");
956 $$ = exnewnode(expr.program, $1, 0, $2->type, $2, NULL);
957 $$->subop = PRE;
958 }
959 | variable INC
960 {
961 pos:
962 if ($1->type == STRING)
963 exerror("++ and -- invalid for string variables");
964 $$ = exnewnode(expr.program, $2, 0, $1->type, $1, NULL);
965 $$->subop = POS;
966 }
968 {
969 if ($3->local == NULL)
970 exerror("cannot apply IN to non-array %s", $3->name);
971 if (($3->index_type > 0) && ($1->type != $3->index_type))
972 exerror("%s indices must have type %s, not %s",
973 $3->name, extypename(expr.program, $3->index_type),extypename(expr.program, $1->type));
975 $$->data.variable.symbol = $3;
976 $$->data.variable.index = $1;
977 }
978 | DEC variable
979 {
980 goto pre;
981 }
982 | variable DEC
983 {
984 goto pos;
985 }
986 | constant
987 ;
988
989splitop : SPLIT
990 | TOKENS
991 ;
992constant : CONSTANT
993 {
994 $$ = exnewnode(expr.program, CONSTANT, 0, $1->type, NULL, NULL);
995 if (!expr.program->disc->reff)
996 exerror("%s: identifier references not supported", $1->name);
997 else
998 $$->data.constant.value = expr.program->disc->reff(expr.program, $$, $1, NULL);
999 }
1000 | FLOATING
1001 {
1003 $$->data.constant.value.floating = $1;
1004 }
1005 | INTEGER
1006 {
1008 $$->data.constant.value.integer = $1;
1009 }
1010 | STRING
1011 {
1013 $$->data.constant.value.string = $1;
1014 }
1015 | UNSIGNED
1016 {
1018 $$->data.constant.value.integer = $1;
1019 }
1020 ;
1021
1022print : PRINTF
1023 | QUERY
1024 | SPRINTF
1025 ;
1026
1027scan : SCANF
1028 | SSCANF
1029 ;
1030
1031variable : ID members
1032 {
1033 $$ = makeVar(expr.program, $1, 0, 0, $2);
1034 }
1035 | DYNAMIC index members
1036 {
1037 Exnode_t* n;
1038
1039 n = exnewnode(expr.program, DYNAMIC, 0, $1->type, NULL, NULL);
1040 n->data.variable.symbol = $1;
1041 n->data.variable.reference = 0;
1042 if (((n->data.variable.index = $2) == 0) != ($1->local == NULL))
1043 exerror("%s: is%s an array", $1->name, $1->local != NULL ? "" : " not");
1044 if ($1->local != NULL && ($1->index_type > 0)) {
1045 if ($2->type != $1->index_type)
1046 exerror("%s: indices must have type %s, not %s",
1047 $1->name, extypename(expr.program, $1->index_type),extypename(expr.program, $2->type));
1048 }
1049 if ($3) {
1050 n->data.variable.dyna =exnewnode(expr.program, 0, 0, 0, NULL, NULL);
1051 $$ = makeVar(expr.program, $1, $2, n, $3);
1052 }
1053 else $$ = n;
1054 }
1055 | NAME
1056 {
1058 $$->data.variable.symbol = $1;
1059 $$->data.variable.reference = 0;
1060 $$->data.variable.index = 0;
1061 $$->data.variable.dyna = 0;
1062 if (!(expr.program->disc->flags & EX_UNDECLARED))
1063 exerror("unknown identifier");
1064 }
1065 ;
1066
1067array : /* empty */
1068 {
1069 $$ = 0;
1070 }
1071 | '[' ']'
1072 {
1073 $$ = -1;
1074 }
1075 | '[' DECLARE ']'
1076 {
1077 /* If DECLARE is VOID, its type is 0, so this acts like
1078 * the empty case.
1079 */
1080 if (INTEGRAL($2->type))
1081 $$ = INTEGER;
1082 else
1083 $$ = $2->type;
1084
1085 }
1086 ;
1087
1088index : /* empty */
1089 {
1090 $$ = 0;
1091 }
1092 | '[' expr ']'
1093 {
1094 $$ = $2;
1095 }
1096 ;
1097
1098args : /* empty */
1099 {
1100 $$ = 0;
1101 }
1102 | arg_list
1103 {
1104 $$ = $1->data.operand.left;
1105 $1->data.operand.left = $1->data.operand.right = 0;
1107 }
1108 ;
1109
1110arg_list : expr %prec ','
1111 {
1112 $$ = exnewnode(expr.program, ',', 1, 0, exnewnode(expr.program, ',', 1, $1->type, $1, NULL), NULL);
1113 $$->data.operand.right = $$->data.operand.left;
1114 }
1115 | arg_list ',' expr
1116 {
1117 $1->data.operand.right = $1->data.operand.right->data.operand.right = exnewnode(expr.program, ',', 1, $1->type, $3, NULL);
1118 }
1119 ;
1120
1121formals : /* empty */
1122 {
1123 $$ = 0;
1124 }
1125 | DECLARE
1126 {
1127 $$ = 0;
1128 if ($1->type)
1129 exerror("(void) expected");
1130 }
1131 | formal_list
1132 ;
1133
1134formal_list : formal_item
1135 {
1136 $$ = exnewnode(expr.program, ',', 1, $1->type, $1, NULL);
1137 }
1138 | formal_list ',' formal_item
1139 {
1140 Exnode_t* x;
1141 Exnode_t* y;
1142
1143 $$ = $1;
1144 for (x = $1; (y = x->data.operand.right); x = y);
1145 x->data.operand.right = exnewnode(expr.program, ',', 1, $3->type, $3, NULL);
1146 }
1147 ;
1148
1149formal_item : DECLARE {expr.declare=$1->type;} name
1150 {
1151 $$ = exnewnode(expr.program, ID, 0, $1->type, NULL, NULL);
1152 $$->data.variable.symbol = $3;
1153 $3->lex = DYNAMIC;
1154 $3->type = $1->type;
1155 $3->value = exnewnode(expr.program, 0, 0, 0, NULL, NULL);
1156 expr.procedure->data.procedure.arity++;
1157 expr.declare = 0;
1158 }
1159 ;
1160
1161members : /* empty */
1162 {
1163 $$ = expr.refs = 0;
1164 }
1165 | member
1166 {
1167 Exref_t* r;
1168
1169 r = ALLOCATE(expr.program, Exref_t);
1170 *r = (Exref_t){0};
1171 r->symbol = $1;
1172 expr.refs = r;
1173 r->next = 0;
1174 r->index = 0;
1175 $$ = expr.refs;
1176 }
1177 | '.' ID member
1178 {
1179 Exref_t* r;
1180 Exref_t* l;
1181
1182 r = ALLOCATE(expr.program, Exref_t);
1183 *r = (Exref_t){0};
1184 r->symbol = $3;
1185 r->index = 0;
1186 r->next = 0;
1187 l = ALLOCATE(expr.program, Exref_t);
1188 *l = (Exref_t){0};
1189 l->symbol = $2;
1190 l->index = 0;
1191 l->next = r;
1192 expr.refs = l;
1193 $$ = expr.refs;
1194 }
1195 ;
1196
1197member : '.' ID
1198 {
1199 $$ = $2;
1200 }
1201 | '.' NAME
1202 {
1203 $$ = $2;
1204 }
1205 ;
1206assign : /* empty */
1207 {
1208 $$ = 0;
1209 }
1210 | '=' expr
1211 {
1212 $$ = exnewnode(expr.program, '=', 1, $2->type, NULL, $2);
1213 $$->subop = $1;
1214 }
1215 ;
1216
1217initialize : assign
1218 | '(' {
1219 Dtdisc_t* disc;
1220
1221 if (expr.procedure)
1222 exerror("%s: nested function definitions not supported", expr.id->name);
1224 if (!(disc = calloc(1, sizeof(Dtdisc_t))))
1225 exnospace();
1226 disc->key = offsetof(Exid_t, name);
1227 if (!streq(expr.id->name, "begin"))
1228 {
1229 if (!(expr.procedure->data.procedure.frame = dtopen(disc, Dtset)) || !dtview(expr.procedure->data.procedure.frame, expr.program->symbols))
1230 exnospace();
1231 expr.program->symbols = expr.program->frame = expr.procedure->data.procedure.frame;
1232 expr.program->formals = 1;
1233 }
1234 expr.declare = 0;
1235 } formals {
1236 expr.id->lex = PROCEDURE;
1238 expr.program->formals = 0;
1239 expr.declare = 0;
1240 } ')' '{' statement_list '}'
1241 {
1242 $$ = expr.procedure;
1243 expr.procedure = 0;
1244 if (expr.program->frame)
1245 {
1246 expr.program->symbols = expr.program->frame->view;
1247 dtview(expr.program->frame, NULL);
1248 expr.program->frame = 0;
1249 }
1250 $$->data.operand.left = $3;
1251 $$->data.operand.right = excast(expr.program, $7, $$->type, NULL, 0);
1252
1253 /*
1254 * NOTE: procedure definition was slipped into the
1255 * declaration initializer statement production,
1256 * therefore requiring the statement terminator
1257 */
1258
1259 exunlex(expr.program, ';');
1260 }
1261 ;
1262
1263%%
1264
1265const char *exop(size_t index) {
1266
1267 /* yytname is generated by the %token-table directive */
1268
1269 /* find the index of MINTOKEN */
1270 size_t minid;
1271 for (minid = 0; yytname[minid] != NULL; ++minid) {
1272 if (strcmp(yytname[minid], "MINTOKEN") == 0) {
1273 break;
1274 }
1275 }
1276
1277 assert(yytname[minid] != NULL
1278 && "failed to find MINTOKEN; incorrect token list in exparse.y?");
1279
1280 /* find the requested token */
1281 {
1282 size_t i, j;
1283 for (i = j = minid; yytname[i] != NULL; ++i) {
1284
1285 /* if this token is not a word, skip it */
1286 {
1287 size_t k;
1288 for (k = 0; yytname[i][k] != '\0'; ++k) {
1289 if (yytname[i][k] != '_' && !gv_isalnum(yytname[i][k])) {
1290 break;
1291 }
1292 }
1293 if (yytname[i][k] != '\0') {
1294 continue;
1295 }
1296 }
1297
1298 if (j == index + minid) {
1299 return yytname[i];
1300 }
1301 ++j;
1302 }
1303 }
1304
1305 /* failed to find the requested token */
1306 return NULL;
1307}
1308
1309void ex_error(const char *message) {
1310 exerror("%s", message);
1311}
1312
1313#include <expr/exgram.h>
CDT_API Dtmethod_t * Dtset
set with unique elements
Definition dthash.c:277
CDT_API Dt_t * dtview(Dt_t *, Dt_t *)
Definition dtview.c:91
CDT_API Dtmethod_t * Dtoset
ordered set (self-adjusting tree)
Definition dttree.c:304
CDT_API Dt_t * dtopen(Dtdisc_t *, Dtmethod_t *)
Definition dtopen.c:9
static int binary(Exnode_t *l, Exnode_t *ex, Exnode_t *r, int arg)
Definition compile.c:1884
static void scan(Excc_t *cc, Exnode_t *exnode)
Definition excc.c:162
static void print(Excc_t *cc, Exnode_t *exnode)
Definition excc.c:125
void exwarn(const char *format,...)
Definition exerror.c:79
void exerror(const char *format,...)
Definition exerror.c:62
Extype_t exeval(Expr_t *ex, Exnode_t *exnode, void *env)
Definition exeval.c:1965
Exstate_t expr
#define exunlex(p, c)
Definition exlib.h:126
char * exnospace(void)
Definition exnospace.c:25
const char * exop(size_t id)
Definition exparse.c:3615
#define UNSIGNED
Definition exparse.c:237
#define ELSE
Definition exparse.c:253
#define STATIC
Definition exparse.c:242
#define CHARACTER
Definition exparse.c:238
#define DYNAMIC
Definition exparse.c:252
#define SCANF
Definition exparse.c:274
#define F2S
Definition exparse.c:286
#define SSCANF
Definition exparse.c:278
#define RSH
Definition exparse.c:307
#define ADDRESS
Definition exparse.c:243
#define OR
Definition exparse.c:300
#define PRE
Definition exparse.c:267
#define GE
Definition exparse.c:305
#define MINTOKEN
Definition exparse.c:235
#define DEFAULT
Definition exparse.c:251
#define ITERATER
Definition exparse.c:259
#define X2F
Definition exparse.c:295
#define S2X
Definition exparse.c:294
#define WHILE
Definition exparse.c:284
#define ITERATE
Definition exparse.c:258
#define MAXTOKEN
Definition exparse.c:313
#define NE
Definition exparse.c:303
#define SRAND
Definition exparse.c:277
#define S2I
Definition exparse.c:291
#define SUB
Definition exparse.c:279
#define POS
Definition exparse.c:265
#define LSH
Definition exparse.c:306
#define FLOATING
Definition exparse.c:239
#define FOR
Definition exparse.c:255
#define I2X
Definition exparse.c:293
#define IN_OP
Definition exparse.c:308
#define SUBSTR
Definition exparse.c:280
#define TOKENS
Definition exparse.c:282
#define VOIDTYPE
Definition exparse.c:241
#define RAND
Definition exparse.c:272
#define PRINT
Definition exparse.c:268
#define CAST
Definition exparse.c:312
#define I2F
Definition exparse.c:287
#define SPRINTF
Definition exparse.c:276
#define I2S
Definition exparse.c:288
#define CONSTANT
Definition exparse.c:248
#define LE
Definition exparse.c:304
#define MEMBER
Definition exparse.c:263
#define S2B
Definition exparse.c:289
#define CALL
Definition exparse.c:246
#define GSUB
Definition exparse.c:257
#define PRAGMA
Definition exparse.c:266
#define UNARY
Definition exparse.c:309
#define UNSET
Definition exparse.c:283
#define CONTINUE
Definition exparse.c:249
#define XPRINT
Definition exparse.c:299
static const char *const yytname[]
Definition exparse.c:743
#define F2I
Definition exparse.c:285
#define X2S
Definition exparse.c:297
#define EQ
Definition exparse.c:302
#define BREAK
Definition exparse.c:245
#define S2F
Definition exparse.c:290
#define IF
Definition exparse.c:261
#define PROCEDURE
Definition exparse.c:270
#define SWITCH
Definition exparse.c:281
#define AND
Definition exparse.c:301
#define X2X
Definition exparse.c:298
#define EXIT
Definition exparse.c:254
#define F2X
Definition exparse.c:292
#define X2I
Definition exparse.c:296
#define PRINTF
Definition exparse.c:269
#define QUERY
Definition exparse.c:271
void ex_error(const char *message)
Definition exparse.c:3659
#define FUNCTION
Definition exparse.c:256
#define CASE
Definition exparse.c:247
#define ARRAY
Definition exparse.c:244
#define INC
Definition exparse.c:310
#define DEC
Definition exparse.c:311
else $$
Definition exparse.y:258
disc key
Definition exparse.y:214
dcl_list
Definition exparse.y:270
expr_opt
Definition exparse.y:266
statement_list
Definition exparse.y:222
static DECLARE
Definition exparse.y:270
statement_list statement
Definition exparse.y:248
expr procedure type
Definition exparse.y:211
struct Exref_s Exref_t
Definition expr.h:87
int exisAssign(Exnode_t *)
#define exalloc(p, n)
Definition expr.h:79
EX_STYPE Extype_t
Definition expr.h:81
Exnode_t * excast(Expr_t *, Exnode_t *, long, Exnode_t *, int)
#define BUILTIN(t)
Definition expr.h:58
Exnode_t * exnewnode(Expr_t *, int, int, long, Exnode_t *, Exnode_t *)
void exfreenode(Expr_t *, Exnode_t *)
char * extypename(Expr_t *p, long)
#define EX_UNDECLARED
Definition expr.h:45
#define INTEGRAL(t)
Definition expr.h:57
Extype_t exzero(long int)
Definition exzero.c:24
#define LABEL
Definition gmlparse.c:396
#define NAME
Definition gmlparse.c:416
#define ID
Definition gmlparse.c:415
#define STRING
Definition gmlparse.c:414
#define INTEGER
Definition gmlparse.c:412
void free(void *)
alist $2
Definition gmlparse.y:323
glistitem $1
Definition gmlparse.y:278
atom $5
Definition grammar.y:151
node NULL
Definition grammar.y:149
atom $3
Definition grammar.y:150
static uint64_t id
Definition gv2gml.c:42
replacements for ctype.h functions
static bool gv_isalnum(int c)
Definition gv_ctype.h:43
#define SPLIT(x, n, s)
Definition htmltable.c:1273
#define assign(h, i, j, index)
Definition dijkstra.c:43
char * pre
Definition maze.c:29
static int table[NTYPES][NTYPES]
Definition mincross.c:1752
static bool streq(const char *a, const char *b)
are a and b equal?
Definition streq.h:11
#define RETURN(v)
Definition strmatch.c:144
Definition expr.h:93
long type
Definition expr.h:97
long lex
Definition expr.h:95
char name[EX_NAMELEN]
Definition expr.h:103
long index
Definition expr.h:96
int op
Definition expr.h:153
double(* floating)(char **)
Definition expr.h:158
long type
value type
Definition expr.h:152
Exdata_t data
Definition expr.h:162
Dt_t * symbols
Definition expr.h:204
Vmalloc_t * vm
Definition expr.h:206
Exid_t * symbol
Definition expr.h:109
Exref_t * next
Definition expr.h:108
Exnode_t * index
Definition expr.h:110
int instatic
Definition exlib.h:161
int nolabel
Definition exlib.h:155
int assigned
Definition exlib.h:160
Exid_t * id
Definition exlib.h:153
Expr_t * program
Definition exlib.h:157
Exref_t * refs
Definition exlib.h:159
long declare
current declaration type
Definition exlib.h:154
Exnode_t * procedure
Definition exlib.h:158
Switch_t * swstate
Definition exlib.h:163
Extype_t ** last
Definition exlib.h:138
int def
Definition exlib.h:139
Exnode_t * defcase
Definition exlib.h:135
struct Switch_s * prev
Definition exlib.h:132
long type
switch test type
Definition exlib.h:140
Extype_t ** cur
Definition exlib.h:137
Exnode_t * lastcase
Definition exlib.h:134
Extype_t ** base
Definition exlib.h:136
Exnode_t * firstcase
Definition exlib.h:133
int size
Definition cdt.h:90
int key
Definition cdt.h:89
Dtcompar_f comparf
Definition cdt.h:94
static mytime_t T
Definition timing.c:41
struct Exdata_u::@87 constant
Exnode_t * left
Definition expr.h:124
Exnode_t * right
Definition expr.h:125
Exid_t * reference
Definition expr.h:119
Exnode_t * next
Definition expr.h:132
struct Exdata_u::@88 operand
Exid_t * symbol
Definition expr.h:138
Exnode_t * dyna
Definition expr.h:141
struct Exdata_u::@89 select
Extype_t value
Definition expr.h:118
Exnode_t * index
Definition expr.h:140
struct Exdata_u::@90 variable
char * vmstrdup(Vmalloc_t *, const char *)
Definition vmstrdup.c:19