Graphviz 13.1.3~dev.20250815.1023
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 <stdalign.h>
31#include <stdbool.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <ast/ast.h>
36#include <util/arena.h>
37#include <util/gv_ctype.h>
38#include <util/streq.h>
39
40%}
41
42%union
43{
44 struct Exnode_s*expr;
45 double floating;
46 struct Exref_s* reference;
47 struct Exid_s* id;
48 long long integer;
49 int op;
50 char* string;
51}
52
53%start program
54
55%token MINTOKEN
56
57%token INTEGER
58%token UNSIGNED
59%token CHARACTER
60%token FLOATING
61%token STRING
62%token VOIDTYPE
63
64%token ADDRESS
65%token ARRAY
66%token BREAK
67%token CALL
68%token CASE
69%token CONSTANT
70%token CONTINUE
71%token DECLARE
72%token DEFAULT
73%token DYNAMIC
74%token ELSE
75%token EXIT
76%token FOR
77%token FUNCTION
78%token GSUB
79%token ITERATE
80%token ITERATOR
81%token ID
82%token IF
83%token LABEL
84%token MEMBER
85%token NAME
86%token POS
87%token PRAGMA
88%token PRE
89%token PRINT
90%token PRINTF
91%token PROCEDURE
92%token QUERY
93%token RAND
94%token RETURN
95%token SCANF
96%token SPLIT
97%token SPRINTF
98%token SRAND
99%token SSCANF
100%token SUB
101%token SUBSTR
102%token SWITCH
103%token TOKENS
104%token UNSET
105%token WHILE
106
107%token F2I
108%token F2S
109%token I2F
110%token I2S
111%token S2B
112%token S2F
113%token S2I
114
115%token F2X
116%token I2X
117%token S2X
118%token X2F
119%token X2I
120%token X2S
121%token X2X
122%token XPRINT
123
124%left <op> ','
125%right <op> '='
126%right <op> '?' ':'
127%left <op> OR
128%left <op> AND
129%left <op> '|'
130%left <op> '^'
131%left <op> '&'
132%binary <op> EQ NE
133%binary <op> '<' '>' LE GE
134%left <op> LSH RSH
135%left <op> '+' '-' IN_OP
136%left <op> '*' '/' '%'
137%right <op> '!' '~' '#' UNARY
138%right <op> INC DEC
139%right <op> CAST
140%left <op> '('
141
142%type <expr> statement statement_list arg_list
143%type <expr> else_opt expr_opt expr
144%type <expr> args variable assign
145%type <expr> dcl_list dcl_item index
146%type <expr> initialize switch_item constant
147%type <expr> formals formal_list formal_item
148%type <reference> members
149%type <id> ID LABEL NAME
151%type <id> EXIT PRINT PRINTF QUERY
152%type <id> RAND SRAND
153%type <id> SPRINTF PROCEDURE name dcl_name
154%type <id> GSUB SUB SUBSTR
155%type <id> SPLIT TOKENS splitop
156%type <id> IF WHILE FOR ITERATOR
157%type <id> BREAK CONTINUE print member
158%type <id> RETURN DYNAMIC SWITCH UNSET
159%type <id> SCANF SSCANF scan
160%type <floating> FLOATING
161%type <integer> INTEGER UNSIGNED array
162%type <string> STRING
163
164%token MAXTOKEN
165
166 /* ask Bison to generate a table, yytname, containing string representations
167 * of all the above tokens
168 */
169%token-table
170
171%{
172
173#include <expr/exgram.h>
174
175void ex_error(const char *message);
176
177%}
178
179%%
180
181program : statement_list action_list
182 {
183 if ($1) {
184 if (expr.program->main.value)
185 exfreenode(expr.program, expr.program->main.value);
186 if ($1->op == S2B)
187 {
188 Exnode_t *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 {
220 if (expr.program->frame)
221 {
222 expr.program->symbols = expr.program->frame->view;
223 dtview(expr.program->frame, NULL);
224 expr.program->frame = NULL;
225 }
226 if ($4 && $4->op == S2B)
227 {
228 Exnode_t *x = $4;
229 $4 = x->data.operand.left;
230 x->data.operand.left = 0;
232 }
233 $1->value->data.procedure.body = excast(expr.program, $4, $1->type, NULL, 0);
234 }
235 ;
236
237statement_list : /* empty */
238 {
239 $$ = 0;
240 }
242 {
243 if (!$1)
244 $$ = $2;
245 else if (!$2)
246 $$ = $1;
247 else if ($1->op == CONSTANT)
248 {
250 $$ = $2;
251 }
252 else $$ = exnewnode(expr.program, ';', true, $2->type, $1, $2);
253 }
254 ;
255
257 {
258 $$ = $2;
259 }
261 {
262 $$ = ($1 && $1->type == STRING) ? exnewnode(expr.program, S2B, true, INTEGER, $1, NULL) : $1;
263 }
264 | DECLARE {expr.declare = $1->type;} dcl_list ';'
265 {
266 $$ = $3;
268 }
269 | IF '(' expr ')' statement else_opt
270 {
271 if (exisAssign ($3))
272 exwarn ("assignment used as boolean in if statement");
273 if ($3->type == STRING)
274 $3 = exnewnode(expr.program, S2B, true, INTEGER, $3, NULL);
275 else if (!INTEGRAL($3->type))
277 $$ = exnewnode(expr.program, $1->index, true, INTEGER, $3, exnewnode(expr.program, ':', true, $5 ? $5->type : 0, $5, $6));
278 }
279 | FOR '(' variable ')' statement
280 {
282 $$->data.generate.array = $3;
283 if (!$3->data.variable.index || $3->data.variable.index->op != DYNAMIC)
284 exerror("simple index variable expected");
285 $$->data.generate.index = $3->data.variable.index->data.variable.symbol;
286 if ($3->op == ID && $$->data.generate.index->type != INTEGER)
287 exerror("integer index variable expected");
288 exfreenode(expr.program, $3->data.variable.index);
289 $3->data.variable.index = 0;
290 $$->data.generate.statement = $5;
291 }
292 | FOR '(' expr_opt ';' expr_opt ';' expr_opt ')' statement
293 {
294 if (!$5)
295 {
297 $5->data.constant.value.integer = 1;
298 }
299 else if ($5->type == STRING)
300 $5 = exnewnode(expr.program, S2B, true, INTEGER, $5, NULL);
301 else if (!INTEGRAL($5->type))
303 $$ = exnewnode(expr.program, $1->index, true, INTEGER, $5, exnewnode(expr.program, ';', 1, 0, $7, $9));
304 if ($3)
305 $$ = exnewnode(expr.program, ';', true, INTEGER, $3, $$);
306 }
307 | ITERATOR '(' variable ')' statement
308 {
310 $$->data.generate.array = $3;
311 if (!$3->data.variable.index || $3->data.variable.index->op != DYNAMIC)
312 exerror("simple index variable expected");
313 $$->data.generate.index = $3->data.variable.index->data.variable.symbol;
314 if ($3->op == ID && $$->data.generate.index->type != INTEGER)
315 exerror("integer index variable expected");
316 exfreenode(expr.program, $3->data.variable.index);
317 $3->data.variable.index = 0;
318 $$->data.generate.statement = $5;
319 }
320 | UNSET '(' DYNAMIC ')'
321 {
322 if ($3->local == NULL)
323 exerror("cannot apply unset to non-array %s", $3->name);
325 $$->data.variable.symbol = $3;
326 $$->data.variable.index = NULL;
327 }
328 | UNSET '(' DYNAMIC ',' expr ')'
329 {
330 if ($3->local == NULL)
331 exerror("cannot apply unset to non-array %s", $3->name);
332 if (($3->index_type > 0) && ($5->type != $3->index_type))
333 exerror("%s indices must have type %s, not %s",
334 $3->name, extypename(expr.program, $3->index_type),extypename(expr.program, $5->type));
336 $$->data.variable.symbol = $3;
337 $$->data.variable.index = $5;
338 }
339 | WHILE '(' expr ')' statement
340 {
341 if (exisAssign ($3))
342 exwarn ("assignment used as boolean in while statement");
343 if ($3->type == STRING)
344 $3 = exnewnode(expr.program, S2B, true, INTEGER, $3, NULL);
345 else if (!INTEGRAL($3->type))
347 $$ = exnewnode(expr.program, $1->index, true, INTEGER, $3, exnewnode(expr.program, ';', true, 0, NULL, $5));
348 }
349 | SWITCH '(' expr {expr.declare=$3->type;} ')' '{' switch_list '}'
350 {
351 Switch_t* sw = expr.swstate;
352
353 $$ = exnewnode(expr.program, $1->index, true, INTEGER, $3, exnewnode(expr.program, DEFAULT, true, 0, sw->defcase, sw->firstcase));
355 free(sw->base);
356 free(sw);
357 expr.declare = 0;
358 }
359 | BREAK expr_opt ';'
360 {
361 loopop:
362 if (!$2)
363 {
365 $2->data.constant.value.integer = 1;
366 }
367 else if (!INTEGRAL($2->type))
369 $$ = exnewnode(expr.program, $1->index, true, INTEGER, $2, NULL);
370 }
371 | CONTINUE expr_opt ';'
372 {
373 goto loopop;
374 }
375 | RETURN expr_opt ';'
376 {
377 if ($2)
378 {
380 exerror("return in void function");
382 }
383 $$ = exnewnode(expr.program, RETURN, true, $2 ? $2->type : 0, $2, NULL);
384 }
385 ;
386
387switch_list : /* empty */
388 {
389 Switch_t* sw;
390
391 if (!(sw = calloc(1, sizeof(Switch_t)))) {
392 exnospace();
393 } else {
394 expr.swstate = sw;
395 sw->type = expr.declare;
396 size_t n = 8;
397 if (!(sw->base = calloc(n, sizeof(Extype_t*)))) {
398 exnospace();
399 n = 0;
400 }
401 sw->cap = n;
402 }
403 }
404 | switch_list switch_item
405 ;
406
407switch_item : case_list statement_list
408 {
409 Switch_t* sw = expr.swstate;
410
411 $$ = exnewnode(expr.program, CASE, true, 0, $2, NULL);
412 if (sw->cur > 0)
413 {
414 if (sw->lastcase)
415 sw->lastcase->data.select.next = $$;
416 else
417 sw->firstcase = $$;
418 sw->lastcase = $$;
419 const size_t n = sw->cap;
420 sw->cur = 0;
421 $$->data.select.constant = gv_arena_alloc(&expr.program->vm,
422 alignof(Extype_t *),
423 (n + 1) * sizeof(Extype_t*));
424 memcpy($$->data.select.constant, sw->base, n * sizeof(Extype_t*));
425 }
426 else
427 $$->data.select.constant = 0;
428 if (sw->def)
429 {
430 sw->def = 0;
431 if (sw->defcase)
432 exerror("duplicate default in switch");
433 else
434 sw->defcase = $2;
435 }
436 }
437 ;
438
439case_list : case_item
440 | case_list case_item
441 ;
442
443case_item : CASE constant ':'
444 {
445 if (expr.swstate->cur >= expr.swstate->cap)
446 {
447 size_t n = expr.swstate->cap;
448 if (!(expr.swstate->base = realloc(expr.swstate->base, sizeof(Extype_t*) * 2 * n)))
449 {
450 exerror("too many case labels for switch");
451 n = 0;
452 }
453 expr.swstate->cap = 2 * n;
454 }
455 if (expr.swstate->base != NULL)
456 {
458 expr.swstate->base[expr.swstate->cur++] = &$2->data.constant.value;
459 }
460 }
461 | DEFAULT ':'
462 {
463 expr.swstate->def = 1;
464 }
465 ;
466
467dcl_list : dcl_item
468 | dcl_list ',' dcl_item
469 {
470 if ($3)
471 $$ = $1 ? exnewnode(expr.program, ',', true, $3->type, $1, $3) : $3;
472 }
473 ;
474
475dcl_item : dcl_name {checkName ($1); expr.id=$1;} array initialize
476 {
477 $$ = 0;
478 if (!$1->type || expr.declare)
479 $1->type = expr.declare;
480 if ($4 && $4->op == PROCEDURE)
481 {
482 $1->lex = PROCEDURE;
483 $1->type = $4->type;
484 $1->value = $4;
485 }
486 else
487 {
488 if ($1->type == 0) {
489 exerror("%s: a variable cannot be void typed", $1->name);
490 }
491 $1->lex = DYNAMIC;
492 $1->value = exnewnode(expr.program, 0, false, 0, NULL, NULL);
493 if ($3 && $1->local == NULL)
494 {
495 static Dtdisc_t disc_key = {
496 .key = offsetof(Exassoc_t, key),
497 .size = sizeof(Extype_t),
498 .comparf = cmpKey,
499 };
500 static Dtdisc_t disc_name = {.key = offsetof(Exassoc_t, name)};
501 Dtdisc_t *const disc = $3 == INTEGER ? &disc_key : &disc_name;
502 if (!($1->local = dtopen(disc, Dtoset)))
503 exerror("%s: cannot initialize associative array", $1->name);
504 $1->index_type = $3; /* -1 indicates no typechecking */
505 }
506 if ($4)
507 {
508 if ($4->type != $1->type)
509 {
510 $4->type = $1->type;
511 $4->data.operand.right = excast(expr.program, $4->data.operand.right, $1->type, NULL, 0);
512 }
513 $4->data.operand.left = exnewnode(expr.program, DYNAMIC, false, $1->type, NULL, NULL);
514 $4->data.operand.left->data.variable.symbol = $1;
515 $$ = $4;
516 }
517 else if (!$3)
518 $1->value->data.value = exzero($1->type);
519 }
520 }
521 ;
522
523dcl_name : NAME
524 | DYNAMIC
525 | ID
526 | FUNCTION
527 ;
528
529name : NAME
530 | DYNAMIC
531 ;
532
533else_opt : /* empty */
534 {
535 $$ = 0;
536 }
538 {
539 $$ = $2;
540 }
541 ;
542
543expr_opt : /* empty */
544 {
545 $$ = 0;
546 }
547 | expr
548 ;
549
550expr : '(' expr ')'
551 {
552 $$ = $2;
553 }
554 | '(' DECLARE ')' expr %prec CAST
555 {
556 $$ = ($4->type == $2->type) ? $4 : excast(expr.program, $4, $2->type, NULL, 0);
557 }
558 | expr '<' expr
559 {
560 long rel;
561
562 relational:
563 rel = INTEGER;
564 goto coerce;
565 binary:
566 rel = 0;
567 coerce:
568 if (!$1->type)
569 {
570 if (!$3->type)
571 $1->type = $3->type = rel ? STRING : INTEGER;
572 else
573 $1->type = $3->type;
574 }
575 else if (!$3->type)
576 $3->type = $1->type;
577 if ($1->type != $3->type)
578 {
579 if ($1->type == STRING)
580 $1 = excast(expr.program, $1, $3->type, $3, 0);
581 else if ($3->type == STRING)
582 $3 = excast(expr.program, $3, $1->type, $1, 0);
583 else if ($1->type == FLOATING)
584 $3 = excast(expr.program, $3, FLOATING, $1, 0);
585 else if ($3->type == FLOATING)
586 $1 = excast(expr.program, $1, FLOATING, $3, 0);
587 }
588 if (!rel)
589 rel = ($1->type == STRING) ? STRING : (($1->type == UNSIGNED) ? UNSIGNED : $3->type);
590 $$ = exnewnode(expr.program, $2, true, rel, $1, $3);
591 if (!expr.program->errors && $1->op == CONSTANT && $3->op == CONSTANT)
592 {
593 $$->data.constant.value = exeval(expr.program, $$, NULL);
594 /* If a constant string, re-allocate from program heap. This is because the
595 * value was constructed from string operators, which create a value in the
596 * temporary heap, which is cleared when exeval is called again.
597 */
598 if ($$->type == STRING) {
599 $$->data.constant.value.string =
600 gv_arena_strdup(&expr.program->vm, $$->data.constant.value.string);
601 }
602 $$->binary = false;
603 $$->op = CONSTANT;
606 }
607 else if (!BUILTIN($1->type) || !BUILTIN($3->type)) {
608 checkBinary(expr.program, $1, $$, $3);
609 }
610 }
611 | expr '-' expr
612 {
613 goto binary;
614 }
615 | expr '*' expr
616 {
617 goto binary;
618 }
619 | expr '/' expr
620 {
621 goto binary;
622 }
623 | expr '%' expr
624 {
625 goto binary;
626 }
627 | expr LSH expr
628 {
629 goto binary;
630 }
631 | expr RSH expr
632 {
633 goto binary;
634 }
635 | expr '>' expr
636 {
637 goto relational;
638 }
639 | expr LE expr
640 {
641 goto relational;
642 }
643 | expr GE expr
644 {
645 goto relational;
646 }
647 | expr EQ expr
648 {
649 goto relational;
650 }
651 | expr NE expr
652 {
653 goto relational;
654 }
655 | expr '&' expr
656 {
657 goto binary;
658 }
659 | expr '|' expr
660 {
661 goto binary;
662 }
663 | expr '^' expr
664 {
665 goto binary;
666 }
667 | expr '+' expr
668 {
669 goto binary;
670 }
671 | expr AND expr
672 {
673 logical:
674 if ($1->type == STRING)
675 $1 = exnewnode(expr.program, S2B, true, INTEGER, $1, NULL);
676 else if (!BUILTIN($1->type))
678 if ($3->type == STRING)
679 $3 = exnewnode(expr.program, S2B, true, INTEGER, $3, NULL);
680 else if (!BUILTIN($3->type))
682 goto binary;
683 }
684 | expr OR expr
685 {
686 goto logical;
687 }
688 | expr ',' expr
689 {
690 if ($1->op == CONSTANT)
691 {
693 $$ = $3;
694 }
695 else
696 $$ = exnewnode(expr.program, ',', true, $3->type, $1, $3);
697 }
698 | expr '?' {expr.nolabel=1;} expr ':' {expr.nolabel=0;} expr
699 {
700 if (!$4->type)
701 {
702 if (!$7->type)
703 $4->type = $7->type = INTEGER;
704 else
705 $4->type = $7->type;
706 }
707 else if (!$7->type)
708 $7->type = $4->type;
709 if ($1->type == STRING)
710 $1 = exnewnode(expr.program, S2B, true, INTEGER, $1, NULL);
711 else if (!INTEGRAL($1->type))
713 if ($4->type != $7->type)
714 {
715 if ($4->type == STRING || $7->type == STRING)
716 exerror("if statement string type mismatch");
717 else if ($4->type == FLOATING)
718 $7 = excast(expr.program, $7, FLOATING, NULL, 0);
719 else if ($7->type == FLOATING)
720 $4 = excast(expr.program, $4, FLOATING, NULL, 0);
721 }
722 if ($1->op == CONSTANT)
723 {
724 if ($1->data.constant.value.integer)
725 {
726 $$ = $4;
728 }
729 else
730 {
731 $$ = $7;
733 }
735 }
736 else
737 $$ = exnewnode(expr.program, '?', true, $4->type, $1, exnewnode(expr.program, ':', true, $4->type, $4, $7));
738 }
739 | '!' expr
740 {
741 iunary:
742 if ($2->type == STRING)
743 $2 = exnewnode(expr.program, S2B, true, INTEGER, $2, NULL);
744 else if (!INTEGRAL($2->type))
746 unary:
747 $$ = exnewnode(expr.program, $1, true, $2->type == UNSIGNED ? INTEGER : $2->type, $2, NULL);
748 if ($2->op == CONSTANT)
749 {
751 $$->binary = false;
752 $$->op = CONSTANT;
754 }
755 else if (!BUILTIN($2->type)) {
756 checkBinary(expr.program, $2, $$, 0);
757 }
758 }
759 | '#' DYNAMIC
760 {
761 if ($2->local == NULL)
762 exerror("cannot apply '#' operator to non-array %s", $2->name);
763 $$ = exnewnode(expr.program, '#', false, INTEGER, NULL, NULL);
764 $$->data.variable.symbol = $2;
765 }
766 | '#' ARRAY
767 {
768 $$ = exnewnode(expr.program, '#', false, INTEGER, NULL, NULL);
769 $$->data.variable.symbol = $2;
770 }
771 | '~' expr
772 {
773 goto iunary;
774 }
775 | '-' expr %prec UNARY
776 {
777 goto unary;
778 }
779 | '+' expr %prec UNARY
780 {
781 $$ = $2;
782 }
783 | '&' variable %prec UNARY
784 {
785 $$ = exnewnode(expr.program, ADDRESS, false, T($2->type), $2, NULL);
786 }
787 | ARRAY '[' args ']'
788 {
789 $$ = exnewnode(expr.program, ARRAY, true, T($1->type), call(0, $1, $3), $3);
790 }
791 | FUNCTION '(' args ')'
792 {
793 $$ = exnewnode(expr.program, FUNCTION, true, T($1->type), call(0, $1, $3), $3);
794 }
795 | GSUB '(' args ')'
796 {
797 $$ = exnewsub (expr.program, $3, GSUB);
798 }
799 | SUB '(' args ')'
800 {
801 $$ = exnewsub (expr.program, $3, SUB);
802 }
803 | SUBSTR '(' args ')'
804 {
805 $$ = exnewsubstr (expr.program, $3);
806 }
807 | splitop '(' expr ',' DYNAMIC ')'
808 {
809 $$ = exnewsplit (expr.program, $1->index, $5, $3, NULL);
810 }
811 | splitop '(' expr ',' DYNAMIC ',' expr ')'
812 {
813 $$ = exnewsplit (expr.program, $1->index, $5, $3, $7);
814 }
815 | EXIT '(' expr ')'
816 {
817 if (!INTEGRAL($3->type))
819 $$ = exnewnode(expr.program, EXIT, true, INTEGER, $3, NULL);
820 }
821 | RAND '(' ')'
822 {
824 }
825 | SRAND '(' ')'
826 {
828 }
829 | SRAND '(' expr ')'
830 {
831 if (!INTEGRAL($3->type))
834 }
835 | PROCEDURE '(' args ')'
836 {
837 $$ = exnewnode(expr.program, CALL, true, $1->type, NULL, $3);
838 $$->data.call.procedure = $1;
839 }
840 | PRINT '(' args ')'
841 {
842 $$ = exprint(expr.program, $1, $3);
843 }
844 | print '(' args ')'
845 {
846 $$ = exnewnode(expr.program, $1->index, false, $1->type, NULL, NULL);
847 if ($3 && $3->data.operand.left->type == INTEGER)
848 {
849 $$->data.print.descriptor = $3->data.operand.left;
850 $3 = $3->data.operand.right;
851 }
852 else
853 switch ($1->index)
854 {
855 case QUERY:
856 $$->data.print.descriptor = exnewnode(expr.program, CONSTANT, false, INTEGER, NULL, NULL);
857 $$->data.print.descriptor->data.constant.value.integer = 2;
858 break;
859 case PRINTF:
860 $$->data.print.descriptor = exnewnode(expr.program, CONSTANT, false, INTEGER, NULL, NULL);
861 $$->data.print.descriptor->data.constant.value.integer = 1;
862 break;
863 case SPRINTF:
864 $$->data.print.descriptor = 0;
865 break;
866 }
867 $$->data.print.args = preprint($3);
868 }
869 | scan '(' args ')'
870 {
871 Exnode_t* x;
872
873 $$ = exnewnode(expr.program, $1->index, false, $1->type, NULL, NULL);
874 if ($3 && $3->data.operand.left->type == INTEGER)
875 {
876 $$->data.scan.descriptor = $3->data.operand.left;
877 $3 = $3->data.operand.right;
878 }
879 else
880 switch ($1->index)
881 {
882 case SCANF:
883 $$->data.scan.descriptor = 0;
884 break;
885 case SSCANF:
886 if ($3 && $3->data.operand.left->type == STRING)
887 {
888 $$->data.scan.descriptor = $3->data.operand.left;
889 $3 = $3->data.operand.right;
890 }
891 else
892 exerror("%s: string argument expected", $1->name);
893 break;
894 }
895 if (!$3 || !$3->data.operand.left || $3->data.operand.left->type != STRING)
896 exerror("%s: format argument expected", $1->name);
897 $$->data.scan.format = $3->data.operand.left;
898 for (x = $$->data.scan.args = $3->data.operand.right; x; x = x->data.operand.right)
899 {
900 if (x->data.operand.left->op != ADDRESS)
901 exerror("%s: address argument expected", $1->name);
903 }
904 }
905 | variable assign
906 {
907 if ($2)
908 {
909 if ($1->op == ID && !expr.program->disc->setf)
910 exerror("%s: variable assignment not supported", $1->data.variable.symbol->name);
911 else
912 {
913 if (!$1->type)
914 $1->type = $2->type;
915 else if ($2->type != $1->type)
916 {
917 $2->type = $1->type;
918 $2->data.operand.right = excast(expr.program, $2->data.operand.right, $1->type, NULL, 0);
919 }
920 $2->data.operand.left = $1;
921 $$ = $2;
922 }
923 }
924 }
925 | INC variable
926 {
927 pre:
928 if ($2->type == STRING)
929 exerror("++ and -- invalid for string variables");
930 $$ = exnewnode(expr.program, $1, false, $2->type, $2, NULL);
931 $$->subop = PRE;
932 }
933 | variable INC
934 {
935 pos:
936 if ($1->type == STRING)
937 exerror("++ and -- invalid for string variables");
938 $$ = exnewnode(expr.program, $2, false, $1->type, $1, NULL);
939 $$->subop = POS;
940 }
942 {
943 if ($3->local == NULL)
944 exerror("cannot apply IN to non-array %s", $3->name);
945 if ($3->index_type > 0 && $1->type != $3->index_type)
946 exerror("%s indices must have type %s, not %s",
947 $3->name, extypename(expr.program, $3->index_type),extypename(expr.program, $1->type));
949 $$->data.variable.symbol = $3;
950 $$->data.variable.index = $1;
951 }
953 {
954 if ($3->index_type > 0 && $1->type != $3->index_type)
955 exerror("%s indices must have type %s, not %s",
956 $3->name, extypename(expr.program, $3->index_type),extypename(expr.program, $1->type));
958 $$->data.variable.symbol = $3;
959 $$->data.variable.index = $1;
960 }
961 | DEC variable
962 {
963 goto pre;
964 }
965 | variable DEC
966 {
967 goto pos;
968 }
969 | constant
970 ;
971
972splitop : SPLIT
973 | TOKENS
974 ;
975constant : CONSTANT
976 {
977 $$ = exnewnode(expr.program, CONSTANT, false, $1->type, NULL, NULL);
978 if (!expr.program->disc->reff)
979 exerror("%s: identifier references not supported", $1->name);
980 else
981 $$->data.constant.value = expr.program->disc->reff(expr.program, $$, $1, NULL);
982 }
983 | FLOATING
984 {
986 $$->data.constant.value.floating = $1;
987 }
988 | INTEGER
989 {
991 $$->data.constant.value.integer = $1;
992 }
993 | STRING
994 {
996 $$->data.constant.value.string = $1;
997 }
998 | UNSIGNED
999 {
1001 $$->data.constant.value.integer = $1;
1002 }
1003 ;
1004
1005print : PRINTF
1006 | QUERY
1007 | SPRINTF
1008 ;
1009
1010scan : SCANF
1011 | SSCANF
1012 ;
1013
1014variable : ID members
1015 {
1016 $$ = makeVar(expr.program, $1, 0, 0, $2);
1017 }
1018 | DYNAMIC index members
1019 {
1020 Exnode_t *n = exnewnode(expr.program, DYNAMIC, false, $1->type, NULL, NULL);
1021 n->data.variable.symbol = $1;
1022 n->data.variable.reference = 0;
1023 if (((n->data.variable.index = $2) == 0) != ($1->local == NULL))
1024 exerror("%s: is%s an array", $1->name, $1->local != NULL ? "" : " not");
1025 if ($1->local != NULL && $1->index_type > 0) {
1026 if ($2->type != $1->index_type)
1027 exerror("%s: indices must have type %s, not %s",
1028 $1->name, extypename(expr.program, $1->index_type),extypename(expr.program, $2->type));
1029 }
1030 if ($3) {
1031 n->data.variable.dyna = exnewnode(expr.program, 0, false, 0, NULL, NULL);
1032 $$ = makeVar(expr.program, $1, $2, n, $3);
1033 }
1034 else $$ = n;
1035 }
1036 | NAME
1037 {
1038 $$ = exnewnode(expr.program, ID, false, STRING, NULL, NULL);
1039 $$->data.variable.symbol = $1;
1040 $$->data.variable.reference = 0;
1041 $$->data.variable.index = 0;
1042 $$->data.variable.dyna = 0;
1043 if (!(expr.program->disc->flags & EX_UNDECLARED))
1044 exerror("unknown identifier");
1045 }
1046 ;
1047
1048array : /* empty */
1049 {
1050 $$ = 0;
1051 }
1052 | '[' ']'
1053 {
1054 $$ = -1;
1055 }
1056 | '[' DECLARE ']'
1057 {
1058 /* If DECLARE is VOID, its type is 0, so this acts like
1059 * the empty case.
1060 */
1061 if (INTEGRAL($2->type))
1062 $$ = INTEGER;
1063 else
1064 $$ = $2->type;
1065
1066 }
1067 ;
1068
1069index : /* empty */
1070 {
1071 $$ = 0;
1072 }
1073 | '[' expr ']'
1074 {
1075 $$ = $2;
1076 }
1077 ;
1078
1079args : /* empty */
1080 {
1081 $$ = 0;
1082 }
1083 | arg_list
1084 {
1085 $$ = $1->data.operand.left;
1086 $1->data.operand.left = $1->data.operand.right = 0;
1088 }
1089 ;
1090
1091arg_list : expr %prec ','
1092 {
1093 $$ = exnewnode(expr.program, ',', true, 0, exnewnode(expr.program, ',', true, $1->type, $1, NULL), NULL);
1094 $$->data.operand.right = $$->data.operand.left;
1095 }
1096 | arg_list ',' expr
1097 {
1098 $1->data.operand.right = $1->data.operand.right->data.operand.right = exnewnode(expr.program, ',', true, $1->type, $3, NULL);
1099 }
1100 ;
1101
1102formals : /* empty */
1103 {
1104 $$ = 0;
1105 }
1106 | DECLARE
1107 {
1108 $$ = 0;
1109 if ($1->type)
1110 exerror("(void) expected");
1111 }
1112 | formal_list
1113 ;
1114
1115formal_list : formal_item
1116 {
1117 $$ = exnewnode(expr.program, ',', true, $1->type, $1, NULL);
1118 }
1119 | formal_list ',' formal_item
1120 {
1121 Exnode_t* x;
1122 Exnode_t* y;
1123
1124 $$ = $1;
1125 for (x = $1; (y = x->data.operand.right); x = y);
1126 x->data.operand.right = exnewnode(expr.program, ',', true, $3->type, $3, NULL);
1127 }
1128 ;
1129
1130formal_item : DECLARE {expr.declare=$1->type;} name
1131 {
1132 if ($1->type == 0) {
1133 exerror("%s: parameters to functions cannot be void typed", $3->name);
1134 }
1135 $$ = exnewnode(expr.program, ID, false, $1->type, NULL, NULL);
1136 $$->data.variable.symbol = $3;
1137 $3->lex = DYNAMIC;
1138 $3->type = $1->type;
1139 $3->value = exnewnode(expr.program, 0, false, 0, NULL, NULL);
1140 expr.procedure->data.procedure.arity++;
1141 expr.declare = 0;
1142 }
1143 ;
1144
1145members : /* empty */
1146 {
1147 $$ = expr.refs = 0;
1148 }
1149 | member
1150 {
1151 Exref_t* r;
1152
1154 r->symbol = $1;
1155 expr.refs = r;
1156 r->next = 0;
1157 r->index = 0;
1158 $$ = expr.refs;
1159 }
1160 | '.' ID member
1161 {
1162 Exref_t* r;
1163 Exref_t* l;
1164
1166 r->symbol = $3;
1167 r->index = 0;
1168 r->next = 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>
void * gv_arena_alloc(arena_t *arena, size_t alignment, size_t size)
Definition arena.c:116
char * gv_arena_strdup(arena_t *arena, const char *s)
Definition arena.c:134
Region-based memory allocator.
#define ARENA_NEW(arena, type)
Definition arena.h:55
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:1808
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:1935
Exstate_t expr
#define exunlex(p, c)
Definition exlib.h:126
char * exnospace(void)
Definition exnospace.c:25
const char * exop(size_t id)
Definition exparse.c:3270
static const char *const yytname[]
Definition exparse.c:708
void ex_error(const char *message)
Definition exparse.c:3314
#define UNSIGNED
Definition exparse.h:153
#define ELSE
Definition exparse.h:168
#define CHARACTER
Definition exparse.h:154
#define DYNAMIC
Definition exparse.h:167
#define SCANF
Definition exparse.h:189
#define F2S
Definition exparse.h:201
#define SSCANF
Definition exparse.h:193
#define RSH
Definition exparse.h:222
#define ADDRESS
Definition exparse.h:158
#define OR
Definition exparse.h:215
#define PRE
Definition exparse.h:182
#define GE
Definition exparse.h:220
#define MINTOKEN
Definition exparse.h:151
#define DEFAULT
Definition exparse.h:166
#define X2F
Definition exparse.h:210
#define S2X
Definition exparse.h:209
#define WHILE
Definition exparse.h:199
#define ITERATE
Definition exparse.h:173
#define MAXTOKEN
Definition exparse.h:228
#define NE
Definition exparse.h:218
#define SRAND
Definition exparse.h:192
#define S2I
Definition exparse.h:206
#define SUB
Definition exparse.h:194
#define POS
Definition exparse.h:180
#define LSH
Definition exparse.h:221
#define FLOATING
Definition exparse.h:155
#define FOR
Definition exparse.h:170
#define I2X
Definition exparse.h:208
#define IN_OP
Definition exparse.h:223
#define SUBSTR
Definition exparse.h:195
#define TOKENS
Definition exparse.h:197
#define ITERATOR
Definition exparse.h:174
#define VOIDTYPE
Definition exparse.h:157
#define RAND
Definition exparse.h:187
#define PRINT
Definition exparse.h:183
#define CAST
Definition exparse.h:227
#define I2F
Definition exparse.h:202
#define SPRINTF
Definition exparse.h:191
#define I2S
Definition exparse.h:203
#define CONSTANT
Definition exparse.h:163
#define LE
Definition exparse.h:219
#define MEMBER
Definition exparse.h:178
#define S2B
Definition exparse.h:204
#define CALL
Definition exparse.h:161
#define GSUB
Definition exparse.h:172
#define PRAGMA
Definition exparse.h:181
#define UNARY
Definition exparse.h:224
#define UNSET
Definition exparse.h:198
#define CONTINUE
Definition exparse.h:164
#define XPRINT
Definition exparse.h:214
#define F2I
Definition exparse.h:200
#define X2S
Definition exparse.h:212
#define SPLIT
Definition exparse.h:190
#define EQ
Definition exparse.h:217
#define BREAK
Definition exparse.h:160
#define S2F
Definition exparse.h:205
#define IF
Definition exparse.h:176
#define PROCEDURE
Definition exparse.h:185
#define SWITCH
Definition exparse.h:196
#define AND
Definition exparse.h:216
#define X2X
Definition exparse.h:213
#define EXIT
Definition exparse.h:169
#define F2X
Definition exparse.h:207
#define X2I
Definition exparse.h:211
#define PRINTF
Definition exparse.h:184
#define QUERY
Definition exparse.h:186
#define FUNCTION
Definition exparse.h:171
#define CASE
Definition exparse.h:162
#define ARRAY
Definition exparse.h:159
#define INC
Definition exparse.h:225
#define DEC
Definition exparse.h:226
else $$
Definition exparse.y:252
dcl_list
Definition exparse.y:264
expr_opt
Definition exparse.y:260
statement_list
Definition exparse.y:218
DECLARE
Definition exparse.y:264
statement_list statement
Definition exparse.y:242
static Dtdisc_t disc
Definition exparse.y:209
expr procedure type
Definition exparse.y:208
int exisAssign(Exnode_t *)
EX_STYPE Extype_t
Definition expr.h:79
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
void free(void *)
#define LABEL
Definition gmlparse.h:115
#define NAME
Definition gmlparse.h:135
#define ID
Definition gmlparse.h:134
#define STRING
Definition gmlparse.h:133
#define INTEGER
Definition gmlparse.h:131
alist $2
Definition gmlparse.y:283
glistitem $1
Definition gmlparse.y:238
atom $5
Definition grammar.y:183
node NULL
Definition grammar.y:181
hdr $3
Definition grammar.y:149
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:44
char * pre
Definition maze.c:32
static int table[NTYPES][NTYPES]
Definition mincross.c:1790
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:91
long type
Definition expr.h:95
long lex
Definition expr.h:93
char name[EX_NAMELEN]
Definition expr.h:99
long index
Definition expr.h:94
long op
operator
Definition expr.h:148
double(* floating)(char **)
Definition expr.h:152
long type
value type
Definition expr.h:147
Exdata_t data
Definition expr.h:156
arena_t vm
Definition expr.h:222
Dt_t * symbols
Definition expr.h:220
Exid_t * symbol
Definition expr.h:105
Exref_t * next
Definition expr.h:104
Exnode_t * index
Definition expr.h:106
int assigned
Definition exlib.h:160
Expr_t * program
Definition exlib.h:157
Switch_t * swstate
Definition exlib.h:161
Exid_t * id
Definition exlib.h:153
Exref_t * refs
Definition exlib.h:159
long declare
current declaration type
Definition exlib.h:154
int nolabel
Definition exlib.h:155
Exnode_t * procedure
Definition exlib.h:158
size_t cap
Definition exlib.h:138
int def
Definition exlib.h:139
Exnode_t * defcase
Definition exlib.h:135
struct Switch_s * prev
Definition exlib.h:132
long type
switch test type
Definition exlib.h:140
Exnode_t * lastcase
Definition exlib.h:134
size_t cur
Definition exlib.h:137
Extype_t ** base
Definition exlib.h:136
Exnode_t * firstcase
Definition exlib.h:133
int key
Definition cdt.h:85
static mytime_t T
Definition timing.c:41
Exnode_t * left
Definition expr.h:120
Exnode_t * right
Definition expr.h:121
Exid_t * reference
Definition expr.h:115
Exnode_t * next
Definition expr.h:127
struct Exdata_u::@94 select
struct Exdata_u::@93 operand
Exid_t * symbol
Definition expr.h:133
struct Exdata_u::@95 variable
Exnode_t * dyna
Definition expr.h:136
struct Exdata_u::@92 constant
Extype_t value
Definition expr.h:114
Exnode_t * index
Definition expr.h:135