17988Srrh #ifndef lint
2*32980Sdonn static char sccsid[] = "@(#)lint.c 1.14 (Berkeley) 12/11/87";
37988Srrh #endif lint
47988Srrh
518598Sralph # include "pass1.h"
67988Srrh
718598Sralph # include "lmanifest.h"
87988Srrh
97988Srrh # include <ctype.h>
107988Srrh
117988Srrh # define VAL 0
127988Srrh # define EFF 1
137988Srrh
147988Srrh /* these are appropriate for the -p flag */
157988Srrh int SZCHAR = 8;
167988Srrh int SZINT = 16;
177988Srrh int SZFLOAT = 32;
187988Srrh int SZDOUBLE = 64;
197988Srrh int SZLONG = 32;
207988Srrh int SZSHORT = 16;
217988Srrh int SZPOINT = 16;
227988Srrh int ALCHAR = 8;
237988Srrh int ALINT = 16;
247988Srrh int ALFLOAT = 32;
257988Srrh int ALDOUBLE = 64;
267988Srrh int ALLONG = 32;
277988Srrh int ALSHORT = 16;
287988Srrh int ALPOINT = 16;
297988Srrh int ALSTRUCT = 16;
307988Srrh
3130819Sbostic int nflag = 0; /* avoid gripes about printf et al. */
3230819Sbostic int vflag = 1; /* tell about unused argments */
3330819Sbostic int xflag = 0; /* tell about unused externals */
3430819Sbostic int argflag = 0; /* used to turn off complaints about arguments */
3530819Sbostic int libflag = 0; /* used to generate library descriptions */
3630819Sbostic int vaflag = -1; /* signal functions with a variable number of args */
3730819Sbostic int aflag = 0; /* used to check precision of assignments */
3830819Sbostic int zflag = 0; /* no 'structure never defined' error */
3930819Sbostic int Cflag = 0; /* filter out certain output, for generating libraries */
4030819Sbostic char *libname = 0; /* name of the library we're generating */
417988Srrh
4230819Sbostic /* flags for the "outdef" function */
437988Srrh # define USUAL (-101)
447988Srrh # define DECTY (-102)
457988Srrh # define NOFILE (-103)
467988Srrh # define SVLINE (-104)
477988Srrh
487988Srrh # define LNAMES 250
497988Srrh
507988Srrh struct lnm {
517988Srrh short lid, flgs;
527988Srrh } lnames[LNAMES], *lnp;
537988Srrh
contx(p,down,pl,pr)547988Srrh contx( p, down, pl, pr ) register NODE *p; register *pl, *pr; {
557988Srrh
567988Srrh *pl = *pr = VAL;
577988Srrh switch( p->in.op ){
587988Srrh
597988Srrh case ANDAND:
607988Srrh case OROR:
617988Srrh case QUEST:
627988Srrh *pr = down;
637988Srrh break;
647988Srrh
657988Srrh case SCONV:
667988Srrh case PCONV:
677988Srrh case COLON:
687988Srrh *pr = *pl = down;
697988Srrh break;
707988Srrh
717988Srrh case COMOP:
727988Srrh *pl = EFF;
737988Srrh *pr = down;
747988Srrh
757988Srrh case FORCE:
767988Srrh case INIT:
777988Srrh case UNARY CALL:
787988Srrh case STCALL:
797988Srrh case UNARY STCALL:
807988Srrh case CALL:
817988Srrh case UNARY FORTCALL:
827988Srrh case FORTCALL:
837988Srrh case CBRANCH:
847988Srrh break;
857988Srrh
867988Srrh default:
877988Srrh if( asgop(p->in.op) ) break;
887988Srrh if( p->in.op == UNARY MUL && ( p->in.type == STRTY || p->in.type == UNIONTY || p->in.type == UNDEF) ) {
897988Srrh /* struct x f( ); main( ) { (void) f( ); }
907988Srrh * the the cast call appears as U* UNDEF
917988Srrh */
927988Srrh break; /* the compiler does this... */
937988Srrh }
947988Srrh if( down == EFF && hflag ) werror( "null effect" );
957988Srrh
967988Srrh }
977988Srrh }
987988Srrh
ecode(p)997988Srrh ecode( p ) NODE *p; {
1007988Srrh /* compile code for p */
1017988Srrh
1027988Srrh fwalk( p, contx, EFF );
1037988Srrh lnp = lnames;
1047988Srrh lprt( p, EFF, 0 );
10530819Sbostic strforget();
1067988Srrh }
1077988Srrh
ejobcode(flag)1087988Srrh ejobcode( flag ){
1097988Srrh /* called after processing each job */
1107988Srrh /* flag is nonzero if errors were detected */
1117988Srrh register k;
1127988Srrh register struct symtab *p;
1137988Srrh
1147988Srrh for( p=stab; p< &stab[SYMTSZ]; ++p ){
1157988Srrh
1167988Srrh if( p->stype != TNULL ) {
1177988Srrh
1187988Srrh if( p->stype == STRTY || p->stype == UNIONTY ){
11911761Sedward if( !zflag && dimtab[p->sizoff+1] < 0 ){
12011761Sedward /* never defined */
1217988Srrh #ifndef FLEXNAMES
1227988Srrh if( hflag ) werror( "struct/union %.8s never defined", p->sname );
1237988Srrh #else
1247988Srrh if( hflag ) werror( "struct/union %s never defined", p->sname );
1257988Srrh #endif
1267988Srrh }
1277988Srrh }
1287988Srrh
1297988Srrh switch( p->sclass ){
1307988Srrh
1317988Srrh case STATIC:
1327988Srrh if( p->suse > 0 ){
1337988Srrh k = lineno;
1347988Srrh lineno = p->suse;
1357988Srrh #ifndef FLEXNAMES
1367988Srrh uerror( "static variable %.8s unused",
1377988Srrh #else
1387988Srrh uerror( "static variable %s unused",
1397988Srrh #endif
1407988Srrh p->sname );
1417988Srrh lineno = k;
1427988Srrh break;
1437988Srrh }
14411403Snicklin /* no statics in libraries */
14511403Snicklin if( Cflag ) break;
1467988Srrh
1477988Srrh case EXTERN:
1487988Srrh case USTATIC:
1497988Srrh /* with the xflag, worry about externs not used */
1507988Srrh /* the filename may be wrong here... */
1517988Srrh if( xflag && p->suse >= 0 && !libflag ){
1527988Srrh outdef( p, LDX, NOFILE );
1537988Srrh }
1547988Srrh
1557988Srrh case EXTDEF:
1567988Srrh if( p->suse < 0 ){ /* used */
1577988Srrh outdef( p, LUM, SVLINE );
1587988Srrh }
1597988Srrh break;
1607988Srrh }
1617988Srrh
1627988Srrh }
1637988Srrh
1647988Srrh }
1657988Srrh exit( 0 );
1667988Srrh }
1677988Srrh
astype(t,i)1687988Srrh astype( t, i ) ATYPE *t; {
1697988Srrh TWORD tt;
17011761Sedward int j, k=0, l=0;
1717988Srrh
1727988Srrh if( (tt=BTYPE(t->aty))==STRTY || tt==UNIONTY ){
1737988Srrh if( i<0 || i>= DIMTABSZ-3 ){
1747988Srrh werror( "lint's little mind is blown" );
1757988Srrh }
1767988Srrh else {
1777988Srrh j = dimtab[i+3];
1787988Srrh if( j<0 || j>SYMTSZ ){
17911761Sedward k = dimtab[i];
18011761Sedward l = X_NONAME | stab[j].suse;
1817988Srrh }
1827988Srrh else {
1837988Srrh if( stab[j].suse <= 0 ) {
1847988Srrh #ifndef FLEXNAMES
1857988Srrh werror( "no line number for %.8s",
1867988Srrh #else
1877988Srrh werror( "no line number for %s",
1887988Srrh #endif
1897988Srrh stab[j].sname );
1907988Srrh }
19111761Sedward else {
19211761Sedward k = dimtab[i];
19311761Sedward #ifdef FLEXNAMES
19411761Sedward l = hashstr(stab[j].sname);
19511761Sedward #else
19611761Sedward l = hashstr(stab[j].sname, LCHNM);
19711761Sedward #endif
19811761Sedward }
1997988Srrh }
2007988Srrh }
2017988Srrh
2027988Srrh t->extra = k;
20311761Sedward t->extra1 = l;
2047988Srrh return( 1 );
2057988Srrh }
2067988Srrh else return( 0 );
2077988Srrh }
2087988Srrh
bfcode(a,n)2097988Srrh bfcode( a, n ) int a[]; {
2107988Srrh /* code for the beginning of a function; a is an array of
2117988Srrh indices in stab for the arguments; n is the number */
2127988Srrh /* this must also set retlab */
2137988Srrh register i;
2147988Srrh register struct symtab *cfp;
2157988Srrh static ATYPE t;
2167988Srrh
21730819Sbostic strforget();
2187988Srrh retlab = 1;
21911403Snicklin
2207988Srrh cfp = &stab[curftn];
2217988Srrh
22211403Snicklin /* if creating library, don't do static functions */
22311403Snicklin if( Cflag && cfp->sclass == STATIC ) return;
22411403Snicklin
2257988Srrh /* if variable number of arguments, only print the ones which will be checked */
22632979Sdonn if( vaflag >= 0 ){
2277988Srrh if( n < vaflag ) werror( "declare the VARARGS arguments you want checked!" );
2287988Srrh else n = vaflag;
2297988Srrh }
2307988Srrh fsave( ftitle );
23132979Sdonn if( cfp->sclass == STATIC ) outdef( cfp, LST, vaflag>=0?~n:n );
23232979Sdonn else outdef( cfp, libflag?LIB:LDI, vaflag>=0?~n:n );
2337988Srrh vaflag = -1;
2347988Srrh
2357988Srrh /* output the arguments */
2367988Srrh if( n ){
2377988Srrh for( i=0; i<n; ++i ) {
2387988Srrh t.aty = stab[a[i]].stype;
2397988Srrh t.extra = 0;
24011761Sedward t.extra1 = 0;
2417988Srrh if( !astype( &t, stab[a[i]].sizoff ) ) {
2427988Srrh switch( t.aty ){
2437988Srrh
2447988Srrh case ULONG:
2457988Srrh break;
2467988Srrh
2477988Srrh case CHAR:
2487988Srrh case SHORT:
2497988Srrh t.aty = INT;
2507988Srrh break;
2517988Srrh
2527988Srrh case UCHAR:
2537988Srrh case USHORT:
2547988Srrh case UNSIGNED:
2557988Srrh t.aty = UNSIGNED;
2567988Srrh break;
2577988Srrh
2587988Srrh }
2597988Srrh }
2607988Srrh fwrite( (char *)&t, sizeof(ATYPE), 1, stdout );
2617988Srrh }
2627988Srrh }
2637988Srrh }
2647988Srrh
ctargs(p)2657988Srrh ctargs( p ) NODE *p; {
2667988Srrh /* count arguments; p points to at least one */
2677988Srrh /* the arguemnts are a tower of commas to the left */
2687988Srrh register c;
2697988Srrh c = 1; /* count the rhs */
2707988Srrh while( p->in.op == CM ){
2717988Srrh ++c;
2727988Srrh p = p->in.left;
2737988Srrh }
2747988Srrh return( c );
2757988Srrh }
2767988Srrh
lpta(p)2777988Srrh lpta( p ) NODE *p; {
2787988Srrh static ATYPE t;
2797988Srrh
2807988Srrh if( p->in.op == CM ){
2817988Srrh lpta( p->in.left );
2827988Srrh p = p->in.right;
2837988Srrh }
2847988Srrh
2857988Srrh t.aty = p->in.type;
2867988Srrh t.extra = (p->in.op==ICON);
28711761Sedward t.extra1 = 0;
2887988Srrh
28918598Sralph if( !astype( &t, p->fn.csiz ) ) {
2907988Srrh switch( t.aty ){
2917988Srrh
2927988Srrh case CHAR:
2937988Srrh case SHORT:
2947988Srrh t.aty = INT;
2957988Srrh case LONG:
2967988Srrh case ULONG:
2977988Srrh case INT:
2987988Srrh case UNSIGNED:
2997988Srrh break;
3007988Srrh
3017988Srrh case UCHAR:
3027988Srrh case USHORT:
3037988Srrh t.aty = UNSIGNED;
3047988Srrh break;
3057988Srrh
3067988Srrh case FLOAT:
3077988Srrh t.aty = DOUBLE;
3087988Srrh t.extra = 0;
3097988Srrh break;
3107988Srrh
3117988Srrh default:
3127988Srrh t.extra = 0;
3137988Srrh break;
3147988Srrh }
3157988Srrh }
3167988Srrh fwrite( (char *)&t, sizeof(ATYPE), 1, stdout );
3177988Srrh }
3187988Srrh
3197988Srrh # define VALSET 1
3207988Srrh # define VALUSED 2
3217988Srrh # define VALASGOP 4
3227988Srrh # define VALADDR 8
3237988Srrh
lprt(p,down,uses)3247988Srrh lprt( p, down, uses ) register NODE *p; {
3257988Srrh register struct symtab *q;
3267988Srrh register id;
3277988Srrh register acount;
3287988Srrh register down1, down2;
3297988Srrh register use1, use2;
3307988Srrh register struct lnm *np1, *np2;
3317988Srrh
3327988Srrh /* first, set variables which are set... */
3337988Srrh
3347988Srrh use1 = use2 = VALUSED;
3357988Srrh if( p->in.op == ASSIGN ) use1 = VALSET;
3367988Srrh else if( p->in.op == UNARY AND ) use1 = VALADDR;
3377988Srrh else if( asgop( p->in.op ) ){ /* =ops */
3387988Srrh use1 = VALUSED|VALSET;
3397988Srrh if( down == EFF ) use1 |= VALASGOP;
3407988Srrh }
3417988Srrh
3427988Srrh
3437988Srrh /* print the lines for lint */
3447988Srrh
3457988Srrh down2 = down1 = VAL;
3467988Srrh acount = 0;
3477988Srrh
3487988Srrh switch( p->in.op ){
3497988Srrh
3507988Srrh case EQ:
3517988Srrh case NE:
3527988Srrh case GT:
3537988Srrh case GE:
3547988Srrh case LT:
3557988Srrh case LE:
3567988Srrh if( p->in.left->in.type == CHAR && p->in.right->in.op==ICON && p->in.right->tn.lval < 0 ){
3577988Srrh werror( "nonportable character comparison" );
3587988Srrh }
3597988Srrh if( (p->in.op==EQ || p->in.op==NE ) && ISUNSIGNED(p->in.left->in.type) && p->in.right->in.op == ICON ){
3607988Srrh if( p->in.right->tn.lval < 0 && p->in.right->tn.rval == NONAME && !ISUNSIGNED(p->in.right->in.type) ){
3617988Srrh werror( "comparison of unsigned with negative constant" );
3627988Srrh }
3637988Srrh }
3647988Srrh break;
3657988Srrh
3667988Srrh case UGE:
3677988Srrh case ULT:
3687988Srrh if( p->in.right->in.op == ICON && p->in.right->tn.lval == 0 && p->in.right->tn.rval == NONAME ){
3697988Srrh werror( "unsigned comparison with 0?" );
3707988Srrh break;
3717988Srrh }
3727988Srrh case UGT:
3737988Srrh case ULE:
3747988Srrh if( p->in.right->in.op == ICON && p->in.right->tn.lval <= 0 && !ISUNSIGNED(p->in.right->in.type) && p->in.right->tn.rval == NONAME ){
3757988Srrh werror( "degenerate unsigned comparison" );
3767988Srrh }
3777988Srrh break;
3787988Srrh
3797988Srrh case COMOP:
3807988Srrh down1 = EFF;
3817988Srrh
3827988Srrh case ANDAND:
3837988Srrh case OROR:
3847988Srrh case QUEST:
3857988Srrh down2 = down;
3867988Srrh /* go recursively left, then right */
3877988Srrh np1 = lnp;
3887988Srrh lprt( p->in.left, down1, use1 );
3897988Srrh np2 = lnp;
3907988Srrh lprt( p->in.right, down2, use2 );
3917988Srrh lmerge( np1, np2, 0 );
3927988Srrh return;
3937988Srrh
3947988Srrh case SCONV:
3957988Srrh case PCONV:
3967988Srrh case COLON:
3977988Srrh down1 = down2 = down;
3987988Srrh break;
3997988Srrh
4007988Srrh case CALL:
4017988Srrh case STCALL:
4027988Srrh case FORTCALL:
4037988Srrh acount = ctargs( p->in.right );
4047988Srrh case UNARY CALL:
4057988Srrh case UNARY STCALL:
4067988Srrh case UNARY FORTCALL:
4077988Srrh if( p->in.left->in.op == ICON && (id=p->in.left->tn.rval) != NONAME ){ /* used to be &name */
4087988Srrh struct symtab *sp = &stab[id];
4097988Srrh int lty;
41011403Snicklin
41111403Snicklin fsave( ftitle );
41230905Sbostic if (!nflag)
41330819Sbostic doform(p, sp, acount);
41411403Snicklin /*
41511403Snicklin * if we're generating a library -C then
41611403Snicklin * we don't want to output references to functions
41711403Snicklin */
41811403Snicklin if( Cflag ) break;
4197988Srrh /* if a function used in an effects context is
4207988Srrh * cast to type void then consider its value
4217988Srrh * to have been disposed of properly
4227988Srrh * thus a call of type undef in an effects
4237988Srrh * context is construed to be used in a value
4247988Srrh * context
4257988Srrh */
4267988Srrh if ((down == EFF) && (p->in.type != UNDEF)) {
4277988Srrh lty = LUE;
4287988Srrh } else if (down == EFF) {
4297988Srrh lty = LUV | LUE;
4307988Srrh } else {
4317988Srrh lty = LUV;
4327988Srrh }
43311403Snicklin outdef( sp, lty, acount );
4347988Srrh if( acount ) {
4357988Srrh lpta( p->in.right );
4367988Srrh }
4377988Srrh }
4387988Srrh break;
4397988Srrh
4407988Srrh case ICON:
4417988Srrh /* look for &name case */
4427988Srrh if( (id = p->tn.rval) >= 0 && id != NONAME ){
4437988Srrh q = &stab[id];
4447988Srrh q->sflags |= (SREF|SSET);
4457988Srrh q->suse = -lineno;
4467988Srrh }
4477988Srrh return;
4487988Srrh
4497988Srrh case NAME:
4507988Srrh if( (id = p->tn.rval) >= 0 && id != NONAME ){
4517988Srrh q = &stab[id];
4527988Srrh if( (uses&VALUSED) && !(q->sflags&SSET) ){
4537988Srrh if( q->sclass == AUTO || q->sclass == REGISTER ){
45411761Sedward if( !ISARY(q->stype ) && !ISFTN(q->stype) && q->stype!=STRTY && q->stype!=UNIONTY ){
4557988Srrh #ifndef FLEXNAMES
4567988Srrh werror( "%.8s may be used before set", q->sname );
4577988Srrh #else
4587988Srrh werror( "%s may be used before set", q->sname );
4597988Srrh #endif
4607988Srrh q->sflags |= SSET;
4617988Srrh }
4627988Srrh }
4637988Srrh }
4647988Srrh if( uses & VALASGOP ) break; /* not a real use */
4657988Srrh if( uses & VALSET ) q->sflags |= SSET;
4667988Srrh if( uses & VALUSED ) q->sflags |= SREF;
4677988Srrh if( uses & VALADDR ) q->sflags |= (SREF|SSET);
4687988Srrh if( p->tn.lval == 0 ){
4697988Srrh lnp->lid = id;
4707988Srrh lnp->flgs = (uses&VALADDR)?0:((uses&VALSET)?VALSET:VALUSED);
4717988Srrh if( ++lnp >= &lnames[LNAMES] ) --lnp;
4727988Srrh }
4737988Srrh }
4747988Srrh return;
4757988Srrh
4767988Srrh }
4777988Srrh
4787988Srrh /* recurse, going down the right side first if we can */
4797988Srrh
4807988Srrh switch( optype(p->in.op) ){
4817988Srrh
4827988Srrh case BITYPE:
4837988Srrh np1 = lnp;
4847988Srrh lprt( p->in.right, down2, use2 );
4857988Srrh case UTYPE:
4867988Srrh np2 = lnp;
4877988Srrh lprt( p->in.left, down1, use1 );
4887988Srrh }
4897988Srrh
4907988Srrh if( optype(p->in.op) == BITYPE ){
4917988Srrh if( p->in.op == ASSIGN && p->in.left->in.op == NAME ){ /* special case for a = .. a .. */
4927988Srrh lmerge( np1, np2, 0 );
4937988Srrh }
4947988Srrh else lmerge( np1, np2, p->in.op != COLON );
4957988Srrh /* look for assignments to fields, and complain */
4967988Srrh if( p->in.op == ASSIGN && p->in.left->in.op == FLD && p->in.right->in.op == ICON ) fldcon( p );
4977988Srrh }
4987988Srrh
4997988Srrh }
5007988Srrh
5017988Srrh lmerge( np1, np2, flag ) struct lnm *np1, *np2; {
5027988Srrh /* np1 and np2 point to lists of lnm members, for the two sides
5037988Srrh * of a binary operator
5047988Srrh * flag is 1 if commutation is possible, 0 otherwise
5057988Srrh * lmerge returns a merged list, starting at np1, resetting lnp
5067988Srrh * it also complains, if appropriate, about side effects
5077988Srrh */
5087988Srrh
5097988Srrh register struct lnm *npx, *npy;
5107988Srrh
5117988Srrh for( npx = np2; npx < lnp; ++npx ){
5127988Srrh
5137988Srrh /* is it already there? */
5147988Srrh for( npy = np1; npy < np2; ++npy ){
5157988Srrh if( npx->lid == npy->lid ){ /* yes */
5167988Srrh if( npx->flgs == 0 || npx->flgs == (VALSET|VALUSED) )
5177988Srrh ; /* do nothing */
5187988Srrh else if( (npx->flgs|npy->flgs)== (VALSET|VALUSED) ||
5197988Srrh (npx->flgs&npy->flgs&VALSET) ){
5207988Srrh #ifndef FLEXNAMES
5217988Srrh if( flag ) werror( "%.8s evaluation order undefined", stab[npy->lid].sname );
5227988Srrh #else
5237988Srrh if( flag ) werror( "%s evaluation order undefined", stab[npy->lid].sname );
5247988Srrh #endif
5257988Srrh }
5267988Srrh if( npy->flgs == 0 ) npx->flgs = 0;
5277988Srrh else npy->flgs |= npx->flgs;
5287988Srrh goto foundit;
5297988Srrh }
5307988Srrh }
5317988Srrh
5327988Srrh /* not there: update entry */
5337988Srrh np2->lid = npx->lid;
5347988Srrh np2->flgs = npx->flgs;
5357988Srrh ++np2;
5367988Srrh
5377988Srrh foundit: ;
5387988Srrh }
5397988Srrh
5407988Srrh /* all finished: merged list is at np1 */
5417988Srrh lnp = np2;
5427988Srrh }
5437988Srrh
efcode()5447988Srrh efcode(){
5457988Srrh /* code for the end of a function */
5467988Srrh register struct symtab *cfp;
5477988Srrh
5487988Srrh cfp = &stab[curftn];
54911403Snicklin if( retstat & RETVAL && !(Cflag && cfp->sclass==STATIC) )
55011403Snicklin outdef( cfp, LRV, DECTY );
5517988Srrh if( !vflag ){
5527988Srrh vflag = argflag;
5537988Srrh argflag = 0;
5547988Srrh }
5557988Srrh if( retstat == RETVAL+NRETVAL )
5567988Srrh #ifndef FLEXNAMES
5577988Srrh werror( "function %.8s has return(e); and return;", cfp->sname);
5587988Srrh #else
5597988Srrh werror( "function %s has return(e); and return;", cfp->sname);
5607988Srrh #endif
5617988Srrh }
5627988Srrh
5637988Srrh aocode(p) struct symtab *p; {
5647988Srrh /* called when automatic p removed from stab */
5657988Srrh register struct symtab *cfs;
5667988Srrh cfs = &stab[curftn];
5677988Srrh if(p->suse>0 && !(p->sflags&(SMOS|STAG)) ){
5687988Srrh if( p->sclass == PARAM ){
5697988Srrh #ifndef FLEXNAMES
5707988Srrh if( vflag ) werror( "argument %.8s unused in function %.8s",
5717988Srrh #else
5727988Srrh if( vflag ) werror( "argument %s unused in function %s",
5737988Srrh #endif
5747988Srrh p->sname,
5757988Srrh cfs->sname );
5767988Srrh }
5777988Srrh else {
5787988Srrh #ifndef FLEXNAMES
5797988Srrh if( p->sclass != TYPEDEF ) werror( "%.8s unused in function %.8s",
5807988Srrh #else
5817988Srrh if( p->sclass != TYPEDEF ) werror( "%s unused in function %s",
5827988Srrh #endif
5837988Srrh p->sname, cfs->sname );
5847988Srrh }
5857988Srrh }
5867988Srrh
5877988Srrh if( p->suse < 0 && (p->sflags & (SSET|SREF|SMOS)) == SSET &&
5887988Srrh !ISARY(p->stype) && !ISFTN(p->stype) ){
5897988Srrh
5907988Srrh #ifndef FLEXNAMES
5917988Srrh werror( "%.8s set but not used in function %.8s", p->sname, cfs->sname );
5927988Srrh #else
5937988Srrh werror( "%s set but not used in function %s", p->sname, cfs->sname );
5947988Srrh #endif
5957988Srrh }
5967988Srrh
5977988Srrh if( p->stype == STRTY || p->stype == UNIONTY || p->stype == ENUMTY ){
59811761Sedward if( !zflag && dimtab[p->sizoff+1] < 0 )
5997988Srrh #ifndef FLEXNAMES
60011761Sedward werror( "structure %.8s never defined", p->sname );
6017988Srrh #else
60211761Sedward werror( "structure %s never defined", p->sname );
6037988Srrh #endif
6047988Srrh }
6057988Srrh
6067988Srrh }
6077988Srrh
defnam(p)6087988Srrh defnam( p ) register struct symtab *p; {
6097988Srrh /* define the current location as the name p->sname */
6107988Srrh
61111403Snicklin if( p->sclass == STATIC && (p->slevel>1 || Cflag) ) return;
6127988Srrh
61311761Sedward if( !ISFTN( p->stype ) )
61411761Sedward if( p->sclass == STATIC ) outdef( p, LST, USUAL );
61511761Sedward else outdef( p, libflag?LIB:LDI, USUAL );
6167988Srrh }
6177988Srrh
zecode(n)6187988Srrh zecode( n ){
6197988Srrh /* n integer words of zeros */
6207988Srrh OFFSZ temp;
6217988Srrh temp = n;
6227988Srrh inoff += temp*SZINT;
6237988Srrh ;
6247988Srrh }
6257988Srrh
andable(p)6267988Srrh andable( p ) NODE *p; { /* p is a NAME node; can it accept & ? */
6277988Srrh register r;
6287988Srrh
6297988Srrh if( p->in.op != NAME ) cerror( "andable error" );
6307988Srrh
6317988Srrh if( (r = p->tn.rval) < 0 ) return(1); /* labels are andable */
6327988Srrh
6337988Srrh if( stab[r].sclass == AUTO || stab[r].sclass == PARAM ) return(0);
6347988Srrh #ifndef FLEXNAMES
6357988Srrh if( stab[r].sclass == REGISTER ) uerror( "can't take & of %.8s", stab[r].sname );
6367988Srrh #else
6377988Srrh if( stab[r].sclass == REGISTER ) uerror( "can't take & of %s", stab[r].sname );
6387988Srrh #endif
6397988Srrh return(1);
6407988Srrh }
6417988Srrh
6427988Srrh NODE *
clocal(p)6437988Srrh clocal(p) NODE *p; {
6447988Srrh
6457988Srrh /* this is called to do local transformations on
6467988Srrh an expression tree preparitory to its being
6477988Srrh written out in intermediate code.
6487988Srrh */
6497988Srrh
6507988Srrh /* the major essential job is rewriting the
6517988Srrh automatic variables and arguments in terms of
6527988Srrh REG and OREG nodes */
6537988Srrh /* conversion ops which are not necessary are also clobbered here */
6547988Srrh /* in addition, any special features (such as rewriting
6557988Srrh exclusive or) are easily handled here as well */
6567988Srrh
6577988Srrh register o;
6587988Srrh register unsigned t, tl;
65925757Sdonn int s;
6607988Srrh
6617988Srrh switch( o = p->in.op ){
66230819Sbostic case NAME:
66330819Sbostic {
66430819Sbostic extern int didstr, subscr;
66530819Sbostic extern NODE * strnodes[];
6667988Srrh
66730819Sbostic if (didstr) {
66830819Sbostic didstr = 0;
66930819Sbostic strnodes[subscr] = p;
67030819Sbostic }
67130819Sbostic }
67230819Sbostic break;
67330819Sbostic
6747988Srrh case SCONV:
6757988Srrh case PCONV:
6767988Srrh if( p->in.left->in.type==ENUMTY ){
6777988Srrh p->in.left = pconvert( p->in.left );
6787988Srrh }
6797988Srrh /* assume conversion takes place; type is inherited */
6807988Srrh t = p->in.type;
6817988Srrh tl = p->in.left->in.type;
68226403Sdonn if( aflag && (tl==LONG||tl==ULONG) && (t!=LONG&&t!=ULONG&&t!=UNDEF) ){
6837988Srrh werror( "long assignment may lose accuracy" );
6847988Srrh }
6857988Srrh if( aflag>=2 && (tl!=LONG&&tl!=ULONG) && (t==LONG||t==ULONG) && p->in.left->in.op != ICON ){
6867988Srrh werror( "assignment to long may sign-extend incorrectly" );
6877988Srrh }
6887988Srrh if( ISPTR(tl) && ISPTR(t) ){
6897988Srrh tl = DECREF(tl);
6907988Srrh t = DECREF(t);
6917988Srrh switch( ISFTN(t) + ISFTN(tl) ){
6927988Srrh
6937988Srrh case 0: /* neither is a function pointer */
6947988Srrh if( talign(t,p->fn.csiz) > talign(tl,p->in.left->fn.csiz) ){
6957988Srrh if( hflag||pflag ) werror( "possible pointer alignment problem" );
6967988Srrh }
6977988Srrh break;
6987988Srrh
6997988Srrh case 1:
7007988Srrh werror( "questionable conversion of function pointer" );
7017988Srrh
7027988Srrh case 2:
7037988Srrh ;
7047988Srrh }
7057988Srrh }
7067988Srrh p->in.left->in.type = p->in.type;
7077988Srrh p->in.left->fn.cdim = p->fn.cdim;
7087988Srrh p->in.left->fn.csiz = p->fn.csiz;
7097988Srrh p->in.op = FREE;
7107988Srrh return( p->in.left );
7117988Srrh
7127988Srrh case PVCONV:
7137988Srrh case PMCONV:
7147988Srrh if( p->in.right->in.op != ICON ) cerror( "bad conversion");
7157988Srrh p->in.op = FREE;
7167988Srrh return( buildtree( o==PMCONV?MUL:DIV, p->in.left, p->in.right ) );
7177988Srrh
71825757Sdonn case RS:
71925757Sdonn case LS:
72025757Sdonn case ASG RS:
72125757Sdonn case ASG LS:
72225757Sdonn if( p->in.right->in.op != ICON )
72325757Sdonn break;
72425757Sdonn s = p->in.right->tn.lval;
72525757Sdonn if( s < 0 )
72625757Sdonn werror( "negative shift" );
72725757Sdonn else
72825757Sdonn if( s >= dimtab[ p->fn.csiz ] )
72925757Sdonn werror( "shift greater than size of object" );
73025757Sdonn break;
73125757Sdonn
7327988Srrh }
7337988Srrh
7347988Srrh return(p);
7357988Srrh }
7367988Srrh
7377988Srrh NODE *
offcon(off,t,d,s)7387988Srrh offcon( off, t, d, s ) OFFSZ off; TWORD t;{ /* make a structure offset node */
7397988Srrh register NODE *p;
7407988Srrh p = bcon(0);
7417988Srrh p->tn.lval = off/SZCHAR;
7427988Srrh return(p);
7437988Srrh }
7447988Srrh
noinit()7457988Srrh noinit(){
7467988Srrh /* storage class for such as "int a;" */
7477988Srrh return( pflag ? EXTDEF : EXTERN );
7487988Srrh }
7497988Srrh
7507988Srrh
cinit(p,sz)7517988Srrh cinit( p, sz ) NODE *p; { /* initialize p into size sz */
75232979Sdonn register int id;
75332979Sdonn
7547988Srrh inoff += sz;
7557988Srrh if( p->in.op == INIT ){
7567988Srrh if( p->in.left->in.op == ICON ) return;
7577988Srrh if( p->in.left->in.op == NAME && p->in.left->in.type == MOE ) return;
7587988Srrh }
7597988Srrh uerror( "illegal initialization" );
7607988Srrh }
7617988Srrh
7627988Srrh char *
exname(p)7637988Srrh exname( p ) char *p; {
7647988Srrh /* make a name look like an external name in the local machine */
7657988Srrh static char aa[8];
7667988Srrh register int i;
7677988Srrh
7687988Srrh if( !pflag ) return(p);
7697988Srrh for( i=0; i<6; ++i ){
7707988Srrh if( isupper(*p ) ) aa[i] = tolower( *p );
7717988Srrh else aa[i] = *p;
7727988Srrh if( *p ) ++p;
7737988Srrh }
7747988Srrh aa[6] = '\0';
7757988Srrh return( aa );
7767988Srrh }
7777988Srrh
7787988Srrh char *
strip(s)7797988Srrh strip(s) char *s; {
7807988Srrh #ifndef FLEXNAMES
7817988Srrh static char x[LFNM+1];
7827988Srrh #else
7837988Srrh static char x[BUFSIZ];
7847988Srrh #endif
7857988Srrh register char *p;
7867996Srrh static int stripping = 0;
7877988Srrh
7887996Srrh if (stripping)
7897996Srrh return(s);
7907996Srrh stripping++;
7917988Srrh for( p=x; *s; ++s ){
7927996Srrh if( *s != '"' ){
7937988Srrh #ifndef FLEXNAMES
7947988Srrh /* PATCHED by ROBERT HENRY on 8Jul80 to fix 14 character file name bug */
7957988Srrh if( p >= &x[LFNM] )
79611403Snicklin #else
79711403Snicklin if( p >= &x[BUFSIZ] )
79811403Snicklin #endif
7997988Srrh cerror( "filename too long" );
8007988Srrh *p++ = *s;
8017988Srrh }
8027988Srrh }
8037996Srrh stripping = 0;
8047988Srrh *p = '\0';
8057988Srrh #ifndef FLEXNAMES
8067988Srrh return( x );
8077988Srrh #else
8087988Srrh return( hash(x) );
8097988Srrh #endif
8107988Srrh }
8117988Srrh
fsave(s)8127988Srrh fsave( s ) char *s; {
8137988Srrh static union rec fsname;
8147988Srrh s = strip( s );
8157988Srrh #ifndef FLEXNAMES
81626916Sdonn if( strncmp( s, fsname.f.fn, LFNM ) )
8177988Srrh #else
81826916Sdonn if (fsname.f.fn == NULL || strcmp(s, fsname.f.fn))
8197988Srrh #endif
82026916Sdonn {
8217988Srrh /* new one */
8227988Srrh #ifndef FLEXNAMES
8237988Srrh strncpy( fsname.f.fn, s, LFNM );
8247988Srrh #else
8257988Srrh fsname.f.fn = s;
8267988Srrh #endif
8277988Srrh fsname.f.decflag = LFN;
8287988Srrh fwrite( (char *)&fsname, sizeof(fsname), 1, stdout );
8297988Srrh #ifdef FLEXNAMES
83011403Snicklin /* if generating a library, prefix with the library name */
83111403Snicklin /* only do this for flexnames */
83211403Snicklin if( libname ){
83311403Snicklin fwrite( libname, strlen(libname), 1, stdout );
83411403Snicklin putchar( ':' );
83511403Snicklin }
8367988Srrh fwrite( fsname.f.fn, strlen(fsname.f.fn)+1, 1, stdout );
8377988Srrh #endif
8387988Srrh }
8397988Srrh }
8407988Srrh
where(f)8417988Srrh where(f){ /* print true location of error */
8427996Srrh if( f == 'u' && nerrors > 1 )
8437996Srrh --nerrors; /* don't get "too many errors" */
8447996Srrh fprintf( stderr, "%s(%d): ", strip(ftitle), lineno);
8457988Srrh }
8467988Srrh
8477988Srrh /* a number of dummy routines, unneeded by lint */
8487988Srrh
branch(n)8497988Srrh branch(n){;}
defalign(n)8507988Srrh defalign(n){;}
deflab(n)8517988Srrh deflab(n){;}
8527988Srrh
85330819Sbostic extern char * strchr();
8547988Srrh
85530819Sbostic #define SBUFSIZE 16
85630819Sbostic #define SCLICK 80
85730819Sbostic
85830819Sbostic #ifndef size_t
85930819Sbostic #define size_t unsigned
86030819Sbostic #endif /* !size_t */
86130819Sbostic
86230819Sbostic static char * strings[SBUFSIZE];
86330819Sbostic static NODE * strnodes[SBUFSIZE];
86430819Sbostic static int didstr;
86530819Sbostic static int subscr;
86630819Sbostic static int strapped;
86730819Sbostic
bycode(t,i)86830819Sbostic bycode(t, i)
86930819Sbostic {
87030819Sbostic extern char * calloc();
87130819Sbostic extern char * realloc();
87230819Sbostic
87330905Sbostic if (nflag || strapped)
87430819Sbostic return;
87530819Sbostic if (i == 0)
87630819Sbostic if (subscr < (SBUFSIZE - 1))
87730819Sbostic ++subscr;
87830819Sbostic if (subscr >= SBUFSIZE)
87930819Sbostic return;
88030819Sbostic didstr = 1;
88130819Sbostic if ((i % SCLICK) == 0) {
88230819Sbostic strings[subscr] = (strings[subscr] == NULL) ?
88330819Sbostic calloc((size_t) (SCLICK + 1), 1) :
88430819Sbostic realloc(strings[subscr], (size_t) (i + SCLICK + 1));
88530819Sbostic if (strings[subscr] == NULL) {
88630819Sbostic strapped = 1;
88730819Sbostic return;
8887988Srrh }
8897988Srrh }
89030819Sbostic strings[subscr][i] = t;
89130819Sbostic }
8927988Srrh
strforget()89330819Sbostic strforget()
89430819Sbostic {
89530819Sbostic didstr = subscr = 0;
89630819Sbostic }
8977988Srrh
89830819Sbostic static char *
typestr(t)89930819Sbostic typestr(t)
90030819Sbostic {
90130819Sbostic switch (t) {
90230819Sbostic case CHAR: return "char";
90330819Sbostic case UCHAR: return "unsigned char";
90430819Sbostic case SHORT: return "short";
90530819Sbostic case USHORT: return "unsigned short";
90630819Sbostic case INT: return "int";
90730819Sbostic case UNSIGNED: return "unsigned";
90830819Sbostic case ENUMTY: return "enum";
90930819Sbostic case LONG: return "long";
91030819Sbostic case ULONG: return "unsigned long";
91130819Sbostic case FLOAT: return "float";
91230819Sbostic case DOUBLE: return "double";
91330819Sbostic case STRTY: return "struct";
91430819Sbostic case UNIONTY: return "union";
91530819Sbostic case PTR|CHAR: return "char *";
91630819Sbostic case PTR|UCHAR: return "unsigned char *";
91730819Sbostic case PTR|SHORT: return "short *";
91830819Sbostic case PTR|USHORT: return "unsigned short *";
91930819Sbostic case PTR|INT: return "int *";
92030819Sbostic case PTR|UNSIGNED: return "unsigned *";
92130819Sbostic case PTR|ENUMTY: return "enum *";
92230819Sbostic case PTR|LONG: return "long *";
92330819Sbostic case PTR|ULONG: return "unsigned long *";
92430819Sbostic case PTR|FLOAT: return "float *";
92530819Sbostic case PTR|DOUBLE: return "double *";
92630819Sbostic case PTR|STRTY: return "struct *";
92730819Sbostic case PTR|UNIONTY: return "union *";
92830819Sbostic default: return ISPTR(t) ?
92930819Sbostic "pointer" : "non-scalar";
93030819Sbostic }
93130819Sbostic }
9327988Srrh
93330819Sbostic NODE *
ntharg(p,n,acount)93430819Sbostic ntharg(p, n, acount)
93530819Sbostic NODE * p;
93630819Sbostic register int n;
93730819Sbostic register int acount;
93830819Sbostic {
93930819Sbostic if (n > acount)
94030819Sbostic return NULL;
94130819Sbostic p = p->in.right;
94230819Sbostic while (n != acount) {
94330819Sbostic p = p->in.left;
94430819Sbostic --acount;
94530819Sbostic }
94630819Sbostic return (n == 1) ? p : p->in.right;
94730819Sbostic }
9487988Srrh
94930819Sbostic struct entry {
95030819Sbostic /* If argument to print/scan is of type... */ int argtype;
95130819Sbostic /* ...and this length character is used... */ char lchar;
95230819Sbostic /* ...and one of these is control char... */ char * cchars;
95330819Sbostic /* ...then use this format with werror... */ char * werror;
95430819Sbostic /* ...(where NULL means it's hunky dory)... */
95530819Sbostic };
9567988Srrh
95730819Sbostic /*
95830819Sbostic ** Portable printf.
95930819Sbostic ** H&S says "%o" takes an unsigned argument;
96030819Sbostic ** X3J11 says "%o" takes an int argument;
96130819Sbostic ** we'll allow either here.
96230819Sbostic */
9637988Srrh
96430819Sbostic static struct entry pprintf[] = {
96530819Sbostic CHAR, '\0', "c", NULL, /* this is deliberate */
96630819Sbostic INT, '\0', "cdoxX", NULL,
96730819Sbostic UNSIGNED, '\0', "uoxX", NULL,
96830819Sbostic CHAR, '\0', "cdoxX", NULL,
96930819Sbostic UCHAR, '\0', "udoxX", NULL, /* yes, d is okay */
97030819Sbostic SHORT, '\0', "cdoxX", NULL,
97130819Sbostic USHORT, '\0', "uoxX", NULL,
97230819Sbostic ENUMTY, '\0', "duoxX", NULL,
97330819Sbostic LONG, 'l', "doxX", NULL,
97430819Sbostic ULONG, 'l', "uoxX", NULL,
97530819Sbostic FLOAT, '\0', "eEfgG", NULL,
97630819Sbostic DOUBLE, '\0', "eEfgG", NULL,
97730819Sbostic PTR|CHAR, '\0', "s", NULL,
97830819Sbostic UNDEF, '\0', "", NULL
97930819Sbostic };
9807988Srrh
98130819Sbostic /*
98230819Sbostic ** Berkeley printf.
98330819Sbostic ** It allows %D, %O, and %U, which we deprecate.
98430819Sbostic ** Since
98530819Sbostic ** sizeof (char *) == sizeof (int) &&
98630819Sbostic ** sizeof (int) == sizeof (long) &&
98730819Sbostic ** sizeof (char *) == sizeof (int *)
98830819Sbostic ** you can be lax--and we tolerate *some* laxness.
98930819Sbostic ** g/lax/p to find lax table entries and code.
99030819Sbostic */
9917988Srrh
99230819Sbostic static char uppercase[] = "deprecated upper-case control character (%c)";
99330819Sbostic #define lax NULL
9947988Srrh
99530819Sbostic static struct entry bprintf[] = {
99630819Sbostic CHAR, '\0', "c", NULL, /* this is deliberate */
99730819Sbostic INT, '\0', "cdoxX", NULL,
99830819Sbostic INT, '\0', "DO", uppercase,
99930819Sbostic UNSIGNED, '\0', "uoxX", NULL,
100030819Sbostic UNSIGNED, '\0', "UO", uppercase,
100130819Sbostic CHAR, '\0', "cdoxX", NULL,
100230819Sbostic CHAR, '\0', "DO", uppercase,
100330819Sbostic UCHAR, '\0', "duoxX", NULL, /* yes, d is okay */
100430819Sbostic UCHAR, '\0', "DUO", uppercase,
100530819Sbostic SHORT, '\0', "cdoxX", NULL,
100630819Sbostic SHORT, '\0', "DO", uppercase,
100730819Sbostic USHORT, '\0', "duoxX", NULL, /* d okay on BSD */
100830819Sbostic USHORT, '\0', "DUO", uppercase,
100930819Sbostic ENUMTY, '\0', "duoxX", NULL,
101030819Sbostic ENUMTY, '\0', "DUO", uppercase,
101130819Sbostic LONG, '\0', "doxX", lax,
101230819Sbostic LONG, '\0', "DO", uppercase,
101330819Sbostic LONG, 'l', "doxX", NULL,
101430819Sbostic INT, 'l', "doxX", lax,
101530819Sbostic ULONG, '\0', "uoxX", lax,
101630819Sbostic ULONG, '\0', "UO", uppercase,
101730819Sbostic ULONG, 'l', "uoxX", NULL,
101830819Sbostic UNSIGNED, 'l', "uoxX", lax,
101930819Sbostic FLOAT, '\0', "eEfgG", NULL,
102030819Sbostic DOUBLE, '\0', "eEfgG", NULL,
102130819Sbostic PTR|CHAR, '\0', "s", NULL,
102230819Sbostic UNDEF, '\0', NULL, NULL,
102330819Sbostic };
10247988Srrh
102530819Sbostic /*
102630819Sbostic ** Portable scanf. 'l' and 'h' are universally ignored preceding 'c' and 's',
102730819Sbostic ** and 'h' is universally ignored preceding 'e' and 'f',
102830819Sbostic ** but you won't find such cruft here.
102930819Sbostic */
10307988Srrh
103130819Sbostic static struct entry pscanf[] = {
103230819Sbostic INT, '\0', "dox", NULL,
103330819Sbostic UNSIGNED, '\0', "uox", NULL,
103430819Sbostic CHAR, '\0', "cs[", NULL,
103530819Sbostic SHORT, 'h', "dox", NULL,
103630819Sbostic USHORT, 'h', "uox", NULL,
103730819Sbostic LONG, 'l', "dox", NULL,
103830819Sbostic ULONG, 'l', "uox", NULL,
103930819Sbostic FLOAT, '\0', "ef", NULL, /* BSD doesn't handle g */
104030819Sbostic DOUBLE, 'l', "ef", NULL,
104130819Sbostic UNDEF, '\0', NULL, NULL,
104230819Sbostic };
10437988Srrh
104430819Sbostic /*
104530819Sbostic ** Berkeley scanf. An upper case letter equals an l plus the lower case char,
104630819Sbostic ** but this is deprecated.
104730819Sbostic ** Even though sizeof (int) == sizeof (long), we'll be picky here.
104830819Sbostic */
10497988Srrh
105030819Sbostic static struct entry bscanf[] = {
105130819Sbostic INT, '\0', "dox", NULL,
105230819Sbostic UNSIGNED, '\0', "uox", NULL,
105330819Sbostic CHAR, '\0', "cs[", NULL,
105430819Sbostic SHORT, 'h', "dox", NULL,
105530819Sbostic USHORT, 'h', "uox", NULL,
105630819Sbostic LONG, '\0', "dox", lax,
105730819Sbostic LONG, '\0', "DOX", uppercase,
105830819Sbostic LONG, 'l', "dox", NULL,
105930819Sbostic ULONG, '\0', "uox", lax,
106030819Sbostic ULONG, '\0', "UOX", uppercase,
106130819Sbostic ULONG, 'l', "uox", NULL,
106230819Sbostic FLOAT, '\0', "ef", NULL,
106330819Sbostic DOUBLE, '\0', "EF", uppercase,
106430819Sbostic DOUBLE, 'l', "ef", NULL,
106530819Sbostic UNDEF, '\0', NULL, NULL,
106630819Sbostic };
10677988Srrh
106830819Sbostic static struct item {
106930819Sbostic char * name; /* such as "printf" */
107030819Sbostic int isscan; /* scanf/printf */
107130819Sbostic int fmtarg; /* number of format argument */
107230819Sbostic struct entry * ptable; /* portable checking table */
107330819Sbostic struct entry * btable; /* berkeley checking table */
107430819Sbostic } items[] = {
107530819Sbostic "printf", 0, 1, pprintf, bprintf,
107630819Sbostic "fprintf", 0, 2, pprintf, bprintf,
107730819Sbostic "sprintf", 0, 2, pprintf, bprintf,
107830819Sbostic "scanf", 1, 1, pscanf, bscanf,
107930819Sbostic "fscanf", 1, 2, pscanf, bscanf,
108030819Sbostic "sscanf", 1, 2, pscanf, bscanf,
108130819Sbostic NULL, -1, -1, NULL, NULL
108230819Sbostic };
10837988Srrh
108430819Sbostic static char pwf[] = "possible wild format";
108530819Sbostic static char pfacm[] = "possible format/argument count mismatch";
108611761Sedward
108730819Sbostic static struct entry *
findlc(ep,lchar,cchar)108830819Sbostic findlc(ep, lchar, cchar)
108930819Sbostic register struct entry * ep;
109030819Sbostic register int lchar;
109130819Sbostic register int cchar;
109230819Sbostic {
109330819Sbostic for ( ; ep->argtype != UNDEF; ++ep)
109430819Sbostic if (ep->lchar == lchar && strchr(ep->cchars, cchar) != 0)
109530819Sbostic return ep;
109630819Sbostic return NULL;
109730819Sbostic }
10987988Srrh
109930819Sbostic static char *
subform(p,sp,acount)110030819Sbostic subform(p, sp, acount)
110130819Sbostic register NODE * p;
110230819Sbostic register struct symtab * sp;
110330819Sbostic {
110430819Sbostic register int i, j, isscan;
110530819Sbostic register NODE * tp;
110630819Sbostic register char * cp;
110730819Sbostic register struct entry * basep;
110830819Sbostic register struct entry * ep;
110930819Sbostic register struct item * ip;
111030819Sbostic register int lchar;
111130819Sbostic register int cchar;
111230819Sbostic register int t;
111330819Sbostic register int suppressed;
111430819Sbostic static char errbuf[132];
111511761Sedward
111630905Sbostic if (nflag || strapped)
111730819Sbostic return NULL;
111830819Sbostic cp = sp->sname;
111930819Sbostic for (ip = items; ; ++ip)
112030819Sbostic if (ip->name == NULL)
112130819Sbostic return NULL; /* not a print/scan function */
112230819Sbostic else if (strcmp(ip->name, sp->sname) == 0)
112330819Sbostic break;
112430819Sbostic isscan = ip->isscan;
112530819Sbostic i = ip->fmtarg;
112630819Sbostic if (i > acount)
112730819Sbostic return NULL; /* handled in pass 2 */
112830819Sbostic tp = ntharg(p, i, acount);
112930819Sbostic if (tp->in.type != (PTR|CHAR))
113030819Sbostic return NULL; /* handled in pass 2 */
113130819Sbostic if (tp->in.op != ICON || tp->tn.lval != 0)
113230819Sbostic return NULL; /* can't check it */
113330819Sbostic for (j = 1; j <= subscr; ++j)
113430819Sbostic if (tp == strnodes[j])
113530819Sbostic break;
113630819Sbostic if (j > subscr)
113730819Sbostic return NULL; /* oh well. . . */
113830819Sbostic cp = strings[j];
113930819Sbostic /*
114030819Sbostic ** cp now points to format string.
114130819Sbostic */
114230905Sbostic /*
114330905Sbostic ** For now, ALWAYS use "portable" table, rather than doing this:
114430905Sbostic ** basep = pflag ? ip->ptable : ip->btable;
114530905Sbostic */
114630905Sbostic basep = ip->ptable;
114730819Sbostic for ( ; ; ) {
114830819Sbostic if (*cp == '\0')
114930819Sbostic return (i == acount) ? NULL : pfacm;
115030819Sbostic if (*cp++ != '%')
115130819Sbostic continue;
115230819Sbostic if (*cp == '\0')
115330819Sbostic return "wild trailing %% in format";
115430819Sbostic if (*cp == '%') {
115530819Sbostic ++cp;
115630819Sbostic continue;
115730819Sbostic }
115830819Sbostic if (isscan) {
115930819Sbostic suppressed = *cp == '*';
116030819Sbostic if (suppressed)
116130819Sbostic ++cp;
116230819Sbostic while (isdigit(*cp))
116330819Sbostic ++cp;
116430819Sbostic if (!suppressed && ++i <= acount) {
116530819Sbostic t = ntharg(p, i, acount)->in.type;
116630819Sbostic if (!ISPTR(t)) {
116730819Sbostic (void) sprintf(errbuf,
116830819Sbostic "%s argument is type (%s) rather than pointer (arg %d)",
116930819Sbostic ip->name, typestr(t), i);
117030819Sbostic return errbuf;
117130819Sbostic }
117230819Sbostic t = DECREF(t);
117330819Sbostic }
117430819Sbostic } else {
117530819Sbostic int nspace, ndash, nplus, nhash;
117630819Sbostic
117730819Sbostic suppressed = 0;
117830819Sbostic nspace = ndash = nplus = nhash = 0;
117930819Sbostic for ( ; ; ) {
118030819Sbostic if (*cp == ' ')
118130819Sbostic ++nspace;
118230819Sbostic else if (*cp == '+')
118330819Sbostic ++nplus;
118430819Sbostic else if (*cp == '-')
118530819Sbostic ++ndash;
118630819Sbostic else if (*cp == '#')
118730819Sbostic ++nhash;
118830819Sbostic else break;
118930819Sbostic ++cp;
119030819Sbostic }
119130819Sbostic if (nspace > 1 || ndash > 1 || nplus > 1 || nhash > 1)
119230819Sbostic return "wild repeated flag character in format";
119330819Sbostic if (*cp == '*') {
119430819Sbostic ++cp;
119530819Sbostic if (++i > acount)
119630819Sbostic break;
119730819Sbostic t = ntharg(p, i, acount)->in.type;
119830819Sbostic /*
119930819Sbostic ** Width other than INT or UNSIGNED is suspect.
120030819Sbostic */
120130819Sbostic if (t != INT && t != UNSIGNED) {
120230819Sbostic (void) sprintf(errbuf,
120330819Sbostic "field width argument is type (%s) rather than (int) (arg %d)",
120430819Sbostic typestr(t), i);
120530819Sbostic return errbuf;
120630819Sbostic }
120730819Sbostic } else while (isdigit(*cp))
120830819Sbostic ++cp;
120930819Sbostic if (*cp == '.') {
121030819Sbostic ++cp;
121130819Sbostic if (*cp == '*') {
121230819Sbostic ++cp;
121330819Sbostic if (++i > acount)
121430819Sbostic return pfacm;
121530819Sbostic t = ntharg(p, i, acount)->in.type;
121630819Sbostic if (t != INT && t != UNSIGNED) {
121730819Sbostic (void) sprintf(errbuf,
121830819Sbostic "precision argument is type (%s) rather than (int) (arg %d)",
121930819Sbostic typestr(t), i);
122030819Sbostic return errbuf;
122130819Sbostic }
122230819Sbostic } else while (isdigit(*cp))
122330819Sbostic ++cp;
122430819Sbostic }
122530819Sbostic if (++i <= acount)
122630819Sbostic t = ntharg(p, i, acount)->in.type;
122730819Sbostic }
122830819Sbostic if (*cp == 'h' || *cp == 'l')
122930819Sbostic lchar = *cp++;
123030819Sbostic else lchar = '\0';
123130819Sbostic if ((cchar = *cp++) == '\0')
123230819Sbostic return pwf;
123330819Sbostic if (i > acount)
123430819Sbostic return (findlc(basep, lchar, cchar) == NULL) ?
123530819Sbostic pwf : pfacm;
123630819Sbostic if (!isscan && !pflag && ISPTR(t) &&
123730819Sbostic strchr("douxX", cchar) != 0)
123830819Sbostic continue; /* lax--printf("%d", (int *)) */
123930819Sbostic if (suppressed) {
124030819Sbostic if (findlc(basep, lchar, cchar) == NULL)
124130819Sbostic return pwf;
124230819Sbostic } else for (ep = basep; ; ++ep) {
124330819Sbostic if (ep->argtype == UNDEF) { /* end of table */
124430819Sbostic ep = findlc(basep, lchar, cchar);
124530819Sbostic if (ep == NULL)
124630819Sbostic return pwf;
124730819Sbostic (void) sprintf(errbuf, "%s: (%s) format, (%s) arg (arg %d)",
124830819Sbostic ip->name,
124930819Sbostic typestr(ep->argtype),
125030819Sbostic typestr(isscan ? (t | PTR) : t), i);
125130819Sbostic return errbuf;
125230819Sbostic }
125330819Sbostic if (ep->argtype == t && ep->lchar == lchar &&
125430819Sbostic strchr(ep->cchars, cchar) != 0)
125530819Sbostic if (ep->werror == 0)
125630819Sbostic break;
125730819Sbostic else {
125830819Sbostic werror(ep->werror, cchar);
125930819Sbostic return NULL;
126030819Sbostic }
126130819Sbostic }
126230819Sbostic if (cchar != '[')
126330819Sbostic continue;
126430819Sbostic do {
126530819Sbostic if (*cp == '\0')
126630819Sbostic return "possible unmatched '[' in format";
126730819Sbostic } while (*cp++ != ']');
126830819Sbostic }
126930819Sbostic /*NOTREACHED*/
127030819Sbostic }
127130819Sbostic
doform(p,sp,acount)127230819Sbostic doform(p, sp, acount)
127330819Sbostic NODE * p;
127430819Sbostic struct symtab * sp;
127530819Sbostic {
127630819Sbostic char * cp;
127730819Sbostic
127830819Sbostic if ((cp = subform(p, sp, acount)) != NULL)
127930819Sbostic werror(cp);
128030819Sbostic }
128130819Sbostic
cisreg(t)128230819Sbostic cisreg(t) TWORD t; {return(1);} /* everyting is a register variable! */
128330819Sbostic
128430819Sbostic fldty(p) struct symtab *p; {
128530819Sbostic ; /* all types are OK here... */
128630819Sbostic }
128730819Sbostic
fldal(t)128830819Sbostic fldal(t) unsigned t; { /* field alignment... */
128930819Sbostic if( t == ENUMTY ) return( ALCHAR ); /* this should be thought through better... */
129030819Sbostic if( ISPTR(t) ){ /* really for the benefit of honeywell (and someday IBM) */
129130819Sbostic if( pflag ) uerror( "nonportable field type" );
129230819Sbostic }
129330819Sbostic else uerror( "illegal field type" );
129430819Sbostic return(ALINT);
129530819Sbostic }
129630819Sbostic
main(argc,argv)129730819Sbostic main(argc, argv)
129830819Sbostic int argc;
129930819Sbostic char **argv;
130030819Sbostic {
130130819Sbostic extern char *optarg;
130230819Sbostic extern int optind;
130330819Sbostic int ch;
130430819Sbostic
130532979Sdonn while ((ch = getopt(argc,argv,"C:D:I:U:LX:Pabchnpuvxz")) != EOF)
130630819Sbostic switch((char)ch) {
130711403Snicklin case 'C':
130811403Snicklin Cflag = 1;
130930819Sbostic libname = optarg;
131011403Snicklin continue;
131130819Sbostic case 'D': /* #define */
131230819Sbostic case 'I': /* include path */
131330819Sbostic case 'U': /* #undef */
131432979Sdonn case 'X': /* debugging, done in first pass */
131530819Sbostic case 'P': /* debugging, done in second pass */
131630819Sbostic break;
131730819Sbostic case 'L':
131830819Sbostic libflag = 1;
131930819Sbostic /*FALLTHROUGH*/
132030819Sbostic case 'v': /* unused arguments in functions */
132130819Sbostic vflag = 0;
132230819Sbostic break;
132330819Sbostic case 'a': /* long to int assignment */
132430819Sbostic ++aflag;
132530819Sbostic break;
132630819Sbostic case 'b': /* unreached break statements */
132730819Sbostic brkflag = 1;
132830819Sbostic break;
132930819Sbostic case 'c': /* questionable casts */
133030819Sbostic cflag = 1;
133130819Sbostic break;
133230819Sbostic case 'h': /* heuristics */
133330819Sbostic hflag = 1;
133430819Sbostic break;
133530819Sbostic case 'n': /* standard library check */
133630819Sbostic nflag = 1;
133730819Sbostic break;
133830819Sbostic case 'p': /* IBM & GCOS portability */
133930819Sbostic pflag = 1;
134030819Sbostic break;
134130819Sbostic case 'u': /* 2nd pass: undefined or unused */
134230819Sbostic break;
134330819Sbostic case 'x': /* unused externs */
134430819Sbostic xflag = 1;
134530819Sbostic break;
134630819Sbostic case 'z': /* use of undefined structures */
134730819Sbostic zflag = 1;
134830819Sbostic break;
134930819Sbostic case '?':
135011403Snicklin default:
135130819Sbostic fputs("usage: lint [-C lib] [-D def] [-I include] [-U undef] [-Labchnpuvx] file ...\n",stderr);
135230819Sbostic exit(1);
135330819Sbostic }
135411403Snicklin
135530819Sbostic if (!pflag) { /* set sizes to sizes of target machine */
13567988Srrh # ifdef gcos
13577988Srrh SZCHAR = ALCHAR = 9;
13587988Srrh # else
13597988Srrh SZCHAR = ALCHAR = 8;
13607988Srrh # endif
13617988Srrh SZINT = ALINT = sizeof(int)*SZCHAR;
13627988Srrh SZFLOAT = ALFLOAT = sizeof(float)*SZCHAR;
13637988Srrh SZDOUBLE = ALDOUBLE = sizeof(double)*SZCHAR;
13647988Srrh SZLONG = ALLONG = sizeof(long)*SZCHAR;
13657988Srrh SZSHORT = ALSHORT = sizeof(short)*SZCHAR;
13667988Srrh SZPOINT = ALPOINT = sizeof(int *)*SZCHAR;
13677988Srrh ALSTRUCT = ALINT;
13687988Srrh /* now, fix some things up for various machines (I wish we had "alignof") */
13697988Srrh
13707988Srrh # ifdef pdp11
13717988Srrh ALLONG = ALDOUBLE = ALFLOAT = ALINT;
137230819Sbostic # endif
13737988Srrh # ifdef ibm
13747988Srrh ALSTRUCT = ALCHAR;
137530819Sbostic # endif
13767988Srrh }
137730819Sbostic return(mainp1(argc,argv));
137830819Sbostic }
13797988Srrh
ctype(type)13807988Srrh ctype( type ) unsigned type; { /* are there any funny types? */
13817988Srrh return( type );
13827988Srrh }
13837988Srrh
commdec(i)13847988Srrh commdec( i ){
13857988Srrh /* put out a common declaration */
138611761Sedward if( stab[i].sclass == STATIC ) outdef( &stab[i], LST, USUAL );
138711761Sedward else outdef( &stab[i], libflag?LIB:LDC, USUAL );
13887988Srrh }
13897988Srrh
isitfloat(s)13907988Srrh isitfloat ( s ) char *s; {
13917988Srrh /* s is a character string;
13927988Srrh if floating point is implemented, set dcon to the value of s */
13937988Srrh /* lint version
13947988Srrh */
13957988Srrh dcon = atof( s );
139625304Sbloom return( DCON );
13977988Srrh }
13987988Srrh
fldcon(p)13997988Srrh fldcon( p ) register NODE *p; {
14007988Srrh /* p is an assignment of a constant to a field */
14017988Srrh /* check to see if the assignment is going to overflow, or otherwise cause trouble */
14027988Srrh register s;
14037988Srrh CONSZ v;
14047988Srrh
14057988Srrh if( !hflag & !pflag ) return;
14067988Srrh
14077988Srrh s = UPKFSZ(p->in.left->tn.rval);
14087988Srrh v = p->in.right->tn.lval;
14097988Srrh
14107988Srrh switch( p->in.left->in.type ){
14117988Srrh
14127988Srrh case CHAR:
14137988Srrh case INT:
14147988Srrh case SHORT:
14157988Srrh case LONG:
14167988Srrh case ENUMTY:
14177988Srrh if( v>=0 && (v>>(s-1))==0 ) return;
14187988Srrh werror( "precision lost in assignment to (possibly sign-extended) field" );
14197988Srrh default:
14207988Srrh return;
14217988Srrh
14227988Srrh case UNSIGNED:
14237988Srrh case UCHAR:
14247988Srrh case USHORT:
14257988Srrh case ULONG:
14267988Srrh if( v<0 || (v>>s)!=0 ) werror( "precision lost in field assignment" );
14277988Srrh
14287988Srrh return;
14297988Srrh }
14307988Srrh
14317988Srrh }
14327988Srrh
14337988Srrh outdef( p, lty, mode ) struct symtab *p; {
14347988Srrh /* output a definition for the second pass */
14357988Srrh /* if mode is > USUAL, it is the number of args */
14367988Srrh char *fname;
14377988Srrh TWORD t;
14387988Srrh int line;
14397988Srrh static union rec rc;
14407988Srrh
14417988Srrh if( mode == NOFILE ){
14427988Srrh fname = "???";
14437988Srrh line = p->suse;
14447988Srrh }
14457988Srrh else if( mode == SVLINE ){
14467988Srrh fname = ftitle;
14477988Srrh line = -p->suse;
14487988Srrh }
14497988Srrh else {
14507988Srrh fname = ftitle;
14517988Srrh line = lineno;
14527988Srrh }
14537988Srrh fsave( fname );
14547988Srrh #ifndef FLEXNAMES
14557988Srrh strncpy( rc.l.name, exname(p->sname), LCHNM );
14567988Srrh #endif
14577988Srrh rc.l.decflag = lty;
14587988Srrh t = p->stype;
14597988Srrh if( mode == DECTY ) t = DECREF(t);
14607988Srrh rc.l.type.aty = t;
14617988Srrh rc.l.type.extra = 0;
146211761Sedward rc.l.type.extra1 = 0;
14637988Srrh astype( &rc.l.type, p->sizoff );
14647988Srrh rc.l.nargs = (mode>USUAL) ? mode : 0;
14657988Srrh rc.l.fline = line;
14667988Srrh fwrite( (char *)&rc, sizeof(rc), 1, stdout );
14677988Srrh #ifdef FLEXNAMES
14687988Srrh rc.l.name = exname(p->sname);
14697988Srrh fwrite( rc.l.name, strlen(rc.l.name)+1, 1, stdout );
14707988Srrh #endif
14717988Srrh }
14727988Srrh int proflg;
14737988Srrh int gdebug;
1474