Graphviz 13.0.0~dev.20250607.1528
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 .freef = free,
496 .comparf = cmpKey,
497 };
498 static Dtdisc_t disc_name = {
499 .key = offsetof(Exassoc_t, name),
500 .freef = free,
501 };
502 Dtdisc_t *const disc = $3 == INTEGER ? &disc_key : &disc_name;
503 if (!($1->local = dtopen(disc, Dtoset)))
504 exerror("%s: cannot initialize associative array", $1->name);
505 $1->index_type = $3; /* -1 indicates no typechecking */
506 }
507 if ($4)
508 {
509 if ($4->type != $1->type)
510 {
511 $4->type = $1->type;
512 $4->data.operand.right = excast(expr.program, $4->data.operand.right, $1->type, NULL, 0);
513 }
514 $4->data.operand.left = exnewnode(expr.program, DYNAMIC, false, $1->type, NULL, NULL);
515 $4->data.operand.left->data.variable.symbol = $1;
516 $$ = $4;
517 }
518 else if (!$3)
519 $1->value->data.value = exzero($1->type);
520 }
521 }
522 ;
523
524dcl_name : NAME
525 | DYNAMIC
526 | ID
527 | FUNCTION
528 ;
529
530name : NAME
531 | DYNAMIC
532 ;
533
534else_opt : /* empty */
535 {
536 $$ = 0;
537 }
539 {
540 $$ = $2;
541 }
542 ;
543
544expr_opt : /* empty */
545 {
546 $$ = 0;
547 }
548 | expr
549 ;
550
551expr : '(' expr ')'
552 {
553 $$ = $2;
554 }
555 | '(' DECLARE ')' expr %prec CAST
556 {
557 $$ = ($4->type == $2->type) ? $4 : excast(expr.program, $4, $2->type, NULL, 0);
558 }
559 | expr '<' expr
560 {
561 long rel;
562
563 relational:
564 rel = INTEGER;
565 goto coerce;
566 binary:
567 rel = 0;
568 coerce:
569 if (!$1->type)
570 {
571 if (!$3->type)
572 $1->type = $3->type = rel ? STRING : INTEGER;
573 else
574 $1->type = $3->type;
575 }
576 else if (!$3->type)
577 $3->type = $1->type;
578 if ($1->type != $3->type)
579 {
580 if ($1->type == STRING)
581 $1 = excast(expr.program, $1, $3->type, $3, 0);
582 else if ($3->type == STRING)
583 $3 = excast(expr.program, $3, $1->type, $1, 0);
584 else if ($1->type == FLOATING)
585 $3 = excast(expr.program, $3, FLOATING, $1, 0);
586 else if ($3->type == FLOATING)
587 $1 = excast(expr.program, $1, FLOATING, $3, 0);
588 }
589 if (!rel)
590 rel = ($1->type == STRING) ? STRING : (($1->type == UNSIGNED) ? UNSIGNED : $3->type);
591 $$ = exnewnode(expr.program, $2, true, rel, $1, $3);
592 if (!expr.program->errors && $1->op == CONSTANT && $3->op == CONSTANT)
593 {
594 $$->data.constant.value = exeval(expr.program, $$, NULL);
595 /* If a constant string, re-allocate from program heap. This is because the
596 * value was constructed from string operators, which create a value in the
597 * temporary heap, which is cleared when exeval is called again.
598 */
599 if ($$->type == STRING) {
600 $$->data.constant.value.string =
601 vmstrdup(expr.program->vm, $$->data.constant.value.string);
602 }
603 $$->binary = false;
604 $$->op = CONSTANT;
607 }
608 else if (!BUILTIN($1->type) || !BUILTIN($3->type)) {
609 checkBinary(expr.program, $1, $$, $3);
610 }
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 '%' expr
625 {
626 goto binary;
627 }
628 | expr LSH expr
629 {
630 goto binary;
631 }
632 | expr RSH expr
633 {
634 goto binary;
635 }
636 | expr '>' expr
637 {
638 goto relational;
639 }
640 | expr LE expr
641 {
642 goto relational;
643 }
644 | expr GE expr
645 {
646 goto relational;
647 }
648 | expr EQ expr
649 {
650 goto relational;
651 }
652 | expr NE expr
653 {
654 goto relational;
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 '+' expr
669 {
670 goto binary;
671 }
672 | expr AND expr
673 {
674 logical:
675 if ($1->type == STRING)
676 $1 = exnewnode(expr.program, S2B, true, INTEGER, $1, NULL);
677 else if (!BUILTIN($1->type))
679 if ($3->type == STRING)
680 $3 = exnewnode(expr.program, S2B, true, INTEGER, $3, NULL);
681 else if (!BUILTIN($3->type))
683 goto binary;
684 }
685 | expr OR expr
686 {
687 goto logical;
688 }
689 | expr ',' expr
690 {
691 if ($1->op == CONSTANT)
692 {
694 $$ = $3;
695 }
696 else
697 $$ = exnewnode(expr.program, ',', true, $3->type, $1, $3);
698 }
699 | expr '?' {expr.nolabel=1;} expr ':' {expr.nolabel=0;} expr
700 {
701 if (!$4->type)
702 {
703 if (!$7->type)
704 $4->type = $7->type = INTEGER;
705 else
706 $4->type = $7->type;
707 }
708 else if (!$7->type)
709 $7->type = $4->type;
710 if ($1->type == STRING)
711 $1 = exnewnode(expr.program, S2B, true, INTEGER, $1, NULL);
712 else if (!INTEGRAL($1->type))
714 if ($4->type != $7->type)
715 {
716 if ($4->type == STRING || $7->type == STRING)
717 exerror("if statement string type mismatch");
718 else if ($4->type == FLOATING)
719 $7 = excast(expr.program, $7, FLOATING, NULL, 0);
720 else if ($7->type == FLOATING)
721 $4 = excast(expr.program, $4, FLOATING, NULL, 0);
722 }
723 if ($1->op == CONSTANT)
724 {
725 if ($1->data.constant.value.integer)
726 {
727 $$ = $4;
729 }
730 else
731 {
732 $$ = $7;
734 }
736 }
737 else
738 $$ = exnewnode(expr.program, '?', true, $4->type, $1, exnewnode(expr.program, ':', true, $4->type, $4, $7));
739 }
740 | '!' expr
741 {
742 iunary:
743 if ($2->type == STRING)
744 $2 = exnewnode(expr.program, S2B, true, INTEGER, $2, NULL);
745 else if (!INTEGRAL($2->type))
747 unary:
748 $$ = exnewnode(expr.program, $1, true, $2->type == UNSIGNED ? INTEGER : $2->type, $2, NULL);
749 if ($2->op == CONSTANT)
750 {
752 $$->binary = false;
753 $$->op = CONSTANT;
755 }
756 else if (!BUILTIN($2->type)) {
757 checkBinary(expr.program, $2, $$, 0);
758 }
759 }
760 | '#' DYNAMIC
761 {
762 if ($2->local == NULL)
763 exerror("cannot apply '#' operator to non-array %s", $2->name);
764 $$ = exnewnode(expr.program, '#', false, INTEGER, NULL, NULL);
765 $$->data.variable.symbol = $2;
766 }
767 | '#' ARRAY
768 {
769 $$ = exnewnode(expr.program, '#', false, INTEGER, NULL, NULL);
770 $$->data.variable.symbol = $2;
771 }
772 | '~' expr
773 {
774 goto iunary;
775 }
776 | '-' expr %prec UNARY
777 {
778 goto unary;
779 }
780 | '+' expr %prec UNARY
781 {
782 $$ = $2;
783 }
784 | '&' variable %prec UNARY
785 {
786 $$ = exnewnode(expr.program, ADDRESS, false, T($2->type), $2, NULL);
787 }
788 | ARRAY '[' args ']'
789 {
790 $$ = exnewnode(expr.program, ARRAY, true, T($1->type), call(0, $1, $3), $3);
791 }
792 | FUNCTION '(' args ')'
793 {
794 $$ = exnewnode(expr.program, FUNCTION, true, T($1->type), call(0, $1, $3), $3);
795 }
796 | GSUB '(' args ')'
797 {
798 $$ = exnewsub (expr.program, $3, GSUB);
799 }
800 | SUB '(' args ')'
801 {
802 $$ = exnewsub (expr.program, $3, SUB);
803 }
804 | SUBSTR '(' args ')'
805 {
806 $$ = exnewsubstr (expr.program, $3);
807 }
808 | splitop '(' expr ',' DYNAMIC ')'
809 {
810 $$ = exnewsplit (expr.program, $1->index, $5, $3, NULL);
811 }
812 | splitop '(' expr ',' DYNAMIC ',' expr ')'
813 {
814 $$ = exnewsplit (expr.program, $1->index, $5, $3, $7);
815 }
816 | EXIT '(' expr ')'
817 {
818 if (!INTEGRAL($3->type))
820 $$ = exnewnode(expr.program, EXIT, true, INTEGER, $3, NULL);
821 }
822 | RAND '(' ')'
823 {
825 }
826 | SRAND '(' ')'
827 {
829 }
830 | SRAND '(' expr ')'
831 {
832 if (!INTEGRAL($3->type))
835 }
836 | PROCEDURE '(' args ')'
837 {
838 $$ = exnewnode(expr.program, CALL, true, $1->type, NULL, $3);
839 $$->data.call.procedure = $1;
840 }
841 | PRINT '(' args ')'
842 {
843 $$ = exprint(expr.program, $1, $3);
844 }
845 | print '(' args ')'
846 {
847 $$ = exnewnode(expr.program, $1->index, false, $1->type, NULL, NULL);
848 if ($3 && $3->data.operand.left->type == INTEGER)
849 {
850 $$->data.print.descriptor = $3->data.operand.left;
851 $3 = $3->data.operand.right;
852 }
853 else
854 switch ($1->index)
855 {
856 case QUERY:
857 $$->data.print.descriptor = exnewnode(expr.program, CONSTANT, false, INTEGER, NULL, NULL);
858 $$->data.print.descriptor->data.constant.value.integer = 2;
859 break;
860 case PRINTF:
861 $$->data.print.descriptor = exnewnode(expr.program, CONSTANT, false, INTEGER, NULL, NULL);
862 $$->data.print.descriptor->data.constant.value.integer = 1;
863 break;
864 case SPRINTF:
865 $$->data.print.descriptor = 0;
866 break;
867 }
868 $$->data.print.args = preprint($3);
869 }
870 | scan '(' args ')'
871 {
872 Exnode_t* x;
873
874 $$ = exnewnode(expr.program, $1->index, false, $1->type, NULL, NULL);
875 if ($3 && $3->data.operand.left->type == INTEGER)
876 {
877 $$->data.scan.descriptor = $3->data.operand.left;
878 $3 = $3->data.operand.right;
879 }
880 else
881 switch ($1->index)
882 {
883 case SCANF:
884 $$->data.scan.descriptor = 0;
885 break;
886 case SSCANF:
887 if ($3 && $3->data.operand.left->type == STRING)
888 {
889 $$->data.scan.descriptor = $3->data.operand.left;
890 $3 = $3->data.operand.right;
891 }
892 else
893 exerror("%s: string argument expected", $1->name);
894 break;
895 }
896 if (!$3 || !$3->data.operand.left || $3->data.operand.left->type != STRING)
897 exerror("%s: format argument expected", $1->name);
898 $$->data.scan.format = $3->data.operand.left;
899 for (x = $$->data.scan.args = $3->data.operand.right; x; x = x->data.operand.right)
900 {
901 if (x->data.operand.left->op != ADDRESS)
902 exerror("%s: address argument expected", $1->name);
904 }
905 }
906 | variable assign
907 {
908 if ($2)
909 {
910 if ($1->op == ID && !expr.program->disc->setf)
911 exerror("%s: variable assignment not supported", $1->data.variable.symbol->name);
912 else
913 {
914 if (!$1->type)
915 $1->type = $2->type;
916 else if ($2->type != $1->type)
917 {
918 $2->type = $1->type;
919 $2->data.operand.right = excast(expr.program, $2->data.operand.right, $1->type, NULL, 0);
920 }
921 $2->data.operand.left = $1;
922 $$ = $2;
923 }
924 }
925 }
926 | INC variable
927 {
928 pre:
929 if ($2->type == STRING)
930 exerror("++ and -- invalid for string variables");
931 $$ = exnewnode(expr.program, $1, false, $2->type, $2, NULL);
932 $$->subop = PRE;
933 }
934 | variable INC
935 {
936 pos:
937 if ($1->type == STRING)
938 exerror("++ and -- invalid for string variables");
939 $$ = exnewnode(expr.program, $2, false, $1->type, $1, NULL);
940 $$->subop = POS;
941 }
943 {
944 if ($3->local == NULL)
945 exerror("cannot apply IN to non-array %s", $3->name);
946 if ($3->index_type > 0 && $1->type != $3->index_type)
947 exerror("%s indices must have type %s, not %s",
948 $3->name, extypename(expr.program, $3->index_type),extypename(expr.program, $1->type));
950 $$->data.variable.symbol = $3;
951 $$->data.variable.index = $1;
952 }
954 {
955 if ($3->index_type > 0 && $1->type != $3->index_type)
956 exerror("%s indices must have type %s, not %s",
957 $3->name, extypename(expr.program, $3->index_type),extypename(expr.program, $1->type));
959 $$->data.variable.symbol = $3;
960 $$->data.variable.index = $1;
961 }
962 | DEC variable
963 {
964 goto pre;
965 }
966 | variable DEC
967 {
968 goto pos;
969 }
970 | constant
971 ;
972
973splitop : SPLIT
974 | TOKENS
975 ;
976constant : CONSTANT
977 {
978 $$ = exnewnode(expr.program, CONSTANT, false, $1->type, NULL, NULL);
979 if (!expr.program->disc->reff)
980 exerror("%s: identifier references not supported", $1->name);
981 else
982 $$->data.constant.value = expr.program->disc->reff(expr.program, $$, $1, NULL);
983 }
984 | FLOATING
985 {
987 $$->data.constant.value.floating = $1;
988 }
989 | INTEGER
990 {
992 $$->data.constant.value.integer = $1;
993 }
994 | STRING
995 {
997 $$->data.constant.value.string = $1;
998 }
999 | UNSIGNED
1000 {
1002 $$->data.constant.value.integer = $1;
1003 }
1004 ;
1005
1006print : PRINTF
1007 | QUERY
1008 | SPRINTF
1009 ;
1010
1011scan : SCANF
1012 | SSCANF
1013 ;
1014
1015variable : ID members
1016 {
1017 $$ = makeVar(expr.program, $1, 0, 0, $2);
1018 }
1019 | DYNAMIC index members
1020 {
1021 Exnode_t *n = exnewnode(expr.program, DYNAMIC, false, $1->type, NULL, NULL);
1022 n->data.variable.symbol = $1;
1023 n->data.variable.reference = 0;
1024 if (((n->data.variable.index = $2) == 0) != ($1->local == NULL))
1025 exerror("%s: is%s an array", $1->name, $1->local != NULL ? "" : " not");
1026 if ($1->local != NULL && $1->index_type > 0) {
1027 if ($2->type != $1->index_type)
1028 exerror("%s: indices must have type %s, not %s",
1029 $1->name, extypename(expr.program, $1->index_type),extypename(expr.program, $2->type));
1030 }
1031 if ($3) {
1032 n->data.variable.dyna = exnewnode(expr.program, 0, false, 0, NULL, NULL);
1033 $$ = makeVar(expr.program, $1, $2, n, $3);
1034 }
1035 else $$ = n;
1036 }
1037 | NAME
1038 {
1039 $$ = exnewnode(expr.program, ID, false, STRING, NULL, NULL);
1040 $$->data.variable.symbol = $1;
1041 $$->data.variable.reference = 0;
1042 $$->data.variable.index = 0;
1043 $$->data.variable.dyna = 0;
1044 if (!(expr.program->disc->flags & EX_UNDECLARED))
1045 exerror("unknown identifier");
1046 }
1047 ;
1048
1049array : /* empty */
1050 {
1051 $$ = 0;
1052 }
1053 | '[' ']'
1054 {
1055 $$ = -1;
1056 }
1057 | '[' DECLARE ']'
1058 {
1059 /* If DECLARE is VOID, its type is 0, so this acts like
1060 * the empty case.
1061 */
1062 if (INTEGRAL($2->type))
1063 $$ = INTEGER;
1064 else
1065 $$ = $2->type;
1066
1067 }
1068 ;
1069
1070index : /* empty */
1071 {
1072 $$ = 0;
1073 }
1074 | '[' expr ']'
1075 {
1076 $$ = $2;
1077 }
1078 ;
1079
1080args : /* empty */
1081 {
1082 $$ = 0;
1083 }
1084 | arg_list
1085 {
1086 $$ = $1->data.operand.left;
1087 $1->data.operand.left = $1->data.operand.right = 0;
1089 }
1090 ;
1091
1092arg_list : expr %prec ','
1093 {
1094 $$ = exnewnode(expr.program, ',', true, 0, exnewnode(expr.program, ',', true, $1->type, $1, NULL), NULL);
1095 $$->data.operand.right = $$->data.operand.left;
1096 }
1097 | arg_list ',' expr
1098 {
1099 $1->data.operand.right = $1->data.operand.right->data.operand.right = exnewnode(expr.program, ',', true, $1->type, $3, NULL);
1100 }
1101 ;
1102
1103formals : /* empty */
1104 {
1105 $$ = 0;
1106 }
1107 | DECLARE
1108 {
1109 $$ = 0;
1110 if ($1->type)
1111 exerror("(void) expected");
1112 }
1113 | formal_list
1114 ;
1115
1116formal_list : formal_item
1117 {
1118 $$ = exnewnode(expr.program, ',', true, $1->type, $1, NULL);
1119 }
1120 | formal_list ',' formal_item
1121 {
1122 Exnode_t* x;
1123 Exnode_t* y;
1124
1125 $$ = $1;
1126 for (x = $1; (y = x->data.operand.right); x = y);
1127 x->data.operand.right = exnewnode(expr.program, ',', true, $3->type, $3, NULL);
1128 }
1129 ;
1130
1131formal_item : DECLARE {expr.declare=$1->type;} name
1132 {
1133 if ($1->type == 0) {
1134 exerror("%s: parameters to functions cannot be void typed", $3->name);
1135 }
1136 $$ = exnewnode(expr.program, ID, false, $1->type, NULL, NULL);
1137 $$->data.variable.symbol = $3;
1138 $3->lex = DYNAMIC;
1139 $3->type = $1->type;
1140 $3->value = exnewnode(expr.program, 0, false, 0, NULL, NULL);
1141 expr.procedure->data.procedure.arity++;
1142 expr.declare = 0;
1143 }
1144 ;
1145
1146members : /* empty */
1147 {
1148 $$ = expr.refs = 0;
1149 }
1150 | member
1151 {
1152 Exref_t* r;
1153
1154 r = ALLOCATE(expr.program, Exref_t);
1155 *r = (Exref_t){0};
1156 r->symbol = $1;
1157 expr.refs = r;
1158 r->next = 0;
1159 r->index = 0;
1160 $$ = expr.refs;
1161 }
1162 | '.' ID member
1163 {
1164 Exref_t* r;
1165 Exref_t* l;
1166
1167 r = ALLOCATE(expr.program, Exref_t);
1168 *r = (Exref_t){0};
1169 r->symbol = $3;
1170 r->index = 0;
1171 r->next = 0;
1172 l = ALLOCATE(expr.program, Exref_t);
1173 *l = (Exref_t){0};
1174 l->symbol = $2;
1175 l->index = 0;
1176 l->next = r;
1177 expr.refs = l;
1178 $$ = expr.refs;
1179 }
1180 ;
1181
1182member : '.' ID
1183 {
1184 $$ = $2;
1185 }
1186 | '.' NAME
1187 {
1188 $$ = $2;
1189 }
1190 ;
1191assign : /* empty */
1192 {
1193 $$ = 0;
1194 }
1195 | '=' expr
1196 {
1197 $$ = exnewnode(expr.program, '=', true, $2->type, NULL, $2);
1198 $$->subop = $1;
1199 }
1200 ;
1201
1202initialize : assign
1203 | '(' {
1204 if (expr.procedure)
1205 exerror("%s: nested function definitions not supported", expr.id->name);
1207 if (!streq(expr.id->name, "begin"))
1208 {
1209 static Dtdisc_t disc = {.key = offsetof(Exid_t, name)};
1210 if (!(expr.procedure->data.procedure.frame = dtopen(&disc, Dtset)) || !dtview(expr.procedure->data.procedure.frame, expr.program->symbols))
1211 exnospace();
1212 expr.program->symbols = expr.program->frame = expr.procedure->data.procedure.frame;
1213 }
1214 expr.declare = 0;
1215 } formals {
1216 expr.id->lex = PROCEDURE;
1218 expr.declare = 0;
1219 } ')' '{' statement_list '}'
1220 {
1221 $$ = expr.procedure;
1223 if (expr.program->frame)
1224 {
1225 expr.program->symbols = expr.program->frame->view;
1226 dtview(expr.program->frame, NULL);
1227 expr.program->frame = NULL;
1228 }
1229 // dictionary of locals no longer required, now that we have parsed the body
1230 (void)dtclose($$->data.procedure.frame);
1231 $$->data.procedure.frame = NULL;
1232 $$->data.procedure.args = $3;
1233 $$->data.procedure.body = excast(expr.program, $7, $$->type, NULL, 0);
1234
1235 /*
1236 * NOTE: procedure definition was slipped into the
1237 * declaration initializer statement production,
1238 * therefore requiring the statement terminator
1239 */
1240
1241 exunlex(expr.program, ';');
1242 }
1243 ;
1244
1245%%
1246
1247const char *exop(size_t index) {
1248
1249 /* yytname is generated by the %token-table directive */
1250
1251 /* find the index of MINTOKEN */
1252 size_t minid;
1253 for (minid = 0; yytname[minid] != NULL; ++minid) {
1254 if (strcmp(yytname[minid], "MINTOKEN") == 0) {
1255 break;
1256 }
1257 }
1258
1259 assert(yytname[minid] != NULL
1260 && "failed to find MINTOKEN; incorrect token list in exparse.y?");
1261
1262 /* find the requested token */
1263 {
1264 size_t i, j;
1265 for (i = j = minid; yytname[i] != NULL; ++i) {
1266
1267 /* if this token is not a word, skip it */
1268 {
1269 size_t k;
1270 for (k = 0; yytname[i][k] != '\0'; ++k) {
1271 if (yytname[i][k] != '_' && !gv_isalnum(yytname[i][k])) {
1272 break;
1273 }
1274 }
1275 if (yytname[i][k] != '\0') {
1276 continue;
1277 }
1278 }
1279
1280 if (j == index + minid) {
1281 return yytname[i];
1282 }
1283 ++j;
1284 }
1285 }
1286
1287 /* failed to find the requested token */
1288 return NULL;
1289}
1290
1291void ex_error(const char *message) {
1292 exerror("%s", message);
1293}
1294
1295#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:1834
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:1991
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:3274
static const char *const yytname[]
Definition exparse.c:706
void ex_error(const char *message)
Definition exparse.c:3318
#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: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
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:182
node NULL
Definition grammar.y:180
hdr $3
Definition grammar.y:148
static uint64_t id
Definition gv2gml.c:40
replacements for ctype.h functions
static bool gv_isalnum(int c)
Definition gv_ctype.h:43
static void freef(void *ident)
#define assign(h, i, j, index)
Definition dijkstra.c:43
char * pre
Definition maze.c:32
static int table[NTYPES][NTYPES]
Definition mincross.c:1781
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
struct Exdata_u::@89 constant
Exnode_t * left
Definition expr.h:122
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::@90 operand
struct Exdata_u::@92 variable
Exnode_t * dyna
Definition expr.h:138
struct Exdata_u::@91 select
Extype_t value
Definition expr.h:116
Exnode_t * index
Definition expr.h:137
char * vmstrdup(Vmalloc_t *, const char *)
Definition vmstrdup.c:19