# include "manifest" # include "lerror.h" # include "lmanifest" # include "lpass2.h" # define USED 01 # define VUSED 02 # define EUSED 04 # define RVAL 010 # define VARARGS 0100 # define NSZ 1024 # define TYSZ 2500 # define FSZ 150 STAB stab[NSZ]; STAB *find(); STYPE tary[TYSZ]; STYPE *tget(); char fnm[FSZ][LFNM]; int tfree; /* used to allocate types */ int ffree; /* used to save filenames */ struct ty atyp[50]; /* r is where all the input ends up */ union rec r; /* 28 feb 80 reverse sense of hflag */ int hflag = 1; int pflag = 0; /* 28 feb 80 reverse the sense of the xflag */ int xflag = 1; int uflag = 1; int ddddd = 0; int cfno; /* current file number */ main( argc, argv ) char *argv[]; { register char *p; char *ifilename; extern char *htmpname; ifilename = NULL; for ( --argc, ++argv; argc > 0; --argc, ++argv ) { if ( **argv == '-' ) { p = ++*argv; if ( *p == 'H' ) { /* we have here the name of the header buffer file */ htmpname = ++p; } else if ( *p == 'T' ) { /* we have here the name of the intermediate file */ ifilename = ++p; } else { for( ; *p; ++p ){ switch( *p ){ case 'h': /* 28 feb 80 reverse sense of hflag */ hflag = 0; break; case 'p': pflag = 1; break; case 'x': /* 28 feb 80 reverse sense of xflag */ xflag = 0; break; case 'X': ddddd = 1; break; case 'u': uflag = 0; break; } } } } } tmpopen( ); unbuffer( ); if ( !freopen( ifilename, "r", stdin ) ){ lerror( "cannot open intermediate file", FATAL | CCLOSE | ERRMSG ); } mloop( LDI|LIB ); rewind( stdin ); mloop( LDC|LDX ); rewind( stdin ); mloop( LRV|LUV|LUE|LUM ); cleanup(); un2buffer( ); return(0); } mloop( m ){ /* do the main loop */ register STAB *q; while( lread(m) ){ q = find(); if( q->decflag ) chkcompat(q); else setuse(q); } } lread(m){ /* read a line into r.l */ register n; for(;;) { if( fread( (char *)&r, sizeof(r), 1, stdin ) <= 0 ) return(0); if( r.l.decflag & LFN ){ /* new filename */ setfno( r.f.fn ); continue; } n = r.l.nargs; if( n<0 ) n = -n; if( n ){ fread( (char *)atyp, sizeof(ATYPE), n, stdin ); } if( ( r.l.decflag & m ) ) return( 1 ); } } setfno( s ) char *s; { /* look up current file names */ /* first, strip backwards to the beginning or to the first / */ int i; /* now look up s */ for( i=0; i<ffree; ++i ){ if( !strncmp( s, fnm[i], LFNM ) ){ cfno = i; return; } } /* make a new entry */ strncpy( fnm[ffree], s, LFNM ); cfno = ffree++; } STAB * find(){ /* for this to work, NSZ should be a power of 2 */ register h=0; { register char *p, *q; for( h=0,p=r.l.name,q=p+LCHNM; *p&&p<q; ++p) { h = (h<<1)+ *p; if( h>=NSZ ){ h = (h+1)&(NSZ-1); } } } { register STAB *p, *q; for( p=q= &stab[h]; q->decflag; ){ /* this call to strncmp should be taken out... */ if( !strncmp( r.l.name, q->name, LCHNM)) return(q); if( ++q >= &stab[NSZ] ) q = stab; if( q == p ) lerror( "too many names defined", CCLOSE | FATAL | ERRMSG ); } strncpy( q->name, r.l.name, LCHNM ); return( q ); } } STYPE * tget(){ if( tfree >= TYSZ ){ lerror( "too many types needed", CCLOSE | FATAL | ERRMSG ); } return( &tary[tfree++] ); } chkcompat(q) STAB *q; { /* are the types, etc. in r.l and q compatible */ register int i; STYPE *qq; setuse(q); /* argument check */ if( q->decflag & (LDI|LIB|LUV|LUE) ){ if( r.l.decflag & (LUV|LIB|LUE) ){ if( q->nargs != r.l.nargs ){ if( !(q->use&VARARGS) ){ /* "%.8s: variable # of args." */ buffer( 7, q ); } if( r.l.nargs > q->nargs ) r.l.nargs = q->nargs; if( !(q->decflag & (LDI|LIB) ) ) { q->nargs = r.l.nargs; q->use |= VARARGS; } } for( i=0,qq=q->symty.next; i<r.l.nargs; ++i,qq=qq->next){ if( chktype( &qq->t, &atyp[i] ) ){ /* "%.8s, arg. %d used inconsistently" */ buffer( 6, q, i+1 ); } } } } if( (q->decflag&(LDI|LIB|LUV)) && r.l.decflag==LUV ){ if( chktype( &r.l.type, &q->symty.t ) ){ /* "%.8s value used inconsistently" */ buffer( 4, q ); } } /* check for multiple declaration */ if( (q->decflag&LDI) && (r.l.decflag&(LDI|LIB)) ){ /* "%.8s multiply declared" */ buffer( 3, q ); } /* do a bit of checking of definitions and uses... */ if( (q->decflag & (LDI|LIB|LDX|LDC|LUM)) && (r.l.decflag & (LDX|LDC|LUM)) && q->symty.t.aty != r.l.type.aty ){ /* "%.8s value declared inconsistently" */ buffer( 5, q ); } /* better not call functions which are declared to be structure or union returning */ if( (q->decflag & (LDI|LIB|LDX|LDC)) && (r.l.decflag & LUE) && q->symty.t.aty != r.l.type.aty ){ /* only matters if the function returns union or structure */ TWORD ty; ty = q->symty.t.aty; if( ISFTN(ty) && ((ty = DECREF(ty))==STRTY || ty==UNIONTY ) ){ /* "%.8s function value type must be declared before use" */ buffer( 8, q ); } } if( pflag && q->decflag==LDX && r.l.decflag == LUM && !ISFTN(q->symty.t.aty) ){ /* make the external declaration go away */ /* in effect, it was used without being defined */ } } /* messages for defintion/use */ int mess[2][2] = { 12, 0, 1, 2 }; lastone(q) STAB *q; { register nu, nd, uses; if( ddddd ) pst(q); nu = nd = 0; uses = q->use; if( !(uses&USED) && q->decflag != LIB ) { if( strncmp(q->name,"main",7) ) nu = 1; } if( !ISFTN(q->symty.t.aty) ){ switch( q->decflag ){ case LIB: nu = nd = 0; /* don't complain about uses on libraries */ break; case LDX: if( !xflag ) break; case LUV: case LUE: /* 01/04/80 */ case LUV | LUE: case LUM: nd = 1; } } if( uflag && ( nu || nd ) ) buffer( mess[nu][nd], q ); if( (uses&(RVAL+EUSED)) == (RVAL+EUSED) ){ if ( uses & VUSED ) { /* "%.8s returns value which is sometimes ignored\n" */ buffer( 11, q ); } else { /* "%.8s returns value which is always ignored\n" */ buffer( 10, q ); } } if( (uses&(RVAL+VUSED)) == (VUSED) && (q->decflag&(LDI|LIB)) ){ /* "%.8s value is used, but none returned\n" */ buffer( 9, q ); } } cleanup(){ /* call lastone and die gracefully */ STAB *q; for( q=stab; q< &stab[NSZ]; ++q ){ if( q->decflag ) lastone(q); } return; } setuse(q) STAB *q; { /* check new type to ensure that it is used */ if( !q->decflag ){ /* new one */ q->decflag = r.l.decflag; q->symty.t = r.l.type; if( r.l.nargs < 0 ){ q->nargs = -r.l.nargs; q->use = VARARGS; } else { q->nargs = r.l.nargs; q->use = 0; } q->fline = r.l.fline; q->fno = cfno; if( q->nargs ){ int i; STYPE *qq; for( i=0,qq= &q->symty; i<q->nargs; ++i,qq=qq->next ){ qq->next = tget(); qq->next->t = atyp[i]; } } } switch( r.l.decflag ){ case LRV: q->use |= RVAL; return; case LUV: q->use |= VUSED+USED; return; case LUE: q->use |= EUSED+USED; return; /* 01/04/80 */ case LUV | LUE: case LUM: q->use |= USED; return; } } chktype( pt1, pt2 ) register ATYPE *pt1, *pt2; { TWORD t; /* check the two type words to see if they are compatible */ /* for the moment, enums are turned into ints, and should be checked as such */ if( pt1->aty == ENUMTY ) pt1->aty = INT; if( pt2->aty == ENUMTY ) pt2->aty = INT; if( (t=BTYPE(pt1->aty)==STRTY) || t==UNIONTY ){ return( pt1->aty!=pt2->aty || pt1->extra!=pt2->extra ); } if( pt2->extra ){ /* constant passed in */ if( pt1->aty == UNSIGNED && pt2->aty == INT ) return( 0 ); else if( pt1->aty == ULONG && pt2->aty == LONG ) return( 0 ); } else if( pt1->extra ){ /* for symmetry */ if( pt2->aty == UNSIGNED && pt1->aty == INT ) return( 0 ); else if( pt2->aty == ULONG && pt1->aty == LONG ) return( 0 ); } return( pt1->aty != pt2->aty ); } struct tb { int m; char * nm }; ptb( v, tp ) struct tb *tp; { /* print a value from the table */ int flag; flag = 0; for( ; tp->m; ++tp ){ if( v&tp->m ){ if( flag++ ) putchar( '|' ); printf( "%s", tp->nm ); } } } pst( q ) STAB *q; { /* give a debugging output for q */ static struct tb dfs[] = { LDI, "LDI", LIB, "LIB", LDC, "LDC", LDX, "LDX", LRV, "LRV", LUV, "LUV", LUE, "LUE", LUM, "LUM", 0, "" }; static struct tb us[] = { USED, "USED", VUSED, "VUSED", EUSED, "EUSED", RVAL, "RVAL", VARARGS, "VARARGS", 0, 0, }; printf( "%.8s (", q->name ); ptb( q->decflag, dfs ); printf( "), use= " ); ptb( q->use, us ); printf( ", line %d, nargs=%d\n", q->fline, q->nargs ); }