xref: /csrg-svn/old/pcc/lint/lpass1/lint.c (revision 26916)
17988Srrh #ifndef lint
2*26916Sdonn static char sccsid[] = "@(#)lint.c	1.10	(Berkeley)	03/20/86";
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 
317988Srrh int vflag = 1;  /* tell about unused argments */
327988Srrh int xflag = 0;  /* tell about unused externals */
337988Srrh int argflag = 0;  /* used to turn off complaints about arguments */
347988Srrh int libflag = 0;  /* used to generate library descriptions */
357988Srrh int vaflag = -1;  /* used to signal functions with a variable number of args */
367988Srrh int aflag = 0;  /* used to check precision of assignments */
3711761Sedward int zflag = 0;  /* no 'structure never defined' error */
3811403Snicklin int Cflag = 0;  /* filter out certain output, for generating libraries */
3911403Snicklin char *libname = 0;  /* name of the library we're generating */
407988Srrh 
417988Srrh 	/* flags for the "outdef" function */
427988Srrh # define USUAL (-101)
437988Srrh # define DECTY (-102)
447988Srrh # define NOFILE (-103)
457988Srrh # define SVLINE (-104)
467988Srrh 
477988Srrh # define LNAMES 250
487988Srrh 
497988Srrh struct lnm {
507988Srrh 	short lid, flgs;
517988Srrh 	}  lnames[LNAMES], *lnp;
527988Srrh 
537988Srrh contx( p, down, pl, pr ) register NODE *p; register *pl, *pr; {
547988Srrh 
557988Srrh 	*pl = *pr = VAL;
567988Srrh 	switch( p->in.op ){
577988Srrh 
587988Srrh 	case ANDAND:
597988Srrh 	case OROR:
607988Srrh 	case QUEST:
617988Srrh 		*pr = down;
627988Srrh 		break;
637988Srrh 
647988Srrh 	case SCONV:
657988Srrh 	case PCONV:
667988Srrh 	case COLON:
677988Srrh 		*pr = *pl = down;
687988Srrh 		break;
697988Srrh 
707988Srrh 	case COMOP:
717988Srrh 		*pl = EFF;
727988Srrh 		*pr = down;
737988Srrh 
747988Srrh 	case FORCE:
757988Srrh 	case INIT:
767988Srrh 	case UNARY CALL:
777988Srrh 	case STCALL:
787988Srrh 	case UNARY STCALL:
797988Srrh 	case CALL:
807988Srrh 	case UNARY FORTCALL:
817988Srrh 	case FORTCALL:
827988Srrh 	case CBRANCH:
837988Srrh 		break;
847988Srrh 
857988Srrh 	default:
867988Srrh 		if( asgop(p->in.op) ) break;
877988Srrh 		if( p->in.op == UNARY MUL && ( p->in.type == STRTY || p->in.type == UNIONTY || p->in.type == UNDEF) ) {
887988Srrh 		/* struct x f( );  main( ) {  (void) f( ); }
897988Srrh 		 * the the cast call appears as U* UNDEF
907988Srrh 		 */
917988Srrh 			break;  /* the compiler does this... */
927988Srrh 			}
937988Srrh 		if( down == EFF && hflag ) werror( "null effect" );
947988Srrh 
957988Srrh 		}
967988Srrh 	}
977988Srrh 
987988Srrh ecode( p ) NODE *p; {
997988Srrh 	/* compile code for p */
1007988Srrh 
1017988Srrh 	fwalk( p, contx, EFF );
1027988Srrh 	lnp = lnames;
1037988Srrh 	lprt( p, EFF, 0 );
1047988Srrh 	}
1057988Srrh 
1067988Srrh ejobcode( flag ){
1077988Srrh 	/* called after processing each job */
1087988Srrh 	/* flag is nonzero if errors were detected */
1097988Srrh 	register k;
1107988Srrh 	register struct symtab *p;
1117988Srrh 
1127988Srrh 	for( p=stab; p< &stab[SYMTSZ]; ++p ){
1137988Srrh 
1147988Srrh 		if( p->stype != TNULL ) {
1157988Srrh 
1167988Srrh 			if( p->stype == STRTY || p->stype == UNIONTY ){
11711761Sedward 				if( !zflag && dimtab[p->sizoff+1] < 0 ){
11811761Sedward 					/* never defined */
1197988Srrh #ifndef FLEXNAMES
1207988Srrh 					if( hflag ) werror( "struct/union %.8s never defined", p->sname );
1217988Srrh #else
1227988Srrh 					if( hflag ) werror( "struct/union %s never defined", p->sname );
1237988Srrh #endif
1247988Srrh 					}
1257988Srrh 				}
1267988Srrh 
1277988Srrh 			switch( p->sclass ){
1287988Srrh 
1297988Srrh 			case STATIC:
1307988Srrh 				if( p->suse > 0 ){
1317988Srrh 					k = lineno;
1327988Srrh 					lineno = p->suse;
1337988Srrh #ifndef FLEXNAMES
1347988Srrh 					uerror( "static variable %.8s unused",
1357988Srrh #else
1367988Srrh 					uerror( "static variable %s unused",
1377988Srrh #endif
1387988Srrh 						p->sname );
1397988Srrh 					lineno = k;
1407988Srrh 					break;
1417988Srrh 					}
14211403Snicklin 				/* no statics in libraries */
14311403Snicklin 				if( Cflag ) break;
1447988Srrh 
1457988Srrh 			case EXTERN:
1467988Srrh 			case USTATIC:
1477988Srrh 				/* with the xflag, worry about externs not used */
1487988Srrh 				/* the filename may be wrong here... */
1497988Srrh 				if( xflag && p->suse >= 0 && !libflag ){
1507988Srrh 					outdef( p, LDX, NOFILE );
1517988Srrh 					}
1527988Srrh 
1537988Srrh 			case EXTDEF:
1547988Srrh 				if( p->suse < 0 ){  /* used */
1557988Srrh 					outdef( p, LUM, SVLINE );
1567988Srrh 					}
1577988Srrh 				break;
1587988Srrh 				}
1597988Srrh 
1607988Srrh 			}
1617988Srrh 
1627988Srrh 		}
1637988Srrh 	exit( 0 );
1647988Srrh 	}
1657988Srrh 
1667988Srrh astype( t, i ) ATYPE *t; {
1677988Srrh 	TWORD tt;
16811761Sedward 	int j, k=0, l=0;
1697988Srrh 
1707988Srrh 	if( (tt=BTYPE(t->aty))==STRTY || tt==UNIONTY ){
1717988Srrh 		if( i<0 || i>= DIMTABSZ-3 ){
1727988Srrh 			werror( "lint's little mind is blown" );
1737988Srrh 			}
1747988Srrh 		else {
1757988Srrh 			j = dimtab[i+3];
1767988Srrh 			if( j<0 || j>SYMTSZ ){
17711761Sedward 				k = dimtab[i];
17811761Sedward 				l = X_NONAME | stab[j].suse;
1797988Srrh 				}
1807988Srrh 			else {
1817988Srrh 				if( stab[j].suse <= 0 ) {
1827988Srrh #ifndef FLEXNAMES
1837988Srrh 					werror( "no line number for %.8s",
1847988Srrh #else
1857988Srrh 					werror( "no line number for %s",
1867988Srrh #endif
1877988Srrh 						stab[j].sname );
1887988Srrh 					}
18911761Sedward 				else {
19011761Sedward 					k = dimtab[i];
19111761Sedward #ifdef FLEXNAMES
19211761Sedward 					l = hashstr(stab[j].sname);
19311761Sedward #else
19411761Sedward 					l = hashstr(stab[j].sname, LCHNM);
19511761Sedward #endif
19611761Sedward 					}
1977988Srrh 				}
1987988Srrh 			}
1997988Srrh 
2007988Srrh 		t->extra = k;
20111761Sedward 		t->extra1 = l;
2027988Srrh 		return( 1 );
2037988Srrh 		}
2047988Srrh 	else return( 0 );
2057988Srrh 	}
2067988Srrh 
2077988Srrh bfcode( a, n ) int a[]; {
2087988Srrh 	/* code for the beginning of a function; a is an array of
2097988Srrh 		indices in stab for the arguments; n is the number */
2107988Srrh 	/* this must also set retlab */
2117988Srrh 	register i;
2127988Srrh 	register struct symtab *cfp;
2137988Srrh 	static ATYPE t;
2147988Srrh 
2157988Srrh 	retlab = 1;
21611403Snicklin 
2177988Srrh 	cfp = &stab[curftn];
2187988Srrh 
21911403Snicklin 	/* if creating library, don't do static functions */
22011403Snicklin 	if( Cflag && cfp->sclass == STATIC ) return;
22111403Snicklin 
2227988Srrh 	/* if variable number of arguments, only print the ones which will be checked */
2237988Srrh 	if( vaflag > 0 ){
2247988Srrh 		if( n < vaflag ) werror( "declare the VARARGS arguments you want checked!" );
2257988Srrh 		else n = vaflag;
2267988Srrh 		}
2277988Srrh 	fsave( ftitle );
22811761Sedward 	if( cfp->sclass == STATIC ) outdef( cfp, LST, vaflag>=0?-n:n );
22911761Sedward 	else outdef( cfp, libflag?LIB:LDI, vaflag>=0?-n:n );
2307988Srrh 	vaflag = -1;
2317988Srrh 
2327988Srrh 	/* output the arguments */
2337988Srrh 	if( n ){
2347988Srrh 		for( i=0; i<n; ++i ) {
2357988Srrh 			t.aty = stab[a[i]].stype;
2367988Srrh 			t.extra = 0;
23711761Sedward 			t.extra1 = 0;
2387988Srrh 			if( !astype( &t, stab[a[i]].sizoff ) ) {
2397988Srrh 				switch( t.aty ){
2407988Srrh 
2417988Srrh 				case ULONG:
2427988Srrh 					break;
2437988Srrh 
2447988Srrh 				case CHAR:
2457988Srrh 				case SHORT:
2467988Srrh 					t.aty = INT;
2477988Srrh 					break;
2487988Srrh 
2497988Srrh 				case UCHAR:
2507988Srrh 				case USHORT:
2517988Srrh 				case UNSIGNED:
2527988Srrh 					t.aty = UNSIGNED;
2537988Srrh 					break;
2547988Srrh 
2557988Srrh 					}
2567988Srrh 				}
2577988Srrh 			fwrite( (char *)&t, sizeof(ATYPE), 1, stdout );
2587988Srrh 			}
2597988Srrh 		}
2607988Srrh 	}
2617988Srrh 
2627988Srrh ctargs( p ) NODE *p; {
2637988Srrh 	/* count arguments; p points to at least one */
2647988Srrh 	/* the arguemnts are a tower of commas to the left */
2657988Srrh 	register c;
2667988Srrh 	c = 1; /* count the rhs */
2677988Srrh 	while( p->in.op == CM ){
2687988Srrh 		++c;
2697988Srrh 		p = p->in.left;
2707988Srrh 		}
2717988Srrh 	return( c );
2727988Srrh 	}
2737988Srrh 
2747988Srrh lpta( p ) NODE *p; {
2757988Srrh 	static ATYPE t;
2767988Srrh 
2777988Srrh 	if( p->in.op == CM ){
2787988Srrh 		lpta( p->in.left );
2797988Srrh 		p = p->in.right;
2807988Srrh 		}
2817988Srrh 
2827988Srrh 	t.aty = p->in.type;
2837988Srrh 	t.extra = (p->in.op==ICON);
28411761Sedward 	t.extra1 = 0;
2857988Srrh 
28618598Sralph 	if( !astype( &t, p->fn.csiz ) ) {
2877988Srrh 		switch( t.aty ){
2887988Srrh 
2897988Srrh 			case CHAR:
2907988Srrh 			case SHORT:
2917988Srrh 				t.aty = INT;
2927988Srrh 			case LONG:
2937988Srrh 			case ULONG:
2947988Srrh 			case INT:
2957988Srrh 			case UNSIGNED:
2967988Srrh 				break;
2977988Srrh 
2987988Srrh 			case UCHAR:
2997988Srrh 			case USHORT:
3007988Srrh 				t.aty = UNSIGNED;
3017988Srrh 				break;
3027988Srrh 
3037988Srrh 			case FLOAT:
3047988Srrh 				t.aty = DOUBLE;
3057988Srrh 				t.extra = 0;
3067988Srrh 				break;
3077988Srrh 
3087988Srrh 			default:
3097988Srrh 				t.extra = 0;
3107988Srrh 				break;
3117988Srrh 			}
3127988Srrh 		}
3137988Srrh 	fwrite( (char *)&t, sizeof(ATYPE), 1, stdout );
3147988Srrh 	}
3157988Srrh 
3167988Srrh # define VALSET 1
3177988Srrh # define VALUSED 2
3187988Srrh # define VALASGOP 4
3197988Srrh # define VALADDR 8
3207988Srrh 
3217988Srrh lprt( p, down, uses ) register NODE *p; {
3227988Srrh 	register struct symtab *q;
3237988Srrh 	register id;
3247988Srrh 	register acount;
3257988Srrh 	register down1, down2;
3267988Srrh 	register use1, use2;
3277988Srrh 	register struct lnm *np1, *np2;
3287988Srrh 
3297988Srrh 	/* first, set variables which are set... */
3307988Srrh 
3317988Srrh 	use1 = use2 = VALUSED;
3327988Srrh 	if( p->in.op == ASSIGN ) use1 = VALSET;
3337988Srrh 	else if( p->in.op == UNARY AND ) use1 = VALADDR;
3347988Srrh 	else if( asgop( p->in.op ) ){ /* =ops */
3357988Srrh 		use1 = VALUSED|VALSET;
3367988Srrh 		if( down == EFF ) use1 |= VALASGOP;
3377988Srrh 		}
3387988Srrh 
3397988Srrh 
3407988Srrh 	/* print the lines for lint */
3417988Srrh 
3427988Srrh 	down2 = down1 = VAL;
3437988Srrh 	acount = 0;
3447988Srrh 
3457988Srrh 	switch( p->in.op ){
3467988Srrh 
3477988Srrh 	case EQ:
3487988Srrh 	case NE:
3497988Srrh 	case GT:
3507988Srrh 	case GE:
3517988Srrh 	case LT:
3527988Srrh 	case LE:
3537988Srrh 		if( p->in.left->in.type == CHAR && p->in.right->in.op==ICON && p->in.right->tn.lval < 0 ){
3547988Srrh 			werror( "nonportable character comparison" );
3557988Srrh 			}
3567988Srrh 		if( (p->in.op==EQ || p->in.op==NE ) && ISUNSIGNED(p->in.left->in.type) && p->in.right->in.op == ICON ){
3577988Srrh 			if( p->in.right->tn.lval < 0 && p->in.right->tn.rval == NONAME && !ISUNSIGNED(p->in.right->in.type) ){
3587988Srrh 				werror( "comparison of unsigned with negative constant" );
3597988Srrh 				}
3607988Srrh 			}
3617988Srrh 		break;
3627988Srrh 
3637988Srrh 	case UGE:
3647988Srrh 	case ULT:
3657988Srrh 		if( p->in.right->in.op == ICON && p->in.right->tn.lval == 0 && p->in.right->tn.rval == NONAME ){
3667988Srrh 			werror( "unsigned comparison with 0?" );
3677988Srrh 			break;
3687988Srrh 			}
3697988Srrh 	case UGT:
3707988Srrh 	case ULE:
3717988Srrh 		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 ){
3727988Srrh 			werror( "degenerate unsigned comparison" );
3737988Srrh 			}
3747988Srrh 		break;
3757988Srrh 
3767988Srrh 	case COMOP:
3777988Srrh 		down1 = EFF;
3787988Srrh 
3797988Srrh 	case ANDAND:
3807988Srrh 	case OROR:
3817988Srrh 	case QUEST:
3827988Srrh 		down2 = down;
3837988Srrh 		/* go recursively left, then right  */
3847988Srrh 		np1 = lnp;
3857988Srrh 		lprt( p->in.left, down1, use1 );
3867988Srrh 		np2 = lnp;
3877988Srrh 		lprt( p->in.right, down2, use2 );
3887988Srrh 		lmerge( np1, np2, 0 );
3897988Srrh 		return;
3907988Srrh 
3917988Srrh 	case SCONV:
3927988Srrh 	case PCONV:
3937988Srrh 	case COLON:
3947988Srrh 		down1 = down2 = down;
3957988Srrh 		break;
3967988Srrh 
3977988Srrh 	case CALL:
3987988Srrh 	case STCALL:
3997988Srrh 	case FORTCALL:
4007988Srrh 		acount = ctargs( p->in.right );
4017988Srrh 	case UNARY CALL:
4027988Srrh 	case UNARY STCALL:
4037988Srrh 	case UNARY FORTCALL:
4047988Srrh 		if( p->in.left->in.op == ICON && (id=p->in.left->tn.rval) != NONAME ){ /* used to be &name */
4057988Srrh 			struct symtab *sp = &stab[id];
4067988Srrh 			int lty;
40711403Snicklin 
40811403Snicklin 			fsave( ftitle );
40911403Snicklin 			/*
41011403Snicklin 			 * if we're generating a library -C then
41111403Snicklin 			 * we don't want to output references to functions
41211403Snicklin 			 */
41311403Snicklin 			if( Cflag ) break;
4147988Srrh 			/*  if a function used in an effects context is
4157988Srrh 			 *  cast to type  void  then consider its value
4167988Srrh 			 *  to have been disposed of properly
4177988Srrh 			 *  thus a call of type  undef  in an effects
4187988Srrh 			 *  context is construed to be used in a value
4197988Srrh 			 *  context
4207988Srrh 			 */
4217988Srrh 			if ((down == EFF) && (p->in.type != UNDEF)) {
4227988Srrh 				lty = LUE;
4237988Srrh 			} else if (down == EFF) {
4247988Srrh 				lty = LUV | LUE;
4257988Srrh 			} else {
4267988Srrh 				lty = LUV;
4277988Srrh 			}
42811403Snicklin 			outdef( sp, lty, acount );
4297988Srrh 			if( acount ) {
4307988Srrh 				lpta( p->in.right );
4317988Srrh 				}
4327988Srrh 			}
4337988Srrh 		break;
4347988Srrh 
4357988Srrh 	case ICON:
4367988Srrh 		/* look for &name case */
4377988Srrh 		if( (id = p->tn.rval) >= 0 && id != NONAME ){
4387988Srrh 			q = &stab[id];
4397988Srrh 			q->sflags |= (SREF|SSET);
4407988Srrh 			q->suse = -lineno;
4417988Srrh 			}
4427988Srrh 		return;
4437988Srrh 
4447988Srrh 	case NAME:
4457988Srrh 		if( (id = p->tn.rval) >= 0 && id != NONAME ){
4467988Srrh 			q = &stab[id];
4477988Srrh 			if( (uses&VALUSED) && !(q->sflags&SSET) ){
4487988Srrh 				if( q->sclass == AUTO || q->sclass == REGISTER ){
44911761Sedward 					if( !ISARY(q->stype ) && !ISFTN(q->stype) && q->stype!=STRTY && q->stype!=UNIONTY ){
4507988Srrh #ifndef FLEXNAMES
4517988Srrh 						werror( "%.8s may be used before set", q->sname );
4527988Srrh #else
4537988Srrh 						werror( "%s may be used before set", q->sname );
4547988Srrh #endif
4557988Srrh 						q->sflags |= SSET;
4567988Srrh 						}
4577988Srrh 					}
4587988Srrh 				}
4597988Srrh 			if( uses & VALASGOP ) break;  /* not a real use */
4607988Srrh 			if( uses & VALSET ) q->sflags |= SSET;
4617988Srrh 			if( uses & VALUSED ) q->sflags |= SREF;
4627988Srrh 			if( uses & VALADDR ) q->sflags |= (SREF|SSET);
4637988Srrh 			if( p->tn.lval == 0 ){
4647988Srrh 				lnp->lid = id;
4657988Srrh 				lnp->flgs = (uses&VALADDR)?0:((uses&VALSET)?VALSET:VALUSED);
4667988Srrh 				if( ++lnp >= &lnames[LNAMES] ) --lnp;
4677988Srrh 				}
4687988Srrh 			}
4697988Srrh 		return;
4707988Srrh 
4717988Srrh 		}
4727988Srrh 
4737988Srrh 	/* recurse, going down the right side first if we can */
4747988Srrh 
4757988Srrh 	switch( optype(p->in.op) ){
4767988Srrh 
4777988Srrh 	case BITYPE:
4787988Srrh 		np1 = lnp;
4797988Srrh 		lprt( p->in.right, down2, use2 );
4807988Srrh 	case UTYPE:
4817988Srrh 		np2 = lnp;
4827988Srrh 		lprt( p->in.left, down1, use1 );
4837988Srrh 		}
4847988Srrh 
4857988Srrh 	if( optype(p->in.op) == BITYPE ){
4867988Srrh 		if( p->in.op == ASSIGN && p->in.left->in.op == NAME ){ /* special case for a =  .. a .. */
4877988Srrh 			lmerge( np1, np2, 0 );
4887988Srrh 			}
4897988Srrh 		else lmerge( np1, np2, p->in.op != COLON );
4907988Srrh 		/* look for assignments to fields, and complain */
4917988Srrh 		if( p->in.op == ASSIGN && p->in.left->in.op == FLD && p->in.right->in.op == ICON ) fldcon( p );
4927988Srrh 		}
4937988Srrh 
4947988Srrh 	}
4957988Srrh 
4967988Srrh lmerge( np1, np2, flag ) struct lnm *np1, *np2; {
4977988Srrh 	/* np1 and np2 point to lists of lnm members, for the two sides
4987988Srrh 	 * of a binary operator
4997988Srrh 	 * flag is 1 if commutation is possible, 0 otherwise
5007988Srrh 	 * lmerge returns a merged list, starting at np1, resetting lnp
5017988Srrh 	 * it also complains, if appropriate, about side effects
5027988Srrh 	 */
5037988Srrh 
5047988Srrh 	register struct lnm *npx, *npy;
5057988Srrh 
5067988Srrh 	for( npx = np2; npx < lnp; ++npx ){
5077988Srrh 
5087988Srrh 		/* is it already there? */
5097988Srrh 		for( npy = np1; npy < np2; ++npy ){
5107988Srrh 			if( npx->lid == npy->lid ){ /* yes */
5117988Srrh 				if( npx->flgs == 0 || npx->flgs == (VALSET|VALUSED) )
5127988Srrh 					;  /* do nothing */
5137988Srrh 				else if( (npx->flgs|npy->flgs)== (VALSET|VALUSED) ||
5147988Srrh 					(npx->flgs&npy->flgs&VALSET) ){
5157988Srrh #ifndef FLEXNAMES
5167988Srrh 					if( flag ) werror( "%.8s evaluation order undefined", stab[npy->lid].sname );
5177988Srrh #else
5187988Srrh 					if( flag ) werror( "%s evaluation order undefined", stab[npy->lid].sname );
5197988Srrh #endif
5207988Srrh 					}
5217988Srrh 				if( npy->flgs == 0 ) npx->flgs = 0;
5227988Srrh 				else npy->flgs |= npx->flgs;
5237988Srrh 				goto foundit;
5247988Srrh 				}
5257988Srrh 			}
5267988Srrh 
5277988Srrh 		/* not there: update entry */
5287988Srrh 		np2->lid = npx->lid;
5297988Srrh 		np2->flgs = npx->flgs;
5307988Srrh 		++np2;
5317988Srrh 
5327988Srrh 		foundit: ;
5337988Srrh 		}
5347988Srrh 
5357988Srrh 	/* all finished: merged list is at np1 */
5367988Srrh 	lnp = np2;
5377988Srrh 	}
5387988Srrh 
5397988Srrh efcode(){
5407988Srrh 	/* code for the end of a function */
5417988Srrh 	register struct symtab *cfp;
5427988Srrh 
5437988Srrh 	cfp = &stab[curftn];
54411403Snicklin 	if( retstat & RETVAL && !(Cflag && cfp->sclass==STATIC) )
54511403Snicklin 		outdef( cfp, LRV, DECTY );
5467988Srrh 	if( !vflag ){
5477988Srrh 		vflag = argflag;
5487988Srrh 		argflag = 0;
5497988Srrh 		}
5507988Srrh 	if( retstat == RETVAL+NRETVAL )
5517988Srrh #ifndef FLEXNAMES
5527988Srrh 		werror( "function %.8s has return(e); and return;", cfp->sname);
5537988Srrh #else
5547988Srrh 		werror( "function %s has return(e); and return;", cfp->sname);
5557988Srrh #endif
5567988Srrh 	}
5577988Srrh 
5587988Srrh aocode(p) struct symtab *p; {
5597988Srrh 	/* called when automatic p removed from stab */
5607988Srrh 	register struct symtab *cfs;
5617988Srrh 	cfs = &stab[curftn];
5627988Srrh 	if(p->suse>0 && !(p->sflags&(SMOS|STAG)) ){
5637988Srrh 		if( p->sclass == PARAM ){
5647988Srrh #ifndef FLEXNAMES
5657988Srrh 			if( vflag ) werror( "argument %.8s unused in function %.8s",
5667988Srrh #else
5677988Srrh 			if( vflag ) werror( "argument %s unused in function %s",
5687988Srrh #endif
5697988Srrh 				p->sname,
5707988Srrh 				cfs->sname );
5717988Srrh 			}
5727988Srrh 		else {
5737988Srrh #ifndef FLEXNAMES
5747988Srrh 			if( p->sclass != TYPEDEF ) werror( "%.8s unused in function %.8s",
5757988Srrh #else
5767988Srrh 			if( p->sclass != TYPEDEF ) werror( "%s unused in function %s",
5777988Srrh #endif
5787988Srrh 				p->sname, cfs->sname );
5797988Srrh 			}
5807988Srrh 		}
5817988Srrh 
5827988Srrh 	if( p->suse < 0 && (p->sflags & (SSET|SREF|SMOS)) == SSET &&
5837988Srrh 		!ISARY(p->stype) && !ISFTN(p->stype) ){
5847988Srrh 
5857988Srrh #ifndef FLEXNAMES
5867988Srrh 		werror( "%.8s set but not used in function %.8s", p->sname, cfs->sname );
5877988Srrh #else
5887988Srrh 		werror( "%s set but not used in function %s", p->sname, cfs->sname );
5897988Srrh #endif
5907988Srrh 		}
5917988Srrh 
5927988Srrh 	if( p->stype == STRTY || p->stype == UNIONTY || p->stype == ENUMTY ){
59311761Sedward 		if( !zflag && dimtab[p->sizoff+1] < 0 )
5947988Srrh #ifndef FLEXNAMES
59511761Sedward 			werror( "structure %.8s never defined", p->sname );
5967988Srrh #else
59711761Sedward 			werror( "structure %s never defined", p->sname );
5987988Srrh #endif
5997988Srrh 		}
6007988Srrh 
6017988Srrh 	}
6027988Srrh 
6037988Srrh defnam( p ) register struct symtab *p; {
6047988Srrh 	/* define the current location as the name p->sname */
6057988Srrh 
60611403Snicklin 	if( p->sclass == STATIC && (p->slevel>1 || Cflag) ) return;
6077988Srrh 
60811761Sedward 	if( !ISFTN( p->stype ) )
60911761Sedward 		if( p->sclass == STATIC ) outdef( p, LST, USUAL );
61011761Sedward 		else outdef( p, libflag?LIB:LDI, USUAL );
6117988Srrh 	}
6127988Srrh 
6137988Srrh zecode( n ){
6147988Srrh 	/* n integer words of zeros */
6157988Srrh 	OFFSZ temp;
6167988Srrh 	temp = n;
6177988Srrh 	inoff += temp*SZINT;
6187988Srrh 	;
6197988Srrh 	}
6207988Srrh 
6217988Srrh andable( p ) NODE *p; {  /* p is a NAME node; can it accept & ? */
6227988Srrh 	register r;
6237988Srrh 
6247988Srrh 	if( p->in.op != NAME ) cerror( "andable error" );
6257988Srrh 
6267988Srrh 	if( (r = p->tn.rval) < 0 ) return(1);  /* labels are andable */
6277988Srrh 
6287988Srrh 	if( stab[r].sclass == AUTO || stab[r].sclass == PARAM ) return(0);
6297988Srrh #ifndef FLEXNAMES
6307988Srrh 	if( stab[r].sclass == REGISTER ) uerror( "can't take & of %.8s", stab[r].sname );
6317988Srrh #else
6327988Srrh 	if( stab[r].sclass == REGISTER ) uerror( "can't take & of %s", stab[r].sname );
6337988Srrh #endif
6347988Srrh 	return(1);
6357988Srrh 	}
6367988Srrh 
6377988Srrh NODE *
6387988Srrh clocal(p) NODE *p; {
6397988Srrh 
6407988Srrh 	/* this is called to do local transformations on
6417988Srrh 	   an expression tree preparitory to its being
6427988Srrh 	   written out in intermediate code.
6437988Srrh 	*/
6447988Srrh 
6457988Srrh 	/* the major essential job is rewriting the
6467988Srrh 	   automatic variables and arguments in terms of
6477988Srrh 	   REG and OREG nodes */
6487988Srrh 	/* conversion ops which are not necessary are also clobbered here */
6497988Srrh 	/* in addition, any special features (such as rewriting
6507988Srrh 	   exclusive or) are easily handled here as well */
6517988Srrh 
6527988Srrh 	register o;
6537988Srrh 	register unsigned t, tl;
65425757Sdonn 	int s;
6557988Srrh 
6567988Srrh 	switch( o = p->in.op ){
6577988Srrh 
6587988Srrh 	case SCONV:
6597988Srrh 	case PCONV:
6607988Srrh 		if( p->in.left->in.type==ENUMTY ){
6617988Srrh 			p->in.left = pconvert( p->in.left );
6627988Srrh 			}
6637988Srrh 		/* assume conversion takes place; type is inherited */
6647988Srrh 		t = p->in.type;
6657988Srrh 		tl = p->in.left->in.type;
66626403Sdonn 		if( aflag && (tl==LONG||tl==ULONG) && (t!=LONG&&t!=ULONG&&t!=UNDEF) ){
6677988Srrh 			werror( "long assignment may lose accuracy" );
6687988Srrh 			}
6697988Srrh 		if( aflag>=2 && (tl!=LONG&&tl!=ULONG) && (t==LONG||t==ULONG) && p->in.left->in.op != ICON ){
6707988Srrh 			werror( "assignment to long may sign-extend incorrectly" );
6717988Srrh 			}
6727988Srrh 		if( ISPTR(tl) && ISPTR(t) ){
6737988Srrh 			tl = DECREF(tl);
6747988Srrh 			t = DECREF(t);
6757988Srrh 			switch( ISFTN(t) + ISFTN(tl) ){
6767988Srrh 
6777988Srrh 			case 0:  /* neither is a function pointer */
6787988Srrh 				if( talign(t,p->fn.csiz) > talign(tl,p->in.left->fn.csiz) ){
6797988Srrh 					if( hflag||pflag ) werror( "possible pointer alignment problem" );
6807988Srrh 					}
6817988Srrh 				break;
6827988Srrh 
6837988Srrh 			case 1:
6847988Srrh 				werror( "questionable conversion of function pointer" );
6857988Srrh 
6867988Srrh 			case 2:
6877988Srrh 				;
6887988Srrh 				}
6897988Srrh 			}
6907988Srrh 		p->in.left->in.type = p->in.type;
6917988Srrh 		p->in.left->fn.cdim = p->fn.cdim;
6927988Srrh 		p->in.left->fn.csiz = p->fn.csiz;
6937988Srrh 		p->in.op = FREE;
6947988Srrh 		return( p->in.left );
6957988Srrh 
6967988Srrh 	case PVCONV:
6977988Srrh 	case PMCONV:
6987988Srrh 		if( p->in.right->in.op != ICON ) cerror( "bad conversion");
6997988Srrh 		p->in.op = FREE;
7007988Srrh 		return( buildtree( o==PMCONV?MUL:DIV, p->in.left, p->in.right ) );
7017988Srrh 
70225757Sdonn 	case RS:
70325757Sdonn 	case LS:
70425757Sdonn 	case ASG RS:
70525757Sdonn 	case ASG LS:
70625757Sdonn 		if( p->in.right->in.op != ICON )
70725757Sdonn 			break;
70825757Sdonn 		s = p->in.right->tn.lval;
70925757Sdonn 		if( s < 0 )
71025757Sdonn 			werror( "negative shift" );
71125757Sdonn 		else
71225757Sdonn 		if( s >= dimtab[ p->fn.csiz ] )
71325757Sdonn 			werror( "shift greater than size of object" );
71425757Sdonn 		break;
71525757Sdonn 
7167988Srrh 		}
7177988Srrh 
7187988Srrh 	return(p);
7197988Srrh 	}
7207988Srrh 
7217988Srrh NODE *
7227988Srrh offcon( off, t, d, s ) OFFSZ off; TWORD t;{  /* make a structure offset node */
7237988Srrh 	register NODE *p;
7247988Srrh 	p = bcon(0);
7257988Srrh 	p->tn.lval = off/SZCHAR;
7267988Srrh 	return(p);
7277988Srrh 	}
7287988Srrh 
7297988Srrh noinit(){
7307988Srrh 	/* storage class for such as "int a;" */
7317988Srrh 	return( pflag ? EXTDEF : EXTERN );
7327988Srrh 	}
7337988Srrh 
7347988Srrh 
7357988Srrh cinit( p, sz ) NODE *p; { /* initialize p into size sz */
7367988Srrh 	inoff += sz;
7377988Srrh 	if( p->in.op == INIT ){
7387988Srrh 		if( p->in.left->in.op == ICON ) return;
7397988Srrh 		if( p->in.left->in.op == NAME && p->in.left->in.type == MOE ) return;
7407988Srrh 		}
7417988Srrh 	uerror( "illegal initialization" );
7427988Srrh 	}
7437988Srrh 
7447988Srrh char *
7457988Srrh exname( p ) char *p; {
7467988Srrh 	/* make a name look like an external name in the local machine */
7477988Srrh 	static char aa[8];
7487988Srrh 	register int i;
7497988Srrh 
7507988Srrh 	if( !pflag ) return(p);
7517988Srrh 	for( i=0; i<6; ++i ){
7527988Srrh 		if( isupper(*p ) ) aa[i] = tolower( *p );
7537988Srrh 		else aa[i] = *p;
7547988Srrh 		if( *p ) ++p;
7557988Srrh 		}
7567988Srrh 	aa[6] = '\0';
7577988Srrh 	return( aa );
7587988Srrh 	}
7597988Srrh 
7607988Srrh char *
7617988Srrh strip(s) char *s; {
7627988Srrh #ifndef FLEXNAMES
7637988Srrh 	static char x[LFNM+1];
7647988Srrh #else
7657988Srrh 	static char x[BUFSIZ];
7667988Srrh #endif
7677988Srrh 	register char *p;
7687996Srrh 	static	int	stripping = 0;
7697988Srrh 
7707996Srrh 	if (stripping)
7717996Srrh 		return(s);
7727996Srrh 	stripping++;
7737988Srrh 	for( p=x; *s; ++s ){
7747996Srrh 		if( *s != '"' ){
7757988Srrh #ifndef FLEXNAMES
7767988Srrh /* PATCHED by ROBERT HENRY on 8Jul80 to fix 14 character file name bug */
7777988Srrh 			if( p >= &x[LFNM] )
77811403Snicklin #else
77911403Snicklin 			if( p >= &x[BUFSIZ] )
78011403Snicklin #endif
7817988Srrh 				cerror( "filename too long" );
7827988Srrh 			*p++ = *s;
7837988Srrh 		}
7847988Srrh 	}
7857996Srrh 	stripping = 0;
7867988Srrh 	*p = '\0';
7877988Srrh #ifndef FLEXNAMES
7887988Srrh 	return( x );
7897988Srrh #else
7907988Srrh 	return( hash(x) );
7917988Srrh #endif
7927988Srrh 	}
7937988Srrh 
7947988Srrh fsave( s ) char *s; {
7957988Srrh 	static union rec fsname;
7967988Srrh 	s = strip( s );
7977988Srrh #ifndef FLEXNAMES
798*26916Sdonn 	if( strncmp( s, fsname.f.fn, LFNM ) )
7997988Srrh #else
800*26916Sdonn 	if (fsname.f.fn == NULL || strcmp(s, fsname.f.fn))
8017988Srrh #endif
802*26916Sdonn 		{
8037988Srrh 		/* new one */
8047988Srrh #ifndef FLEXNAMES
8057988Srrh 		strncpy( fsname.f.fn, s, LFNM );
8067988Srrh #else
8077988Srrh 		fsname.f.fn = s;
8087988Srrh #endif
8097988Srrh 		fsname.f.decflag = LFN;
8107988Srrh 		fwrite( (char *)&fsname, sizeof(fsname), 1, stdout );
8117988Srrh #ifdef FLEXNAMES
81211403Snicklin 		/* if generating a library, prefix with the library name */
81311403Snicklin 		/* only do this for flexnames */
81411403Snicklin 		if( libname ){
81511403Snicklin 			fwrite( libname, strlen(libname), 1, stdout );
81611403Snicklin 			putchar( ':' );
81711403Snicklin 			}
8187988Srrh 		fwrite( fsname.f.fn, strlen(fsname.f.fn)+1, 1, stdout );
8197988Srrh #endif
8207988Srrh 		}
8217988Srrh 	}
8227988Srrh 
8237988Srrh where(f){ /* print true location of error */
8247996Srrh 	if( f == 'u' && nerrors > 1 )
8257996Srrh 		--nerrors; /* don't get "too many errors" */
8267996Srrh 	fprintf( stderr, "%s(%d): ", strip(ftitle), lineno);
8277988Srrh 	}
8287988Srrh 
8297988Srrh 	/* a number of dummy routines, unneeded by lint */
8307988Srrh 
8317988Srrh branch(n){;}
8327988Srrh defalign(n){;}
8337988Srrh deflab(n){;}
8347988Srrh bycode(t,i){;}
8357988Srrh cisreg(t) TWORD t; {return(1);}  /* everyting is a register variable! */
8367988Srrh 
8377988Srrh fldty(p) struct symtab *p; {
8387988Srrh 	; /* all types are OK here... */
8397988Srrh 	}
8407988Srrh 
8417988Srrh fldal(t) unsigned t; { /* field alignment... */
8427988Srrh 	if( t == ENUMTY ) return( ALCHAR );  /* this should be thought through better... */
8437988Srrh 	if( ISPTR(t) ){ /* really for the benefit of honeywell (and someday IBM) */
8447988Srrh 		if( pflag ) uerror( "nonportable field type" );
8457988Srrh 		}
8467988Srrh 	else uerror( "illegal field type" );
8477988Srrh 	return(ALINT);
8487988Srrh 	}
8497988Srrh 
8507988Srrh main( argc, argv ) char *argv[]; {
8517988Srrh 	char *p;
85211403Snicklin 	int i;
8537988Srrh 
8547988Srrh 	/* handle options */
8557988Srrh 
85611403Snicklin 	for( i = 1; i < argc; i++ )
85711403Snicklin 		for( p=argv[i]; *p; ++p ){
8587988Srrh 
85911403Snicklin 			switch( *p ){
8607988Srrh 
86111403Snicklin 			case '-':
86211403Snicklin 				continue;
8637988Srrh 
86411403Snicklin 			case '\0':
86511403Snicklin 				break;
8667988Srrh 
86711403Snicklin 			case 'b':
86811403Snicklin 				brkflag = 1;
86911403Snicklin 				continue;
8707988Srrh 
87111403Snicklin 			case 'p':
87211403Snicklin 				pflag = 1;
87311403Snicklin 				continue;
8747988Srrh 
87511403Snicklin 			case 'c':
87611403Snicklin 				cflag = 1;
87711403Snicklin 				continue;
8787988Srrh 
87911403Snicklin 			case 's':
88011403Snicklin 				/* for the moment, -s triggers -h */
8817988Srrh 
88211403Snicklin 			case 'h':
88311403Snicklin 				hflag = 1;
88411403Snicklin 				continue;
8857988Srrh 
88611403Snicklin 			case 'L':
88711403Snicklin 				libflag = 1;
88811403Snicklin 			case 'v':
88911403Snicklin 				vflag = 0;
89011403Snicklin 				continue;
8917988Srrh 
89211403Snicklin 			case 'x':
89311403Snicklin 				xflag = 1;
89411403Snicklin 				continue;
8957988Srrh 
89611403Snicklin 			case 'a':
89711403Snicklin 				++aflag;
89811403Snicklin 			case 'u':	/* done in second pass */
89911403Snicklin 			case 'n':	/* done in shell script */
90011403Snicklin 				continue;
9017988Srrh 
90211761Sedward 			case 'z':
90311761Sedward 				zflag = 1;
90411761Sedward 				continue;
90511761Sedward 
90611403Snicklin 			case 't':
90711403Snicklin 				werror( "option %c now default: see `man 6 lint'", *p );
90811403Snicklin 				continue;
9097988Srrh 
91011761Sedward 			case 'P':	/* debugging, done in second pass */
91111761Sedward 				continue;
91211761Sedward 
91311403Snicklin 			case 'C':
91411403Snicklin 				Cflag = 1;
91511403Snicklin 				if( p[1] ) libname = p + 1;
91611403Snicklin 				while( p[1] ) p++;
91711403Snicklin 				continue;
9187988Srrh 
91911403Snicklin 			default:
92011403Snicklin 				uerror( "illegal option: %c", *p );
92111403Snicklin 				continue;
92211403Snicklin 
92311403Snicklin 				}
9247988Srrh 			}
9257988Srrh 
9267988Srrh 	if( !pflag ){  /* set sizes to sizes of target machine */
9277988Srrh # ifdef gcos
9287988Srrh 		SZCHAR = ALCHAR = 9;
9297988Srrh # else
9307988Srrh 		SZCHAR = ALCHAR = 8;
9317988Srrh # endif
9327988Srrh 		SZINT = ALINT = sizeof(int)*SZCHAR;
9337988Srrh 		SZFLOAT = ALFLOAT = sizeof(float)*SZCHAR;
9347988Srrh 		SZDOUBLE = ALDOUBLE = sizeof(double)*SZCHAR;
9357988Srrh 		SZLONG = ALLONG = sizeof(long)*SZCHAR;
9367988Srrh 		SZSHORT = ALSHORT = sizeof(short)*SZCHAR;
9377988Srrh 		SZPOINT = ALPOINT = sizeof(int *)*SZCHAR;
9387988Srrh 		ALSTRUCT = ALINT;
9397988Srrh 		/* now, fix some things up for various machines (I wish we had "alignof") */
9407988Srrh 
9417988Srrh # ifdef pdp11
9427988Srrh 		ALLONG = ALDOUBLE = ALFLOAT = ALINT;
9437988Srrh #endif
9447988Srrh # ifdef ibm
9457988Srrh 		ALSTRUCT = ALCHAR;
9467988Srrh #endif
9477988Srrh 		}
9487988Srrh 
9497988Srrh 	return( mainp1( argc, argv ) );
9507988Srrh 	}
9517988Srrh 
9527988Srrh ctype( type ) unsigned type; { /* are there any funny types? */
9537988Srrh 	return( type );
9547988Srrh 	}
9557988Srrh 
9567988Srrh commdec( i ){
9577988Srrh 	/* put out a common declaration */
95811761Sedward 	if( stab[i].sclass == STATIC ) outdef( &stab[i], LST, USUAL );
95911761Sedward 	else outdef( &stab[i], libflag?LIB:LDC, USUAL );
9607988Srrh 	}
9617988Srrh 
9627988Srrh isitfloat ( s ) char *s; {
9637988Srrh 	/* s is a character string;
9647988Srrh 	   if floating point is implemented, set dcon to the value of s */
9657988Srrh 	/* lint version
9667988Srrh 	*/
9677988Srrh 	dcon = atof( s );
96825304Sbloom 	return( DCON );
9697988Srrh 	}
9707988Srrh 
9717988Srrh fldcon( p ) register NODE *p; {
9727988Srrh 	/* p is an assignment of a constant to a field */
9737988Srrh 	/* check to see if the assignment is going to overflow, or otherwise cause trouble */
9747988Srrh 	register s;
9757988Srrh 	CONSZ v;
9767988Srrh 
9777988Srrh 	if( !hflag & !pflag ) return;
9787988Srrh 
9797988Srrh 	s = UPKFSZ(p->in.left->tn.rval);
9807988Srrh 	v = p->in.right->tn.lval;
9817988Srrh 
9827988Srrh 	switch( p->in.left->in.type ){
9837988Srrh 
9847988Srrh 	case CHAR:
9857988Srrh 	case INT:
9867988Srrh 	case SHORT:
9877988Srrh 	case LONG:
9887988Srrh 	case ENUMTY:
9897988Srrh 		if( v>=0 && (v>>(s-1))==0 ) return;
9907988Srrh 		werror( "precision lost in assignment to (possibly sign-extended) field" );
9917988Srrh 	default:
9927988Srrh 		return;
9937988Srrh 
9947988Srrh 	case UNSIGNED:
9957988Srrh 	case UCHAR:
9967988Srrh 	case USHORT:
9977988Srrh 	case ULONG:
9987988Srrh 		if( v<0 || (v>>s)!=0 ) werror( "precision lost in field assignment" );
9997988Srrh 
10007988Srrh 		return;
10017988Srrh 		}
10027988Srrh 
10037988Srrh 	}
10047988Srrh 
10057988Srrh outdef( p, lty, mode ) struct symtab *p; {
10067988Srrh 	/* output a definition for the second pass */
10077988Srrh 	/* if mode is > USUAL, it is the number of args */
10087988Srrh 	char *fname;
10097988Srrh 	TWORD t;
10107988Srrh 	int line;
10117988Srrh 	static union rec rc;
10127988Srrh 
10137988Srrh 	if( mode == NOFILE ){
10147988Srrh 		fname = "???";
10157988Srrh 		line = p->suse;
10167988Srrh 		}
10177988Srrh 	else if( mode == SVLINE ){
10187988Srrh 		fname = ftitle;
10197988Srrh 		line = -p->suse;
10207988Srrh 		}
10217988Srrh 	else {
10227988Srrh 		fname = ftitle;
10237988Srrh 		line = lineno;
10247988Srrh 		}
10257988Srrh 	fsave( fname );
10267988Srrh #ifndef FLEXNAMES
10277988Srrh 	strncpy( rc.l.name, exname(p->sname), LCHNM );
10287988Srrh #endif
10297988Srrh 	rc.l.decflag = lty;
10307988Srrh 	t = p->stype;
10317988Srrh 	if( mode == DECTY ) t = DECREF(t);
10327988Srrh 	rc.l.type.aty = t;
10337988Srrh 	rc.l.type.extra = 0;
103411761Sedward 	rc.l.type.extra1 = 0;
10357988Srrh 	astype( &rc.l.type, p->sizoff );
10367988Srrh 	rc.l.nargs = (mode>USUAL) ? mode : 0;
10377988Srrh 	rc.l.fline = line;
10387988Srrh 	fwrite( (char *)&rc, sizeof(rc), 1, stdout );
10397988Srrh #ifdef FLEXNAMES
10407988Srrh 	rc.l.name = exname(p->sname);
10417988Srrh 	fwrite( rc.l.name, strlen(rc.l.name)+1, 1, stdout );
10427988Srrh #endif
10437988Srrh 	}
10447988Srrh int proflg;
10457988Srrh int gdebug;
1046