xref: /csrg-svn/old/pcc/lint/lpass1/lint.c (revision 7988)
1*7988Srrh 
2*7988Srrh #ifndef lint
3*7988Srrh static char sccsid[] = "@(#)lint.c	1.1	(Berkeley)	08/30/82";
4*7988Srrh #endif lint
5*7988Srrh 
6*7988Srrh # include "mfile1"
7*7988Srrh 
8*7988Srrh # include "lmanifest"
9*7988Srrh 
10*7988Srrh # include <ctype.h>
11*7988Srrh 
12*7988Srrh # define VAL 0
13*7988Srrh # define EFF 1
14*7988Srrh 
15*7988Srrh /* these are appropriate for the -p flag */
16*7988Srrh int  SZCHAR = 8;
17*7988Srrh int  SZINT = 16;
18*7988Srrh int  SZFLOAT = 32;
19*7988Srrh int  SZDOUBLE = 64;
20*7988Srrh int  SZLONG = 32;
21*7988Srrh int  SZSHORT = 16;
22*7988Srrh int SZPOINT = 16;
23*7988Srrh int ALCHAR = 8;
24*7988Srrh int ALINT = 16;
25*7988Srrh int ALFLOAT = 32;
26*7988Srrh int ALDOUBLE = 64;
27*7988Srrh int ALLONG = 32;
28*7988Srrh int ALSHORT = 16;
29*7988Srrh int ALPOINT = 16;
30*7988Srrh int ALSTRUCT = 16;
31*7988Srrh 
32*7988Srrh int vflag = 1;  /* tell about unused argments */
33*7988Srrh int xflag = 0;  /* tell about unused externals */
34*7988Srrh int argflag = 0;  /* used to turn off complaints about arguments */
35*7988Srrh int libflag = 0;  /* used to generate library descriptions */
36*7988Srrh int vaflag = -1;  /* used to signal functions with a variable number of args */
37*7988Srrh int aflag = 0;  /* used to check precision of assignments */
38*7988Srrh 
39*7988Srrh 	/* flags for the "outdef" function */
40*7988Srrh # define USUAL (-101)
41*7988Srrh # define DECTY (-102)
42*7988Srrh # define NOFILE (-103)
43*7988Srrh # define SVLINE (-104)
44*7988Srrh 
45*7988Srrh # define LNAMES 250
46*7988Srrh 
47*7988Srrh struct lnm {
48*7988Srrh 	short lid, flgs;
49*7988Srrh 	}  lnames[LNAMES], *lnp;
50*7988Srrh 
51*7988Srrh contx( p, down, pl, pr ) register NODE *p; register *pl, *pr; {
52*7988Srrh 
53*7988Srrh 	*pl = *pr = VAL;
54*7988Srrh 	switch( p->in.op ){
55*7988Srrh 
56*7988Srrh 	case ANDAND:
57*7988Srrh 	case OROR:
58*7988Srrh 	case QUEST:
59*7988Srrh 		*pr = down;
60*7988Srrh 		break;
61*7988Srrh 
62*7988Srrh 	case SCONV:
63*7988Srrh 	case PCONV:
64*7988Srrh 	case COLON:
65*7988Srrh 		*pr = *pl = down;
66*7988Srrh 		break;
67*7988Srrh 
68*7988Srrh 	case COMOP:
69*7988Srrh 		*pl = EFF;
70*7988Srrh 		*pr = down;
71*7988Srrh 
72*7988Srrh 	case FORCE:
73*7988Srrh 	case INIT:
74*7988Srrh 	case UNARY CALL:
75*7988Srrh 	case STCALL:
76*7988Srrh 	case UNARY STCALL:
77*7988Srrh 	case CALL:
78*7988Srrh 	case UNARY FORTCALL:
79*7988Srrh 	case FORTCALL:
80*7988Srrh 	case CBRANCH:
81*7988Srrh 		break;
82*7988Srrh 
83*7988Srrh 	default:
84*7988Srrh 		if( asgop(p->in.op) ) break;
85*7988Srrh 		if( p->in.op == UNARY MUL && ( p->in.type == STRTY || p->in.type == UNIONTY || p->in.type == UNDEF) ) {
86*7988Srrh 		/* struct x f( );  main( ) {  (void) f( ); }
87*7988Srrh 		 * the the cast call appears as U* UNDEF
88*7988Srrh 		 */
89*7988Srrh 			break;  /* the compiler does this... */
90*7988Srrh 			}
91*7988Srrh 		if( down == EFF && hflag ) werror( "null effect" );
92*7988Srrh 
93*7988Srrh 		}
94*7988Srrh 	}
95*7988Srrh 
96*7988Srrh ecode( p ) NODE *p; {
97*7988Srrh 	/* compile code for p */
98*7988Srrh 
99*7988Srrh 	fwalk( p, contx, EFF );
100*7988Srrh 	lnp = lnames;
101*7988Srrh 	lprt( p, EFF, 0 );
102*7988Srrh 	}
103*7988Srrh 
104*7988Srrh ejobcode( flag ){
105*7988Srrh 	/* called after processing each job */
106*7988Srrh 	/* flag is nonzero if errors were detected */
107*7988Srrh 	register k;
108*7988Srrh 	register struct symtab *p;
109*7988Srrh 
110*7988Srrh 	for( p=stab; p< &stab[SYMTSZ]; ++p ){
111*7988Srrh 
112*7988Srrh 		if( p->stype != TNULL ) {
113*7988Srrh 
114*7988Srrh 			if( p->stype == STRTY || p->stype == UNIONTY ){
115*7988Srrh 				if( dimtab[p->sizoff+1] < 0 ){ /* never defined */
116*7988Srrh #ifndef FLEXNAMES
117*7988Srrh 					if( hflag ) werror( "struct/union %.8s never defined", p->sname );
118*7988Srrh #else
119*7988Srrh 					if( hflag ) werror( "struct/union %s never defined", p->sname );
120*7988Srrh #endif
121*7988Srrh 					}
122*7988Srrh 				}
123*7988Srrh 
124*7988Srrh 			switch( p->sclass ){
125*7988Srrh 
126*7988Srrh 			case STATIC:
127*7988Srrh 				if( p->suse > 0 ){
128*7988Srrh 					k = lineno;
129*7988Srrh 					lineno = p->suse;
130*7988Srrh #ifndef FLEXNAMES
131*7988Srrh 					uerror( "static variable %.8s unused",
132*7988Srrh #else
133*7988Srrh 					uerror( "static variable %s unused",
134*7988Srrh #endif
135*7988Srrh 						p->sname );
136*7988Srrh 					lineno = k;
137*7988Srrh 					break;
138*7988Srrh 					}
139*7988Srrh 
140*7988Srrh 			case EXTERN:
141*7988Srrh 			case USTATIC:
142*7988Srrh 				/* with the xflag, worry about externs not used */
143*7988Srrh 				/* the filename may be wrong here... */
144*7988Srrh 				if( xflag && p->suse >= 0 && !libflag ){
145*7988Srrh 					outdef( p, LDX, NOFILE );
146*7988Srrh 					}
147*7988Srrh 
148*7988Srrh 			case EXTDEF:
149*7988Srrh 				if( p->suse < 0 ){  /* used */
150*7988Srrh 					outdef( p, LUM, SVLINE );
151*7988Srrh 					}
152*7988Srrh 				break;
153*7988Srrh 				}
154*7988Srrh 
155*7988Srrh 			}
156*7988Srrh 
157*7988Srrh 		}
158*7988Srrh 	exit( 0 );
159*7988Srrh 	}
160*7988Srrh 
161*7988Srrh astype( t, i ) ATYPE *t; {
162*7988Srrh 	TWORD tt;
163*7988Srrh 	int j, k=0;
164*7988Srrh 
165*7988Srrh 	if( (tt=BTYPE(t->aty))==STRTY || tt==UNIONTY ){
166*7988Srrh 		if( i<0 || i>= DIMTABSZ-3 ){
167*7988Srrh 			werror( "lint's little mind is blown" );
168*7988Srrh 			}
169*7988Srrh 		else {
170*7988Srrh 			j = dimtab[i+3];
171*7988Srrh 			if( j<0 || j>SYMTSZ ){
172*7988Srrh 				k = ((-j)<<5)^dimtab[i]|1;
173*7988Srrh 				}
174*7988Srrh 			else {
175*7988Srrh 				if( stab[j].suse <= 0 ) {
176*7988Srrh #ifndef FLEXNAMES
177*7988Srrh 					werror( "no line number for %.8s",
178*7988Srrh #else
179*7988Srrh 					werror( "no line number for %s",
180*7988Srrh #endif
181*7988Srrh 						stab[j].sname );
182*7988Srrh 					}
183*7988Srrh 				else k = (stab[j].suse<<5) ^ dimtab[i];
184*7988Srrh 				}
185*7988Srrh 			}
186*7988Srrh 
187*7988Srrh 		t->extra = k;
188*7988Srrh 		return( 1 );
189*7988Srrh 		}
190*7988Srrh 	else return( 0 );
191*7988Srrh 	}
192*7988Srrh 
193*7988Srrh bfcode( a, n ) int a[]; {
194*7988Srrh 	/* code for the beginning of a function; a is an array of
195*7988Srrh 		indices in stab for the arguments; n is the number */
196*7988Srrh 	/* this must also set retlab */
197*7988Srrh 	register i;
198*7988Srrh 	register struct symtab *cfp;
199*7988Srrh 	static ATYPE t;
200*7988Srrh 
201*7988Srrh 	retlab = 1;
202*7988Srrh 	cfp = &stab[curftn];
203*7988Srrh 
204*7988Srrh 	/* if variable number of arguments, only print the ones which will be checked */
205*7988Srrh 	if( vaflag > 0 ){
206*7988Srrh 		if( n < vaflag ) werror( "declare the VARARGS arguments you want checked!" );
207*7988Srrh 		else n = vaflag;
208*7988Srrh 		}
209*7988Srrh 	fsave( ftitle );
210*7988Srrh 	outdef( cfp, libflag?LIB:LDI, vaflag>=0?-n:n );
211*7988Srrh 	vaflag = -1;
212*7988Srrh 
213*7988Srrh 	/* output the arguments */
214*7988Srrh 	if( n ){
215*7988Srrh 		for( i=0; i<n; ++i ) {
216*7988Srrh 			t.aty = stab[a[i]].stype;
217*7988Srrh 			t.extra = 0;
218*7988Srrh 			if( !astype( &t, stab[a[i]].sizoff ) ) {
219*7988Srrh 				switch( t.aty ){
220*7988Srrh 
221*7988Srrh 				case ULONG:
222*7988Srrh 					break;
223*7988Srrh 
224*7988Srrh 				case CHAR:
225*7988Srrh 				case SHORT:
226*7988Srrh 					t.aty = INT;
227*7988Srrh 					break;
228*7988Srrh 
229*7988Srrh 				case UCHAR:
230*7988Srrh 				case USHORT:
231*7988Srrh 				case UNSIGNED:
232*7988Srrh 					t.aty = UNSIGNED;
233*7988Srrh 					break;
234*7988Srrh 
235*7988Srrh 					}
236*7988Srrh 				}
237*7988Srrh 			fwrite( (char *)&t, sizeof(ATYPE), 1, stdout );
238*7988Srrh 			}
239*7988Srrh 		}
240*7988Srrh 	}
241*7988Srrh 
242*7988Srrh ctargs( p ) NODE *p; {
243*7988Srrh 	/* count arguments; p points to at least one */
244*7988Srrh 	/* the arguemnts are a tower of commas to the left */
245*7988Srrh 	register c;
246*7988Srrh 	c = 1; /* count the rhs */
247*7988Srrh 	while( p->in.op == CM ){
248*7988Srrh 		++c;
249*7988Srrh 		p = p->in.left;
250*7988Srrh 		}
251*7988Srrh 	return( c );
252*7988Srrh 	}
253*7988Srrh 
254*7988Srrh lpta( p ) NODE *p; {
255*7988Srrh 	static ATYPE t;
256*7988Srrh 
257*7988Srrh 	if( p->in.op == CM ){
258*7988Srrh 		lpta( p->in.left );
259*7988Srrh 		p = p->in.right;
260*7988Srrh 		}
261*7988Srrh 
262*7988Srrh 	t.aty = p->in.type;
263*7988Srrh 	t.extra = (p->in.op==ICON);
264*7988Srrh 
265*7988Srrh 	if( !astype( &t, p->in.csiz ) ) {
266*7988Srrh 		switch( t.aty ){
267*7988Srrh 
268*7988Srrh 			case CHAR:
269*7988Srrh 			case SHORT:
270*7988Srrh 				t.aty = INT;
271*7988Srrh 			case LONG:
272*7988Srrh 			case ULONG:
273*7988Srrh 			case INT:
274*7988Srrh 			case UNSIGNED:
275*7988Srrh 				break;
276*7988Srrh 
277*7988Srrh 			case UCHAR:
278*7988Srrh 			case USHORT:
279*7988Srrh 				t.aty = UNSIGNED;
280*7988Srrh 				break;
281*7988Srrh 
282*7988Srrh 			case FLOAT:
283*7988Srrh 				t.aty = DOUBLE;
284*7988Srrh 				t.extra = 0;
285*7988Srrh 				break;
286*7988Srrh 
287*7988Srrh 			default:
288*7988Srrh 				t.extra = 0;
289*7988Srrh 				break;
290*7988Srrh 			}
291*7988Srrh 		}
292*7988Srrh 	fwrite( (char *)&t, sizeof(ATYPE), 1, stdout );
293*7988Srrh 	}
294*7988Srrh 
295*7988Srrh # define VALSET 1
296*7988Srrh # define VALUSED 2
297*7988Srrh # define VALASGOP 4
298*7988Srrh # define VALADDR 8
299*7988Srrh 
300*7988Srrh lprt( p, down, uses ) register NODE *p; {
301*7988Srrh 	register struct symtab *q;
302*7988Srrh 	register id;
303*7988Srrh 	register acount;
304*7988Srrh 	register down1, down2;
305*7988Srrh 	register use1, use2;
306*7988Srrh 	register struct lnm *np1, *np2;
307*7988Srrh 
308*7988Srrh 	/* first, set variables which are set... */
309*7988Srrh 
310*7988Srrh 	use1 = use2 = VALUSED;
311*7988Srrh 	if( p->in.op == ASSIGN ) use1 = VALSET;
312*7988Srrh 	else if( p->in.op == UNARY AND ) use1 = VALADDR;
313*7988Srrh 	else if( asgop( p->in.op ) ){ /* =ops */
314*7988Srrh 		use1 = VALUSED|VALSET;
315*7988Srrh 		if( down == EFF ) use1 |= VALASGOP;
316*7988Srrh 		}
317*7988Srrh 
318*7988Srrh 
319*7988Srrh 	/* print the lines for lint */
320*7988Srrh 
321*7988Srrh 	down2 = down1 = VAL;
322*7988Srrh 	acount = 0;
323*7988Srrh 
324*7988Srrh 	switch( p->in.op ){
325*7988Srrh 
326*7988Srrh 	case EQ:
327*7988Srrh 	case NE:
328*7988Srrh 	case GT:
329*7988Srrh 	case GE:
330*7988Srrh 	case LT:
331*7988Srrh 	case LE:
332*7988Srrh 		if( p->in.left->in.type == CHAR && p->in.right->in.op==ICON && p->in.right->tn.lval < 0 ){
333*7988Srrh 			werror( "nonportable character comparison" );
334*7988Srrh 			}
335*7988Srrh 		if( (p->in.op==EQ || p->in.op==NE ) && ISUNSIGNED(p->in.left->in.type) && p->in.right->in.op == ICON ){
336*7988Srrh 			if( p->in.right->tn.lval < 0 && p->in.right->tn.rval == NONAME && !ISUNSIGNED(p->in.right->in.type) ){
337*7988Srrh 				werror( "comparison of unsigned with negative constant" );
338*7988Srrh 				}
339*7988Srrh 			}
340*7988Srrh 		break;
341*7988Srrh 
342*7988Srrh 	case UGE:
343*7988Srrh 	case ULT:
344*7988Srrh 		if( p->in.right->in.op == ICON && p->in.right->tn.lval == 0 && p->in.right->tn.rval == NONAME ){
345*7988Srrh 			werror( "unsigned comparison with 0?" );
346*7988Srrh 			break;
347*7988Srrh 			}
348*7988Srrh 	case UGT:
349*7988Srrh 	case ULE:
350*7988Srrh 		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 ){
351*7988Srrh 			werror( "degenerate unsigned comparison" );
352*7988Srrh 			}
353*7988Srrh 		break;
354*7988Srrh 
355*7988Srrh 	case COMOP:
356*7988Srrh 		down1 = EFF;
357*7988Srrh 
358*7988Srrh 	case ANDAND:
359*7988Srrh 	case OROR:
360*7988Srrh 	case QUEST:
361*7988Srrh 		down2 = down;
362*7988Srrh 		/* go recursively left, then right  */
363*7988Srrh 		np1 = lnp;
364*7988Srrh 		lprt( p->in.left, down1, use1 );
365*7988Srrh 		np2 = lnp;
366*7988Srrh 		lprt( p->in.right, down2, use2 );
367*7988Srrh 		lmerge( np1, np2, 0 );
368*7988Srrh 		return;
369*7988Srrh 
370*7988Srrh 	case SCONV:
371*7988Srrh 	case PCONV:
372*7988Srrh 	case COLON:
373*7988Srrh 		down1 = down2 = down;
374*7988Srrh 		break;
375*7988Srrh 
376*7988Srrh 	case CALL:
377*7988Srrh 	case STCALL:
378*7988Srrh 	case FORTCALL:
379*7988Srrh 		acount = ctargs( p->in.right );
380*7988Srrh 	case UNARY CALL:
381*7988Srrh 	case UNARY STCALL:
382*7988Srrh 	case UNARY FORTCALL:
383*7988Srrh 		if( p->in.left->in.op == ICON && (id=p->in.left->tn.rval) != NONAME ){ /* used to be &name */
384*7988Srrh 			struct symtab *sp = &stab[id];
385*7988Srrh 			int lty;
386*7988Srrh 			/*  if a function used in an effects context is
387*7988Srrh 			 *  cast to type  void  then consider its value
388*7988Srrh 			 *  to have been disposed of properly
389*7988Srrh 			 *  thus a call of type  undef  in an effects
390*7988Srrh 			 *  context is construed to be used in a value
391*7988Srrh 			 *  context
392*7988Srrh 			 */
393*7988Srrh 			if ((down == EFF) && (p->in.type != UNDEF)) {
394*7988Srrh 				lty = LUE;
395*7988Srrh 			} else if (down == EFF) {
396*7988Srrh 				lty = LUV | LUE;
397*7988Srrh 			} else {
398*7988Srrh 				lty = LUV;
399*7988Srrh 			}
400*7988Srrh 			fsave( ftitle );
401*7988Srrh 			outdef(sp, lty, acount);
402*7988Srrh 			if( acount ) {
403*7988Srrh 				lpta( p->in.right );
404*7988Srrh 				}
405*7988Srrh 			}
406*7988Srrh 		break;
407*7988Srrh 
408*7988Srrh 	case ICON:
409*7988Srrh 		/* look for &name case */
410*7988Srrh 		if( (id = p->tn.rval) >= 0 && id != NONAME ){
411*7988Srrh 			q = &stab[id];
412*7988Srrh 			q->sflags |= (SREF|SSET);
413*7988Srrh 			q->suse = -lineno;
414*7988Srrh 			}
415*7988Srrh 		return;
416*7988Srrh 
417*7988Srrh 	case NAME:
418*7988Srrh 		if( (id = p->tn.rval) >= 0 && id != NONAME ){
419*7988Srrh 			q = &stab[id];
420*7988Srrh 			if( (uses&VALUSED) && !(q->sflags&SSET) ){
421*7988Srrh 				if( q->sclass == AUTO || q->sclass == REGISTER ){
422*7988Srrh 					if( !ISARY(q->stype ) && !ISFTN(q->stype) && q->stype!=STRTY ){
423*7988Srrh #ifndef FLEXNAMES
424*7988Srrh 						werror( "%.8s may be used before set", q->sname );
425*7988Srrh #else
426*7988Srrh 						werror( "%s may be used before set", q->sname );
427*7988Srrh #endif
428*7988Srrh 						q->sflags |= SSET;
429*7988Srrh 						}
430*7988Srrh 					}
431*7988Srrh 				}
432*7988Srrh 			if( uses & VALASGOP ) break;  /* not a real use */
433*7988Srrh 			if( uses & VALSET ) q->sflags |= SSET;
434*7988Srrh 			if( uses & VALUSED ) q->sflags |= SREF;
435*7988Srrh 			if( uses & VALADDR ) q->sflags |= (SREF|SSET);
436*7988Srrh 			if( p->tn.lval == 0 ){
437*7988Srrh 				lnp->lid = id;
438*7988Srrh 				lnp->flgs = (uses&VALADDR)?0:((uses&VALSET)?VALSET:VALUSED);
439*7988Srrh 				if( ++lnp >= &lnames[LNAMES] ) --lnp;
440*7988Srrh 				}
441*7988Srrh 			}
442*7988Srrh 		return;
443*7988Srrh 
444*7988Srrh 		}
445*7988Srrh 
446*7988Srrh 	/* recurse, going down the right side first if we can */
447*7988Srrh 
448*7988Srrh 	switch( optype(p->in.op) ){
449*7988Srrh 
450*7988Srrh 	case BITYPE:
451*7988Srrh 		np1 = lnp;
452*7988Srrh 		lprt( p->in.right, down2, use2 );
453*7988Srrh 	case UTYPE:
454*7988Srrh 		np2 = lnp;
455*7988Srrh 		lprt( p->in.left, down1, use1 );
456*7988Srrh 		}
457*7988Srrh 
458*7988Srrh 	if( optype(p->in.op) == BITYPE ){
459*7988Srrh 		if( p->in.op == ASSIGN && p->in.left->in.op == NAME ){ /* special case for a =  .. a .. */
460*7988Srrh 			lmerge( np1, np2, 0 );
461*7988Srrh 			}
462*7988Srrh 		else lmerge( np1, np2, p->in.op != COLON );
463*7988Srrh 		/* look for assignments to fields, and complain */
464*7988Srrh 		if( p->in.op == ASSIGN && p->in.left->in.op == FLD && p->in.right->in.op == ICON ) fldcon( p );
465*7988Srrh 		}
466*7988Srrh 
467*7988Srrh 	}
468*7988Srrh 
469*7988Srrh lmerge( np1, np2, flag ) struct lnm *np1, *np2; {
470*7988Srrh 	/* np1 and np2 point to lists of lnm members, for the two sides
471*7988Srrh 	 * of a binary operator
472*7988Srrh 	 * flag is 1 if commutation is possible, 0 otherwise
473*7988Srrh 	 * lmerge returns a merged list, starting at np1, resetting lnp
474*7988Srrh 	 * it also complains, if appropriate, about side effects
475*7988Srrh 	 */
476*7988Srrh 
477*7988Srrh 	register struct lnm *npx, *npy;
478*7988Srrh 
479*7988Srrh 	for( npx = np2; npx < lnp; ++npx ){
480*7988Srrh 
481*7988Srrh 		/* is it already there? */
482*7988Srrh 		for( npy = np1; npy < np2; ++npy ){
483*7988Srrh 			if( npx->lid == npy->lid ){ /* yes */
484*7988Srrh 				if( npx->flgs == 0 || npx->flgs == (VALSET|VALUSED) )
485*7988Srrh 					;  /* do nothing */
486*7988Srrh 				else if( (npx->flgs|npy->flgs)== (VALSET|VALUSED) ||
487*7988Srrh 					(npx->flgs&npy->flgs&VALSET) ){
488*7988Srrh #ifndef FLEXNAMES
489*7988Srrh 					if( flag ) werror( "%.8s evaluation order undefined", stab[npy->lid].sname );
490*7988Srrh #else
491*7988Srrh 					if( flag ) werror( "%s evaluation order undefined", stab[npy->lid].sname );
492*7988Srrh #endif
493*7988Srrh 					}
494*7988Srrh 				if( npy->flgs == 0 ) npx->flgs = 0;
495*7988Srrh 				else npy->flgs |= npx->flgs;
496*7988Srrh 				goto foundit;
497*7988Srrh 				}
498*7988Srrh 			}
499*7988Srrh 
500*7988Srrh 		/* not there: update entry */
501*7988Srrh 		np2->lid = npx->lid;
502*7988Srrh 		np2->flgs = npx->flgs;
503*7988Srrh 		++np2;
504*7988Srrh 
505*7988Srrh 		foundit: ;
506*7988Srrh 		}
507*7988Srrh 
508*7988Srrh 	/* all finished: merged list is at np1 */
509*7988Srrh 	lnp = np2;
510*7988Srrh 	}
511*7988Srrh 
512*7988Srrh efcode(){
513*7988Srrh 	/* code for the end of a function */
514*7988Srrh 	register struct symtab *cfp;
515*7988Srrh 
516*7988Srrh 	cfp = &stab[curftn];
517*7988Srrh 	if( retstat & RETVAL ) outdef( cfp, LRV, DECTY );
518*7988Srrh 	if( !vflag ){
519*7988Srrh 		vflag = argflag;
520*7988Srrh 		argflag = 0;
521*7988Srrh 		}
522*7988Srrh 	if( retstat == RETVAL+NRETVAL )
523*7988Srrh #ifndef FLEXNAMES
524*7988Srrh 		werror( "function %.8s has return(e); and return;", cfp->sname);
525*7988Srrh #else
526*7988Srrh 		werror( "function %s has return(e); and return;", cfp->sname);
527*7988Srrh #endif
528*7988Srrh 	}
529*7988Srrh 
530*7988Srrh aocode(p) struct symtab *p; {
531*7988Srrh 	/* called when automatic p removed from stab */
532*7988Srrh 	register struct symtab *cfs;
533*7988Srrh 	cfs = &stab[curftn];
534*7988Srrh 	if(p->suse>0 && !(p->sflags&(SMOS|STAG)) ){
535*7988Srrh 		if( p->sclass == PARAM ){
536*7988Srrh #ifndef FLEXNAMES
537*7988Srrh 			if( vflag ) werror( "argument %.8s unused in function %.8s",
538*7988Srrh #else
539*7988Srrh 			if( vflag ) werror( "argument %s unused in function %s",
540*7988Srrh #endif
541*7988Srrh 				p->sname,
542*7988Srrh 				cfs->sname );
543*7988Srrh 			}
544*7988Srrh 		else {
545*7988Srrh #ifndef FLEXNAMES
546*7988Srrh 			if( p->sclass != TYPEDEF ) werror( "%.8s unused in function %.8s",
547*7988Srrh #else
548*7988Srrh 			if( p->sclass != TYPEDEF ) werror( "%s unused in function %s",
549*7988Srrh #endif
550*7988Srrh 				p->sname, cfs->sname );
551*7988Srrh 			}
552*7988Srrh 		}
553*7988Srrh 
554*7988Srrh 	if( p->suse < 0 && (p->sflags & (SSET|SREF|SMOS)) == SSET &&
555*7988Srrh 		!ISARY(p->stype) && !ISFTN(p->stype) ){
556*7988Srrh 
557*7988Srrh #ifndef FLEXNAMES
558*7988Srrh 		werror( "%.8s set but not used in function %.8s", p->sname, cfs->sname );
559*7988Srrh #else
560*7988Srrh 		werror( "%s set but not used in function %s", p->sname, cfs->sname );
561*7988Srrh #endif
562*7988Srrh 		}
563*7988Srrh 
564*7988Srrh 	if( p->stype == STRTY || p->stype == UNIONTY || p->stype == ENUMTY ){
565*7988Srrh #ifndef FLEXNAMES
566*7988Srrh 		if( dimtab[p->sizoff+1] < 0 ) werror( "structure %.8s never defined", p->sname );
567*7988Srrh #else
568*7988Srrh 		if( dimtab[p->sizoff+1] < 0 ) werror( "structure %s never defined", p->sname );
569*7988Srrh #endif
570*7988Srrh 		}
571*7988Srrh 
572*7988Srrh 	}
573*7988Srrh 
574*7988Srrh defnam( p ) register struct symtab *p; {
575*7988Srrh 	/* define the current location as the name p->sname */
576*7988Srrh 
577*7988Srrh 	if( p->sclass == STATIC && p->slevel>1 ) return;
578*7988Srrh 
579*7988Srrh 	if( !ISFTN( p->stype ) ) outdef( p, libflag?LIB:LDI, USUAL );
580*7988Srrh 	}
581*7988Srrh 
582*7988Srrh zecode( n ){
583*7988Srrh 	/* n integer words of zeros */
584*7988Srrh 	OFFSZ temp;
585*7988Srrh 	temp = n;
586*7988Srrh 	inoff += temp*SZINT;
587*7988Srrh 	;
588*7988Srrh 	}
589*7988Srrh 
590*7988Srrh andable( p ) NODE *p; {  /* p is a NAME node; can it accept & ? */
591*7988Srrh 	register r;
592*7988Srrh 
593*7988Srrh 	if( p->in.op != NAME ) cerror( "andable error" );
594*7988Srrh 
595*7988Srrh 	if( (r = p->tn.rval) < 0 ) return(1);  /* labels are andable */
596*7988Srrh 
597*7988Srrh 	if( stab[r].sclass == AUTO || stab[r].sclass == PARAM ) return(0);
598*7988Srrh #ifndef FLEXNAMES
599*7988Srrh 	if( stab[r].sclass == REGISTER ) uerror( "can't take & of %.8s", stab[r].sname );
600*7988Srrh #else
601*7988Srrh 	if( stab[r].sclass == REGISTER ) uerror( "can't take & of %s", stab[r].sname );
602*7988Srrh #endif
603*7988Srrh 	return(1);
604*7988Srrh 	}
605*7988Srrh 
606*7988Srrh NODE *
607*7988Srrh clocal(p) NODE *p; {
608*7988Srrh 
609*7988Srrh 	/* this is called to do local transformations on
610*7988Srrh 	   an expression tree preparitory to its being
611*7988Srrh 	   written out in intermediate code.
612*7988Srrh 	*/
613*7988Srrh 
614*7988Srrh 	/* the major essential job is rewriting the
615*7988Srrh 	   automatic variables and arguments in terms of
616*7988Srrh 	   REG and OREG nodes */
617*7988Srrh 	/* conversion ops which are not necessary are also clobbered here */
618*7988Srrh 	/* in addition, any special features (such as rewriting
619*7988Srrh 	   exclusive or) are easily handled here as well */
620*7988Srrh 
621*7988Srrh 	register o;
622*7988Srrh 	register unsigned t, tl;
623*7988Srrh 
624*7988Srrh 	switch( o = p->in.op ){
625*7988Srrh 
626*7988Srrh 	case SCONV:
627*7988Srrh 	case PCONV:
628*7988Srrh 		if( p->in.left->in.type==ENUMTY ){
629*7988Srrh 			p->in.left = pconvert( p->in.left );
630*7988Srrh 			}
631*7988Srrh 		/* assume conversion takes place; type is inherited */
632*7988Srrh 		t = p->in.type;
633*7988Srrh 		tl = p->in.left->in.type;
634*7988Srrh 		if( aflag && (tl==LONG||tl==ULONG) && (t!=LONG&&t!=ULONG) ){
635*7988Srrh 			werror( "long assignment may lose accuracy" );
636*7988Srrh 			}
637*7988Srrh 		if( aflag>=2 && (tl!=LONG&&tl!=ULONG) && (t==LONG||t==ULONG) && p->in.left->in.op != ICON ){
638*7988Srrh 			werror( "assignment to long may sign-extend incorrectly" );
639*7988Srrh 			}
640*7988Srrh 		if( ISPTR(tl) && ISPTR(t) ){
641*7988Srrh 			tl = DECREF(tl);
642*7988Srrh 			t = DECREF(t);
643*7988Srrh 			switch( ISFTN(t) + ISFTN(tl) ){
644*7988Srrh 
645*7988Srrh 			case 0:  /* neither is a function pointer */
646*7988Srrh 				if( talign(t,p->fn.csiz) > talign(tl,p->in.left->fn.csiz) ){
647*7988Srrh 					if( hflag||pflag ) werror( "possible pointer alignment problem" );
648*7988Srrh 					}
649*7988Srrh 				break;
650*7988Srrh 
651*7988Srrh 			case 1:
652*7988Srrh 				werror( "questionable conversion of function pointer" );
653*7988Srrh 
654*7988Srrh 			case 2:
655*7988Srrh 				;
656*7988Srrh 				}
657*7988Srrh 			}
658*7988Srrh 		p->in.left->in.type = p->in.type;
659*7988Srrh 		p->in.left->fn.cdim = p->fn.cdim;
660*7988Srrh 		p->in.left->fn.csiz = p->fn.csiz;
661*7988Srrh 		p->in.op = FREE;
662*7988Srrh 		return( p->in.left );
663*7988Srrh 
664*7988Srrh 	case PVCONV:
665*7988Srrh 	case PMCONV:
666*7988Srrh 		if( p->in.right->in.op != ICON ) cerror( "bad conversion");
667*7988Srrh 		p->in.op = FREE;
668*7988Srrh 		return( buildtree( o==PMCONV?MUL:DIV, p->in.left, p->in.right ) );
669*7988Srrh 
670*7988Srrh 		}
671*7988Srrh 
672*7988Srrh 	return(p);
673*7988Srrh 	}
674*7988Srrh 
675*7988Srrh NODE *
676*7988Srrh offcon( off, t, d, s ) OFFSZ off; TWORD t;{  /* make a structure offset node */
677*7988Srrh 	register NODE *p;
678*7988Srrh 	p = bcon(0);
679*7988Srrh 	p->tn.lval = off/SZCHAR;
680*7988Srrh 	return(p);
681*7988Srrh 	}
682*7988Srrh 
683*7988Srrh noinit(){
684*7988Srrh 	/* storage class for such as "int a;" */
685*7988Srrh 	return( pflag ? EXTDEF : EXTERN );
686*7988Srrh 	}
687*7988Srrh 
688*7988Srrh 
689*7988Srrh cinit( p, sz ) NODE *p; { /* initialize p into size sz */
690*7988Srrh 	inoff += sz;
691*7988Srrh 	if( p->in.op == INIT ){
692*7988Srrh 		if( p->in.left->in.op == ICON ) return;
693*7988Srrh 		if( p->in.left->in.op == NAME && p->in.left->in.type == MOE ) return;
694*7988Srrh 		}
695*7988Srrh 	uerror( "illegal initialization" );
696*7988Srrh 	}
697*7988Srrh 
698*7988Srrh char *
699*7988Srrh exname( p ) char *p; {
700*7988Srrh 	/* make a name look like an external name in the local machine */
701*7988Srrh 	static char aa[8];
702*7988Srrh 	register int i;
703*7988Srrh 
704*7988Srrh 	if( !pflag ) return(p);
705*7988Srrh 	for( i=0; i<6; ++i ){
706*7988Srrh 		if( isupper(*p ) ) aa[i] = tolower( *p );
707*7988Srrh 		else aa[i] = *p;
708*7988Srrh 		if( *p ) ++p;
709*7988Srrh 		}
710*7988Srrh 	aa[6] = '\0';
711*7988Srrh 	return( aa );
712*7988Srrh 	}
713*7988Srrh 
714*7988Srrh char *
715*7988Srrh strip(s) char *s; {
716*7988Srrh #ifndef FLEXNAMES
717*7988Srrh 	static char x[LFNM+1];
718*7988Srrh #else
719*7988Srrh 	static char x[BUFSIZ];
720*7988Srrh #endif
721*7988Srrh 	register char *p;
722*7988Srrh 
723*7988Srrh 	for( p=x; *s; ++s ){
724*7988Srrh 		if( *s == '/' ) p=x;
725*7988Srrh 		else if( *s != '"' ){
726*7988Srrh #ifndef FLEXNAMES
727*7988Srrh /* PATCHED by ROBERT HENRY on 8Jul80 to fix 14 character file name bug */
728*7988Srrh 			if( p >= &x[LFNM] )
729*7988Srrh 				cerror( "filename too long" );
730*7988Srrh #endif
731*7988Srrh 			*p++ = *s;
732*7988Srrh 		}
733*7988Srrh 	}
734*7988Srrh 	*p = '\0';
735*7988Srrh #ifndef FLEXNAMES
736*7988Srrh 	return( x );
737*7988Srrh #else
738*7988Srrh 	return( hash(x) );
739*7988Srrh #endif
740*7988Srrh 	}
741*7988Srrh 
742*7988Srrh fsave( s ) char *s; {
743*7988Srrh 	static union rec fsname;
744*7988Srrh 	s = strip( s );
745*7988Srrh #ifndef FLEXNAMES
746*7988Srrh 	if( strncmp( s, fsname.f.fn, LFNM ) ){
747*7988Srrh #else
748*7988Srrh 	if( strcmp(s, fsname.f.fn)) {
749*7988Srrh #endif
750*7988Srrh 		/* new one */
751*7988Srrh #ifndef FLEXNAMES
752*7988Srrh 		strncpy( fsname.f.fn, s, LFNM );
753*7988Srrh #else
754*7988Srrh 		fsname.f.fn = s;
755*7988Srrh #endif
756*7988Srrh 		fsname.f.decflag = LFN;
757*7988Srrh 		fwrite( (char *)&fsname, sizeof(fsname), 1, stdout );
758*7988Srrh #ifdef FLEXNAMES
759*7988Srrh 		fwrite( fsname.f.fn, strlen(fsname.f.fn)+1, 1, stdout );
760*7988Srrh #endif
761*7988Srrh 		}
762*7988Srrh 	}
763*7988Srrh 
764*7988Srrh where(f){ /* print true location of error */
765*7988Srrh 	if( f == 'u' && nerrors>1 ) --nerrors; /* don't get "too many errors" */
766*7988Srrh 	fprintf( stderr, "%s(%d): ", (f == 'c') ? ftitle : strip(ftitle), lineno );
767*7988Srrh 	}
768*7988Srrh 
769*7988Srrh 	/* a number of dummy routines, unneeded by lint */
770*7988Srrh 
771*7988Srrh branch(n){;}
772*7988Srrh defalign(n){;}
773*7988Srrh deflab(n){;}
774*7988Srrh bycode(t,i){;}
775*7988Srrh cisreg(t) TWORD t; {return(1);}  /* everyting is a register variable! */
776*7988Srrh 
777*7988Srrh fldty(p) struct symtab *p; {
778*7988Srrh 	; /* all types are OK here... */
779*7988Srrh 	}
780*7988Srrh 
781*7988Srrh fldal(t) unsigned t; { /* field alignment... */
782*7988Srrh 	if( t == ENUMTY ) return( ALCHAR );  /* this should be thought through better... */
783*7988Srrh 	if( ISPTR(t) ){ /* really for the benefit of honeywell (and someday IBM) */
784*7988Srrh 		if( pflag ) uerror( "nonportable field type" );
785*7988Srrh 		}
786*7988Srrh 	else uerror( "illegal field type" );
787*7988Srrh 	return(ALINT);
788*7988Srrh 	}
789*7988Srrh 
790*7988Srrh main( argc, argv ) char *argv[]; {
791*7988Srrh 	char *p;
792*7988Srrh 
793*7988Srrh 	/* handle options */
794*7988Srrh 
795*7988Srrh 	for( p=argv[1]; argc>1 && *p; ++p ){
796*7988Srrh 
797*7988Srrh 		switch( *p ){
798*7988Srrh 
799*7988Srrh 		case '-':
800*7988Srrh 			continue;
801*7988Srrh 
802*7988Srrh 		case '\0':
803*7988Srrh 			break;
804*7988Srrh 
805*7988Srrh 		case 'b':
806*7988Srrh 			brkflag = 1;
807*7988Srrh 			continue;
808*7988Srrh 
809*7988Srrh 		case 'p':
810*7988Srrh 			pflag = 1;
811*7988Srrh 			continue;
812*7988Srrh 
813*7988Srrh 		case 'c':
814*7988Srrh 			cflag = 1;
815*7988Srrh 			continue;
816*7988Srrh 
817*7988Srrh 		case 's':
818*7988Srrh 			/* for the moment, -s triggers -h */
819*7988Srrh 
820*7988Srrh 		case 'h':
821*7988Srrh 			hflag = 1;
822*7988Srrh 			continue;
823*7988Srrh 
824*7988Srrh 		case 'L':
825*7988Srrh 			libflag = 1;
826*7988Srrh 		case 'v':
827*7988Srrh 			vflag = 0;
828*7988Srrh 			continue;
829*7988Srrh 
830*7988Srrh 		case 'x':
831*7988Srrh 			xflag = 1;
832*7988Srrh 			continue;
833*7988Srrh 
834*7988Srrh 		case 'a':
835*7988Srrh 			++aflag;
836*7988Srrh 		case 'u':	/* done in second pass */
837*7988Srrh 		case 'n':	/* done in shell script */
838*7988Srrh 			continue;
839*7988Srrh 
840*7988Srrh 		case 't':
841*7988Srrh 			werror( "option %c now default: see `man 6 lint'", *p );
842*7988Srrh 			continue;
843*7988Srrh 
844*7988Srrh 		default:
845*7988Srrh 			uerror( "illegal option: %c", *p );
846*7988Srrh 			continue;
847*7988Srrh 
848*7988Srrh 			}
849*7988Srrh 		}
850*7988Srrh 
851*7988Srrh 	if( !pflag ){  /* set sizes to sizes of target machine */
852*7988Srrh # ifdef gcos
853*7988Srrh 		SZCHAR = ALCHAR = 9;
854*7988Srrh # else
855*7988Srrh 		SZCHAR = ALCHAR = 8;
856*7988Srrh # endif
857*7988Srrh 		SZINT = ALINT = sizeof(int)*SZCHAR;
858*7988Srrh 		SZFLOAT = ALFLOAT = sizeof(float)*SZCHAR;
859*7988Srrh 		SZDOUBLE = ALDOUBLE = sizeof(double)*SZCHAR;
860*7988Srrh 		SZLONG = ALLONG = sizeof(long)*SZCHAR;
861*7988Srrh 		SZSHORT = ALSHORT = sizeof(short)*SZCHAR;
862*7988Srrh 		SZPOINT = ALPOINT = sizeof(int *)*SZCHAR;
863*7988Srrh 		ALSTRUCT = ALINT;
864*7988Srrh 		/* now, fix some things up for various machines (I wish we had "alignof") */
865*7988Srrh 
866*7988Srrh # ifdef pdp11
867*7988Srrh 		ALLONG = ALDOUBLE = ALFLOAT = ALINT;
868*7988Srrh #endif
869*7988Srrh # ifdef ibm
870*7988Srrh 		ALSTRUCT = ALCHAR;
871*7988Srrh #endif
872*7988Srrh 		}
873*7988Srrh 
874*7988Srrh 	return( mainp1( argc, argv ) );
875*7988Srrh 	}
876*7988Srrh 
877*7988Srrh ctype( type ) unsigned type; { /* are there any funny types? */
878*7988Srrh 	return( type );
879*7988Srrh 	}
880*7988Srrh 
881*7988Srrh commdec( i ){
882*7988Srrh 	/* put out a common declaration */
883*7988Srrh 	outdef( &stab[i], libflag?LIB:LDC, USUAL );
884*7988Srrh 	}
885*7988Srrh 
886*7988Srrh isitfloat ( s ) char *s; {
887*7988Srrh 	/* s is a character string;
888*7988Srrh 	   if floating point is implemented, set dcon to the value of s */
889*7988Srrh 	/* lint version
890*7988Srrh 	*/
891*7988Srrh 	dcon = atof( s );
892*7988Srrh 	return( FCON );
893*7988Srrh 	}
894*7988Srrh 
895*7988Srrh fldcon( p ) register NODE *p; {
896*7988Srrh 	/* p is an assignment of a constant to a field */
897*7988Srrh 	/* check to see if the assignment is going to overflow, or otherwise cause trouble */
898*7988Srrh 	register s;
899*7988Srrh 	CONSZ v;
900*7988Srrh 
901*7988Srrh 	if( !hflag & !pflag ) return;
902*7988Srrh 
903*7988Srrh 	s = UPKFSZ(p->in.left->tn.rval);
904*7988Srrh 	v = p->in.right->tn.lval;
905*7988Srrh 
906*7988Srrh 	switch( p->in.left->in.type ){
907*7988Srrh 
908*7988Srrh 	case CHAR:
909*7988Srrh 	case INT:
910*7988Srrh 	case SHORT:
911*7988Srrh 	case LONG:
912*7988Srrh 	case ENUMTY:
913*7988Srrh 		if( v>=0 && (v>>(s-1))==0 ) return;
914*7988Srrh 		werror( "precision lost in assignment to (possibly sign-extended) field" );
915*7988Srrh 	default:
916*7988Srrh 		return;
917*7988Srrh 
918*7988Srrh 	case UNSIGNED:
919*7988Srrh 	case UCHAR:
920*7988Srrh 	case USHORT:
921*7988Srrh 	case ULONG:
922*7988Srrh 		if( v<0 || (v>>s)!=0 ) werror( "precision lost in field assignment" );
923*7988Srrh 
924*7988Srrh 		return;
925*7988Srrh 		}
926*7988Srrh 
927*7988Srrh 	}
928*7988Srrh 
929*7988Srrh outdef( p, lty, mode ) struct symtab *p; {
930*7988Srrh 	/* output a definition for the second pass */
931*7988Srrh 	/* if mode is > USUAL, it is the number of args */
932*7988Srrh 	char *fname;
933*7988Srrh 	TWORD t;
934*7988Srrh 	int line;
935*7988Srrh 	static union rec rc;
936*7988Srrh 
937*7988Srrh 	if( mode == NOFILE ){
938*7988Srrh 		fname = "???";
939*7988Srrh 		line = p->suse;
940*7988Srrh 		}
941*7988Srrh 	else if( mode == SVLINE ){
942*7988Srrh 		fname = ftitle;
943*7988Srrh 		line = -p->suse;
944*7988Srrh 		}
945*7988Srrh 	else {
946*7988Srrh 		fname = ftitle;
947*7988Srrh 		line = lineno;
948*7988Srrh 		}
949*7988Srrh 	fsave( fname );
950*7988Srrh #ifndef FLEXNAMES
951*7988Srrh 	strncpy( rc.l.name, exname(p->sname), LCHNM );
952*7988Srrh #endif
953*7988Srrh 	rc.l.decflag = lty;
954*7988Srrh 	t = p->stype;
955*7988Srrh 	if( mode == DECTY ) t = DECREF(t);
956*7988Srrh 	rc.l.type.aty = t;
957*7988Srrh 	rc.l.type.extra = 0;
958*7988Srrh 	astype( &rc.l.type, p->sizoff );
959*7988Srrh 	rc.l.nargs = (mode>USUAL) ? mode : 0;
960*7988Srrh 	rc.l.fline = line;
961*7988Srrh 	fwrite( (char *)&rc, sizeof(rc), 1, stdout );
962*7988Srrh #ifdef FLEXNAMES
963*7988Srrh 	rc.l.name = exname(p->sname);
964*7988Srrh 	fwrite( rc.l.name, strlen(rc.l.name)+1, 1, stdout );
965*7988Srrh #endif
966*7988Srrh 	}
967*7988Srrh int proflg;
968*7988Srrh int gdebug;
969