Graphviz 13.0.0~dev.20250511.0440
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 | '#' ARRAY
764 {
765 $$ = exnewnode(expr.program, '#', false, INTEGER, NULL, NULL);
766 $$->data.variable.symbol = $2;
767 }
768 | '~' expr
769 {
770 goto iunary;
771 }
772 | '-' expr %prec UNARY
773 {
774 goto unary;
775 }
776 | '+' expr %prec UNARY
777 {
778 $$ = $2;
779 }
780 | '&' variable %prec UNARY
781 {
782 $$ = exnewnode(expr.program, ADDRESS, false, T($2->type), $2, NULL);
783 }
784 | ARRAY '[' args ']'
785 {
786 $$ = exnewnode(expr.program, ARRAY, true, T($1->type), call(0, $1, $3), $3);
787 }
788 | FUNCTION '(' args ')'
789 {
790 $$ = exnewnode(expr.program, FUNCTION, true, T($1->type), call(0, $1, $3), $3);
791 }
792 | GSUB '(' args ')'
793 {
794 $$ = exnewsub (expr.program, $3, GSUB);
795 }
796 | SUB '(' args ')'
797 {
798 $$ = exnewsub (expr.program, $3, SUB);
799 }
800 | SUBSTR '(' args ')'
801 {
802 $$ = exnewsubstr (expr.program, $3);
803 }
804 | splitop '(' expr ',' DYNAMIC ')'
805 {
806 $$ = exnewsplit (expr.program, $1->index, $5, $3, NULL);
807 }
808 | splitop '(' expr ',' DYNAMIC ',' expr ')'
809 {
810 $$ = exnewsplit (expr.program, $1->index, $5, $3, $7);
811 }
812 | EXIT '(' expr ')'
813 {
814 if (!INTEGRAL($3->type))
816 $$ = exnewnode(expr.program, EXIT, true, INTEGER, $3, NULL);
817 }
818 | RAND '(' ')'
819 {
821 }
822 | SRAND '(' ')'
823 {
825 }
826 | SRAND '(' expr ')'
827 {
828 if (!INTEGRAL($3->type))
831 }
832 | PROCEDURE '(' args ')'
833 {
834 $$ = exnewnode(expr.program, CALL, true, $1->type, NULL, $3);
835 $$->data.call.procedure = $1;
836 }
837 | PRINT '(' args ')'
838 {
839 $$ = exprint(expr.program, $1, $3);
840 }
841 | print '(' args ')'
842 {
843 $$ = exnewnode(expr.program, $1->index, false, $1->type, NULL, NULL);
844 if ($3 && $3->data.operand.left->type == INTEGER)
845 {
846 $$->data.print.descriptor = $3->data.operand.left;
847 $3 = $3->data.operand.right;
848 }
849 else
850 switch ($1->index)
851 {
852 case QUERY:
853 $$->data.print.descriptor = exnewnode(expr.program, CONSTANT, false, INTEGER, NULL, NULL);
854 $$->data.print.descriptor->data.constant.value.integer = 2;
855 break;
856 case PRINTF:
857 $$->data.print.descriptor = exnewnode(expr.program, CONSTANT, false, INTEGER, NULL, NULL);
858 $$->data.print.descriptor->data.constant.value.integer = 1;
859 break;
860 case SPRINTF:
861 $$->data.print.descriptor = 0;
862 break;
863 }
864 $$->data.print.args = preprint($3);
865 }
866 | scan '(' args ')'
867 {
868 Exnode_t* x;
869
870 $$ = exnewnode(expr.program, $1->index, false, $1->type, NULL, NULL);
871 if ($3 && $3->data.operand.left->type == INTEGER)
872 {
873 $$->data.scan.descriptor = $3->data.operand.left;
874 $3 = $3->data.operand.right;
875 }
876 else
877 switch ($1->index)
878 {
879 case SCANF:
880 $$->data.scan.descriptor = 0;
881 break;
882 case SSCANF:
883 if ($3 && $3->data.operand.left->type == STRING)
884 {
885 $$->data.scan.descriptor = $3->data.operand.left;
886 $3 = $3->data.operand.right;
887 }
888 else
889 exerror("%s: string argument expected", $1->name);
890 break;
891 }
892 if (!$3 || !$3->data.operand.left || $3->data.operand.left->type != STRING)
893 exerror("%s: format argument expected", $1->name);
894 $$->data.scan.format = $3->data.operand.left;
895 for (x = $$->data.scan.args = $3->data.operand.right; x; x = x->data.operand.right)
896 {
897 if (x->data.operand.left->op != ADDRESS)
898 exerror("%s: address argument expected", $1->name);
900 }
901 }
902 | variable assign
903 {
904 if ($2)
905 {
906 if ($1->op == ID && !expr.program->disc->setf)
907 exerror("%s: variable assignment not supported", $1->data.variable.symbol->name);
908 else
909 {
910 if (!$1->type)
911 $1->type = $2->type;
912 else if ($2->type != $1->type)
913 {
914 $2->type = $1->type;
915 $2->data.operand.right = excast(expr.program, $2->data.operand.right, $1->type, NULL, 0);
916 }
917 $2->data.operand.left = $1;
918 $$ = $2;
919 }
920 }
921 }
922 | INC variable
923 {
924 pre:
925 if ($2->type == STRING)
926 exerror("++ and -- invalid for string variables");
927 $$ = exnewnode(expr.program, $1, false, $2->type, $2, NULL);
928 $$->subop = PRE;
929 }
930 | variable INC
931 {
932 pos:
933 if ($1->type == STRING)
934 exerror("++ and -- invalid for string variables");
935 $$ = exnewnode(expr.program, $2, false, $1->type, $1, NULL);
936 $$->subop = POS;
937 }
939 {
940 if ($3->local == NULL)
941 exerror("cannot apply IN to non-array %s", $3->name);
942 if ($3->index_type > 0 && $1->type != $3->index_type)
943 exerror("%s indices must have type %s, not %s",
944 $3->name, extypename(expr.program, $3->index_type),extypename(expr.program, $1->type));
946 $$->data.variable.symbol = $3;
947 $$->data.variable.index = $1;
948 }
950 {
951 if ($3->index_type > 0 && $1->type != $3->index_type)
952 exerror("%s indices must have type %s, not %s",
953 $3->name, extypename(expr.program, $3->index_type),extypename(expr.program, $1->type));
955 $$->data.variable.symbol = $3;
956 $$->data.variable.index = $1;
957 }
958 | DEC variable
959 {
960 goto pre;
961 }
962 | variable DEC
963 {
964 goto pos;
965 }
966 | constant
967 ;
968
969splitop : SPLIT
970 | TOKENS
971 ;
972constant : CONSTANT
973 {
974 $$ = exnewnode(expr.program, CONSTANT, false, $1->type, NULL, NULL);
975 if (!expr.program->disc->reff)
976 exerror("%s: identifier references not supported", $1->name);
977 else
978 $$->data.constant.value = expr.program->disc->reff(expr.program, $$, $1, NULL);
979 }
980 | FLOATING
981 {
983 $$->data.constant.value.floating = $1;
984 }
985 | INTEGER
986 {
988 $$->data.constant.value.integer = $1;
989 }
990 | STRING
991 {
993 $$->data.constant.value.string = $1;
994 }
995 | UNSIGNED
996 {
998 $$->data.constant.value.integer = $1;
999 }
1000 ;
1001
1002print : PRINTF
1003 | QUERY
1004 | SPRINTF
1005 ;
1006
1007scan : SCANF
1008 | SSCANF
1009 ;
1010
1011variable : ID members
1012 {
1013 $$ = makeVar(expr.program, $1, 0, 0, $2);
1014 }
1015 | DYNAMIC index members
1016 {
1017 Exnode_t *n = exnewnode(expr.program, DYNAMIC, false, $1->type, NULL, NULL);
1018 n->data.variable.symbol = $1;
1019 n->data.variable.reference = 0;
1020 if (((n->data.variable.index = $2) == 0) != ($1->local == NULL))
1021 exerror("%s: is%s an array", $1->name, $1->local != NULL ? "" : " not");
1022 if ($1->local != NULL && $1->index_type > 0) {
1023 if ($2->type != $1->index_type)
1024 exerror("%s: indices must have type %s, not %s",
1025 $1->name, extypename(expr.program, $1->index_type),extypename(expr.program, $2->type));
1026 }
1027 if ($3) {
1028 n->data.variable.dyna = exnewnode(expr.program, 0, false, 0, NULL, NULL);
1029 $$ = makeVar(expr.program, $1, $2, n, $3);
1030 }
1031 else $$ = n;
1032 }
1033 | NAME
1034 {
1035 $$ = exnewnode(expr.program, ID, false, STRING, NULL, NULL);
1036 $$->data.variable.symbol = $1;
1037 $$->data.variable.reference = 0;
1038 $$->data.variable.index = 0;
1039 $$->data.variable.dyna = 0;
1040 if (!(expr.program->disc->flags & EX_UNDECLARED))
1041 exerror("unknown identifier");
1042 }
1043 ;
1044
1045array : /* empty */
1046 {
1047 $$ = 0;
1048 }
1049 | '[' ']'
1050 {
1051 $$ = -1;
1052 }
1053 | '[' DECLARE ']'
1054 {
1055 /* If DECLARE is VOID, its type is 0, so this acts like
1056 * the empty case.
1057 */
1058 if (INTEGRAL($2->type))
1059 $$ = INTEGER;
1060 else
1061 $$ = $2->type;
1062
1063 }
1064 ;
1065
1066index : /* empty */
1067 {
1068 $$ = 0;
1069 }
1070 | '[' expr ']'
1071 {
1072 $$ = $2;
1073 }
1074 ;
1075
1076args : /* empty */
1077 {
1078 $$ = 0;
1079 }
1080 | arg_list
1081 {
1082 $$ = $1->data.operand.left;
1083 $1->data.operand.left = $1->data.operand.right = 0;
1085 }
1086 ;
1087
1088arg_list : expr %prec ','
1089 {
1090 $$ = exnewnode(expr.program, ',', true, 0, exnewnode(expr.program, ',', true, $1->type, $1, NULL), NULL);
1091 $$->data.operand.right = $$->data.operand.left;
1092 }
1093 | arg_list ',' expr
1094 {
1095 $1->data.operand.right = $1->data.operand.right->data.operand.right = exnewnode(expr.program, ',', true, $1->type, $3, NULL);
1096 }
1097 ;
1098
1099formals : /* empty */
1100 {
1101 $$ = 0;
1102 }
1103 | DECLARE
1104 {
1105 $$ = 0;
1106 if ($1->type)
1107 exerror("(void) expected");
1108 }
1109 | formal_list
1110 ;
1111
1112formal_list : formal_item
1113 {
1114 $$ = exnewnode(expr.program, ',', true, $1->type, $1, NULL);
1115 }
1116 | formal_list ',' formal_item
1117 {
1118 Exnode_t* x;
1119 Exnode_t* y;
1120
1121 $$ = $1;
1122 for (x = $1; (y = x->data.operand.right); x = y);
1123 x->data.operand.right = exnewnode(expr.program, ',', true, $3->type, $3, NULL);
1124 }
1125 ;
1126
1127formal_item : DECLARE {expr.declare=$1->type;} name
1128 {
1129 if ($1->type == 0) {
1130 exerror("%s: parameters to functions cannot be void typed", $3->name);
1131 }
1132 $$ = exnewnode(expr.program, ID, false, $1->type, NULL, NULL);
1133 $$->data.variable.symbol = $3;
1134 $3->lex = DYNAMIC;
1135 $3->type = $1->type;
1136 $3->value = exnewnode(expr.program, 0, false, 0, NULL, NULL);
1137 expr.procedure->data.procedure.arity++;
1138 expr.declare = 0;
1139 }
1140 ;
1141
1142members : /* empty */
1143 {
1144 $$ = expr.refs = 0;
1145 }
1146 | member
1147 {
1148 Exref_t* r;
1149
1150 r = ALLOCATE(expr.program, Exref_t);
1151 *r = (Exref_t){0};
1152 r->symbol = $1;
1153 expr.refs = r;
1154 r->next = 0;
1155 r->index = 0;
1156 $$ = expr.refs;
1157 }
1158 | '.' ID member
1159 {
1160 Exref_t* r;
1161 Exref_t* l;
1162
1163 r = ALLOCATE(expr.program, Exref_t);
1164 *r = (Exref_t){0};
1165 r->symbol = $3;
1166 r->index = 0;
1167 r->next = 0;
1168 l = ALLOCATE(expr.program, Exref_t);
1169 *l = (Exref_t){0};
1170 l->symbol = $2;
1171 l->index = 0;
1172 l->next = r;
1173 expr.refs = l;
1174 $$ = expr.refs;
1175 }
1176 ;
1177
1178member : '.' ID
1179 {
1180 $$ = $2;
1181 }
1182 | '.' NAME
1183 {
1184 $$ = $2;
1185 }
1186 ;
1187assign : /* empty */
1188 {
1189 $$ = 0;
1190 }
1191 | '=' expr
1192 {
1193 $$ = exnewnode(expr.program, '=', true, $2->type, NULL, $2);
1194 $$->subop = $1;
1195 }
1196 ;
1197
1198initialize : assign
1199 | '(' {
1200 if (expr.procedure)
1201 exerror("%s: nested function definitions not supported", expr.id->name);
1203 if (!streq(expr.id->name, "begin"))
1204 {
1205 static Dtdisc_t disc = {.key = offsetof(Exid_t, name)};
1206 if (!(expr.procedure->data.procedure.frame = dtopen(&disc, Dtset)) || !dtview(expr.procedure->data.procedure.frame, expr.program->symbols))
1207 exnospace();
1208 expr.program->symbols = expr.program->frame = expr.procedure->data.procedure.frame;
1209 }
1210 expr.declare = 0;
1211 } formals {
1212 expr.id->lex = PROCEDURE;
1214 expr.declare = 0;
1215 } ')' '{' statement_list '}'
1216 {
1217 $$ = expr.procedure;
1219 if (expr.program->frame)
1220 {
1221 expr.program->symbols = expr.program->frame->view;
1222 dtview(expr.program->frame, NULL);
1223 expr.program->frame = NULL;
1224 }
1225 // dictionary of locals no longer required, now that we have parsed the body
1226 (void)dtclose($$->data.procedure.frame);
1227 $$->data.procedure.frame = NULL;
1228 $$->data.procedure.args = $3;
1229 $$->data.procedure.body = excast(expr.program, $7, $$->type, NULL, 0);
1230
1231 /*
1232 * NOTE: procedure definition was slipped into the
1233 * declaration initializer statement production,
1234 * therefore requiring the statement terminator
1235 */
1236
1237 exunlex(expr.program, ';');
1238 }
1239 ;
1240
1241%%
1242
1243const char *exop(size_t index) {
1244
1245 /* yytname is generated by the %token-table directive */
1246
1247 /* find the index of MINTOKEN */
1248 size_t minid;
1249 for (minid = 0; yytname[minid] != NULL; ++minid) {
1250 if (strcmp(yytname[minid], "MINTOKEN") == 0) {
1251 break;
1252 }
1253 }
1254
1255 assert(yytname[minid] != NULL
1256 && "failed to find MINTOKEN; incorrect token list in exparse.y?");
1257
1258 /* find the requested token */
1259 {
1260 size_t i, j;
1261 for (i = j = minid; yytname[i] != NULL; ++i) {
1262
1263 /* if this token is not a word, skip it */
1264 {
1265 size_t k;
1266 for (k = 0; yytname[i][k] != '\0'; ++k) {
1267 if (yytname[i][k] != '_' && !gv_isalnum(yytname[i][k])) {
1268 break;
1269 }
1270 }
1271 if (yytname[i][k] != '\0') {
1272 continue;
1273 }
1274 }
1275
1276 if (j == index + minid) {
1277 return yytname[i];
1278 }
1279 ++j;
1280 }
1281 }
1282
1283 /* failed to find the requested token */
1284 return NULL;
1285}
1286
1287void ex_error(const char *message) {
1288 exerror("%s", message);
1289}
1290
1291#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:1878
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:1987
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:3590
#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:742
#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:3634
#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:356
#define NAME
Definition gmlparse.c:376
#define ID
Definition gmlparse.c:375
#define STRING
Definition gmlparse.c:374
#define INTEGER
Definition gmlparse.c:372
void free(void *)
alist $2
Definition gmlparse.y:283
glistitem $1
Definition gmlparse.y:238
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:40
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:32
static int table[NTYPES][NTYPES]
Definition mincross.c:1782
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:222
Vmalloc_t * vm
Definition expr.h:224
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
Exnode_t * left
Definition expr.h:122
Exnode_t * right
Definition expr.h:123
struct Exdata_u::@87 select
Exid_t * reference
Definition expr.h:117
Exnode_t * next
Definition expr.h:129
Exid_t * symbol
Definition expr.h:135
struct Exdata_u::@88 variable
struct Exdata_u::@86 operand
Exnode_t * dyna
Definition expr.h:138
Extype_t value
Definition expr.h:116
struct Exdata_u::@85 constant
Exnode_t * index
Definition expr.h:137
char * vmstrdup(Vmalloc_t *, const char *)
Definition vmstrdup.c:19