diff --git a/WEGA/contrib/lcc/cmd/comp/common/cgram.y b/WEGA/contrib/lcc/cmd/comp/common/cgram.y new file mode 100644 index 0000000..93ed335 --- /dev/null +++ b/WEGA/contrib/lcc/cmd/comp/common/cgram.y @@ -0,0 +1,976 @@ +%{ +static char SCCSID[] = "~(#) cgram.y: 2.1 83/07/08"; +%} +%term NAME 2 +%term STRING 3 +%term ICON 4 +%term FCON 5 +%term PLUS 6 +%term MINUS 8 +%term MUL 11 +%term AND 14 +%term OR 17 +%term ER 19 +%term QUEST 21 +%term COLON 22 +%term ANDAND 23 +%term OROR 24 + +/* special interfaces for yacc alone */ +/* These serve as abbreviations of 2 or more ops: + ASOP =, = ops + RELOP LE,LT,GE,GT + EQUOP EQ,NE + DIVOP DIV,MOD + SHIFTOP LS,RS + ICOP ICR,DECR + UNOP NOT,COMPL + STROP DOT,STREF + + */ +%term ASOP 25 +%term RELOP 26 +%term EQUOP 27 +%term DIVOP 28 +%term SHIFTOP 29 +%term INCOP 30 +%term UNOP 31 +%term STROP 32 + +/* reserved words, etc */ +%term TYPE 33 +%term CLASS 34 +%term STRUCT 35 +%term RETURN 36 +%term GOTO 37 +%term IF 38 +%term ELSE 39 +%term SWITCH 40 +%term BREAK 41 +%term CONTINUE 42 +%term WHILE 43 +%term DO 44 +%term FOR 45 +%term DEFAULT 46 +%term CASE 47 +%term SIZEOF 48 +%term ENUM 49 + +/* little symbols, etc. */ +/* namely, + + LP ( + RP ) + + LC { + RC } + + LB [ + RB ] + + CM , + SM ; + + */ + +%term LP 50 +%term RP 51 +%term LC 52 +%term RC 53 +%term LB 54 +%term RB 55 +%term CM 56 +%term SM 57 +%term ASSIGN 58 +%term ASM 59 + +/* at last count, there were 7 shift/reduce, 1 reduce/reduce conflicts +/* these involved: + if/else + recognizing functions in various contexts, including declarations + error recovery + */ + +%left CM +%right ASOP ASSIGN +%right QUEST COLON +%left OROR +%left ANDAND +%left OR +%left ER +%left AND +%left EQUOP +%left RELOP +%left SHIFTOP +%left PLUS MINUS +%left MUL DIVOP +%right UNOP +%right INCOP SIZEOF +%left LB LP STROP +%{ +# include "mfile1.h" +%} + + /* define types */ +%start ext_def_list + +%type con_e ifelprefix ifprefix whprefix forprefix doprefix switchpart + enum_head str_head name_lp +%type e .e term attributes oattributes type enum_dcl struct_dcl + cast_type null_decl funct_idn declarator fdeclarator + nfdeclarator elist + +%token CLASS NAME STRUCT RELOP CM DIVOP PLUS MINUS SHIFTOP MUL AND OR + ER ANDAND OROR ASSIGN STROP INCOP UNOP ICON +%token TYPE + +%% + +%{ + static int fake = 0; + static char fakename[NCHNAM+1]; +%} + +ext_def_list: ext_def_list external_def + | /* EMPTY */ + { +#ifndef LINT + beg_file(); +#endif + ftnend(); + } + ; +external_def: data_def + { curclass = SNULL; blevel = 0; } + | error + { curclass = SNULL; blevel = 0; } + | ASM SM + { asmout(); curclass = SNULL; blevel = 0; } + ; +data_def: oattributes SM + { $1->in.op = FREE; } + | oattributes init_dcl_list SM + { $1->in.op = FREE; } + | oattributes fdeclarator + { defid( tymerge($1,$2), + curclass==STATIC?STATIC:EXTDEF ); } + function_body + { + if( blevel ) cerror( "function level error" ); + if( reached ) retstat |= NRETVAL; + $1->in.op = FREE; + ftnend(); + } + ; + +function_body: arg_dcl_list compoundstmt + { regvar = 0; } /* clear out arguments */ + ; + +arg_dcl_list: arg_dcl_list attributes declarator_list SM + { curclass = SNULL; $2->in.op = FREE; } + | arg_dcl_list attributes SM + /* to permit structs in decl. lists */ + { curclass = SNULL; $2->in.op = FREE; } + | /* EMPTY */ { blevel = 1; } + ; + +stmt_list: stmt_list statement + | /* EMPTY */ + { bccode(); + locctr(PROG); + } + ; + +dcl_stat_list : dcl_stat_list attributes SM + { $2->in.op = FREE; } + | dcl_stat_list attributes init_dcl_list SM + { $2->in.op = FREE; } + | /* EMPTY */ + ; + +oattributes: attributes + | /* empty */ + { $$ = mkty(INT,0,INT); curclass = SNULL; } + ; +attributes: class type + { $$ = $2; } + | type class + | class + { $$ = mkty(INT,0,INT); } + | type + { curclass = SNULL ; } + | type class type + { $1->in.type = types( $1->in.type, $3->in.type, + UNDEF ); + $3->in.op = FREE; + } + ; + +class: CLASS + { curclass = $1; } + ; + +type: TYPE + | TYPE TYPE + { $1->in.type = types( $1->in.type, $2->in.type, UNDEF ); + $2->in.op = FREE; + } + | TYPE TYPE TYPE + { $1->in.type = types( $1->in.type, $2->in.type, $3->in.type ); + $2->in.op = $3->in.op = FREE; + } + | struct_dcl + | enum_dcl + ; + +enum_dcl: enum_head LC moe_list optcomma RC + { $$ = dclstruct($1); } + | ENUM NAME + { $$ = rstruct($2,0); stwart = instruct; } + ; + +enum_head: ENUM + { $$ = bstruct(-1,0); stwart = SEENAME; } + | ENUM NAME + { $$ = bstruct($2,0); stwart = SEENAME; } + ; + +moe_list: moe + | moe_list CM moe + ; + +moe: NAME + { moedef( $1 ); } + | NAME ASSIGN con_e + { strucoff = $3; moedef( $1 ); } + ; + +struct_dcl: str_head LC type_dcl_list optsemi RC + { $$ = dclstruct($1); } + | STRUCT NAME + { $$ = rstruct($2,$1); } + ; + +str_head: STRUCT + { $$ = bstruct(-1,$1); stwart=0; } + | STRUCT NAME + { $$ = bstruct($2,$1); stwart=0; } + ; + +type_dcl_list: type_declaration + | type_dcl_list SM type_declaration + ; + +type_declaration: type declarator_list + { curclass = SNULL; stwart=0; $1->in.op = FREE; } + | type + { if( curclass != MOU ){ + curclass = SNULL; + } + else { + sprintf( fakename, "$%dFAKE", fake++ ); + defid( tymerge($1, bdty(NAME,NIL, + lookup( fakename, SMOS ))), curclass ); + werror("union member must be named"); + } + stwart = 0; + $1->in.op = FREE; + } + ; + + +declarator_list: declarator + { defid( tymerge($0,$1), curclass); + stwart = instruct; } + | declarator_list CM {$$=$0;} declarator + { defid( tymerge($0,$4), curclass); + stwart = instruct; } + ; +declarator: nfdeclarator + | nfdeclarator COLON con_e + %prec CM + { if( !(instruct&INSTRUCT) ) + uerror( "field outside of structure" ); + if( $3<0 || $3 >= FIELD ){ + uerror( "illegal field size" ); + $3 = 1; + } + defid( tymerge($0,$1), FIELD|$3 ); + $$ = NIL; + } + | COLON con_e + %prec CM + { if( !(instruct&INSTRUCT) ) + uerror( "field outside of structure" ); + /* alignment or hole */ + falloc( stab, $2, -1, $0 ); + $$ = NIL; + } + | error + { $$ = NIL; } + ; + + /* int (a)(); is not a function --- sorry! */ +nfdeclarator: MUL nfdeclarator + { umul: + $$ = bdty( UNARY MUL, $2, 0 ); } + | nfdeclarator LP RP + { uftn: + $$ = bdty( UNARY CALL, $1, 0 ); } + | nfdeclarator LB RB + { uary: + $$ = bdty( LB, $1, 0 ); } + | nfdeclarator LB con_e RB + { bary: + if( (int)$3 <= 0 ) + werror( "zero or negative subscript" ); + $$ = bdty( LB, $1, $3 ); } + | NAME + { $$ = bdty( NAME, NIL, $1 ); } + | LP nfdeclarator RP + { $$=$2; } + ; +fdeclarator: MUL fdeclarator + { goto umul; } + | fdeclarator LP RP + { goto uftn; } + | fdeclarator LB RB + { goto uary; } + | fdeclarator LB con_e RB + { goto bary; } + | LP fdeclarator RP + { $$ = $2; } + | name_lp name_list RP + { + if( blevel!=0 ) + uerror( + "function declaration in bad context"); + $$ = bdty( UNARY CALL, bdty(NAME,NIL,$1), 0 ); + stwart = 0; + } + | name_lp RP + { + $$ = bdty( UNARY CALL, bdty(NAME,NIL,$1), 0 ); + stwart = 0; + } + ; + +name_lp: NAME LP + { + /* turn off typedefs for argument names */ + stwart = SEENAME; + if( stab[$1].sclass == SNULL ) + stab[$1].stype = FTN; + } + ; + +name_list: NAME + { ftnarg( $1 ); stwart = SEENAME; } + | name_list CM NAME + { ftnarg( $3 ); stwart = SEENAME; } + | error + ; + /* always preceeded by attributes: thus the $0's */ +init_dcl_list: init_declarator + %prec CM + | init_dcl_list CM {$$=$0;} init_declarator + ; + /* always preceeded by attributes */ +xnfdeclarator: nfdeclarator + { defid( $1 = tymerge($0,$1), curclass); + beginit($1->tn.rval); + } + | error + ; + /* always preceeded by attributes */ +init_declarator: nfdeclarator + { nidcl( tymerge($0,$1) ); } + | fdeclarator + { defid( tymerge($0,$1), uclass(curclass) ); + } + | xnfdeclarator ASSIGN e + %prec CM + { doinit( $3 ); + endinit(); } + | xnfdeclarator ASSIGN LC init_list optcomma RC + { endinit(); } + | error + ; + +init_list: initializer + %prec CM + | init_list CM initializer + ; +initializer: e + %prec CM + { doinit( $1 ); } + | ibrace init_list optcomma RC + { irbrace(); } + ; + +optcomma : /* empty */ + | CM + ; + +optsemi : /* empty */ + | SM + ; + +ibrace : LC + { ilbrace(); } + ; + +/* STATEMENTS */ + +compoundstmt: begin dcl_stat_list stmt_list RC + { + clearst(blevel); + if (--blevel == 1) + { + clearst(blevel); + blevel = 0; + } + checkst(blevel); + autooff = *--psavbc; + regvar = *--psavbc; + } + ; + +begin: LC + { if( blevel == 1 ) dclargs(); + ++blevel; + if( psavbc > &asavbc[BCSZ-2] ) + cerror( "nesting too deep" ); + *psavbc++ = regvar; + *psavbc++ = autooff; + } + ; + +statement: e SM + { ecomp( $1 ); } + | ASM SM + { asmout(); } + | compoundstmt + | ifprefix statement + { deflab($1); + reached = 1; + } + | ifelprefix statement + { if( $1 != NOLAB ){ + deflab( $1 ); + reached = 1; + } + } + | whprefix statement + { branch((int)( contlab)); + deflab( brklab ); + if( (flostat&FBRK) || !(flostat&FLOOP)) reached = 1; + else reached = 0; + resetbc(0); + } + | doprefix statement WHILE LP e RP SM + { deflab( contlab ); + if( flostat & FCONT ) reached = 1; + ecomp( buildtree( CBRANCH, + buildtree( NOT, $5, NIL ), bcon( $1 ) ) ); + deflab( brklab ); + reached = 1; + resetbc(0); + } + | forprefix .e RP statement + { deflab( contlab ); + if( flostat&FCONT ) reached = 1; + if( $2 ) ecomp( $2 ); + branch((int)($1)); + deflab( brklab ); + if( (flostat&FBRK) || !(flostat&FLOOP) ) reached=1; + else reached=0; + resetbc(0); + } + | switchpart statement + { if( reached ) branch((int)(brklab)); + deflab( $1 ); + swend(); + deflab(brklab); + if( (flostat&FBRK) || !(flostat&FDEF) ) reached=1; + resetbc(FCONT); + } + | BREAK SM + { if( brklab == NOLAB ) uerror( "illegal break"); + else if(reached) branch((int)(brklab)); + flostat |= FBRK; + if( brkflag ) goto rch; + reached = 0; + } + | CONTINUE SM + { if( contlab == NOLAB ) uerror( "illegal continue"); + else branch((int)(contlab)); + flostat |= FCONT; + goto rch; + } + | RETURN SM + { retstat |= NRETVAL; + branch((int)(retlab)); + rch: + if( !reached ) werror( "statement not reached"); + reached = 0; + } + | RETURN e SM + { register NODE *temp; + TWORD indtype(); + idname = curftn; + temp = buildtree( NAME, NIL, NIL ); + if(temp->in.type == (FTN|VOID)) + lerror( + "void function %s cannot return value", + stab[idname].sname); + temp->in.type = DECREF( temp->in.type ); + temp->in.type = indtype( temp->in.type ); + temp->tn.op = RNODE; /* node for return */ + temp = buildtree( ASSIGN, temp, $2 ); + ecomp( temp ); + retstat |= RETVAL; + branch((int)(retlab)); + reached = 0; + } + | GOTO NAME SM + { register NODE *q; + q = block( FREE, NIL, NIL, INT|ARY, 0, INT ); + q->tn.rval = idname = $2; + defid( q, ULABEL ); + stab[idname].suse = -lineno; + branch((int)(stab[idname].offset)); + goto rch; + } + | SM + | error SM + | error RC + | label statement + ; +label: NAME COLON + { register NODE *q; + q = block( FREE, NIL, NIL, INT|ARY, 0, LABEL ); + q->tn.rval = $1; + defid( q, LABEL ); + reached = 1; + } + | CASE e COLON + { addcase($2); + reached = 1; + } + | DEFAULT COLON + { reached = 1; + adddef(); + flostat |= FDEF; + } + ; +doprefix: DO + { savebc(); + if( !reached ) werror( "loop not entered at top"); + brklab = getlab(); + contlab = getlab(); + deflab( $$ = getlab() ); + reached = 1; + } + ; +ifprefix: IF LP e RP + { ecomp( buildtree( CBRANCH, $3, bcon( $$=getlab()) ) ) ; + reached = 1; + } + ; +ifelprefix: ifprefix statement ELSE + { if( reached ) branch((int)($$ = getlab())); + else $$ = NOLAB; + deflab( $1 ); + reached = 1; + } + ; + +whprefix: WHILE LP e RP + { savebc(); + if( !reached ) werror( "loop not entered at top"); + if( $3->in.op == ICON && $3->tn.lval != 0 ) flostat = FLOOP; + deflab( contlab = getlab() ); + reached = 1; + brklab = getlab(); + if( flostat == FLOOP ) tfree( $3 ); + else ecomp( buildtree( CBRANCH, $3, bcon( brklab) ) ); + } + ; +forprefix: FOR LP .e SM .e SM + { if( $3 ) ecomp( $3 ); + else if( !reached ) werror( "loop not entered at top"); + savebc(); + contlab = getlab(); + brklab = getlab(); + deflab( $$ = getlab() ); + reached = 1; + if( $5 ) + ecomp( buildtree( CBRANCH, $5, bcon( brklab) )); + else flostat |= FLOOP; + } + ; +switchpart: SWITCH LP e RP + { register NODE *temp; + savebc(); + temp = block( SNODE, NIL, NIL, INT, 0, INT ); + temp = buildtree( ASSIGN, temp, $3 ); + brklab = getlab(); + ecomp( temp ); + branch((int)($$ = getlab())); + swstart(); + reached = 0; + } + ; +/* EXPRESSIONS */ +con_e: { $$=instruct; stwart=instruct=0; } e + %prec CM + { $$ = icons( $2 ); instruct=$1; } + ; +.e: e + | + { $$=0; } + ; +elist: e + %prec CM + | elist CM e + { goto bop; } + ; + +e: e RELOP e + { + preconf: + if( yychar==RELOP || yychar==EQUOP || yychar==AND + || yychar==OR || yychar==ER ){ + precplaint: + if( hflag ) werror( + "precedence confusion possible: parenthesize!" + ); + } + bop: + $$ = buildtree( $2, $1, $3 ); + } + | e CM e + { $2 = COMOP; + goto bop; + } + | e DIVOP e + { goto bop; } + | e PLUS e + { if(yychar==SHIFTOP) goto precplaint; else goto bop; } + | e MINUS e + { if(yychar==SHIFTOP ) goto precplaint; else goto bop; } + | e SHIFTOP e + { if(yychar==PLUS||yychar==MINUS) goto precplaint; else goto bop; } + | e MUL e + { goto bop; } + | e EQUOP e + { goto preconf; } + | e AND e + { if( yychar==RELOP||yychar==EQUOP ) goto preconf; else goto bop; } + | e OR e + { if(yychar==RELOP||yychar==EQUOP) goto preconf; else goto bop; } + | e ER e + { if(yychar==RELOP||yychar==EQUOP) goto preconf; else goto bop; } + | e ANDAND e + { goto bop; } + | e OROR e + { goto bop; } + | e MUL ASSIGN e + { abop: + $$ = buildtree( ASG $2, $1, $4 ); + } + | e DIVOP ASSIGN e + { goto abop; } + | e PLUS ASSIGN e + { goto abop; } + | e MINUS ASSIGN e + { goto abop; } + | e SHIFTOP ASSIGN e + { goto abop; } + | e AND ASSIGN e + { goto abop; } + | e OR ASSIGN e + { goto abop; } + | e ER ASSIGN e + { goto abop; } + | e QUEST e COLON e + { $$=buildtree(QUEST, $1, buildtree( COLON, $3, $5 ) ); + } + | e ASOP e + { werror( "old-fashioned assignment operator" ); + goto bop; } + | e ASSIGN e + { goto bop; } + | term + ; + +term: term INCOP + { $$ = buildtree( $2, $1, bcon(1) ); } + | MUL term + { ubop: + $$ = buildtree( UNARY $1, $2, NIL ); + } + | AND term + { if( ISFTN($2->in.type) || ISARY($2->in.type) ){ + werror( "& before array or function: ignored" ); + $$ = $2; + } + else goto ubop; + } + | MINUS term + { goto ubop; } + | UNOP term + { + $$ = buildtree( $1, $2, NIL ); + } + | INCOP term + { $$ = buildtree( $1==INCR ? ASG PLUS : ASG MINUS, + $2, + bcon(1) ); + } + | SIZEOF term + { $$ = doszof( $2 ); } + | LP cast_type RP term %prec INCOP + { $$ = buildtree( CAST, $2, $4 ); + $$->in.left->in.op = FREE; + $$->in.op = FREE; + $$ = $$->in.right; + } + | SIZEOF LP cast_type RP %prec SIZEOF + { $$ = doszof( $3 ); } + | term LB e RB + { $$ = buildtree( LB, $1, $3 ); } + | term LB e COLON e RB + { $$ = xicolon( $1, $3, $5 ); } + | funct_idn RP + { $$=buildtree(UNARY CALL,$1,NIL); } + | funct_idn elist RP + { $$=buildtree(CALL,$1,$2); } + | term STROP NAME + { if( $2 == DOT ){ + if( notlval( $1 ) )uerror( + "structure reference must be addressable" + ); + $1 = buildtree( UNARY AND, $1, NIL ); + } + idname = $3; + $$ = buildtree( STREF, $1, + buildtree( NAME, NIL, NIL ) ); + } + | NAME + { idname = $1; + /* recognize identifiers in initializations */ + if( blevel==0 && stab[idname].stype == UNDEF ) { + register NODE *q; + werror( "undeclared initializer name %s", + stab[idname].sname ); + q = block( FREE, NIL, NIL, INT, 0, INT ); + q->tn.rval = idname; + defid( q, EXTERN ); + } + $$=buildtree(NAME,NIL,NIL); + stab[$1].suse = -lineno; + } + | ICON + { $$=bcon(0); + $$->tn.lval = lastcon; + $$->tn.rval = NONAME; + if( $1 ) $$->fn.csiz = $$->in.type = ctype(LONG); + } + | FCON + { $$=buildtree(FCON,NIL,NIL); + $$->fpn.dval = dcon; + } + | STRING + { $$ = getstr(); /* get string contents */ } + | LP e RP + { $$=$2; } + ; + +cast_type: type null_decl + { + $$ = tymerge( $1, $2 ); + $$->in.op = NAME; + $1->in.op = FREE; + } + ; + +null_decl: /* EMPTY */ + { $$ = bdty( NAME, NIL, -1 ); } + | LP RP + { $$ = bdty( UNARY CALL, bdty(NAME,NIL,-1),0); } + | LP null_decl RP LP RP + { $$ = bdty( UNARY CALL, $2, 0 ); } + | MUL null_decl + { goto umul; } + | null_decl LB RB + { goto uary; } + | null_decl LB con_e RB + { goto bary; } + | LP null_decl RP + { $$ = $2; } + ; + +funct_idn: NAME LP + { if( stab[$1].stype == UNDEF ){ + register NODE *q; + q = block( FREE, NIL, NIL, FTN|INT, 0, INT ); + q->tn.rval = $1; + defid( q, EXTERN ); + } + idname = $1; + $$=buildtree(NAME,NIL,NIL); + stab[idname].suse = -lineno; + } + | term LP + ; +%% + +NODE * +mkty( t, d, s ) unsigned t; { + return( block( TYPE, NIL, NIL, t, d, s ) ); + } + +NODE * +bdty( op, p, v ) NODE *p; { + register NODE *q; + + q = block( op, p, NIL, INT, 0, INT ); + + switch( op ){ + + case UNARY MUL: + case UNARY CALL: + break; + + case LB: + q->in.right = bcon(v); + break; + + case NAME: + q->tn.rval = v; + break; + + default: + cerror( "bad bdty" ); + } + + return( q ); + } + +dstash( n ){ /* put n into the dimension table */ + if( curdim >= DIMTABSZ-1 ){ + cerror( "dimension table overflow"); + } + dimtab[ curdim++ ] = n; + } + +savebc() { + if( psavbc > & asavbc[BCSZ-4 ] ){ + cerror( "whiles, fors, etc. too deeply nested"); + } + *psavbc++ = brklab; + *psavbc++ = contlab; + *psavbc++ = flostat; + *psavbc++ = swx; + flostat = 0; + } + +resetbc(mask){ + + swx = *--psavbc; + flostat = *--psavbc | (flostat&mask); + contlab = *--psavbc; + brklab = *--psavbc; + + } + +addcase(p) NODE *p; { /* add case to switch */ + + p = optim( p ); /* change enum to ints */ + if( p->in.op != ICON ){ + uerror( "non-constant case expression"); + return; + } + if( swp == swtab ){ + uerror( "case not in switch"); + return; + } + if( swp >= &swtab[SWITSZ] ){ + cerror( "switch table overflow"); + } + swp->sval = p->tn.lval; + deflab( swp->slab = getlab() ); + ++swp; + tfree(p); + } + +adddef(){ /* add default case to switch */ + if( swtab[swx].slab >= 0 ){ + uerror( "duplicate default in switch"); + return; + } + if( swp == swtab ){ + uerror( "default not inside switch"); + return; + } + deflab( swtab[swx].slab = getlab() ); + } + +swstart(){ + /* begin a switch block */ + if( swp >= &swtab[SWITSZ] ){ + cerror( "switch table overflow"); + } + swx = swp - swtab; + swp->slab = -1; + ++swp; + } + +swend(){ /* end a switch block */ + + register struct sw *swbeg, *p, *q, *r, *r1; + CONSZ temp; + int tempi; + + swbeg = &swtab[swx+1]; + + /* sort */ + + r1 = swbeg; + r = swp-1; + + while( swbeg < r ){ + /* bubble largest to end */ + for( q=swbeg; qsval > (q+1)->sval ){ + /* swap */ + r1 = q+1; + temp = q->sval; + q->sval = r1->sval; + r1->sval = temp; + tempi = q->slab; + q->slab = r1->slab; + r1->slab = tempi; + } + } + r = r1; + r1 = swbeg; + } + + /* it is now sorted */ + + for( p = swbeg+1; psval == (p-1)->sval ){ + uerror( "duplicate case in switch, %d", + tempi=(int)p->sval ); + return; + } + } + + reached = 1; + genswitch( swbeg-1, (int)(swp-swbeg) ); + swp = swbeg-1; + }