xref: /csrg-svn/old/pcc/lint/lpass1/lint.c (revision 30819)
17988Srrh #ifndef lint
2*30819Sbostic static char sccsid[] = "@(#)lint.c	1.11	(Berkeley)	04/06/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 
31*30819Sbostic int nflag = 0;		/* avoid gripes about printf et al. */
32*30819Sbostic int vflag = 1;		/* tell about unused argments */
33*30819Sbostic int xflag = 0;		/* tell about unused externals */
34*30819Sbostic int argflag = 0;	/* used to turn off complaints about arguments */
35*30819Sbostic int libflag = 0;	/* used to generate library descriptions */
36*30819Sbostic int vaflag = -1;	/* signal functions with a variable number of args */
37*30819Sbostic int aflag = 0;		/* used to check precision of assignments */
38*30819Sbostic int zflag = 0;		/* no 'structure never defined' error */
39*30819Sbostic int Cflag = 0;	/* filter out certain output, for generating libraries */
40*30819Sbostic char *libname = 0;	/* name of the library we're generating */
417988Srrh 
42*30819Sbostic 			/* 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 
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 
997988Srrh ecode( p ) NODE *p; {
1007988Srrh 	/* compile code for p */
1017988Srrh 
1027988Srrh 	fwalk( p, contx, EFF );
1037988Srrh 	lnp = lnames;
1047988Srrh 	lprt( p, EFF, 0 );
105*30819Sbostic 	strforget();
1067988Srrh 	}
1077988Srrh 
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 
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 
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 
217*30819Sbostic 	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 */
2267988Srrh 	if( vaflag > 0 ){
2277988Srrh 		if( n < vaflag ) werror( "declare the VARARGS arguments you want checked!" );
2287988Srrh 		else n = vaflag;
2297988Srrh 		}
2307988Srrh 	fsave( ftitle );
23111761Sedward 	if( cfp->sclass == STATIC ) outdef( cfp, LST, vaflag>=0?-n:n );
23211761Sedward 	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 
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 
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 
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 );
412*30819Sbostic 			if (hflag && !nflag)
413*30819Sbostic 				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 
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 
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 
6187988Srrh zecode( n ){
6197988Srrh 	/* n integer words of zeros */
6207988Srrh 	OFFSZ temp;
6217988Srrh 	temp = n;
6227988Srrh 	inoff += temp*SZINT;
6237988Srrh 	;
6247988Srrh 	}
6257988Srrh 
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 *
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 ){
662*30819Sbostic 	case NAME:
663*30819Sbostic 		{
664*30819Sbostic 			extern int	didstr, subscr;
665*30819Sbostic 			extern NODE *	strnodes[];
6667988Srrh 
667*30819Sbostic 			if (didstr) {
668*30819Sbostic 				didstr = 0;
669*30819Sbostic 				strnodes[subscr] = p;
670*30819Sbostic 			}
671*30819Sbostic 		}
672*30819Sbostic 		break;
673*30819Sbostic 
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 *
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 
7457988Srrh noinit(){
7467988Srrh 	/* storage class for such as "int a;" */
7477988Srrh 	return( pflag ? EXTDEF : EXTERN );
7487988Srrh 	}
7497988Srrh 
7507988Srrh 
7517988Srrh cinit( p, sz ) NODE *p; { /* initialize p into size sz */
7527988Srrh 	inoff += sz;
7537988Srrh 	if( p->in.op == INIT ){
7547988Srrh 		if( p->in.left->in.op == ICON ) return;
7557988Srrh 		if( p->in.left->in.op == NAME && p->in.left->in.type == MOE ) return;
7567988Srrh 		}
7577988Srrh 	uerror( "illegal initialization" );
7587988Srrh 	}
7597988Srrh 
7607988Srrh char *
7617988Srrh exname( p ) char *p; {
7627988Srrh 	/* make a name look like an external name in the local machine */
7637988Srrh 	static char aa[8];
7647988Srrh 	register int i;
7657988Srrh 
7667988Srrh 	if( !pflag ) return(p);
7677988Srrh 	for( i=0; i<6; ++i ){
7687988Srrh 		if( isupper(*p ) ) aa[i] = tolower( *p );
7697988Srrh 		else aa[i] = *p;
7707988Srrh 		if( *p ) ++p;
7717988Srrh 		}
7727988Srrh 	aa[6] = '\0';
7737988Srrh 	return( aa );
7747988Srrh 	}
7757988Srrh 
7767988Srrh char *
7777988Srrh strip(s) char *s; {
7787988Srrh #ifndef FLEXNAMES
7797988Srrh 	static char x[LFNM+1];
7807988Srrh #else
7817988Srrh 	static char x[BUFSIZ];
7827988Srrh #endif
7837988Srrh 	register char *p;
7847996Srrh 	static	int	stripping = 0;
7857988Srrh 
7867996Srrh 	if (stripping)
7877996Srrh 		return(s);
7887996Srrh 	stripping++;
7897988Srrh 	for( p=x; *s; ++s ){
7907996Srrh 		if( *s != '"' ){
7917988Srrh #ifndef FLEXNAMES
7927988Srrh /* PATCHED by ROBERT HENRY on 8Jul80 to fix 14 character file name bug */
7937988Srrh 			if( p >= &x[LFNM] )
79411403Snicklin #else
79511403Snicklin 			if( p >= &x[BUFSIZ] )
79611403Snicklin #endif
7977988Srrh 				cerror( "filename too long" );
7987988Srrh 			*p++ = *s;
7997988Srrh 		}
8007988Srrh 	}
8017996Srrh 	stripping = 0;
8027988Srrh 	*p = '\0';
8037988Srrh #ifndef FLEXNAMES
8047988Srrh 	return( x );
8057988Srrh #else
8067988Srrh 	return( hash(x) );
8077988Srrh #endif
8087988Srrh 	}
8097988Srrh 
8107988Srrh fsave( s ) char *s; {
8117988Srrh 	static union rec fsname;
8127988Srrh 	s = strip( s );
8137988Srrh #ifndef FLEXNAMES
81426916Sdonn 	if( strncmp( s, fsname.f.fn, LFNM ) )
8157988Srrh #else
81626916Sdonn 	if (fsname.f.fn == NULL || strcmp(s, fsname.f.fn))
8177988Srrh #endif
81826916Sdonn 		{
8197988Srrh 		/* new one */
8207988Srrh #ifndef FLEXNAMES
8217988Srrh 		strncpy( fsname.f.fn, s, LFNM );
8227988Srrh #else
8237988Srrh 		fsname.f.fn = s;
8247988Srrh #endif
8257988Srrh 		fsname.f.decflag = LFN;
8267988Srrh 		fwrite( (char *)&fsname, sizeof(fsname), 1, stdout );
8277988Srrh #ifdef FLEXNAMES
82811403Snicklin 		/* if generating a library, prefix with the library name */
82911403Snicklin 		/* only do this for flexnames */
83011403Snicklin 		if( libname ){
83111403Snicklin 			fwrite( libname, strlen(libname), 1, stdout );
83211403Snicklin 			putchar( ':' );
83311403Snicklin 			}
8347988Srrh 		fwrite( fsname.f.fn, strlen(fsname.f.fn)+1, 1, stdout );
8357988Srrh #endif
8367988Srrh 		}
8377988Srrh 	}
8387988Srrh 
8397988Srrh where(f){ /* print true location of error */
8407996Srrh 	if( f == 'u' && nerrors > 1 )
8417996Srrh 		--nerrors; /* don't get "too many errors" */
8427996Srrh 	fprintf( stderr, "%s(%d): ", strip(ftitle), lineno);
8437988Srrh 	}
8447988Srrh 
8457988Srrh 	/* a number of dummy routines, unneeded by lint */
8467988Srrh 
8477988Srrh branch(n){;}
8487988Srrh defalign(n){;}
8497988Srrh deflab(n){;}
8507988Srrh 
851*30819Sbostic extern char *	strchr();
8527988Srrh 
853*30819Sbostic #define SBUFSIZE	16
854*30819Sbostic #define SCLICK		80
855*30819Sbostic 
856*30819Sbostic #ifndef size_t
857*30819Sbostic #define size_t	unsigned
858*30819Sbostic #endif /* !size_t */
859*30819Sbostic 
860*30819Sbostic static char *	strings[SBUFSIZE];
861*30819Sbostic static NODE *	strnodes[SBUFSIZE];
862*30819Sbostic static int	didstr;
863*30819Sbostic static int	subscr;
864*30819Sbostic static int	strapped;
865*30819Sbostic 
866*30819Sbostic bycode(t, i)
867*30819Sbostic {
868*30819Sbostic 	extern char *	calloc();
869*30819Sbostic 	extern char *	realloc();
870*30819Sbostic 
871*30819Sbostic 	if (!hflag || nflag || strapped)
872*30819Sbostic 		return;
873*30819Sbostic 	if (i == 0)
874*30819Sbostic 		if (subscr < (SBUFSIZE - 1))
875*30819Sbostic 			++subscr;
876*30819Sbostic 	if (subscr >= SBUFSIZE)
877*30819Sbostic 		return;
878*30819Sbostic 	didstr = 1;
879*30819Sbostic 	if ((i % SCLICK) == 0) {
880*30819Sbostic 		strings[subscr] = (strings[subscr] == NULL) ?
881*30819Sbostic 			calloc((size_t) (SCLICK + 1), 1) :
882*30819Sbostic 			realloc(strings[subscr], (size_t) (i + SCLICK + 1));
883*30819Sbostic 		if (strings[subscr] == NULL) {
884*30819Sbostic 			strapped = 1;
885*30819Sbostic 			return;
8867988Srrh 		}
8877988Srrh 	}
888*30819Sbostic 	strings[subscr][i] = t;
889*30819Sbostic }
8907988Srrh 
891*30819Sbostic strforget()
892*30819Sbostic {
893*30819Sbostic 	didstr = subscr = 0;
894*30819Sbostic }
8957988Srrh 
896*30819Sbostic static char *
897*30819Sbostic typestr(t)
898*30819Sbostic {
899*30819Sbostic 	switch (t) {
900*30819Sbostic 		case CHAR:		return "char";
901*30819Sbostic 		case UCHAR:		return "unsigned char";
902*30819Sbostic 		case SHORT:		return "short";
903*30819Sbostic 		case USHORT:		return "unsigned short";
904*30819Sbostic 		case INT:		return "int";
905*30819Sbostic 		case UNSIGNED:		return "unsigned";
906*30819Sbostic 		case ENUMTY:		return "enum";
907*30819Sbostic 		case LONG:		return "long";
908*30819Sbostic 		case ULONG:		return "unsigned long";
909*30819Sbostic 		case FLOAT:		return "float";
910*30819Sbostic 		case DOUBLE:		return "double";
911*30819Sbostic 		case STRTY:		return "struct";
912*30819Sbostic 		case UNIONTY:		return "union";
913*30819Sbostic 		case PTR|CHAR:		return "char *";
914*30819Sbostic 		case PTR|UCHAR:		return "unsigned char *";
915*30819Sbostic 		case PTR|SHORT:		return "short *";
916*30819Sbostic 		case PTR|USHORT:	return "unsigned short *";
917*30819Sbostic 		case PTR|INT:		return "int *";
918*30819Sbostic 		case PTR|UNSIGNED:	return "unsigned *";
919*30819Sbostic 		case PTR|ENUMTY:	return "enum *";
920*30819Sbostic 		case PTR|LONG:		return "long *";
921*30819Sbostic 		case PTR|ULONG:		return "unsigned long *";
922*30819Sbostic 		case PTR|FLOAT:		return "float *";
923*30819Sbostic 		case PTR|DOUBLE:	return "double *";
924*30819Sbostic 		case PTR|STRTY:		return "struct *";
925*30819Sbostic 		case PTR|UNIONTY:	return "union *";
926*30819Sbostic 		default:		return ISPTR(t) ?
927*30819Sbostic 						"pointer" : "non-scalar";
928*30819Sbostic 	}
929*30819Sbostic }
9307988Srrh 
931*30819Sbostic NODE *
932*30819Sbostic ntharg(p, n, acount)
933*30819Sbostic NODE *		p;
934*30819Sbostic register int	n;
935*30819Sbostic register int	acount;
936*30819Sbostic {
937*30819Sbostic 	if (n > acount)
938*30819Sbostic 		return NULL;
939*30819Sbostic 	p = p->in.right;
940*30819Sbostic 	while (n != acount) {
941*30819Sbostic 		p = p->in.left;
942*30819Sbostic 		--acount;
943*30819Sbostic 	}
944*30819Sbostic 	return (n == 1) ? p : p->in.right;
945*30819Sbostic }
9467988Srrh 
947*30819Sbostic struct entry {
948*30819Sbostic 	/* If argument to print/scan is of type... */	int	argtype;
949*30819Sbostic 	/* ...and this length character is used... */	char	lchar;
950*30819Sbostic 	/* ...and one of these is control char... */	char *	cchars;
951*30819Sbostic 	/* ...then use this format with werror... */	char *	werror;
952*30819Sbostic 	/* ...(where NULL means it's hunky dory)... */
953*30819Sbostic };
9547988Srrh 
955*30819Sbostic /*
956*30819Sbostic ** Portable printf.
957*30819Sbostic ** H&S says "%o" takes an unsigned argument;
958*30819Sbostic ** X3J11 says "%o" takes an int argument;
959*30819Sbostic ** we'll allow either here.
960*30819Sbostic */
9617988Srrh 
962*30819Sbostic static struct entry pprintf[] = {
963*30819Sbostic 	CHAR,		'\0',	"c",		NULL, /* this is deliberate */
964*30819Sbostic 	INT,		'\0',	"cdoxX",	NULL,
965*30819Sbostic 	UNSIGNED,	'\0',	"uoxX",		NULL,
966*30819Sbostic 	CHAR,		'\0',	"cdoxX",	NULL,
967*30819Sbostic 	UCHAR,		'\0',	"udoxX",	NULL, /* yes, d is okay */
968*30819Sbostic 	SHORT,		'\0',	"cdoxX",	NULL,
969*30819Sbostic 	USHORT,		'\0',	"uoxX",		NULL,
970*30819Sbostic 	ENUMTY,		'\0',	"duoxX",	NULL,
971*30819Sbostic 	LONG,		'l',	"doxX",		NULL,
972*30819Sbostic 	ULONG,		'l',	"uoxX",		NULL,
973*30819Sbostic 	FLOAT,		'\0',	"eEfgG",	NULL,
974*30819Sbostic 	DOUBLE,		'\0',	"eEfgG",	NULL,
975*30819Sbostic 	PTR|CHAR,	'\0',	"s",		NULL,
976*30819Sbostic 	UNDEF,		'\0',	"",		NULL
977*30819Sbostic };
9787988Srrh 
979*30819Sbostic /*
980*30819Sbostic ** Berkeley printf.
981*30819Sbostic ** It allows %D, %O, and %U, which we deprecate.
982*30819Sbostic ** Since
983*30819Sbostic **	sizeof (char *) == sizeof (int) &&
984*30819Sbostic **	sizeof (int) == sizeof (long) &&
985*30819Sbostic **	sizeof (char *) == sizeof (int *)
986*30819Sbostic ** you can be lax--and we tolerate *some* laxness.
987*30819Sbostic ** g/lax/p to find lax table entries and code.
988*30819Sbostic */
9897988Srrh 
990*30819Sbostic static char	uppercase[] = "deprecated upper-case control character (%c)";
991*30819Sbostic #define lax	NULL
9927988Srrh 
993*30819Sbostic static struct entry bprintf[] = {
994*30819Sbostic 	CHAR,		'\0',	"c",		NULL,	/* this is deliberate */
995*30819Sbostic 	INT,		'\0',	"cdoxX",	NULL,
996*30819Sbostic 	INT,		'\0',	"DO",		uppercase,
997*30819Sbostic 	UNSIGNED,	'\0',	"uoxX",		NULL,
998*30819Sbostic 	UNSIGNED,	'\0',	"UO",		uppercase,
999*30819Sbostic 	CHAR,		'\0',	"cdoxX",	NULL,
1000*30819Sbostic 	CHAR,		'\0',	"DO",		uppercase,
1001*30819Sbostic 	UCHAR,		'\0',	"duoxX",	NULL,	/* yes, d is okay */
1002*30819Sbostic 	UCHAR,		'\0',	"DUO",		uppercase,
1003*30819Sbostic 	SHORT,		'\0',	"cdoxX",	NULL,
1004*30819Sbostic 	SHORT,		'\0',	"DO",		uppercase,
1005*30819Sbostic 	USHORT,		'\0',	"duoxX",	NULL,	/* d okay on BSD */
1006*30819Sbostic 	USHORT,		'\0',	"DUO",		uppercase,
1007*30819Sbostic 	ENUMTY,		'\0',	"duoxX",	NULL,
1008*30819Sbostic 	ENUMTY,		'\0',	"DUO",		uppercase,
1009*30819Sbostic 	LONG,		'\0',	"doxX",		lax,
1010*30819Sbostic 	LONG,		'\0',	"DO",		uppercase,
1011*30819Sbostic 	LONG,		'l',	"doxX",		NULL,
1012*30819Sbostic 	INT,		'l',	"doxX",		lax,
1013*30819Sbostic 	ULONG,		'\0',	"uoxX",		lax,
1014*30819Sbostic 	ULONG,		'\0',	"UO",		uppercase,
1015*30819Sbostic 	ULONG,		'l',	"uoxX",		NULL,
1016*30819Sbostic 	UNSIGNED,	'l',	"uoxX",		lax,
1017*30819Sbostic 	FLOAT,		'\0',	"eEfgG",	NULL,
1018*30819Sbostic 	DOUBLE,		'\0',	"eEfgG",	NULL,
1019*30819Sbostic 	PTR|CHAR,	'\0',	"s",		NULL,
1020*30819Sbostic 	UNDEF,		'\0',	NULL,		NULL,
1021*30819Sbostic };
10227988Srrh 
1023*30819Sbostic /*
1024*30819Sbostic ** Portable scanf.  'l' and 'h' are universally ignored preceding 'c' and 's',
1025*30819Sbostic ** and 'h' is universally ignored preceding 'e' and 'f',
1026*30819Sbostic ** but you won't find such cruft here.
1027*30819Sbostic */
10287988Srrh 
1029*30819Sbostic static struct entry pscanf[] = {
1030*30819Sbostic 	INT,		'\0',	"dox",	NULL,
1031*30819Sbostic 	UNSIGNED,	'\0',	"uox",	NULL,
1032*30819Sbostic 	CHAR,		'\0',	"cs[",	NULL,
1033*30819Sbostic 	SHORT,		'h',	"dox",	NULL,
1034*30819Sbostic 	USHORT,		'h',	"uox",	NULL,
1035*30819Sbostic 	LONG,		'l',	"dox",	NULL,
1036*30819Sbostic 	ULONG,		'l',	"uox",	NULL,
1037*30819Sbostic 	FLOAT,		'\0',	"ef",	NULL,	/* BSD doesn't handle g */
1038*30819Sbostic 	DOUBLE,		'l',	"ef",	NULL,
1039*30819Sbostic 	UNDEF,		'\0',	NULL,	NULL,
1040*30819Sbostic };
10417988Srrh 
1042*30819Sbostic /*
1043*30819Sbostic ** Berkeley scanf.  An upper case letter equals an l plus the lower case char,
1044*30819Sbostic ** but this is deprecated.
1045*30819Sbostic ** Even though sizeof (int) == sizeof (long), we'll be picky here.
1046*30819Sbostic */
10477988Srrh 
1048*30819Sbostic static struct entry bscanf[] = {
1049*30819Sbostic 	INT,		'\0',	"dox",	NULL,
1050*30819Sbostic 	UNSIGNED,	'\0',	"uox",	NULL,
1051*30819Sbostic 	CHAR,		'\0',	"cs[",	NULL,
1052*30819Sbostic 	SHORT,		'h',	"dox",	NULL,
1053*30819Sbostic 	USHORT,		'h',	"uox",	NULL,
1054*30819Sbostic 	LONG,		'\0',	"dox",	lax,
1055*30819Sbostic 	LONG,		'\0',	"DOX",	uppercase,
1056*30819Sbostic 	LONG,		'l',	"dox",	NULL,
1057*30819Sbostic 	ULONG,		'\0',	"uox",	lax,
1058*30819Sbostic 	ULONG,		'\0',	"UOX",	uppercase,
1059*30819Sbostic 	ULONG,		'l',	"uox",	NULL,
1060*30819Sbostic 	FLOAT,		'\0',	"ef",	NULL,
1061*30819Sbostic 	DOUBLE,		'\0',	"EF",	uppercase,
1062*30819Sbostic 	DOUBLE,		'l',	"ef",	NULL,
1063*30819Sbostic 	UNDEF,		'\0',	NULL,	NULL,
1064*30819Sbostic };
10657988Srrh 
1066*30819Sbostic static struct item {
1067*30819Sbostic 	char *		name;		/* such as "printf" */
1068*30819Sbostic 	int		isscan;		/* scanf/printf */
1069*30819Sbostic 	int		fmtarg;		/* number of format argument */
1070*30819Sbostic 	struct entry *	ptable;		/* portable checking table */
1071*30819Sbostic 	struct entry *	btable;		/* berkeley checking table */
1072*30819Sbostic } items[] = {
1073*30819Sbostic 	"printf",	0,	1,	pprintf,	bprintf,
1074*30819Sbostic 	"fprintf",	0,	2,	pprintf,	bprintf,
1075*30819Sbostic 	"sprintf",	0,	2,	pprintf,	bprintf,
1076*30819Sbostic 	"scanf",	1,	1,	pscanf,		bscanf,
1077*30819Sbostic 	"fscanf",	1,	2,	pscanf,		bscanf,
1078*30819Sbostic 	"sscanf",	1,	2,	pscanf,		bscanf,
1079*30819Sbostic 	NULL,		-1,	-1,	NULL,		NULL
1080*30819Sbostic };
10817988Srrh 
1082*30819Sbostic static char	pwf[]	= "possible wild format";
1083*30819Sbostic static char	pfacm[]	= "possible format/argument count mismatch";
108411761Sedward 
1085*30819Sbostic static struct entry *
1086*30819Sbostic findlc(ep, lchar, cchar)
1087*30819Sbostic register struct entry *	ep;
1088*30819Sbostic register int		lchar;
1089*30819Sbostic register int		cchar;
1090*30819Sbostic {
1091*30819Sbostic 	for ( ; ep->argtype != UNDEF; ++ep)
1092*30819Sbostic 		if (ep->lchar == lchar && strchr(ep->cchars, cchar) != 0)
1093*30819Sbostic 			return ep;
1094*30819Sbostic 	return NULL;
1095*30819Sbostic }
10967988Srrh 
1097*30819Sbostic static char *
1098*30819Sbostic subform(p, sp, acount)
1099*30819Sbostic register NODE *			p;
1100*30819Sbostic register struct symtab *	sp;
1101*30819Sbostic {
1102*30819Sbostic 	register int		i, j, isscan;
1103*30819Sbostic 	register NODE *		tp;
1104*30819Sbostic 	register char *		cp;
1105*30819Sbostic 	register struct entry *	basep;
1106*30819Sbostic 	register struct entry *	ep;
1107*30819Sbostic 	register struct item *	ip;
1108*30819Sbostic 	register int		lchar;
1109*30819Sbostic 	register int		cchar;
1110*30819Sbostic 	register int		t;
1111*30819Sbostic 	register int		suppressed;
1112*30819Sbostic 	static char		errbuf[132];
111311761Sedward 
1114*30819Sbostic 	if (!hflag || nflag || strapped)
1115*30819Sbostic 		return NULL;
1116*30819Sbostic 	cp = sp->sname;
1117*30819Sbostic 	for (ip = items; ; ++ip)
1118*30819Sbostic 		if (ip->name == NULL)
1119*30819Sbostic 			return NULL;	/* not a print/scan function */
1120*30819Sbostic 		else if (strcmp(ip->name, sp->sname) == 0)
1121*30819Sbostic 			break;
1122*30819Sbostic 	isscan = ip->isscan;
1123*30819Sbostic 	i = ip->fmtarg;
1124*30819Sbostic 	if (i > acount)
1125*30819Sbostic 		return NULL;	/* handled in pass 2 */
1126*30819Sbostic 	tp = ntharg(p, i, acount);
1127*30819Sbostic 	if (tp->in.type != (PTR|CHAR))
1128*30819Sbostic 		return NULL;	/* handled in pass 2 */
1129*30819Sbostic 	if (tp->in.op != ICON || tp->tn.lval != 0)
1130*30819Sbostic 		return NULL;	/* can't check it */
1131*30819Sbostic 	for (j = 1; j <= subscr; ++j)
1132*30819Sbostic 		if (tp == strnodes[j])
1133*30819Sbostic 			break;
1134*30819Sbostic 	if (j > subscr)
1135*30819Sbostic 		return NULL;	/* oh well. . . */
1136*30819Sbostic 	cp = strings[j];
1137*30819Sbostic 	/*
1138*30819Sbostic 	** cp now points to format string.
1139*30819Sbostic 	*/
1140*30819Sbostic 	basep = pflag ? ip->ptable : ip->btable;
1141*30819Sbostic 	for ( ; ; ) {
1142*30819Sbostic 		if (*cp == '\0')
1143*30819Sbostic 			return (i == acount) ? NULL : pfacm;
1144*30819Sbostic 		if (*cp++ != '%')
1145*30819Sbostic 			continue;
1146*30819Sbostic 		if (*cp == '\0')
1147*30819Sbostic 			return "wild trailing %% in format";
1148*30819Sbostic 		if (*cp == '%') {
1149*30819Sbostic 			++cp;
1150*30819Sbostic 			continue;
1151*30819Sbostic 		}
1152*30819Sbostic 		if (isscan) {
1153*30819Sbostic 			suppressed = *cp == '*';
1154*30819Sbostic 			if (suppressed)
1155*30819Sbostic 				++cp;
1156*30819Sbostic 			while (isdigit(*cp))
1157*30819Sbostic 				++cp;
1158*30819Sbostic 			if (!suppressed && ++i <= acount) {
1159*30819Sbostic 				t = ntharg(p, i, acount)->in.type;
1160*30819Sbostic 				if (!ISPTR(t)) {
1161*30819Sbostic (void) sprintf(errbuf,
1162*30819Sbostic 	"%s argument is type (%s) rather than pointer (arg %d)",
1163*30819Sbostic 	ip->name, typestr(t), i);
1164*30819Sbostic 					return errbuf;
1165*30819Sbostic 				}
1166*30819Sbostic 				t = DECREF(t);
1167*30819Sbostic 			}
1168*30819Sbostic 		} else {
1169*30819Sbostic 			int	nspace, ndash, nplus, nhash;
1170*30819Sbostic 
1171*30819Sbostic 			suppressed = 0;
1172*30819Sbostic 			nspace = ndash = nplus = nhash = 0;
1173*30819Sbostic 			for ( ; ; ) {
1174*30819Sbostic 				if (*cp == ' ')
1175*30819Sbostic 					++nspace;
1176*30819Sbostic 				else if (*cp == '+')
1177*30819Sbostic 					++nplus;
1178*30819Sbostic 				else if (*cp == '-')
1179*30819Sbostic 					++ndash;
1180*30819Sbostic 				else if (*cp == '#')
1181*30819Sbostic 					++nhash;
1182*30819Sbostic 				else	break;
1183*30819Sbostic 				++cp;
1184*30819Sbostic 			}
1185*30819Sbostic 			if (nspace > 1 || ndash > 1 || nplus > 1 || nhash > 1)
1186*30819Sbostic 				return "wild repeated flag character in format";
1187*30819Sbostic 			if (*cp == '*') {
1188*30819Sbostic 				++cp;
1189*30819Sbostic 				if (++i > acount)
1190*30819Sbostic 					break;
1191*30819Sbostic 				t = ntharg(p, i, acount)->in.type;
1192*30819Sbostic 				/*
1193*30819Sbostic 				** Width other than INT or UNSIGNED is suspect.
1194*30819Sbostic 				*/
1195*30819Sbostic 				if (t != INT && t != UNSIGNED) {
1196*30819Sbostic (void) sprintf(errbuf,
1197*30819Sbostic 	"field width argument is type (%s) rather than (int) (arg %d)",
1198*30819Sbostic 	typestr(t), i);
1199*30819Sbostic 					return errbuf;
1200*30819Sbostic 				}
1201*30819Sbostic 			} else while (isdigit(*cp))
1202*30819Sbostic 				++cp;
1203*30819Sbostic 			if (*cp == '.') {
1204*30819Sbostic 				++cp;
1205*30819Sbostic 				if (*cp == '*') {
1206*30819Sbostic 					++cp;
1207*30819Sbostic 					if (++i > acount)
1208*30819Sbostic 						return pfacm;
1209*30819Sbostic 					t = ntharg(p, i, acount)->in.type;
1210*30819Sbostic 					if (t != INT && t != UNSIGNED) {
1211*30819Sbostic (void) sprintf(errbuf,
1212*30819Sbostic 	"precision argument is type (%s) rather than (int) (arg %d)",
1213*30819Sbostic 	typestr(t), i);
1214*30819Sbostic 						return errbuf;
1215*30819Sbostic 					}
1216*30819Sbostic 				} else while (isdigit(*cp))
1217*30819Sbostic 					++cp;
1218*30819Sbostic 			}
1219*30819Sbostic 			if (++i <= acount)
1220*30819Sbostic 				t = ntharg(p, i, acount)->in.type;
1221*30819Sbostic 		}
1222*30819Sbostic 		if (*cp == 'h' || *cp == 'l')
1223*30819Sbostic 			lchar = *cp++;
1224*30819Sbostic 		else	lchar = '\0';
1225*30819Sbostic 		if ((cchar = *cp++) == '\0')
1226*30819Sbostic 			return pwf;
1227*30819Sbostic 		if (i > acount)
1228*30819Sbostic 			return (findlc(basep, lchar, cchar) == NULL) ?
1229*30819Sbostic 				pwf : pfacm;
1230*30819Sbostic 		if (!isscan && !pflag && ISPTR(t) &&
1231*30819Sbostic 			strchr("douxX", cchar) != 0)
1232*30819Sbostic 				continue;	/* lax--printf("%d", (int *)) */
1233*30819Sbostic 		if (suppressed) {
1234*30819Sbostic 			if (findlc(basep, lchar, cchar) == NULL)
1235*30819Sbostic 				return pwf;
1236*30819Sbostic 		} else for (ep = basep; ; ++ep) {
1237*30819Sbostic 			if (ep->argtype == UNDEF) {	/* end of table */
1238*30819Sbostic 				ep = findlc(basep, lchar, cchar);
1239*30819Sbostic 				if (ep == NULL)
1240*30819Sbostic 					return pwf;
1241*30819Sbostic (void) sprintf(errbuf, "%s: (%s) format, (%s) arg (arg %d)",
1242*30819Sbostic 					ip->name,
1243*30819Sbostic 					typestr(ep->argtype),
1244*30819Sbostic 					typestr(isscan ? (t | PTR) : t), i);
1245*30819Sbostic 				return errbuf;
1246*30819Sbostic 			}
1247*30819Sbostic 			if (ep->argtype == t && ep->lchar == lchar &&
1248*30819Sbostic 				strchr(ep->cchars, cchar) != 0)
1249*30819Sbostic 					if (ep->werror == 0)
1250*30819Sbostic 						break;
1251*30819Sbostic 					else {
1252*30819Sbostic 						werror(ep->werror, cchar);
1253*30819Sbostic 						return NULL;
1254*30819Sbostic 					}
1255*30819Sbostic 		}
1256*30819Sbostic 		if (cchar != '[')
1257*30819Sbostic 			continue;
1258*30819Sbostic 		do {
1259*30819Sbostic 			if (*cp == '\0')
1260*30819Sbostic 				return "possible unmatched '[' in format";
1261*30819Sbostic 		} while (*cp++ != ']');
1262*30819Sbostic 	}
1263*30819Sbostic 	/*NOTREACHED*/
1264*30819Sbostic }
1265*30819Sbostic 
1266*30819Sbostic doform(p, sp, acount)
1267*30819Sbostic NODE *		p;
1268*30819Sbostic struct symtab *	sp;
1269*30819Sbostic {
1270*30819Sbostic 	char *	cp;
1271*30819Sbostic 
1272*30819Sbostic 	if ((cp = subform(p, sp, acount)) != NULL)
1273*30819Sbostic 		werror(cp);
1274*30819Sbostic }
1275*30819Sbostic 
1276*30819Sbostic cisreg(t) TWORD t; {return(1);}  /* everyting is a register variable! */
1277*30819Sbostic 
1278*30819Sbostic fldty(p) struct symtab *p; {
1279*30819Sbostic 	; /* all types are OK here... */
1280*30819Sbostic 	}
1281*30819Sbostic 
1282*30819Sbostic fldal(t) unsigned t; { /* field alignment... */
1283*30819Sbostic 	if( t == ENUMTY ) return( ALCHAR );  /* this should be thought through better... */
1284*30819Sbostic 	if( ISPTR(t) ){ /* really for the benefit of honeywell (and someday IBM) */
1285*30819Sbostic 		if( pflag ) uerror( "nonportable field type" );
1286*30819Sbostic 		}
1287*30819Sbostic 	else uerror( "illegal field type" );
1288*30819Sbostic 	return(ALINT);
1289*30819Sbostic 	}
1290*30819Sbostic 
1291*30819Sbostic main(argc, argv)
1292*30819Sbostic 	int	argc;
1293*30819Sbostic 	char	**argv;
1294*30819Sbostic {
1295*30819Sbostic 	extern char	*optarg;
1296*30819Sbostic 	extern int	optind;
1297*30819Sbostic 	int	ch;
1298*30819Sbostic 
1299*30819Sbostic 	while ((ch = getopt(argc,argv,"C:D:I:U:LPabchnpuvxz")) != EOF)
1300*30819Sbostic 		switch((char)ch) {
130111403Snicklin 			case 'C':
130211403Snicklin 				Cflag = 1;
1303*30819Sbostic 				libname = optarg;
130411403Snicklin 				continue;
1305*30819Sbostic 			case 'D':	/* #define */
1306*30819Sbostic 			case 'I':	/* include path */
1307*30819Sbostic 			case 'U':	/* #undef */
1308*30819Sbostic 			case 'P':	/* debugging, done in second pass */
1309*30819Sbostic 				break;
1310*30819Sbostic 			case 'L':
1311*30819Sbostic 				libflag = 1;
1312*30819Sbostic 				/*FALLTHROUGH*/
1313*30819Sbostic 			case 'v':	/* unused arguments in functions */
1314*30819Sbostic 				vflag = 0;
1315*30819Sbostic 				break;
1316*30819Sbostic 			case 'a':	/* long to int assignment */
1317*30819Sbostic 				++aflag;
1318*30819Sbostic 				break;
1319*30819Sbostic 			case 'b':	/* unreached break statements */
1320*30819Sbostic 				brkflag = 1;
1321*30819Sbostic 				break;
1322*30819Sbostic 			case 'c':	/* questionable casts */
1323*30819Sbostic 				cflag = 1;
1324*30819Sbostic 				break;
1325*30819Sbostic 			case 'h':	/* heuristics */
1326*30819Sbostic 				hflag = 1;
1327*30819Sbostic 				break;
1328*30819Sbostic 			case 'n':	/* standard library check */
1329*30819Sbostic 				nflag = 1;
1330*30819Sbostic 				break;
1331*30819Sbostic 			case 'p':	/* IBM & GCOS portability */
1332*30819Sbostic 				pflag = 1;
1333*30819Sbostic 				break;
1334*30819Sbostic 			case 'u':	/* 2nd pass: undefined or unused */
1335*30819Sbostic 				break;
1336*30819Sbostic 			case 'x':	/* unused externs */
1337*30819Sbostic 				xflag = 1;
1338*30819Sbostic 				break;
1339*30819Sbostic 			case 'z':	/* use of undefined structures */
1340*30819Sbostic 				zflag = 1;
1341*30819Sbostic 				break;
1342*30819Sbostic 			case '?':
134311403Snicklin 			default:
1344*30819Sbostic 				fputs("usage: lint [-C lib] [-D def] [-I include] [-U undef] [-Labchnpuvx] file ...\n",stderr);
1345*30819Sbostic 				exit(1);
1346*30819Sbostic 		}
134711403Snicklin 
1348*30819Sbostic 	if (!pflag) {		/* set sizes to sizes of target machine */
13497988Srrh # ifdef gcos
13507988Srrh 		SZCHAR = ALCHAR = 9;
13517988Srrh # else
13527988Srrh 		SZCHAR = ALCHAR = 8;
13537988Srrh # endif
13547988Srrh 		SZINT = ALINT = sizeof(int)*SZCHAR;
13557988Srrh 		SZFLOAT = ALFLOAT = sizeof(float)*SZCHAR;
13567988Srrh 		SZDOUBLE = ALDOUBLE = sizeof(double)*SZCHAR;
13577988Srrh 		SZLONG = ALLONG = sizeof(long)*SZCHAR;
13587988Srrh 		SZSHORT = ALSHORT = sizeof(short)*SZCHAR;
13597988Srrh 		SZPOINT = ALPOINT = sizeof(int *)*SZCHAR;
13607988Srrh 		ALSTRUCT = ALINT;
13617988Srrh 		/* now, fix some things up for various machines (I wish we had "alignof") */
13627988Srrh 
13637988Srrh # ifdef pdp11
13647988Srrh 		ALLONG = ALDOUBLE = ALFLOAT = ALINT;
1365*30819Sbostic # endif
13667988Srrh # ifdef ibm
13677988Srrh 		ALSTRUCT = ALCHAR;
1368*30819Sbostic # endif
13697988Srrh 	}
1370*30819Sbostic 	return(mainp1(argc,argv));
1371*30819Sbostic }
13727988Srrh 
13737988Srrh ctype( type ) unsigned type; { /* are there any funny types? */
13747988Srrh 	return( type );
13757988Srrh 	}
13767988Srrh 
13777988Srrh commdec( i ){
13787988Srrh 	/* put out a common declaration */
137911761Sedward 	if( stab[i].sclass == STATIC ) outdef( &stab[i], LST, USUAL );
138011761Sedward 	else outdef( &stab[i], libflag?LIB:LDC, USUAL );
13817988Srrh 	}
13827988Srrh 
13837988Srrh isitfloat ( s ) char *s; {
13847988Srrh 	/* s is a character string;
13857988Srrh 	   if floating point is implemented, set dcon to the value of s */
13867988Srrh 	/* lint version
13877988Srrh 	*/
13887988Srrh 	dcon = atof( s );
138925304Sbloom 	return( DCON );
13907988Srrh 	}
13917988Srrh 
13927988Srrh fldcon( p ) register NODE *p; {
13937988Srrh 	/* p is an assignment of a constant to a field */
13947988Srrh 	/* check to see if the assignment is going to overflow, or otherwise cause trouble */
13957988Srrh 	register s;
13967988Srrh 	CONSZ v;
13977988Srrh 
13987988Srrh 	if( !hflag & !pflag ) return;
13997988Srrh 
14007988Srrh 	s = UPKFSZ(p->in.left->tn.rval);
14017988Srrh 	v = p->in.right->tn.lval;
14027988Srrh 
14037988Srrh 	switch( p->in.left->in.type ){
14047988Srrh 
14057988Srrh 	case CHAR:
14067988Srrh 	case INT:
14077988Srrh 	case SHORT:
14087988Srrh 	case LONG:
14097988Srrh 	case ENUMTY:
14107988Srrh 		if( v>=0 && (v>>(s-1))==0 ) return;
14117988Srrh 		werror( "precision lost in assignment to (possibly sign-extended) field" );
14127988Srrh 	default:
14137988Srrh 		return;
14147988Srrh 
14157988Srrh 	case UNSIGNED:
14167988Srrh 	case UCHAR:
14177988Srrh 	case USHORT:
14187988Srrh 	case ULONG:
14197988Srrh 		if( v<0 || (v>>s)!=0 ) werror( "precision lost in field assignment" );
14207988Srrh 
14217988Srrh 		return;
14227988Srrh 		}
14237988Srrh 
14247988Srrh 	}
14257988Srrh 
14267988Srrh outdef( p, lty, mode ) struct symtab *p; {
14277988Srrh 	/* output a definition for the second pass */
14287988Srrh 	/* if mode is > USUAL, it is the number of args */
14297988Srrh 	char *fname;
14307988Srrh 	TWORD t;
14317988Srrh 	int line;
14327988Srrh 	static union rec rc;
14337988Srrh 
14347988Srrh 	if( mode == NOFILE ){
14357988Srrh 		fname = "???";
14367988Srrh 		line = p->suse;
14377988Srrh 		}
14387988Srrh 	else if( mode == SVLINE ){
14397988Srrh 		fname = ftitle;
14407988Srrh 		line = -p->suse;
14417988Srrh 		}
14427988Srrh 	else {
14437988Srrh 		fname = ftitle;
14447988Srrh 		line = lineno;
14457988Srrh 		}
14467988Srrh 	fsave( fname );
14477988Srrh #ifndef FLEXNAMES
14487988Srrh 	strncpy( rc.l.name, exname(p->sname), LCHNM );
14497988Srrh #endif
14507988Srrh 	rc.l.decflag = lty;
14517988Srrh 	t = p->stype;
14527988Srrh 	if( mode == DECTY ) t = DECREF(t);
14537988Srrh 	rc.l.type.aty = t;
14547988Srrh 	rc.l.type.extra = 0;
145511761Sedward 	rc.l.type.extra1 = 0;
14567988Srrh 	astype( &rc.l.type, p->sizoff );
14577988Srrh 	rc.l.nargs = (mode>USUAL) ? mode : 0;
14587988Srrh 	rc.l.fline = line;
14597988Srrh 	fwrite( (char *)&rc, sizeof(rc), 1, stdout );
14607988Srrh #ifdef FLEXNAMES
14617988Srrh 	rc.l.name = exname(p->sname);
14627988Srrh 	fwrite( rc.l.name, strlen(rc.l.name)+1, 1, stdout );
14637988Srrh #endif
14647988Srrh 	}
14657988Srrh int proflg;
14667988Srrh int gdebug;
1467