Research V7 development
[unix-history] / usr / src / cmd / mip / cgram.y
CommitLineData
3c5d933b
SJ
1%term NAME 2
2%term STRING 3
3%term ICON 4
4%term FCON 5
5%term PLUS 6
6%term MINUS 8
7%term MUL 11
8%term AND 14
9%term OR 17
10%term ER 19
11%term QUEST 21
12%term COLON 22
13%term ANDAND 23
14%term OROR 24
15
16/* special interfaces for yacc alone */
17/* These serve as abbreviations of 2 or more ops:
18 ASOP =, = ops
19 RELOP LE,LT,GE,GT
20 EQUOP EQ,NE
21 DIVOP DIV,MOD
22 SHIFTOP LS,RS
23 ICOP ICR,DECR
24 UNOP NOT,COMPL
25 STROP DOT,STREF
26
27 */
28%term ASOP 25
29%term RELOP 26
30%term EQUOP 27
31%term DIVOP 28
32%term SHIFTOP 29
33%term INCOP 30
34%term UNOP 31
35%term STROP 32
36
37/* reserved words, etc */
38%term TYPE 33
39%term CLASS 34
40%term STRUCT 35
41%term RETURN 36
42%term GOTO 37
43%term IF 38
44%term ELSE 39
45%term SWITCH 40
46%term BREAK 41
47%term CONTINUE 42
48%term WHILE 43
49%term DO 44
50%term FOR 45
51%term DEFAULT 46
52%term CASE 47
53%term SIZEOF 48
54%term ENUM 49
55
56
57/* little symbols, etc. */
58/* namely,
59
60 LP (
61 RP )
62
63 LC {
64 RC }
65
66 LB [
67 RB ]
68
69 CM ,
70 SM ;
71
72 */
73
74%term LP 50
75%term RP 51
76%term LC 52
77%term RC 53
78%term LB 54
79%term RB 55
80%term CM 56
81%term SM 57
82%term ASSIGN 58
83
84/* at last count, there were 7 shift/reduce, 1 reduce/reduce conflicts
85/* these involved:
86 if/else
87 recognizing functions in various contexts, including declarations
88 error recovery
89 */
90
91%left CM
92%right ASOP ASSIGN
93%right QUEST COLON
94%left OROR
95%left ANDAND
96%left OR
97%left ER
98%left AND
99%left EQUOP
100%left RELOP
101%left SHIFTOP
102%left PLUS MINUS
103%left MUL DIVOP
104%right UNOP
105%right INCOP SIZEOF
106%left LB LP STROP
107%{
108# include "mfile1"
109%}
110
111 /* define types */
112%start ext_def_list
113
114%type <intval> con_e ifelprefix ifprefix whprefix forprefix doprefix switchpart
115 enum_head str_head name_lp
116%type <nodep> e .e term attributes oattributes type enum_dcl struct_dcl
117 cast_type null_decl funct_idn declarator fdeclarator nfdeclarator
118 elist
119
120%token <intval> CLASS NAME STRUCT RELOP CM DIVOP PLUS MINUS SHIFTOP MUL AND OR ER ANDAND OROR
121 ASSIGN STROP INCOP UNOP ICON
122%token <nodep> TYPE
123
124%%
125
126%{
127 static int fake = 0;
128 static char fakename[NCHNAM+1];
129%}
130
131ext_def_list: ext_def_list external_def
132 |
133 =ftnend();
134 ;
135external_def: data_def
136 ={ curclass = SNULL; blevel = 0; }
137 | error
138 ={ curclass = SNULL; blevel = 0; }
139 ;
140data_def:
141 oattributes SM
142 ={ $1->op = FREE; }
143 | oattributes init_dcl_list SM
144 ={ $1->op = FREE; }
145 | oattributes fdeclarator {
146 defid( tymerge($1,$2), curclass==STATIC?STATIC:EXTDEF );
147 } function_body
148 ={
149 if( blevel ) cerror( "function level error" );
150 if( reached ) retstat |= NRETVAL;
151 $1->op = FREE;
152 ftnend();
153 }
154 ;
155
156function_body: arg_dcl_list compoundstmt
157 ;
158arg_dcl_list: arg_dcl_list declaration
159 | ={ blevel = 1; }
160 ;
161
162stmt_list: stmt_list statement
163 | /* empty */
164 ={ bccode();
165 locctr(PROG);
166 }
167 ;
168
169dcl_stat_list : dcl_stat_list attributes SM
170 ={ $2->op = FREE; }
171 | dcl_stat_list attributes init_dcl_list SM
172 ={ $2->op = FREE; }
173 | /* empty */
174 ;
175declaration: attributes declarator_list SM
176 ={ curclass = SNULL; $1->op = FREE; }
177 | attributes SM
178 ={ curclass = SNULL; $1->op = FREE; }
179 | error SM
180 ={ curclass = SNULL; }
181 ;
182oattributes: attributes
183 | /* VOID */
184 ={ $$ = mkty(INT,0,INT); curclass = SNULL; }
185 ;
186attributes: class type
187 ={ $$ = $2; }
188 | type class
189 | class
190 ={ $$ = mkty(INT,0,INT); }
191 | type
192 ={ curclass = SNULL ; }
193 ;
194
195
196class: CLASS
197 ={ curclass = $1; }
198 ;
199
200type: TYPE
201 | TYPE TYPE
202 ={ $1->type = types( $1->type, $2->type, UNDEF );
203 $2->op = FREE;
204 }
205 | TYPE TYPE TYPE
206 ={ $1->type = types( $1->type, $2->type, $3->type );
207 $2->op = $3->op = FREE;
208 }
209 | struct_dcl
210 | enum_dcl
211 ;
212
213enum_dcl: enum_head LC moe_list optcomma RC
214 ={ $$ = dclstruct($1); }
215 | ENUM NAME
216 ={ $$ = rstruct($2,0); stwart = instruct; }
217 ;
218
219enum_head: ENUM
220 ={ $$ = bstruct(-1,0); }
221 | ENUM NAME
222 ={ $$ = bstruct($2,0); }
223 ;
224
225moe_list: moe
226 | moe_list CM moe
227 ;
228
229moe: NAME
230 ={ moedef( $1 ); }
231 | NAME ASSIGN con_e
232 ={ strucoff = $3; moedef( $1 ); }
233 ;
234
235struct_dcl: str_head LC type_dcl_list optsemi RC
236 ={ $$ = dclstruct($1); }
237 | STRUCT NAME
238 ={ $$ = rstruct($2,$1); }
239 ;
240
241str_head: STRUCT
242 ={ $$ = bstruct(-1,$1); stwart=0; }
243 | STRUCT NAME
244 ={ $$ = bstruct($2,$1); stwart=0; }
245 ;
246
247type_dcl_list: type_declaration
248 | type_dcl_list SM type_declaration
249 ;
250
251type_declaration: type declarator_list
252 ={ curclass = SNULL; stwart=0; $1->op = FREE; }
253 | type
254 ={ if( curclass != MOU ){
255 curclass = SNULL;
256 }
257 else {
258 sprintf( fakename, "$%dFAKE", fake++ );
259 defid( tymerge($1, bdty(NAME,NIL,lookup( fakename, SMOS ))), curclass );
260 }
261 stwart = 0;
262 $1->op = FREE;
263 }
264 ;
265
266
267declarator_list: declarator
268 ={ defid( tymerge($<nodep>0,$1), curclass); stwart = instruct; }
269 | declarator_list CM {$<nodep>$=$<nodep>0;} declarator
270 ={ defid( tymerge($<nodep>0,$4), curclass); stwart = instruct; }
271 ;
272declarator: fdeclarator
273 | nfdeclarator
274 | nfdeclarator COLON con_e
275 %prec CM
276 ={ if( !(instruct&INSTRUCT) ) uerror( "field outside of structure" );
277 if( $3<0 || $3 >= FIELD ){
278 uerror( "illegal field size" );
279 $3 = 1;
280 }
281 defid( tymerge($<nodep>0,$1), FIELD|$3 );
282 $$ = NIL;
283 }
284 | COLON con_e
285 %prec CM
286 ={ if( !(instruct&INSTRUCT) ) uerror( "field outside of structure" );
287 falloc( stab, $2, -1, $<nodep>0 ); /* alignment or hole */
288 $$ = NIL;
289 }
290 | error
291 ={ $$ = NIL; }
292 ;
293
294 /* int (a)(); is not a function --- sorry! */
295nfdeclarator: MUL nfdeclarator
296 ={ umul:
297 $$ = bdty( UNARY MUL, $2, 0 ); }
298 | nfdeclarator LP RP
299 ={ uftn:
300 $$ = bdty( UNARY CALL, $1, 0 ); }
301 | nfdeclarator LB RB
302 ={ uary:
303 $$ = bdty( LB, $1, 0 ); }
304 | nfdeclarator LB con_e RB
305 ={ bary:
306 if( (int)$3 <= 0 ) werror( "zero or negative subscript" );
307 $$ = bdty( LB, $1, $3 ); }
308 | NAME
309 ={ $$ = bdty( NAME, NIL, $1 ); }
310 | LP nfdeclarator RP
311 ={ $$=$2; }
312 ;
313fdeclarator: MUL fdeclarator
314 ={ goto umul; }
315 | fdeclarator LP RP
316 ={ goto uftn; }
317 | fdeclarator LB RB
318 ={ goto uary; }
319 | fdeclarator LB con_e RB
320 ={ goto bary; }
321 | LP fdeclarator RP
322 ={ $$ = $2; }
323 | name_lp name_list RP
324 ={
325 if( blevel!=0 ) uerror("function declaration in bad context");
326 $$ = bdty( UNARY CALL, bdty(NAME,NIL,$1), 0 );
327 stwart = 0;
328 }
329 | name_lp RP
330 ={
331 $$ = bdty( UNARY CALL, bdty(NAME,NIL,$1), 0 );
332 stwart = 0;
333 }
334 ;
335
336name_lp: NAME LP
337 ={
338 /* turn off typedefs for argument names */
339 stwart = SEENAME;
340 }
341 ;
342
343name_list: NAME
344 ={ ftnarg( $1 ); stwart = SEENAME; }
345 | name_list CM NAME
346 ={ ftnarg( $3 ); stwart = SEENAME; }
347 ;
348 /* always preceeded by attributes: thus the $<nodep>0's */
349init_dcl_list: init_declarator
350 %prec CM
351 | init_dcl_list CM {$<nodep>$=$<nodep>0;} init_declarator
352 ;
353 /* always preceeded by attributes */
354xnfdeclarator: nfdeclarator
355 ={ defid( $1 = tymerge($<nodep>0,$1), curclass);
356 beginit($1->rval);
357 }
358 | error
359 ;
360 /* always preceeded by attributes */
361init_declarator: nfdeclarator
362 ={ nidcl( tymerge($<nodep>0,$1) ); }
363 | fdeclarator
364 ={ defid( tymerge($<nodep>0,$1), uclass(curclass) );
365 }
366 | xnfdeclarator optasgn e
367 %prec CM
368 ={ doinit( $3 );
369 endinit(); }
370 | xnfdeclarator optasgn LC init_list optcomma RC
371 ={ endinit(); }
372 ;
373
374init_list: initializer
375 %prec CM
376 | init_list CM initializer
377 ;
378initializer: e
379 %prec CM
380 ={ doinit( $1 ); }
381 | ibrace init_list optcomma RC
382 ={ irbrace(); }
383 ;
384
385optcomma : /* VOID */
386 | CM
387 ;
388
389optsemi : /* VOID */
390 | SM
391 ;
392
393optasgn : /* VOID */
394 ={ werror( "old-fashioned initialization: use =" ); }
395 | ASSIGN
396 ;
397
398ibrace : LC
399 ={ ilbrace(); }
400 ;
401
402/* STATEMENTS */
403
404compoundstmt: begin dcl_stat_list stmt_list RC
405 ={ --blevel;
406 if( blevel == 1 ) blevel = 0;
407 clearst( blevel );
408 checkst( blevel );
409 autooff = *--psavbc;
410 regvar = *--psavbc;
411 }
412 ;
413
414begin: LC
415 ={ if( blevel == 1 ) dclargs();
416 ++blevel;
417 if( psavbc > &asavbc[BCSZ-2] ) cerror( "nesting too deep" );
418 *psavbc++ = regvar;
419 *psavbc++ = autooff;
420 }
421 ;
422
423statement: e SM
424 ={ ecomp( $1 ); }
425 | compoundstmt
426 | ifprefix statement
427 ={ deflab($1);
428 reached = 1;
429 }
430 | ifelprefix statement
431 ={ if( $1 != NOLAB ){
432 deflab( $1 );
433 reached = 1;
434 }
435 }
436 | whprefix statement
437 ={ branch( contlab );
438 deflab( brklab );
439 if( (flostat&FBRK) || !(flostat&FLOOP)) reached = 1;
440 else reached = 0;
441 resetbc(0);
442 }
443 | doprefix statement WHILE LP e RP SM
444 ={ deflab( contlab );
445 if( flostat & FCONT ) reached = 1;
446 ecomp( buildtree( CBRANCH, buildtree( NOT, $5, NIL ), bcon( $1 ) ) );
447 deflab( brklab );
448 reached = 1;
449 resetbc(0);
450 }
451 | forprefix .e RP statement
452 ={ deflab( contlab );
453 if( flostat&FCONT ) reached = 1;
454 if( $2 ) ecomp( $2 );
455 branch( $1 );
456 deflab( brklab );
457 if( (flostat&FBRK) || !(flostat&FLOOP) ) reached = 1;
458 else reached = 0;
459 resetbc(0);
460 }
461 | switchpart statement
462 ={ if( reached ) branch( brklab );
463 deflab( $1 );
464 swend();
465 deflab(brklab);
466 if( (flostat&FBRK) || !(flostat&FDEF) ) reached = 1;
467 resetbc(FCONT);
468 }
469 | BREAK SM
470 ={ if( brklab == NOLAB ) uerror( "illegal break");
471 else if(reached) branch( brklab );
472 flostat |= FBRK;
473 if( brkflag ) goto rch;
474 reached = 0;
475 }
476 | CONTINUE SM
477 ={ if( contlab == NOLAB ) uerror( "illegal continue");
478 else branch( contlab );
479 flostat |= FCONT;
480 goto rch;
481 }
482 | RETURN SM
483 ={ retstat |= NRETVAL;
484 branch( retlab );
485 rch:
486 if( !reached ) werror( "statement not reached");
487 reached = 0;
488 }
489 | RETURN e SM
490 ={ register NODE *temp;
491 idname = curftn;
492 temp = buildtree( NAME, NIL, NIL );
493 temp->type = DECREF( temp->type );
494 temp = buildtree( RETURN, temp, $2 );
495 /* now, we have the type of the RHS correct */
496 temp->left->op = FREE;
497 temp->op = FREE;
498 ecomp( buildtree( FORCE, temp->right, NIL ) );
499 retstat |= RETVAL;
500 branch( retlab );
501 reached = 0;
502 }
503 | GOTO NAME SM
504 ={ register NODE *q;
505 q = block( FREE, NIL, NIL, INT|ARY, 0, INT );
506 q->rval = idname = $2;
507 defid( q, ULABEL );
508 stab[idname].suse = -lineno;
509 branch( stab[idname].offset );
510 goto rch;
511 }
512 | SM
513 | error SM
514 | error RC
515 | label statement
516 ;
517label: NAME COLON
518 ={ register NODE *q;
519 q = block( FREE, NIL, NIL, INT|ARY, 0, LABEL );
520 q->rval = $1;
521 defid( q, LABEL );
522 reached = 1;
523 }
524 | CASE e COLON
525 ={ addcase($2);
526 reached = 1;
527 }
528 | DEFAULT COLON
529 ={ reached = 1;
530 adddef();
531 flostat |= FDEF;
532 }
533 ;
534doprefix: DO
535 ={ savebc();
536 if( !reached ) werror( "loop not entered at top");
537 brklab = getlab();
538 contlab = getlab();
539 deflab( $$ = getlab() );
540 reached = 1;
541 }
542 ;
543ifprefix: IF LP e RP
544 ={ ecomp( buildtree( CBRANCH, $3, bcon( $$=getlab()) ) ) ;
545 reached = 1;
546 }
547 ;
548ifelprefix: ifprefix statement ELSE
549 ={ if( reached ) branch( $$ = getlab() );
550 else $$ = NOLAB;
551 deflab( $1 );
552 reached = 1;
553 }
554 ;
555
556whprefix: WHILE LP e RP
557 ={ savebc();
558 if( !reached ) werror( "loop not entered at top");
559 if( $3->op == ICON && $3->lval != 0 ) flostat = FLOOP;
560 deflab( contlab = getlab() );
561 reached = 1;
562 brklab = getlab();
563 if( flostat == FLOOP ) tfree( $3 );
564 else ecomp( buildtree( CBRANCH, $3, bcon( brklab) ) );
565 }
566 ;
567forprefix: FOR LP .e SM .e SM
568 ={ if( $3 ) ecomp( $3 );
569 else if( !reached ) werror( "loop not entered at top");
570 savebc();
571 contlab = getlab();
572 brklab = getlab();
573 deflab( $$ = getlab() );
574 reached = 1;
575 if( $5 ) ecomp( buildtree( CBRANCH, $5, bcon( brklab) ) );
576 else flostat |= FLOOP;
577 }
578 ;
579switchpart: SWITCH LP e RP
580 ={ savebc();
581 brklab = getlab();
582 ecomp( buildtree( FORCE, $3, NIL ) );
583 branch( $$ = getlab() );
584 swstart();
585 reached = 0;
586 }
587 ;
588/* EXPRESSIONS */
589con_e: { $<intval>$=instruct; stwart=instruct=0; } e
590 %prec CM
591 ={ $$ = icons( $2 ); instruct=$<intval>1; }
592 ;
593.e: e
594 |
595 ={ $$=0; }
596 ;
597elist: e
598 %prec CM
599 | elist CM e
600 ={ goto bop; }
601 ;
602
603e: e RELOP e
604 ={
605 preconf:
606 if( yychar==RELOP||yychar==EQUOP||yychar==AND||yychar==OR||yychar==ER ){
607 precplaint:
608 if( hflag ) werror( "precedence confusion possible: parenthesize!" );
609 }
610 bop:
611 $$ = buildtree( $2, $1, $3 );
612 }
613 | e CM e
614 ={ $2 = COMOP;
615 goto bop;
616 }
617 | e DIVOP e
618 ={ goto bop; }
619 | e PLUS e
620 ={ if(yychar==SHIFTOP) goto precplaint; else goto bop; }
621 | e MINUS e
622 ={ if(yychar==SHIFTOP ) goto precplaint; else goto bop; }
623 | e SHIFTOP e
624 ={ if(yychar==PLUS||yychar==MINUS) goto precplaint; else goto bop; }
625 | e MUL e
626 ={ goto bop; }
627 | e EQUOP e
628 ={ goto preconf; }
629 | e AND e
630 ={ if( yychar==RELOP||yychar==EQUOP ) goto preconf; else goto bop; }
631 | e OR e
632 ={ if(yychar==RELOP||yychar==EQUOP) goto preconf; else goto bop; }
633 | e ER e
634 ={ if(yychar==RELOP||yychar==EQUOP) goto preconf; else goto bop; }
635 | e ANDAND e
636 ={ goto bop; }
637 | e OROR e
638 ={ goto bop; }
639 | e MUL ASSIGN e
640 ={ abop:
641 $$ = buildtree( ASG $2, $1, $4 );
642 }
643 | e DIVOP ASSIGN e
644 ={ goto abop; }
645 | e PLUS ASSIGN e
646 ={ goto abop; }
647 | e MINUS ASSIGN e
648 ={ goto abop; }
649 | e SHIFTOP ASSIGN e
650 ={ goto abop; }
651 | e AND ASSIGN e
652 ={ goto abop; }
653 | e OR ASSIGN e
654 ={ goto abop; }
655 | e ER ASSIGN e
656 ={ goto abop; }
657 | e QUEST e COLON e
658 ={ $$=buildtree(QUEST, $1, buildtree( COLON, $3, $5 ) );
659 }
660 | e ASOP e
661 ={ werror( "old-fashioned assignment operator" ); goto bop; }
662 | e ASSIGN e
663 ={ goto bop; }
664 | term
665 ;
666term: term INCOP
667 ={ $$ = buildtree( $2, $1, bcon(1) ); }
668 | MUL term
669 ={ ubop:
670 $$ = buildtree( UNARY $1, $2, NIL );
671 }
672 | AND term
673 ={ if( ISFTN($2->type) || ISARY($2->type) ){
674 werror( "& before array or function: ignored" );
675 $$ = $2;
676 }
677 else goto ubop;
678 }
679 | MINUS term
680 ={ goto ubop; }
681 | UNOP term
682 ={
683 $$ = buildtree( $1, $2, NIL );
684 }
685 | INCOP term
686 ={ $$ = buildtree( $1==INCR ? ASG PLUS : ASG MINUS,
687 $2,
688 bcon(1) );
689 }
690 | SIZEOF term
691 ={ $$ = doszof( $2 ); }
692 | LP cast_type RP term %prec INCOP
693 ={ $$ = buildtree( CAST, $2, $4 );
694 $$->left->op = FREE;
695 $$->op = FREE;
696 $$ = $$->right;
697 }
698 | SIZEOF LP cast_type RP %prec SIZEOF
699 ={ $$ = doszof( $3 ); }
700 | term LB e RB
701 ={ $$ = buildtree( UNARY MUL, buildtree( PLUS, $1, $3 ), NIL ); }
702 | funct_idn RP
703 ={ $$=buildtree(UNARY CALL,$1,NIL); }
704 | funct_idn elist RP
705 ={ $$=buildtree(CALL,$1,$2); }
706 | term STROP NAME
707 ={ if( $2 == DOT ){
708 $1 = buildtree( UNARY AND, $1, NIL );
709 }
710 idname = $3;
711 $$ = buildtree( STREF, $1, buildtree( NAME, NIL, NIL ) );
712 }
713 | NAME
714 ={ idname = $1;
715 /* recognize identifiers in initializations */
716 if( blevel==0 && stab[idname].stype == UNDEF ) {
717 register NODE *q;
718 werror( "undeclared initializer name %.8s", stab[idname].sname );
719 q = block( FREE, NIL, NIL, INT, 0, INT );
720 q->rval = idname;
721 defid( q, EXTERN );
722 }
723 $$=buildtree(NAME,NIL,NIL);
724 stab[$1].suse = -lineno;
725 }
726 | ICON
727 ={ $$=bcon(0);
728 $$->lval = lastcon;
729 $$->rval = NONAME;
730 if( $1 ) $$->csiz = $$->type = ctype(LONG);
731 }
732 | FCON
733 ={ $$=buildtree(FCON,NIL,NIL);
734 $$->dval = dcon;
735 }
736 | STRING
737 ={ $$ = getstr(); /* get string contents */ }
738 | LP e RP
739 ={ $$=$2; }
740 ;
741
742cast_type: type null_decl
743 ={
744 $$ = tymerge( $1, $2 );
745 $$->op = NAME;
746 $1->op = FREE;
747 }
748 ;
749
750null_decl: /* empty */
751 ={ $$ = bdty( NAME, NIL, -1 ); }
752 | LP RP
753 ={ $$ = bdty( UNARY CALL, bdty(NAME,NIL,-1),0); }
754 | LP null_decl RP LP RP
755 ={ $$ = bdty( UNARY CALL, $2, 0 ); }
756 | MUL null_decl
757 ={ goto umul; }
758 | null_decl LB RB
759 ={ goto uary; }
760 | null_decl LB con_e RB
761 ={ goto bary; }
762 | LP null_decl RP
763 ={ $$ = $2; }
764 ;
765
766funct_idn: NAME LP
767 ={ if( stab[$1].stype == UNDEF ){
768 register NODE *q;
769 q = block( FREE, NIL, NIL, FTN|INT, 0, INT );
770 q->rval = $1;
771 defid( q, EXTERN );
772 }
773 idname = $1;
774 $$=buildtree(NAME,NIL,NIL);
775 stab[idname].suse = -lineno;
776 }
777 | term LP
778 ;
779%%
780
781NODE *
782mkty( t, d, s ) unsigned t; {
783 return( block( TYPE, NIL, NIL, t, d, s ) );
784 }
785
786NODE *
787bdty( op, p, v ) NODE *p; {
788 register NODE *q;
789
790 q = block( op, p, NIL, INT, 0, INT );
791
792 switch( op ){
793
794 case UNARY MUL:
795 case UNARY CALL:
796 break;
797
798 case LB:
799 q->right = bcon(v);
800 break;
801
802 case NAME:
803 q->rval = v;
804 break;
805
806 default:
807 cerror( "bad bdty" );
808 }
809
810 return( q );
811 }
812
813dstash( n ){ /* put n into the dimension table */
814 if( curdim >= DIMTABSZ-1 ){
815 cerror( "dimension table overflow");
816 }
817 dimtab[ curdim++ ] = n;
818 }
819
820savebc() {
821 if( psavbc > & asavbc[BCSZ-4 ] ){
822 cerror( "whiles, fors, etc. too deeply nested");
823 }
824 *psavbc++ = brklab;
825 *psavbc++ = contlab;
826 *psavbc++ = flostat;
827 *psavbc++ = swx;
828 flostat = 0;
829 }
830
831resetbc(mask){
832
833 swx = *--psavbc;
834 flostat = *--psavbc | (flostat&mask);
835 contlab = *--psavbc;
836 brklab = *--psavbc;
837
838 }
839
840addcase(p) NODE *p; { /* add case to switch */
841
842 p = optim( p ); /* change enum to ints */
843 if( p->op != ICON ){
844 uerror( "non-constant case expression");
845 return;
846 }
847 if( swp == swtab ){
848 uerror( "case not in switch");
849 return;
850 }
851 if( swp >= &swtab[SWITSZ] ){
852 cerror( "switch table overflow");
853 }
854 swp->sval = p->lval;
855 deflab( swp->slab = getlab() );
856 ++swp;
857 tfree(p);
858 }
859
860adddef(){ /* add default case to switch */
861 if( swtab[swx].slab >= 0 ){
862 uerror( "duplicate default in switch");
863 return;
864 }
865 if( swp == swtab ){
866 uerror( "default not inside switch");
867 return;
868 }
869 deflab( swtab[swx].slab = getlab() );
870 }
871
872swstart(){
873 /* begin a switch block */
874 if( swp >= &swtab[SWITSZ] ){
875 cerror( "switch table overflow");
876 }
877 swx = swp - swtab;
878 swp->slab = -1;
879 ++swp;
880 }
881
882swend(){ /* end a switch block */
883
884 register struct sw *swbeg, *p, *q, *r, *r1;
885 CONSZ temp;
886 int tempi;
887
888 swbeg = &swtab[swx+1];
889
890 /* sort */
891
892 r1 = swbeg;
893 r = swp-1;
894
895 while( swbeg < r ){
896 /* bubble largest to end */
897 for( q=swbeg; q<r; ++q ){
898 if( q->sval > (q+1)->sval ){
899 /* swap */
900 r1 = q+1;
901 temp = q->sval;
902 q->sval = r1->sval;
903 r1->sval = temp;
904 tempi = q->slab;
905 q->slab = r1->slab;
906 r1->slab = tempi;
907 }
908 }
909 r = r1;
910 r1 = swbeg;
911 }
912
913 /* it is now sorted */
914
915 for( p = swbeg+1; p<swp; ++p ){
916 if( p->sval == (p-1)->sval ){
917 uerror( "duplicate case in switch, %d", tempi=p->sval );
918 return;
919 }
920 }
921
922 genswitch( swbeg-1, swp-swbeg );
923 swp = swbeg-1;
924 }