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