/* special interfaces for yacc alone */
/* These serve as abbreviations of 2 or more ops:
/* reserved words, etc */
/* little symbols, etc. */
/* at last count, there were 7 shift/reduce, 1 reduce/reduce conflicts
recognizing functions in various contexts, including declarations
%type <intval> con_e ifelprefix ifprefix whprefix forprefix doprefix switchpart
enum_head str_head name_lp
%type <nodep> e .e term attributes oattributes type enum_dcl struct_dcl
cast_type null_decl funct_idn declarator fdeclarator nfdeclarator
%token <intval> CLASS NAME STRUCT RELOP CM DIVOP PLUS MINUS SHIFTOP MUL AND OR ER ANDAND OROR
ASSIGN STROP INCOP UNOP ICON
static char fakename[NCHNAM+1];
ext_def_list: ext_def_list external_def
={ curclass = SNULL; blevel = 0; }
={ curclass = SNULL; blevel = 0; }
| oattributes init_dcl_list SM
| oattributes fdeclarator {
defid( tymerge($1,$2), curclass==STATIC?STATIC:EXTDEF );
if( blevel ) cerror( "function level error" );
if( reached ) retstat |= NRETVAL;
function_body: arg_dcl_list compoundstmt
arg_dcl_list: arg_dcl_list declaration
stmt_list: stmt_list statement
dcl_stat_list : dcl_stat_list attributes SM
| dcl_stat_list attributes init_dcl_list SM
declaration: attributes declarator_list SM
={ curclass = SNULL; $1->op = FREE; }
={ curclass = SNULL; $1->op = FREE; }
={ $$ = mkty(INT,0,INT); curclass = SNULL; }
={ $$ = mkty(INT,0,INT); }
={ $1->type = types( $1->type, $2->type, UNDEF );
={ $1->type = types( $1->type, $2->type, $3->type );
enum_dcl: enum_head LC moe_list optcomma RC
={ $$ = rstruct($2,0); stwart = instruct; }
={ strucoff = $3; moedef( $1 ); }
struct_dcl: str_head LC type_dcl_list optsemi RC
={ $$ = rstruct($2,$1); }
={ $$ = bstruct(-1,$1); stwart=0; }
={ $$ = 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->op = FREE; }
={ if( curclass != MOU ){
sprintf( fakename, "$%dFAKE", fake++ );
defid( tymerge($1, bdty(NAME,NIL,lookup( fakename, SMOS ))), curclass );
declarator_list: declarator
={ defid( tymerge($<nodep>0,$1), curclass); stwart = instruct; }
| declarator_list CM {$<nodep>$=$<nodep>0;} declarator
={ defid( tymerge($<nodep>0,$4), curclass); stwart = instruct; }
| nfdeclarator COLON con_e
={ if( !(instruct&INSTRUCT) ) uerror( "field outside of structure" );
if( $3<0 || $3 >= FIELD ){
uerror( "illegal field size" );
defid( tymerge($<nodep>0,$1), FIELD|$3 );
={ if( !(instruct&INSTRUCT) ) uerror( "field outside of structure" );
falloc( stab, $2, -1, $<nodep>0 ); /* alignment or hole */
/* int (a)(); is not a function --- sorry! */
nfdeclarator: MUL nfdeclarator
$$ = bdty( UNARY MUL, $2, 0 ); }
$$ = bdty( UNARY CALL, $1, 0 ); }
$$ = bdty( LB, $1, 0 ); }
| nfdeclarator LB con_e RB
if( (int)$3 <= 0 ) werror( "zero or negative subscript" );
$$ = bdty( LB, $1, $3 ); }
={ $$ = bdty( NAME, NIL, $1 ); }
fdeclarator: MUL fdeclarator
| fdeclarator LB con_e RB
if( blevel!=0 ) uerror("function declaration in bad context");
$$ = bdty( UNARY CALL, bdty(NAME,NIL,$1), 0 );
$$ = bdty( UNARY CALL, bdty(NAME,NIL,$1), 0 );
/* turn off typedefs for argument names */
={ ftnarg( $1 ); stwart = SEENAME; }
={ ftnarg( $3 ); stwart = SEENAME; }
/* always preceeded by attributes: thus the $<nodep>0's */
init_dcl_list: init_declarator
| init_dcl_list CM {$<nodep>$=$<nodep>0;} init_declarator
/* always preceeded by attributes */
xnfdeclarator: nfdeclarator
={ defid( $1 = tymerge($<nodep>0,$1), curclass);
/* always preceeded by attributes */
init_declarator: nfdeclarator
={ nidcl( tymerge($<nodep>0,$1) ); }
={ defid( tymerge($<nodep>0,$1), uclass(curclass) );
| xnfdeclarator optasgn e
| xnfdeclarator optasgn LC init_list optcomma RC
| init_list CM initializer
| ibrace init_list optcomma RC
={ werror( "old-fashioned initialization: use =" ); }
compoundstmt: begin dcl_stat_list stmt_list RC
if( blevel == 1 ) blevel = 0;
={ if( blevel == 1 ) dclargs();
if( psavbc > &asavbc[BCSZ-2] ) cerror( "nesting too deep" );
if( (flostat&FBRK) || !(flostat&FLOOP)) reached = 1;
| doprefix statement WHILE LP e RP SM
if( flostat & FCONT ) reached = 1;
ecomp( buildtree( CBRANCH, buildtree( NOT, $5, NIL ), bcon( $1 ) ) );
| forprefix .e RP statement
if( flostat&FCONT ) reached = 1;
if( (flostat&FBRK) || !(flostat&FLOOP) ) reached = 1;
={ if( reached ) branch( brklab );
if( (flostat&FBRK) || !(flostat&FDEF) ) reached = 1;
={ if( brklab == NOLAB ) uerror( "illegal break");
else if(reached) branch( brklab );
={ if( contlab == NOLAB ) uerror( "illegal continue");
if( !reached ) werror( "statement not reached");
temp = buildtree( NAME, NIL, NIL );
temp->type = DECREF( temp->type );
temp = buildtree( RETURN, temp, $2 );
/* now, we have the type of the RHS correct */
ecomp( buildtree( FORCE, temp->right, NIL ) );
q = block( FREE, NIL, NIL, INT|ARY, 0, INT );
stab[idname].suse = -lineno;
branch( stab[idname].offset );
q = block( FREE, NIL, NIL, INT|ARY, 0, LABEL );
if( !reached ) werror( "loop not entered at top");
={ ecomp( buildtree( CBRANCH, $3, bcon( $$=getlab()) ) ) ;
ifelprefix: ifprefix statement ELSE
={ if( reached ) branch( $$ = getlab() );
if( !reached ) werror( "loop not entered at top");
if( $3->op == ICON && $3->lval != 0 ) flostat = FLOOP;
deflab( contlab = getlab() );
if( flostat == FLOOP ) tfree( $3 );
else ecomp( buildtree( CBRANCH, $3, bcon( brklab) ) );
forprefix: FOR LP .e SM .e SM
else if( !reached ) werror( "loop not entered at top");
if( $5 ) ecomp( buildtree( CBRANCH, $5, bcon( brklab) ) );
switchpart: SWITCH LP e RP
ecomp( buildtree( FORCE, $3, NIL ) );
con_e: { $<intval>$=instruct; stwart=instruct=0; } e
={ $$ = icons( $2 ); instruct=$<intval>1; }
if( yychar==RELOP||yychar==EQUOP||yychar==AND||yychar==OR||yychar==ER ){
if( hflag ) werror( "precedence confusion possible: parenthesize!" );
$$ = buildtree( $2, $1, $3 );
={ if(yychar==SHIFTOP) goto precplaint; else goto bop; }
={ if(yychar==SHIFTOP ) goto precplaint; else goto bop; }
={ if(yychar==PLUS||yychar==MINUS) goto precplaint; else goto bop; }
={ if( yychar==RELOP||yychar==EQUOP ) goto preconf; else goto bop; }
={ if(yychar==RELOP||yychar==EQUOP) goto preconf; else goto bop; }
={ if(yychar==RELOP||yychar==EQUOP) goto preconf; else goto bop; }
$$ = buildtree( ASG $2, $1, $4 );
={ $$=buildtree(QUEST, $1, buildtree( COLON, $3, $5 ) );
={ werror( "old-fashioned assignment operator" ); goto bop; }
={ $$ = buildtree( $2, $1, bcon(1) ); }
$$ = buildtree( UNARY $1, $2, NIL );
={ if( ISFTN($2->type) || ISARY($2->type) ){
werror( "& before array or function: ignored" );
$$ = buildtree( $1, $2, NIL );
={ $$ = buildtree( $1==INCR ? ASG PLUS : ASG MINUS,
| LP cast_type RP term %prec INCOP
={ $$ = buildtree( CAST, $2, $4 );
| SIZEOF LP cast_type RP %prec SIZEOF
={ $$ = buildtree( UNARY MUL, buildtree( PLUS, $1, $3 ), NIL ); }
={ $$=buildtree(UNARY CALL,$1,NIL); }
={ $$=buildtree(CALL,$1,$2); }
$1 = buildtree( UNARY AND, $1, NIL );
$$ = buildtree( STREF, $1, buildtree( NAME, NIL, NIL ) );
/* recognize identifiers in initializations */
if( blevel==0 && stab[idname].stype == UNDEF ) {
werror( "undeclared initializer name %.8s", stab[idname].sname );
q = block( FREE, NIL, NIL, INT, 0, INT );
$$=buildtree(NAME,NIL,NIL);
if( $1 ) $$->csiz = $$->type = ctype(LONG);
={ $$=buildtree(FCON,NIL,NIL);
={ $$ = getstr(); /* get string contents */ }
cast_type: type null_decl
={ $$ = bdty( NAME, NIL, -1 ); }
={ $$ = bdty( UNARY CALL, bdty(NAME,NIL,-1),0); }
={ $$ = bdty( UNARY CALL, $2, 0 ); }
={ if( stab[$1].stype == UNDEF ){
q = block( FREE, NIL, NIL, FTN|INT, 0, INT );
$$=buildtree(NAME,NIL,NIL);
stab[idname].suse = -lineno;
mkty( t, d, s ) unsigned t; {
return( block( TYPE, NIL, NIL, t, d, s ) );
bdty( op, p, v ) NODE *p; {
q = block( op, p, NIL, INT, 0, INT );
dstash( n ){ /* put n into the dimension table */
if( curdim >= DIMTABSZ-1 ){
cerror( "dimension table overflow");
if( psavbc > & asavbc[BCSZ-4 ] ){
cerror( "whiles, fors, etc. too deeply nested");
flostat = *--psavbc | (flostat&mask);
addcase(p) NODE *p; { /* add case to switch */
p = optim( p ); /* change enum to ints */
uerror( "non-constant case expression");
uerror( "case not in switch");
if( swp >= &swtab[SWITSZ] ){
cerror( "switch table overflow");
deflab( swp->slab = getlab() );
adddef(){ /* add default case to switch */
if( swtab[swx].slab >= 0 ){
uerror( "duplicate default in switch");
uerror( "default not inside switch");
deflab( swtab[swx].slab = getlab() );
/* begin a switch block */
if( swp >= &swtab[SWITSZ] ){
cerror( "switch table overflow");
swend(){ /* end a switch block */
register struct sw *swbeg, *p, *q, *r, *r1;
/* bubble largest to end */
for( q=swbeg; q<r; ++q ){
if( q->sval > (q+1)->sval ){
for( p = swbeg+1; p<swp; ++p ){
if( p->sval == (p-1)->sval ){
uerror( "duplicate case in switch, %d", tempi=p->sval );
genswitch( swbeg-1, swp-swbeg );