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