/* Copyright 1982, 1983 Alcyon Corporation 8716 Production Ave. San Diego, Ca. 92121 @(#)init.c 1.13 1/3/84 */ #include "parser.h" #define NULL (char *)0 short inittype; short bfield_ty; /* [vlh] 4.2 type of bit field currently initializing */ short bits_init; /* [vlh] 4.2 current bit field init value */ short in_bitinit; /* [vlh] 4.2 are we currently initializing a bit field ?? */ short lst_boffset; /* [vlh] 4.2 new bit field entity ?? */ #define BCHK(plus) {plus = out_bfield(CHAR); nbout += plus; nbleft += plus;} /* * doinit - do external definition initialization * Handles following C syntax: * initializer: * = constant_expression * = { initializer_list } * = { initializer_list , } * initializer_list: * constant_expression * initializer_list , initializer_list * { initializer_list } */ doinit(sp) /* returns number of elements init'ed*/ struct symbol *sp; /* pointer to symbol to init*/ { register short type; long isize, datasize; type = sp->s_type; datasize = dsize(type,sp->s_dp,sp->s_ssp); if( PEEK(COMMA) || PEEK(SEMI) ) { /*no initialization*/ isize = WALIGN(datasize); #ifdef DEBUG if(initdebug) printf("%s sc %x attrib %x\n",sp->s_symbol,sp->s_sc,sp->s_attrib); #endif if( sp->s_sc == EXTERNAL ) OUTCOMMON(sp->s_symbol,isize); else if (sp->s_sc == DEXTERN) /* explicitly EXTERN */ sp->s_sc = EXTERNAL; else { OUTBSS(); /*bss segment*/ OUTLAB(sp->s_offset); OUTRESMEM(isize); OUTTEXT(); /*resume text segment*/ } } else { if (!(next(ASSIGN))) /*ignore '=' if there*/ warning("old fashion initialization"); if( type == LONG || ISPOINTER(type) ) outldata(); else if(type == DOUBLE || type == FLOAT) /*[vlh] 3.4*/ outfpdata(); else outdata(); if( sp->s_sc == EXTERNAL ) OUTDLAB(sp->s_symbol); else OUTLAB(sp->s_offset); isize = initlist(sp, sp->s_type, sp->s_dp, sp->s_ssp); if( isize < datasize ) { OUTRESMEM(datasize-isize); isize = datasize; } if( WALIGN(isize) != isize ) OUTPAD(); if( isize > datasize ) { if( ISARRAY(sp->s_type) ) { for( type = sp->s_type; ISARRAY(type); type = delsp(type) ) ; dtab[sp->s_dp] = (isize / dsize(type,sp->s_dp,sp->s_ssp)); } else error("too many initializers"); } if( sp->s_sc == STATIC ) OUTTEXT(); } } /* * initlist - handles initializer lists * This handles multi-level braces, and a character pointer pointing * to a string. Most of the work is in keeping track of how many * bytes are left on the current "row", and outputting padding if * necessary. */ long initlist(sp,type,dp,ssp) /* returns size of initializers in bytes*/ struct symbol *sp; /* [vlh] 4.2 for use in struct init */ int type, dp, ssp; { register short onetype, plus, atype; long datasize, i, j, elsize, nbleft, nbout; /* [vlh] 3.4 int=>long */ #ifdef SYM_TO_DSK struct symbol par_str; /* parent structure.... */ #endif i = (next(LCURBR)); for( onetype = type; ISARRAY(onetype); onetype = delsp(onetype) ) ; #ifdef DEBUG if (initdebug) { printf("type: %d BTYPE %d ISARRAY %d ",type,BTYPE(type),ISARRAY(type)); printf("POINTER %d\n",ISPOINTER(type)); printf("onetype: %d BTYPE %d ",onetype,BTYPE(onetype)); printf("ISARRAY %d POINTER %d\n",ISARRAY(onetype),ISPOINTER(onetype)); } #endif nbout = 0; datasize = dsize(type,dp,ssp); nbleft = 0; /*keep track of no. of bytes left*/ atype = (ISARRAY(type)) ? delsp(type) : type; /*[vlh]4.2 multi dimens */ if(type==(ARRAY|CHAR) || type==(ARRAY|INT) || type==(ARRAY|LONG)) nbout = str_init(datasize,type); else if(atype==(ARRAY|CHAR) || atype==(ARRAY|INT) || atype==(ARRAY|LONG)) { datasize = dsize(atype,dp,ssp); elsize = dsize(atype,dp+1,ssp); if( !i ) error("missing { in initialization"); do { j = (next(LCURBR)); nbout += str_init(elsize,atype); if (j && !(next(RCURBR))) error("missing } in initialization"); next(COMMA); /* skip over comma... */ } while(!PEEK(RCURBR) && !PEEK(SEMI)); nbleft = datasize - nbout; if ((elsize==INTSIZE && (onetype==INT) || (onetype==SHORT)) || (elsize==CHARSIZE && (onetype==CHAR)) || (elsize==LONGSIZE && (onetype==LONG)) || (datasize==elsize)) /*undimensioned array*/ nbleft = 0; if (nbleft < 0) { error("initializer list too long"); nbleft = 0; } } /* multi-dimensional array */ else if (BTYPE(type)==STRUCT && NOTPOINTER(type) && ISPOINTER(onetype)) { nbleft = elsize = PTRSIZE; /* [vlh] 4.2.f */ if( !i ) error("missing { in initialization"); do { nbleft = s_or_a(POINTER|CHAR,elsize,&nbout,nbleft,NULL,NULL); next(COMMA); /* skip over comma... */ } while(!PEEK(RCURBR) && !PEEK(SEMI)); } else if (ISARRAY(type) || (BTYPE(type)==STRUCT && NOTPOINTER(type))) { nbleft = elsize = dsize(delsp(type),dp,ssp); /* was dp+1 */ /* [vlh] 4.2, added proper handling of structure init... */ if( !i && BTYPE(type)==STRUCT ) error("missing { in initialization"); do { #ifndef SYM_TO_DSK nbleft = s_or_a(onetype,elsize,&nbout,nbleft,sp->s_par,NULL); #else read_st(&par_str,sp->s_par); nbleft = s_or_a(onetype,elsize,&nbout,nbleft,&par_str,NULL); #endif next(COMMA); /* skip over comma... */ } while(!PEEK(RCURBR) && !PEEK(SEMI)); } else { indecl = 0; /* [vlh] 4.2 */ nbout = oneinit(onetype,dp,(int)sp->s_sc); /* [vlh] 4.2.c add 2 args */ } if (in_bitinit) BCHK(plus) /* [vlh] 4.2 bit field initialization */ if( nbleft && (nbleft != elsize)) { /*pad current row*/ OUTRESMEM(nbleft); nbout += nbleft; } if (i) { next(COMMA); /* [vlh] 4.2 skip over extra comma */ if (!(next(RCURBR))) error("missing } in initialization"); } return(nbout); } #ifndef SYM_TO_DSK # define COPY(c,s) c = s # define HCOPY(c,s) c = s #else # define COPY(c,s) c_addr = s; c = &child_str; read_st(c,c_addr) # define HCOPY(c,s) c_addr = s; c = &hold_str; read_st(c,c_addr) #endif #define BASIC_AR(x) (x==(ARRAY|CHAR)||x==(ARRAY|INT)||x==(ARRAY|LONG)) /** * s_or_a - initialize structure or array * routine to deal with initializing structures and arrays and * assure that structures are aligned properly. Checks initializers * with the expected type. * Attempts to match structure initializations against the * elements of the structure. * sp -- pointer to structure symbol table entry **/ long s_or_a(original,elsize,pnbout,bleft,sp,child) /* returns nbleft */ int original; /* [vlh] original type... */ long elsize, bleft, *pnbout; struct symbol *sp; /* [vlh] 4.2 for use in struct init */ struct symbol *child; /* [vlh] 4.2 for use in struct init */ { register long nbleft, nbout; register short onetype, plus; long i, temp, datasize, addup, x; short nest, snest; /* [vlh] 4.2 nest <= number of LCURBR */ struct symbol *hold; #ifdef SYM_TO_DSK long c_addr; struct symbol child_str; /* child structure */ struct symbol hold_str; /* hold structure */ #endif nbleft = bleft; nbout = *pnbout; onetype = original; nest = i = 0; #ifdef DEBUG if (initdebug) printf("s_or_a: [%s] elsize %ld\n",(sp) ? sp->s_symbol : "",elsize); #endif do { /*in current row.*/ restart: if (BTYPE(original) == STRUCT) { /* [vlh] 4.3 */ if(!child) { if (!sp->s_child) break; else { COPY(child,sp->s_child); } } onetype = child->s_type; #ifdef DEBUG if (initdebug) printf("s_or_a: child %s type %d\n",child->s_symbol,onetype); #endif } if( PEEK(SEMI) || PEEK(EOF) || PEEK(RCURBR) ) break; if(child && onetype == STRUCT) { /* [vlh] 4.3 */ #ifdef DEBUG if(initdebug) printf("s_or_a recurse onetype STRUCT\n"); #endif snest = (next(LCURBR)); temp = nbout; HCOPY(hold,child->s_par); /* was s_child */ i = dsize(onetype,(hold->s_dp)+1,hold->s_ssp); s_or_a(onetype,i,&temp,i,hold,NULL); if(snest) { if (!next(RCURBR)) /* force release of matched curbr */ error("mismatched curly braces"); } else if (!peektok) peektok = COMMA; /* [vlh] 4.2 put it back.... */ goto past; } else if( next(LCURBR) ) { /*recurse down one level?*/ nest++; if (in_bitinit) BCHK(plus) /* [vlh] 4.2 bit field initialization */ if( nbout && nbleft && (nbleft elsize ) error("initializer list too long"); child = 0; /* force restart of structure match up */ goto restart; } else if( PEEK(RCURBR) ) { if (nest) { next(RCURBR); nest--; continue; /* goes to next comma... */ } else break; } else { if ( BASIC_AR(onetype) ) { /* [vlh]4.2 simple arrays */ #ifdef DEBUG if(initdebug) printf("BASIC_AR onetype 0%o\n",onetype); #endif datasize = dsize(onetype,child->s_dp,child->s_ssp); i = str_init(datasize, onetype); } else if ( BASIC_AR(original) ) { /* [vlh]4.2 simple arrays */ #ifdef DEBUG if(initdebug) printf("BASIC_AR original 0%o\n",original); #endif datasize = dsize(original,child->s_dp,child->s_ssp); i = str_init(datasize, original); } else if (ISARRAY(onetype)) { /* [vlh] 4.2 */ #ifdef DEBUG if(initdebug) printf("ISARRAY onetype 0%o\n",onetype); #endif addup = 0; /* array of structures or arrays */ temp = nbout; i = dsize(onetype,child->s_dp,child->s_ssp); onetype = delsp(onetype); datasize = dsize(onetype,child->s_dp+1,child->s_ssp); HCOPY(hold,child->s_par); /* was s_child */ x = onetype & ~POINTER; /* [vlh] 4.3, simple pointer */ if( SIMPLE_TYP(x) ) { #ifdef DEBUG if(initdebug) printf("simple type 0%o 0%o\n",onetype,x); #endif for(addup=0; addup != i; addup += datasize) { if (PEEK(RCURBR) || PEEK(SEMI)) { OUTRESMEM(i); break; } /*[vlh] 4.3, no more initializers */ oneinit(onetype,hold->s_dp,(int)hold->s_sc); next(COMMA); } if (!peektok) peektok = COMMA; /* [vlh] 4.2 put it back.... */ #ifdef DEBUG if(initdebug) printf("peektok %d addup %ld\n",peektok,addup); #endif } else for(addup=0; addup != i; addup += datasize) { x = s_or_a(onetype,datasize,&temp,datasize,hold,NULL); if(x) { /*[vlh] 4.3, no initializer for current item*/ OUTRESMEM(i - (addup + datasize - x)); break; } } } else { /* simple type....... */ if ((nbleft & 1) && onetype != CHAR) { nbleft--; nbout++; OUTEVEN(); } if (!child) /* mra/vlh4.2+ don't access off of zero !!! */ i = oneinit(onetype,0,0); else i = oneinit(onetype,child->s_dp,(int)child->s_sc); } past: nbout += i; if ( !nbleft && !SIMPLE_TYP(original) ) nbleft = elsize; if( i > nbleft ) error("initializer alignment"); nbleft = (i >= nbleft) ? 0 : nbleft - i; if (BTYPE(original)==STRUCT) { /* [vlh] 4.2, get next child */ if (!child->s_sib) { /* [vlh] 4.2 at end... */ plus = (in_bitinit) ? out_bfield(CHAR) : 0; nbleft -= plus; nbout += nbleft; if ( nbleft ) { /* was checking against elsize */ OUTRESMEM(nbleft); nbleft = 0; } if (SUPTYPE(original) != ARRAY) break; #ifdef DEBUG if(initdebug) printf("last child out...\n"); #endif } else { COPY(child,child->s_sib); } } } #ifdef DEBUG if(initdebug && child) printf("child [%s] PEEKTOK comma %d\n",child->s_symbol,PEEK(COMMA)); #endif } while( next(COMMA) ); #ifdef DEBUG if(initdebug) printf("exiting s_or_a: nbleft %ld\n",nbleft); #endif if (BTYPE(original)==STRUCT) { /* [vlh] 4.2, ensure padding... */ plus = (in_bitinit) ? out_bfield(CHAR) : 0; nbout += nbleft; if ( nbleft ) { /* was checking against elsize */ OUTRESMEM(nbleft); nbleft = 0; } } *pnbout = nbout; while(nest--) { next(COMMA); /* comma's may separate.... */ if (!next(RCURBR)) /* force release of matched curbr */ error("mismatched curly braces"); } next(COMMA); /* comma's may separate.... */ return(nbleft); } /** * str_init - string (array) initialization [vlh] 4.2 * initialize a character array, truncating or padding as required **/ long str_init(datasize,type) long datasize; int type; /* should not get a bit field here..... */ { register long maxsize, output; #ifdef DEBUG if (initdebug) printf("str_init: type %d, datasize %ld\n",type,datasize); if (initdebug) printf("str_init: SUPTYPE %d, ",SUPTYPE(type)); if (initdebug) printf("BTYPE %d\n",BTYPE(type)); #endif output = 0L; if ((datasize==CHARSIZE && (BTYPE(type)==CHAR)) || /*undimensioned array*/ (datasize==INTSIZE && (BTYPE(type)==INT) || (BTYPE(type)==SHORT)) || (datasize==LONGSIZE && (BTYPE(type)==LONG))) { datasize = 0; maxsize = 0x7fff; /* max 32 bit positive value */ #ifdef DEBUG if (initdebug) printf("undimensioned type %d datasize %ld\n",type,datasize); #endif } else maxsize = datasize; do { if (next(STRING)) { output += (!datasize) ? outstr((long)cstrsize,(long)cstrsize) : outstr(maxsize-output,(long)cstrsize); return(output); } output += oneinit(BTYPE(type)|ARRAY,0,0); #ifdef DEBUG if (initdebug) printf("output %ld, ",output); if (initdebug) printf("maxsize %ld, ",maxsize); #endif if (maxsize <= output) { if (maxsize < output) error("character array initializer alignment"); return(output); } } while (next(COMMA) && !PEEK(SEMI) && !PEEK(RCURBR)); if (datasize) { OUTRESMEM(maxsize-output); return(maxsize); } return(output); } /** * oneinit - get one initializer expression or constant * This checks the type of the data item expected against the * type obtained from expr. **/ oneinit(type,dp,sc) /* returns size of initializer*/ int type; /* type of initializer*/ int dp, sc; /* [vlh] 4.2.c add for bit field init */ { register short op, plus, ivalue; register struct tnode *tp; register long value; commastop++; #ifdef DEBUG if (initdebug) printf("oneinit: type = %d\n",type); #endif if ((tp = (struct tnode *)expr(0)) == 0) { error("invalid initializer"); commastop--; return(0); } commastop--; if ((op = tp->t_op) == CINT) clvalue = ((struct conode *)tp)->t_value; else if (op == CLONG) clvalue = ((struct lconode *)tp)->t_lvalue; ivalue = value = clvalue; if (sc == BFIELDCL) return(one_binit(type,dp,value)); plus = (in_bitinit) ? out_bfield(type) : 0; switch( ISALLTYPE(type) ) { case UCHAR: if( op == CINT || op == CLONG ) { /* [vlh] 4.2, added CLONG */ outc(CHAR,((int)(ivalue&0xff))); if ((ivalue&0xff00) && ((ivalue&0xff00) != 0xff00)) warning("initializer truncated"); return(1+plus); } if( op == ADDR ) { /* [vlh] 4.2, STRING.... */ outc(CHAR,((int)(*cstr&0xff))); warning("string used to initialize character value"); return(1+plus); } break; case CHAR: if( op == CINT || op == CLONG ) { /* [vlh] 4.2, added CLONG */ outc(CHAR,((int)ivalue)&0xff); #ifdef DEBUG if (initdebug) printf("ivalue %d\n",ivalue); #endif if ((ivalue>255) || (ivalue<-128)) warning("initializer truncated"); return(1+plus); } if( op == ADDR ) { /* [vlh] 4.2, STRING.... */ outc(CHAR,((int)*cstr)&0xff); warning("string used to initialize character value"); return(1+plus); } break; case ARRAY|CHAR: if( op == CINT || op == CLONG ) { /* [vlh] 4.2, added CLONG */ if (ccbytes < 2) { outc(CHAR,((int)ivalue)&0xff); if ((ivalue>255) || (ivalue<-128)) warning("initializer truncated"); return(1+plus); } else { /* 2 character charconst eg. 'ab' */ outc(INT,ivalue); return(2+plus); } } break; case INT: case ARRAY|INT: if (op == ADDR) break; if( op == CINT || op == CLONG ) { /* [vlh] 4.2, added CLONG */ outc(INT,(int)value); if ((value&0xffff0000) && ((value&0xffff0000) != 0xffff0000)) warning("initializer truncated"); } else outinit(tp,inittype); return(2+plus); case UNSIGNED: /* [vlh] 4.0 split from INT... */ case USHORT: /* [vlh] 4.2 added... */ case ARRAY|UNSIGNED: if (op == ADDR) break; if( op == CLONG || op == CINT ) { /* [vlh] 4.2, rewrote */ if ((value&0xffff0000) && ((value&0xffff0000) != 0xffff0000)) warning("initializer truncated"); ivalue = value & 0xffff; outc(INT,ivalue); } else outinit(tp,inittype); return(2+plus); case LONG: case ULONG: case ARRAY|LONG: case POINTER|CHAR: case POINTER|UCHAR: case POINTER|INT: case POINTER|LONG: case POINTER|ULONG: case POINTER|STRUCT: case POINTER|UNSIGNED: case POINTER|DOUBLE: /* [vlh] 4.2 */ case POINTER|FLOAT: /* [vlh] 4.2 */ if( op!=CINT && op!=CLONG ) { outinit(tp,inittype); return(4+plus); } case DOUBLE: /* [vlh] 3.4 */ case FLOAT: outfp_or_l(value); return(4+plus); } error("invalid initializer type=%d",ISALLTYPE(type)); return(plus); } /** * one_binit - individula element bit field initialization. [vlh] 4.2 * returns the number of bytes actually initialize 1, 2 or 0 **/ one_binit(type,dp,value) int type,dp; long value; { register short plus, mask, op; op = (BTYPE(type) == CHAR) ? BITSPCHAR : BITSPWORD; op = (dp>>8)%op; if (in_bitinit && ((bfield_ty != BTYPE(type)) || (op < lst_boffset))) plus = out_bfield(type); else plus = 0; lst_boffset = op; bfield_ty = BTYPE(type); mask = (1 << (dp & 0xff)) - 1; bits_init |= ((value & mask) << op); in_bitinit++; return(plus); } /* out_bfield - last item was a bit field output it [vlh] 4.2 */ out_bfield(type) /* return number of bytes output */ int type; { in_bitinit = 0; if (bfield_ty == CHAR) { /* char bit field type */ outc(CHAR,(int)bits_init); bits_init = 0; if (ISALLTYPE(type) != CHAR) /* returns 2 */ OUTEVEN(); else return(1); } else { /* int/unsigned bit field type */ outc(INT,(int)bits_init); bits_init = 0; } return(2); }