xref: /original-bsd/old/pcc/lint/lpass1/lint.c (revision cd18b70b)
1 #ifndef lint
2 static char sccsid[] = "@(#)lint.c	1.12	(Berkeley)	04/13/87";
3 #endif lint
4 
5 # include "pass1.h"
6 
7 # include "lmanifest.h"
8 
9 # include <ctype.h>
10 
11 # define VAL 0
12 # define EFF 1
13 
14 /* these are appropriate for the -p flag */
15 int  SZCHAR = 8;
16 int  SZINT = 16;
17 int  SZFLOAT = 32;
18 int  SZDOUBLE = 64;
19 int  SZLONG = 32;
20 int  SZSHORT = 16;
21 int SZPOINT = 16;
22 int ALCHAR = 8;
23 int ALINT = 16;
24 int ALFLOAT = 32;
25 int ALDOUBLE = 64;
26 int ALLONG = 32;
27 int ALSHORT = 16;
28 int ALPOINT = 16;
29 int ALSTRUCT = 16;
30 
31 int nflag = 0;		/* avoid gripes about printf et al. */
32 int vflag = 1;		/* tell about unused argments */
33 int xflag = 0;		/* tell about unused externals */
34 int argflag = 0;	/* used to turn off complaints about arguments */
35 int libflag = 0;	/* used to generate library descriptions */
36 int vaflag = -1;	/* signal functions with a variable number of args */
37 int aflag = 0;		/* used to check precision of assignments */
38 int zflag = 0;		/* no 'structure never defined' error */
39 int Cflag = 0;	/* filter out certain output, for generating libraries */
40 char *libname = 0;	/* name of the library we're generating */
41 
42 			/* flags for the "outdef" function */
43 # define USUAL (-101)
44 # define DECTY (-102)
45 # define NOFILE (-103)
46 # define SVLINE (-104)
47 
48 # define LNAMES 250
49 
50 struct lnm {
51 	short lid, flgs;
52 	}  lnames[LNAMES], *lnp;
53 
54 contx( p, down, pl, pr ) register NODE *p; register *pl, *pr; {
55 
56 	*pl = *pr = VAL;
57 	switch( p->in.op ){
58 
59 	case ANDAND:
60 	case OROR:
61 	case QUEST:
62 		*pr = down;
63 		break;
64 
65 	case SCONV:
66 	case PCONV:
67 	case COLON:
68 		*pr = *pl = down;
69 		break;
70 
71 	case COMOP:
72 		*pl = EFF;
73 		*pr = down;
74 
75 	case FORCE:
76 	case INIT:
77 	case UNARY CALL:
78 	case STCALL:
79 	case UNARY STCALL:
80 	case CALL:
81 	case UNARY FORTCALL:
82 	case FORTCALL:
83 	case CBRANCH:
84 		break;
85 
86 	default:
87 		if( asgop(p->in.op) ) break;
88 		if( p->in.op == UNARY MUL && ( p->in.type == STRTY || p->in.type == UNIONTY || p->in.type == UNDEF) ) {
89 		/* struct x f( );  main( ) {  (void) f( ); }
90 		 * the the cast call appears as U* UNDEF
91 		 */
92 			break;  /* the compiler does this... */
93 			}
94 		if( down == EFF && hflag ) werror( "null effect" );
95 
96 		}
97 	}
98 
99 ecode( p ) NODE *p; {
100 	/* compile code for p */
101 
102 	fwalk( p, contx, EFF );
103 	lnp = lnames;
104 	lprt( p, EFF, 0 );
105 	strforget();
106 	}
107 
108 ejobcode( flag ){
109 	/* called after processing each job */
110 	/* flag is nonzero if errors were detected */
111 	register k;
112 	register struct symtab *p;
113 
114 	for( p=stab; p< &stab[SYMTSZ]; ++p ){
115 
116 		if( p->stype != TNULL ) {
117 
118 			if( p->stype == STRTY || p->stype == UNIONTY ){
119 				if( !zflag && dimtab[p->sizoff+1] < 0 ){
120 					/* never defined */
121 #ifndef FLEXNAMES
122 					if( hflag ) werror( "struct/union %.8s never defined", p->sname );
123 #else
124 					if( hflag ) werror( "struct/union %s never defined", p->sname );
125 #endif
126 					}
127 				}
128 
129 			switch( p->sclass ){
130 
131 			case STATIC:
132 				if( p->suse > 0 ){
133 					k = lineno;
134 					lineno = p->suse;
135 #ifndef FLEXNAMES
136 					uerror( "static variable %.8s unused",
137 #else
138 					uerror( "static variable %s unused",
139 #endif
140 						p->sname );
141 					lineno = k;
142 					break;
143 					}
144 				/* no statics in libraries */
145 				if( Cflag ) break;
146 
147 			case EXTERN:
148 			case USTATIC:
149 				/* with the xflag, worry about externs not used */
150 				/* the filename may be wrong here... */
151 				if( xflag && p->suse >= 0 && !libflag ){
152 					outdef( p, LDX, NOFILE );
153 					}
154 
155 			case EXTDEF:
156 				if( p->suse < 0 ){  /* used */
157 					outdef( p, LUM, SVLINE );
158 					}
159 				break;
160 				}
161 
162 			}
163 
164 		}
165 	exit( 0 );
166 	}
167 
168 astype( t, i ) ATYPE *t; {
169 	TWORD tt;
170 	int j, k=0, l=0;
171 
172 	if( (tt=BTYPE(t->aty))==STRTY || tt==UNIONTY ){
173 		if( i<0 || i>= DIMTABSZ-3 ){
174 			werror( "lint's little mind is blown" );
175 			}
176 		else {
177 			j = dimtab[i+3];
178 			if( j<0 || j>SYMTSZ ){
179 				k = dimtab[i];
180 				l = X_NONAME | stab[j].suse;
181 				}
182 			else {
183 				if( stab[j].suse <= 0 ) {
184 #ifndef FLEXNAMES
185 					werror( "no line number for %.8s",
186 #else
187 					werror( "no line number for %s",
188 #endif
189 						stab[j].sname );
190 					}
191 				else {
192 					k = dimtab[i];
193 #ifdef FLEXNAMES
194 					l = hashstr(stab[j].sname);
195 #else
196 					l = hashstr(stab[j].sname, LCHNM);
197 #endif
198 					}
199 				}
200 			}
201 
202 		t->extra = k;
203 		t->extra1 = l;
204 		return( 1 );
205 		}
206 	else return( 0 );
207 	}
208 
209 bfcode( a, n ) int a[]; {
210 	/* code for the beginning of a function; a is an array of
211 		indices in stab for the arguments; n is the number */
212 	/* this must also set retlab */
213 	register i;
214 	register struct symtab *cfp;
215 	static ATYPE t;
216 
217 	strforget();
218 	retlab = 1;
219 
220 	cfp = &stab[curftn];
221 
222 	/* if creating library, don't do static functions */
223 	if( Cflag && cfp->sclass == STATIC ) return;
224 
225 	/* if variable number of arguments, only print the ones which will be checked */
226 	if( vaflag > 0 ){
227 		if( n < vaflag ) werror( "declare the VARARGS arguments you want checked!" );
228 		else n = vaflag;
229 		}
230 	fsave( ftitle );
231 	if( cfp->sclass == STATIC ) outdef( cfp, LST, vaflag>=0?-n:n );
232 	else outdef( cfp, libflag?LIB:LDI, vaflag>=0?-n:n );
233 	vaflag = -1;
234 
235 	/* output the arguments */
236 	if( n ){
237 		for( i=0; i<n; ++i ) {
238 			t.aty = stab[a[i]].stype;
239 			t.extra = 0;
240 			t.extra1 = 0;
241 			if( !astype( &t, stab[a[i]].sizoff ) ) {
242 				switch( t.aty ){
243 
244 				case ULONG:
245 					break;
246 
247 				case CHAR:
248 				case SHORT:
249 					t.aty = INT;
250 					break;
251 
252 				case UCHAR:
253 				case USHORT:
254 				case UNSIGNED:
255 					t.aty = UNSIGNED;
256 					break;
257 
258 					}
259 				}
260 			fwrite( (char *)&t, sizeof(ATYPE), 1, stdout );
261 			}
262 		}
263 	}
264 
265 ctargs( p ) NODE *p; {
266 	/* count arguments; p points to at least one */
267 	/* the arguemnts are a tower of commas to the left */
268 	register c;
269 	c = 1; /* count the rhs */
270 	while( p->in.op == CM ){
271 		++c;
272 		p = p->in.left;
273 		}
274 	return( c );
275 	}
276 
277 lpta( p ) NODE *p; {
278 	static ATYPE t;
279 
280 	if( p->in.op == CM ){
281 		lpta( p->in.left );
282 		p = p->in.right;
283 		}
284 
285 	t.aty = p->in.type;
286 	t.extra = (p->in.op==ICON);
287 	t.extra1 = 0;
288 
289 	if( !astype( &t, p->fn.csiz ) ) {
290 		switch( t.aty ){
291 
292 			case CHAR:
293 			case SHORT:
294 				t.aty = INT;
295 			case LONG:
296 			case ULONG:
297 			case INT:
298 			case UNSIGNED:
299 				break;
300 
301 			case UCHAR:
302 			case USHORT:
303 				t.aty = UNSIGNED;
304 				break;
305 
306 			case FLOAT:
307 				t.aty = DOUBLE;
308 				t.extra = 0;
309 				break;
310 
311 			default:
312 				t.extra = 0;
313 				break;
314 			}
315 		}
316 	fwrite( (char *)&t, sizeof(ATYPE), 1, stdout );
317 	}
318 
319 # define VALSET 1
320 # define VALUSED 2
321 # define VALASGOP 4
322 # define VALADDR 8
323 
324 lprt( p, down, uses ) register NODE *p; {
325 	register struct symtab *q;
326 	register id;
327 	register acount;
328 	register down1, down2;
329 	register use1, use2;
330 	register struct lnm *np1, *np2;
331 
332 	/* first, set variables which are set... */
333 
334 	use1 = use2 = VALUSED;
335 	if( p->in.op == ASSIGN ) use1 = VALSET;
336 	else if( p->in.op == UNARY AND ) use1 = VALADDR;
337 	else if( asgop( p->in.op ) ){ /* =ops */
338 		use1 = VALUSED|VALSET;
339 		if( down == EFF ) use1 |= VALASGOP;
340 		}
341 
342 
343 	/* print the lines for lint */
344 
345 	down2 = down1 = VAL;
346 	acount = 0;
347 
348 	switch( p->in.op ){
349 
350 	case EQ:
351 	case NE:
352 	case GT:
353 	case GE:
354 	case LT:
355 	case LE:
356 		if( p->in.left->in.type == CHAR && p->in.right->in.op==ICON && p->in.right->tn.lval < 0 ){
357 			werror( "nonportable character comparison" );
358 			}
359 		if( (p->in.op==EQ || p->in.op==NE ) && ISUNSIGNED(p->in.left->in.type) && p->in.right->in.op == ICON ){
360 			if( p->in.right->tn.lval < 0 && p->in.right->tn.rval == NONAME && !ISUNSIGNED(p->in.right->in.type) ){
361 				werror( "comparison of unsigned with negative constant" );
362 				}
363 			}
364 		break;
365 
366 	case UGE:
367 	case ULT:
368 		if( p->in.right->in.op == ICON && p->in.right->tn.lval == 0 && p->in.right->tn.rval == NONAME ){
369 			werror( "unsigned comparison with 0?" );
370 			break;
371 			}
372 	case UGT:
373 	case ULE:
374 		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 ){
375 			werror( "degenerate unsigned comparison" );
376 			}
377 		break;
378 
379 	case COMOP:
380 		down1 = EFF;
381 
382 	case ANDAND:
383 	case OROR:
384 	case QUEST:
385 		down2 = down;
386 		/* go recursively left, then right  */
387 		np1 = lnp;
388 		lprt( p->in.left, down1, use1 );
389 		np2 = lnp;
390 		lprt( p->in.right, down2, use2 );
391 		lmerge( np1, np2, 0 );
392 		return;
393 
394 	case SCONV:
395 	case PCONV:
396 	case COLON:
397 		down1 = down2 = down;
398 		break;
399 
400 	case CALL:
401 	case STCALL:
402 	case FORTCALL:
403 		acount = ctargs( p->in.right );
404 	case UNARY CALL:
405 	case UNARY STCALL:
406 	case UNARY FORTCALL:
407 		if( p->in.left->in.op == ICON && (id=p->in.left->tn.rval) != NONAME ){ /* used to be &name */
408 			struct symtab *sp = &stab[id];
409 			int lty;
410 
411 			fsave( ftitle );
412 			if (!nflag)
413 				doform(p, sp, acount);
414 			/*
415 			 * if we're generating a library -C then
416 			 * we don't want to output references to functions
417 			 */
418 			if( Cflag ) break;
419 			/*  if a function used in an effects context is
420 			 *  cast to type  void  then consider its value
421 			 *  to have been disposed of properly
422 			 *  thus a call of type  undef  in an effects
423 			 *  context is construed to be used in a value
424 			 *  context
425 			 */
426 			if ((down == EFF) && (p->in.type != UNDEF)) {
427 				lty = LUE;
428 			} else if (down == EFF) {
429 				lty = LUV | LUE;
430 			} else {
431 				lty = LUV;
432 			}
433 			outdef( sp, lty, acount );
434 			if( acount ) {
435 				lpta( p->in.right );
436 				}
437 			}
438 		break;
439 
440 	case ICON:
441 		/* look for &name case */
442 		if( (id = p->tn.rval) >= 0 && id != NONAME ){
443 			q = &stab[id];
444 			q->sflags |= (SREF|SSET);
445 			q->suse = -lineno;
446 			}
447 		return;
448 
449 	case NAME:
450 		if( (id = p->tn.rval) >= 0 && id != NONAME ){
451 			q = &stab[id];
452 			if( (uses&VALUSED) && !(q->sflags&SSET) ){
453 				if( q->sclass == AUTO || q->sclass == REGISTER ){
454 					if( !ISARY(q->stype ) && !ISFTN(q->stype) && q->stype!=STRTY && q->stype!=UNIONTY ){
455 #ifndef FLEXNAMES
456 						werror( "%.8s may be used before set", q->sname );
457 #else
458 						werror( "%s may be used before set", q->sname );
459 #endif
460 						q->sflags |= SSET;
461 						}
462 					}
463 				}
464 			if( uses & VALASGOP ) break;  /* not a real use */
465 			if( uses & VALSET ) q->sflags |= SSET;
466 			if( uses & VALUSED ) q->sflags |= SREF;
467 			if( uses & VALADDR ) q->sflags |= (SREF|SSET);
468 			if (uses & (VALSET | VALADDR))
469 				q->suse = -lineno;
470 			if( p->tn.lval == 0 ){
471 				lnp->lid = id;
472 				lnp->flgs = (uses&VALADDR)?0:((uses&VALSET)?VALSET:VALUSED);
473 				if( ++lnp >= &lnames[LNAMES] ) --lnp;
474 				}
475 			}
476 		return;
477 
478 		}
479 
480 	/* recurse, going down the right side first if we can */
481 
482 	switch( optype(p->in.op) ){
483 
484 	case BITYPE:
485 		np1 = lnp;
486 		lprt( p->in.right, down2, use2 );
487 	case UTYPE:
488 		np2 = lnp;
489 		lprt( p->in.left, down1, use1 );
490 		}
491 
492 	if( optype(p->in.op) == BITYPE ){
493 		if( p->in.op == ASSIGN && p->in.left->in.op == NAME ){ /* special case for a =  .. a .. */
494 			lmerge( np1, np2, 0 );
495 			}
496 		else lmerge( np1, np2, p->in.op != COLON );
497 		/* look for assignments to fields, and complain */
498 		if( p->in.op == ASSIGN && p->in.left->in.op == FLD && p->in.right->in.op == ICON ) fldcon( p );
499 		}
500 
501 	}
502 
503 lmerge( np1, np2, flag ) struct lnm *np1, *np2; {
504 	/* np1 and np2 point to lists of lnm members, for the two sides
505 	 * of a binary operator
506 	 * flag is 1 if commutation is possible, 0 otherwise
507 	 * lmerge returns a merged list, starting at np1, resetting lnp
508 	 * it also complains, if appropriate, about side effects
509 	 */
510 
511 	register struct lnm *npx, *npy;
512 
513 	for( npx = np2; npx < lnp; ++npx ){
514 
515 		/* is it already there? */
516 		for( npy = np1; npy < np2; ++npy ){
517 			if( npx->lid == npy->lid ){ /* yes */
518 				if( npx->flgs == 0 || npx->flgs == (VALSET|VALUSED) )
519 					;  /* do nothing */
520 				else if( (npx->flgs|npy->flgs)== (VALSET|VALUSED) ||
521 					(npx->flgs&npy->flgs&VALSET) ){
522 #ifndef FLEXNAMES
523 					if( flag ) werror( "%.8s evaluation order undefined", stab[npy->lid].sname );
524 #else
525 					if( flag ) werror( "%s evaluation order undefined", stab[npy->lid].sname );
526 #endif
527 					}
528 				if( npy->flgs == 0 ) npx->flgs = 0;
529 				else npy->flgs |= npx->flgs;
530 				goto foundit;
531 				}
532 			}
533 
534 		/* not there: update entry */
535 		np2->lid = npx->lid;
536 		np2->flgs = npx->flgs;
537 		++np2;
538 
539 		foundit: ;
540 		}
541 
542 	/* all finished: merged list is at np1 */
543 	lnp = np2;
544 	}
545 
546 efcode(){
547 	/* code for the end of a function */
548 	register struct symtab *cfp;
549 
550 	cfp = &stab[curftn];
551 	if( retstat & RETVAL && !(Cflag && cfp->sclass==STATIC) )
552 		outdef( cfp, LRV, DECTY );
553 	if( !vflag ){
554 		vflag = argflag;
555 		argflag = 0;
556 		}
557 	if( retstat == RETVAL+NRETVAL )
558 #ifndef FLEXNAMES
559 		werror( "function %.8s has return(e); and return;", cfp->sname);
560 #else
561 		werror( "function %s has return(e); and return;", cfp->sname);
562 #endif
563 	}
564 
565 aocode(p) struct symtab *p; {
566 	/* called when automatic p removed from stab */
567 	register struct symtab *cfs;
568 	cfs = &stab[curftn];
569 	if(p->suse>0 && !(p->sflags&(SMOS|STAG)) ){
570 		if( p->sclass == PARAM ){
571 #ifndef FLEXNAMES
572 			if( vflag ) werror( "argument %.8s unused in function %.8s",
573 #else
574 			if( vflag ) werror( "argument %s unused in function %s",
575 #endif
576 				p->sname,
577 				cfs->sname );
578 			}
579 		else {
580 #ifndef FLEXNAMES
581 			if( p->sclass != TYPEDEF ) werror( "%.8s unused in function %.8s",
582 #else
583 			if( p->sclass != TYPEDEF ) werror( "%s unused in function %s",
584 #endif
585 				p->sname, cfs->sname );
586 			}
587 		}
588 
589 	if( p->suse < 0 && (p->sflags & (SSET|SREF|SMOS)) == SSET &&
590 		!ISARY(p->stype) && !ISFTN(p->stype) ){
591 
592 #ifndef FLEXNAMES
593 		werror( "%.8s set but not used in function %.8s", p->sname, cfs->sname );
594 #else
595 		werror( "%s set but not used in function %s", p->sname, cfs->sname );
596 #endif
597 		}
598 
599 	if( p->stype == STRTY || p->stype == UNIONTY || p->stype == ENUMTY ){
600 		if( !zflag && dimtab[p->sizoff+1] < 0 )
601 #ifndef FLEXNAMES
602 			werror( "structure %.8s never defined", p->sname );
603 #else
604 			werror( "structure %s never defined", p->sname );
605 #endif
606 		}
607 
608 	}
609 
610 defnam( p ) register struct symtab *p; {
611 	/* define the current location as the name p->sname */
612 
613 	if( p->sclass == STATIC && (p->slevel>1 || Cflag) ) return;
614 
615 	if( !ISFTN( p->stype ) )
616 		if( p->sclass == STATIC ) outdef( p, LST, USUAL );
617 		else outdef( p, libflag?LIB:LDI, USUAL );
618 	}
619 
620 zecode( n ){
621 	/* n integer words of zeros */
622 	OFFSZ temp;
623 	temp = n;
624 	inoff += temp*SZINT;
625 	;
626 	}
627 
628 andable( p ) NODE *p; {  /* p is a NAME node; can it accept & ? */
629 	register r;
630 
631 	if( p->in.op != NAME ) cerror( "andable error" );
632 
633 	if( (r = p->tn.rval) < 0 ) return(1);  /* labels are andable */
634 
635 	if( stab[r].sclass == AUTO || stab[r].sclass == PARAM ) return(0);
636 #ifndef FLEXNAMES
637 	if( stab[r].sclass == REGISTER ) uerror( "can't take & of %.8s", stab[r].sname );
638 #else
639 	if( stab[r].sclass == REGISTER ) uerror( "can't take & of %s", stab[r].sname );
640 #endif
641 	return(1);
642 	}
643 
644 NODE *
645 clocal(p) NODE *p; {
646 
647 	/* this is called to do local transformations on
648 	   an expression tree preparitory to its being
649 	   written out in intermediate code.
650 	*/
651 
652 	/* the major essential job is rewriting the
653 	   automatic variables and arguments in terms of
654 	   REG and OREG nodes */
655 	/* conversion ops which are not necessary are also clobbered here */
656 	/* in addition, any special features (such as rewriting
657 	   exclusive or) are easily handled here as well */
658 
659 	register o;
660 	register unsigned t, tl;
661 	int s;
662 
663 	switch( o = p->in.op ){
664 	case NAME:
665 		{
666 			extern int	didstr, subscr;
667 			extern NODE *	strnodes[];
668 
669 			if (didstr) {
670 				didstr = 0;
671 				strnodes[subscr] = p;
672 			}
673 		}
674 		break;
675 
676 	case SCONV:
677 	case PCONV:
678 		if( p->in.left->in.type==ENUMTY ){
679 			p->in.left = pconvert( p->in.left );
680 			}
681 		/* assume conversion takes place; type is inherited */
682 		t = p->in.type;
683 		tl = p->in.left->in.type;
684 		if( aflag && (tl==LONG||tl==ULONG) && (t!=LONG&&t!=ULONG&&t!=UNDEF) ){
685 			werror( "long assignment may lose accuracy" );
686 			}
687 		if( aflag>=2 && (tl!=LONG&&tl!=ULONG) && (t==LONG||t==ULONG) && p->in.left->in.op != ICON ){
688 			werror( "assignment to long may sign-extend incorrectly" );
689 			}
690 		if( ISPTR(tl) && ISPTR(t) ){
691 			tl = DECREF(tl);
692 			t = DECREF(t);
693 			switch( ISFTN(t) + ISFTN(tl) ){
694 
695 			case 0:  /* neither is a function pointer */
696 				if( talign(t,p->fn.csiz) > talign(tl,p->in.left->fn.csiz) ){
697 					if( hflag||pflag ) werror( "possible pointer alignment problem" );
698 					}
699 				break;
700 
701 			case 1:
702 				werror( "questionable conversion of function pointer" );
703 
704 			case 2:
705 				;
706 				}
707 			}
708 		p->in.left->in.type = p->in.type;
709 		p->in.left->fn.cdim = p->fn.cdim;
710 		p->in.left->fn.csiz = p->fn.csiz;
711 		p->in.op = FREE;
712 		return( p->in.left );
713 
714 	case PVCONV:
715 	case PMCONV:
716 		if( p->in.right->in.op != ICON ) cerror( "bad conversion");
717 		p->in.op = FREE;
718 		return( buildtree( o==PMCONV?MUL:DIV, p->in.left, p->in.right ) );
719 
720 	case RS:
721 	case LS:
722 	case ASG RS:
723 	case ASG LS:
724 		if( p->in.right->in.op != ICON )
725 			break;
726 		s = p->in.right->tn.lval;
727 		if( s < 0 )
728 			werror( "negative shift" );
729 		else
730 		if( s >= dimtab[ p->fn.csiz ] )
731 			werror( "shift greater than size of object" );
732 		break;
733 
734 		}
735 
736 	return(p);
737 	}
738 
739 NODE *
740 offcon( off, t, d, s ) OFFSZ off; TWORD t;{  /* make a structure offset node */
741 	register NODE *p;
742 	p = bcon(0);
743 	p->tn.lval = off/SZCHAR;
744 	return(p);
745 	}
746 
747 noinit(){
748 	/* storage class for such as "int a;" */
749 	return( pflag ? EXTDEF : EXTERN );
750 	}
751 
752 
753 cinit( p, sz ) NODE *p; { /* initialize p into size sz */
754 	inoff += sz;
755 	if( p->in.op == INIT ){
756 		if( p->in.left->in.op == ICON ) return;
757 		if( p->in.left->in.op == NAME && p->in.left->in.type == MOE ) return;
758 		}
759 	uerror( "illegal initialization" );
760 	}
761 
762 char *
763 exname( p ) char *p; {
764 	/* make a name look like an external name in the local machine */
765 	static char aa[8];
766 	register int i;
767 
768 	if( !pflag ) return(p);
769 	for( i=0; i<6; ++i ){
770 		if( isupper(*p ) ) aa[i] = tolower( *p );
771 		else aa[i] = *p;
772 		if( *p ) ++p;
773 		}
774 	aa[6] = '\0';
775 	return( aa );
776 	}
777 
778 char *
779 strip(s) char *s; {
780 #ifndef FLEXNAMES
781 	static char x[LFNM+1];
782 #else
783 	static char x[BUFSIZ];
784 #endif
785 	register char *p;
786 	static	int	stripping = 0;
787 
788 	if (stripping)
789 		return(s);
790 	stripping++;
791 	for( p=x; *s; ++s ){
792 		if( *s != '"' ){
793 #ifndef FLEXNAMES
794 /* PATCHED by ROBERT HENRY on 8Jul80 to fix 14 character file name bug */
795 			if( p >= &x[LFNM] )
796 #else
797 			if( p >= &x[BUFSIZ] )
798 #endif
799 				cerror( "filename too long" );
800 			*p++ = *s;
801 		}
802 	}
803 	stripping = 0;
804 	*p = '\0';
805 #ifndef FLEXNAMES
806 	return( x );
807 #else
808 	return( hash(x) );
809 #endif
810 	}
811 
812 fsave( s ) char *s; {
813 	static union rec fsname;
814 	s = strip( s );
815 #ifndef FLEXNAMES
816 	if( strncmp( s, fsname.f.fn, LFNM ) )
817 #else
818 	if (fsname.f.fn == NULL || strcmp(s, fsname.f.fn))
819 #endif
820 		{
821 		/* new one */
822 #ifndef FLEXNAMES
823 		strncpy( fsname.f.fn, s, LFNM );
824 #else
825 		fsname.f.fn = s;
826 #endif
827 		fsname.f.decflag = LFN;
828 		fwrite( (char *)&fsname, sizeof(fsname), 1, stdout );
829 #ifdef FLEXNAMES
830 		/* if generating a library, prefix with the library name */
831 		/* only do this for flexnames */
832 		if( libname ){
833 			fwrite( libname, strlen(libname), 1, stdout );
834 			putchar( ':' );
835 			}
836 		fwrite( fsname.f.fn, strlen(fsname.f.fn)+1, 1, stdout );
837 #endif
838 		}
839 	}
840 
841 where(f){ /* print true location of error */
842 	if( f == 'u' && nerrors > 1 )
843 		--nerrors; /* don't get "too many errors" */
844 	fprintf( stderr, "%s(%d): ", strip(ftitle), lineno);
845 	}
846 
847 	/* a number of dummy routines, unneeded by lint */
848 
849 branch(n){;}
850 defalign(n){;}
851 deflab(n){;}
852 
853 extern char *	strchr();
854 
855 #define SBUFSIZE	16
856 #define SCLICK		80
857 
858 #ifndef size_t
859 #define size_t	unsigned
860 #endif /* !size_t */
861 
862 static char *	strings[SBUFSIZE];
863 static NODE *	strnodes[SBUFSIZE];
864 static int	didstr;
865 static int	subscr;
866 static int	strapped;
867 
868 bycode(t, i)
869 {
870 	extern char *	calloc();
871 	extern char *	realloc();
872 
873 	if (nflag || strapped)
874 		return;
875 	if (i == 0)
876 		if (subscr < (SBUFSIZE - 1))
877 			++subscr;
878 	if (subscr >= SBUFSIZE)
879 		return;
880 	didstr = 1;
881 	if ((i % SCLICK) == 0) {
882 		strings[subscr] = (strings[subscr] == NULL) ?
883 			calloc((size_t) (SCLICK + 1), 1) :
884 			realloc(strings[subscr], (size_t) (i + SCLICK + 1));
885 		if (strings[subscr] == NULL) {
886 			strapped = 1;
887 			return;
888 		}
889 	}
890 	strings[subscr][i] = t;
891 }
892 
893 strforget()
894 {
895 	didstr = subscr = 0;
896 }
897 
898 static char *
899 typestr(t)
900 {
901 	switch (t) {
902 		case CHAR:		return "char";
903 		case UCHAR:		return "unsigned char";
904 		case SHORT:		return "short";
905 		case USHORT:		return "unsigned short";
906 		case INT:		return "int";
907 		case UNSIGNED:		return "unsigned";
908 		case ENUMTY:		return "enum";
909 		case LONG:		return "long";
910 		case ULONG:		return "unsigned long";
911 		case FLOAT:		return "float";
912 		case DOUBLE:		return "double";
913 		case STRTY:		return "struct";
914 		case UNIONTY:		return "union";
915 		case PTR|CHAR:		return "char *";
916 		case PTR|UCHAR:		return "unsigned char *";
917 		case PTR|SHORT:		return "short *";
918 		case PTR|USHORT:	return "unsigned short *";
919 		case PTR|INT:		return "int *";
920 		case PTR|UNSIGNED:	return "unsigned *";
921 		case PTR|ENUMTY:	return "enum *";
922 		case PTR|LONG:		return "long *";
923 		case PTR|ULONG:		return "unsigned long *";
924 		case PTR|FLOAT:		return "float *";
925 		case PTR|DOUBLE:	return "double *";
926 		case PTR|STRTY:		return "struct *";
927 		case PTR|UNIONTY:	return "union *";
928 		default:		return ISPTR(t) ?
929 						"pointer" : "non-scalar";
930 	}
931 }
932 
933 NODE *
934 ntharg(p, n, acount)
935 NODE *		p;
936 register int	n;
937 register int	acount;
938 {
939 	if (n > acount)
940 		return NULL;
941 	p = p->in.right;
942 	while (n != acount) {
943 		p = p->in.left;
944 		--acount;
945 	}
946 	return (n == 1) ? p : p->in.right;
947 }
948 
949 struct entry {
950 	/* If argument to print/scan is of type... */	int	argtype;
951 	/* ...and this length character is used... */	char	lchar;
952 	/* ...and one of these is control char... */	char *	cchars;
953 	/* ...then use this format with werror... */	char *	werror;
954 	/* ...(where NULL means it's hunky dory)... */
955 };
956 
957 /*
958 ** Portable printf.
959 ** H&S says "%o" takes an unsigned argument;
960 ** X3J11 says "%o" takes an int argument;
961 ** we'll allow either here.
962 */
963 
964 static struct entry pprintf[] = {
965 	CHAR,		'\0',	"c",		NULL, /* this is deliberate */
966 	INT,		'\0',	"cdoxX",	NULL,
967 	UNSIGNED,	'\0',	"uoxX",		NULL,
968 	CHAR,		'\0',	"cdoxX",	NULL,
969 	UCHAR,		'\0',	"udoxX",	NULL, /* yes, d is okay */
970 	SHORT,		'\0',	"cdoxX",	NULL,
971 	USHORT,		'\0',	"uoxX",		NULL,
972 	ENUMTY,		'\0',	"duoxX",	NULL,
973 	LONG,		'l',	"doxX",		NULL,
974 	ULONG,		'l',	"uoxX",		NULL,
975 	FLOAT,		'\0',	"eEfgG",	NULL,
976 	DOUBLE,		'\0',	"eEfgG",	NULL,
977 	PTR|CHAR,	'\0',	"s",		NULL,
978 	UNDEF,		'\0',	"",		NULL
979 };
980 
981 /*
982 ** Berkeley printf.
983 ** It allows %D, %O, and %U, which we deprecate.
984 ** Since
985 **	sizeof (char *) == sizeof (int) &&
986 **	sizeof (int) == sizeof (long) &&
987 **	sizeof (char *) == sizeof (int *)
988 ** you can be lax--and we tolerate *some* laxness.
989 ** g/lax/p to find lax table entries and code.
990 */
991 
992 static char	uppercase[] = "deprecated upper-case control character (%c)";
993 #define lax	NULL
994 
995 static struct entry bprintf[] = {
996 	CHAR,		'\0',	"c",		NULL,	/* this is deliberate */
997 	INT,		'\0',	"cdoxX",	NULL,
998 	INT,		'\0',	"DO",		uppercase,
999 	UNSIGNED,	'\0',	"uoxX",		NULL,
1000 	UNSIGNED,	'\0',	"UO",		uppercase,
1001 	CHAR,		'\0',	"cdoxX",	NULL,
1002 	CHAR,		'\0',	"DO",		uppercase,
1003 	UCHAR,		'\0',	"duoxX",	NULL,	/* yes, d is okay */
1004 	UCHAR,		'\0',	"DUO",		uppercase,
1005 	SHORT,		'\0',	"cdoxX",	NULL,
1006 	SHORT,		'\0',	"DO",		uppercase,
1007 	USHORT,		'\0',	"duoxX",	NULL,	/* d okay on BSD */
1008 	USHORT,		'\0',	"DUO",		uppercase,
1009 	ENUMTY,		'\0',	"duoxX",	NULL,
1010 	ENUMTY,		'\0',	"DUO",		uppercase,
1011 	LONG,		'\0',	"doxX",		lax,
1012 	LONG,		'\0',	"DO",		uppercase,
1013 	LONG,		'l',	"doxX",		NULL,
1014 	INT,		'l',	"doxX",		lax,
1015 	ULONG,		'\0',	"uoxX",		lax,
1016 	ULONG,		'\0',	"UO",		uppercase,
1017 	ULONG,		'l',	"uoxX",		NULL,
1018 	UNSIGNED,	'l',	"uoxX",		lax,
1019 	FLOAT,		'\0',	"eEfgG",	NULL,
1020 	DOUBLE,		'\0',	"eEfgG",	NULL,
1021 	PTR|CHAR,	'\0',	"s",		NULL,
1022 	UNDEF,		'\0',	NULL,		NULL,
1023 };
1024 
1025 /*
1026 ** Portable scanf.  'l' and 'h' are universally ignored preceding 'c' and 's',
1027 ** and 'h' is universally ignored preceding 'e' and 'f',
1028 ** but you won't find such cruft here.
1029 */
1030 
1031 static struct entry pscanf[] = {
1032 	INT,		'\0',	"dox",	NULL,
1033 	UNSIGNED,	'\0',	"uox",	NULL,
1034 	CHAR,		'\0',	"cs[",	NULL,
1035 	SHORT,		'h',	"dox",	NULL,
1036 	USHORT,		'h',	"uox",	NULL,
1037 	LONG,		'l',	"dox",	NULL,
1038 	ULONG,		'l',	"uox",	NULL,
1039 	FLOAT,		'\0',	"ef",	NULL,	/* BSD doesn't handle g */
1040 	DOUBLE,		'l',	"ef",	NULL,
1041 	UNDEF,		'\0',	NULL,	NULL,
1042 };
1043 
1044 /*
1045 ** Berkeley scanf.  An upper case letter equals an l plus the lower case char,
1046 ** but this is deprecated.
1047 ** Even though sizeof (int) == sizeof (long), we'll be picky here.
1048 */
1049 
1050 static struct entry bscanf[] = {
1051 	INT,		'\0',	"dox",	NULL,
1052 	UNSIGNED,	'\0',	"uox",	NULL,
1053 	CHAR,		'\0',	"cs[",	NULL,
1054 	SHORT,		'h',	"dox",	NULL,
1055 	USHORT,		'h',	"uox",	NULL,
1056 	LONG,		'\0',	"dox",	lax,
1057 	LONG,		'\0',	"DOX",	uppercase,
1058 	LONG,		'l',	"dox",	NULL,
1059 	ULONG,		'\0',	"uox",	lax,
1060 	ULONG,		'\0',	"UOX",	uppercase,
1061 	ULONG,		'l',	"uox",	NULL,
1062 	FLOAT,		'\0',	"ef",	NULL,
1063 	DOUBLE,		'\0',	"EF",	uppercase,
1064 	DOUBLE,		'l',	"ef",	NULL,
1065 	UNDEF,		'\0',	NULL,	NULL,
1066 };
1067 
1068 static struct item {
1069 	char *		name;		/* such as "printf" */
1070 	int		isscan;		/* scanf/printf */
1071 	int		fmtarg;		/* number of format argument */
1072 	struct entry *	ptable;		/* portable checking table */
1073 	struct entry *	btable;		/* berkeley checking table */
1074 } items[] = {
1075 	"printf",	0,	1,	pprintf,	bprintf,
1076 	"fprintf",	0,	2,	pprintf,	bprintf,
1077 	"sprintf",	0,	2,	pprintf,	bprintf,
1078 	"scanf",	1,	1,	pscanf,		bscanf,
1079 	"fscanf",	1,	2,	pscanf,		bscanf,
1080 	"sscanf",	1,	2,	pscanf,		bscanf,
1081 	NULL,		-1,	-1,	NULL,		NULL
1082 };
1083 
1084 static char	pwf[]	= "possible wild format";
1085 static char	pfacm[]	= "possible format/argument count mismatch";
1086 
1087 static struct entry *
1088 findlc(ep, lchar, cchar)
1089 register struct entry *	ep;
1090 register int		lchar;
1091 register int		cchar;
1092 {
1093 	for ( ; ep->argtype != UNDEF; ++ep)
1094 		if (ep->lchar == lchar && strchr(ep->cchars, cchar) != 0)
1095 			return ep;
1096 	return NULL;
1097 }
1098 
1099 static char *
1100 subform(p, sp, acount)
1101 register NODE *			p;
1102 register struct symtab *	sp;
1103 {
1104 	register int		i, j, isscan;
1105 	register NODE *		tp;
1106 	register char *		cp;
1107 	register struct entry *	basep;
1108 	register struct entry *	ep;
1109 	register struct item *	ip;
1110 	register int		lchar;
1111 	register int		cchar;
1112 	register int		t;
1113 	register int		suppressed;
1114 	static char		errbuf[132];
1115 
1116 	if (nflag || strapped)
1117 		return NULL;
1118 	cp = sp->sname;
1119 	for (ip = items; ; ++ip)
1120 		if (ip->name == NULL)
1121 			return NULL;	/* not a print/scan function */
1122 		else if (strcmp(ip->name, sp->sname) == 0)
1123 			break;
1124 	isscan = ip->isscan;
1125 	i = ip->fmtarg;
1126 	if (i > acount)
1127 		return NULL;	/* handled in pass 2 */
1128 	tp = ntharg(p, i, acount);
1129 	if (tp->in.type != (PTR|CHAR))
1130 		return NULL;	/* handled in pass 2 */
1131 	if (tp->in.op != ICON || tp->tn.lval != 0)
1132 		return NULL;	/* can't check it */
1133 	for (j = 1; j <= subscr; ++j)
1134 		if (tp == strnodes[j])
1135 			break;
1136 	if (j > subscr)
1137 		return NULL;	/* oh well. . . */
1138 	cp = strings[j];
1139 	/*
1140 	** cp now points to format string.
1141 	*/
1142 	/*
1143 	** For now, ALWAYS use "portable" table, rather than doing this:
1144 	**	basep = pflag ? ip->ptable : ip->btable;
1145 	*/
1146 	basep = ip->ptable;
1147 	for ( ; ; ) {
1148 		if (*cp == '\0')
1149 			return (i == acount) ? NULL : pfacm;
1150 		if (*cp++ != '%')
1151 			continue;
1152 		if (*cp == '\0')
1153 			return "wild trailing %% in format";
1154 		if (*cp == '%') {
1155 			++cp;
1156 			continue;
1157 		}
1158 		if (isscan) {
1159 			suppressed = *cp == '*';
1160 			if (suppressed)
1161 				++cp;
1162 			while (isdigit(*cp))
1163 				++cp;
1164 			if (!suppressed && ++i <= acount) {
1165 				t = ntharg(p, i, acount)->in.type;
1166 				if (!ISPTR(t)) {
1167 (void) sprintf(errbuf,
1168 	"%s argument is type (%s) rather than pointer (arg %d)",
1169 	ip->name, typestr(t), i);
1170 					return errbuf;
1171 				}
1172 				t = DECREF(t);
1173 			}
1174 		} else {
1175 			int	nspace, ndash, nplus, nhash;
1176 
1177 			suppressed = 0;
1178 			nspace = ndash = nplus = nhash = 0;
1179 			for ( ; ; ) {
1180 				if (*cp == ' ')
1181 					++nspace;
1182 				else if (*cp == '+')
1183 					++nplus;
1184 				else if (*cp == '-')
1185 					++ndash;
1186 				else if (*cp == '#')
1187 					++nhash;
1188 				else	break;
1189 				++cp;
1190 			}
1191 			if (nspace > 1 || ndash > 1 || nplus > 1 || nhash > 1)
1192 				return "wild repeated flag character in format";
1193 			if (*cp == '*') {
1194 				++cp;
1195 				if (++i > acount)
1196 					break;
1197 				t = ntharg(p, i, acount)->in.type;
1198 				/*
1199 				** Width other than INT or UNSIGNED is suspect.
1200 				*/
1201 				if (t != INT && t != UNSIGNED) {
1202 (void) sprintf(errbuf,
1203 	"field width argument is type (%s) rather than (int) (arg %d)",
1204 	typestr(t), i);
1205 					return errbuf;
1206 				}
1207 			} else while (isdigit(*cp))
1208 				++cp;
1209 			if (*cp == '.') {
1210 				++cp;
1211 				if (*cp == '*') {
1212 					++cp;
1213 					if (++i > acount)
1214 						return pfacm;
1215 					t = ntharg(p, i, acount)->in.type;
1216 					if (t != INT && t != UNSIGNED) {
1217 (void) sprintf(errbuf,
1218 	"precision argument is type (%s) rather than (int) (arg %d)",
1219 	typestr(t), i);
1220 						return errbuf;
1221 					}
1222 				} else while (isdigit(*cp))
1223 					++cp;
1224 			}
1225 			if (++i <= acount)
1226 				t = ntharg(p, i, acount)->in.type;
1227 		}
1228 		if (*cp == 'h' || *cp == 'l')
1229 			lchar = *cp++;
1230 		else	lchar = '\0';
1231 		if ((cchar = *cp++) == '\0')
1232 			return pwf;
1233 		if (i > acount)
1234 			return (findlc(basep, lchar, cchar) == NULL) ?
1235 				pwf : pfacm;
1236 		if (!isscan && !pflag && ISPTR(t) &&
1237 			strchr("douxX", cchar) != 0)
1238 				continue;	/* lax--printf("%d", (int *)) */
1239 		if (suppressed) {
1240 			if (findlc(basep, lchar, cchar) == NULL)
1241 				return pwf;
1242 		} else for (ep = basep; ; ++ep) {
1243 			if (ep->argtype == UNDEF) {	/* end of table */
1244 				ep = findlc(basep, lchar, cchar);
1245 				if (ep == NULL)
1246 					return pwf;
1247 (void) sprintf(errbuf, "%s: (%s) format, (%s) arg (arg %d)",
1248 					ip->name,
1249 					typestr(ep->argtype),
1250 					typestr(isscan ? (t | PTR) : t), i);
1251 				return errbuf;
1252 			}
1253 			if (ep->argtype == t && ep->lchar == lchar &&
1254 				strchr(ep->cchars, cchar) != 0)
1255 					if (ep->werror == 0)
1256 						break;
1257 					else {
1258 						werror(ep->werror, cchar);
1259 						return NULL;
1260 					}
1261 		}
1262 		if (cchar != '[')
1263 			continue;
1264 		do {
1265 			if (*cp == '\0')
1266 				return "possible unmatched '[' in format";
1267 		} while (*cp++ != ']');
1268 	}
1269 	/*NOTREACHED*/
1270 }
1271 
1272 doform(p, sp, acount)
1273 NODE *		p;
1274 struct symtab *	sp;
1275 {
1276 	char *	cp;
1277 
1278 	if ((cp = subform(p, sp, acount)) != NULL)
1279 		werror(cp);
1280 }
1281 
1282 cisreg(t) TWORD t; {return(1);}  /* everyting is a register variable! */
1283 
1284 fldty(p) struct symtab *p; {
1285 	; /* all types are OK here... */
1286 	}
1287 
1288 fldal(t) unsigned t; { /* field alignment... */
1289 	if( t == ENUMTY ) return( ALCHAR );  /* this should be thought through better... */
1290 	if( ISPTR(t) ){ /* really for the benefit of honeywell (and someday IBM) */
1291 		if( pflag ) uerror( "nonportable field type" );
1292 		}
1293 	else uerror( "illegal field type" );
1294 	return(ALINT);
1295 	}
1296 
1297 main(argc, argv)
1298 	int	argc;
1299 	char	**argv;
1300 {
1301 	extern char	*optarg;
1302 	extern int	optind;
1303 	int	ch;
1304 
1305 	while ((ch = getopt(argc,argv,"C:D:I:U:LPabchnpuvxz")) != EOF)
1306 		switch((char)ch) {
1307 			case 'C':
1308 				Cflag = 1;
1309 				libname = optarg;
1310 				continue;
1311 			case 'D':	/* #define */
1312 			case 'I':	/* include path */
1313 			case 'U':	/* #undef */
1314 			case 'P':	/* debugging, done in second pass */
1315 				break;
1316 			case 'L':
1317 				libflag = 1;
1318 				/*FALLTHROUGH*/
1319 			case 'v':	/* unused arguments in functions */
1320 				vflag = 0;
1321 				break;
1322 			case 'a':	/* long to int assignment */
1323 				++aflag;
1324 				break;
1325 			case 'b':	/* unreached break statements */
1326 				brkflag = 1;
1327 				break;
1328 			case 'c':	/* questionable casts */
1329 				cflag = 1;
1330 				break;
1331 			case 'h':	/* heuristics */
1332 				hflag = 1;
1333 				break;
1334 			case 'n':	/* standard library check */
1335 				nflag = 1;
1336 				break;
1337 			case 'p':	/* IBM & GCOS portability */
1338 				pflag = 1;
1339 				break;
1340 			case 'u':	/* 2nd pass: undefined or unused */
1341 				break;
1342 			case 'x':	/* unused externs */
1343 				xflag = 1;
1344 				break;
1345 			case 'z':	/* use of undefined structures */
1346 				zflag = 1;
1347 				break;
1348 			case '?':
1349 			default:
1350 				fputs("usage: lint [-C lib] [-D def] [-I include] [-U undef] [-Labchnpuvx] file ...\n",stderr);
1351 				exit(1);
1352 		}
1353 
1354 	if (!pflag) {		/* set sizes to sizes of target machine */
1355 # ifdef gcos
1356 		SZCHAR = ALCHAR = 9;
1357 # else
1358 		SZCHAR = ALCHAR = 8;
1359 # endif
1360 		SZINT = ALINT = sizeof(int)*SZCHAR;
1361 		SZFLOAT = ALFLOAT = sizeof(float)*SZCHAR;
1362 		SZDOUBLE = ALDOUBLE = sizeof(double)*SZCHAR;
1363 		SZLONG = ALLONG = sizeof(long)*SZCHAR;
1364 		SZSHORT = ALSHORT = sizeof(short)*SZCHAR;
1365 		SZPOINT = ALPOINT = sizeof(int *)*SZCHAR;
1366 		ALSTRUCT = ALINT;
1367 		/* now, fix some things up for various machines (I wish we had "alignof") */
1368 
1369 # ifdef pdp11
1370 		ALLONG = ALDOUBLE = ALFLOAT = ALINT;
1371 # endif
1372 # ifdef ibm
1373 		ALSTRUCT = ALCHAR;
1374 # endif
1375 	}
1376 	return(mainp1(argc,argv));
1377 }
1378 
1379 ctype( type ) unsigned type; { /* are there any funny types? */
1380 	return( type );
1381 	}
1382 
1383 commdec( i ){
1384 	/* put out a common declaration */
1385 	if( stab[i].sclass == STATIC ) outdef( &stab[i], LST, USUAL );
1386 	else outdef( &stab[i], libflag?LIB:LDC, USUAL );
1387 	}
1388 
1389 isitfloat ( s ) char *s; {
1390 	/* s is a character string;
1391 	   if floating point is implemented, set dcon to the value of s */
1392 	/* lint version
1393 	*/
1394 	dcon = atof( s );
1395 	return( DCON );
1396 	}
1397 
1398 fldcon( p ) register NODE *p; {
1399 	/* p is an assignment of a constant to a field */
1400 	/* check to see if the assignment is going to overflow, or otherwise cause trouble */
1401 	register s;
1402 	CONSZ v;
1403 
1404 	if( !hflag & !pflag ) return;
1405 
1406 	s = UPKFSZ(p->in.left->tn.rval);
1407 	v = p->in.right->tn.lval;
1408 
1409 	switch( p->in.left->in.type ){
1410 
1411 	case CHAR:
1412 	case INT:
1413 	case SHORT:
1414 	case LONG:
1415 	case ENUMTY:
1416 		if( v>=0 && (v>>(s-1))==0 ) return;
1417 		werror( "precision lost in assignment to (possibly sign-extended) field" );
1418 	default:
1419 		return;
1420 
1421 	case UNSIGNED:
1422 	case UCHAR:
1423 	case USHORT:
1424 	case ULONG:
1425 		if( v<0 || (v>>s)!=0 ) werror( "precision lost in field assignment" );
1426 
1427 		return;
1428 		}
1429 
1430 	}
1431 
1432 outdef( p, lty, mode ) struct symtab *p; {
1433 	/* output a definition for the second pass */
1434 	/* if mode is > USUAL, it is the number of args */
1435 	char *fname;
1436 	TWORD t;
1437 	int line;
1438 	static union rec rc;
1439 
1440 	if( mode == NOFILE ){
1441 		fname = "???";
1442 		line = p->suse;
1443 		}
1444 	else if( mode == SVLINE ){
1445 		fname = ftitle;
1446 		line = -p->suse;
1447 		}
1448 	else {
1449 		fname = ftitle;
1450 		line = lineno;
1451 		}
1452 	fsave( fname );
1453 #ifndef FLEXNAMES
1454 	strncpy( rc.l.name, exname(p->sname), LCHNM );
1455 #endif
1456 	rc.l.decflag = lty;
1457 	t = p->stype;
1458 	if( mode == DECTY ) t = DECREF(t);
1459 	rc.l.type.aty = t;
1460 	rc.l.type.extra = 0;
1461 	rc.l.type.extra1 = 0;
1462 	astype( &rc.l.type, p->sizoff );
1463 	rc.l.nargs = (mode>USUAL) ? mode : 0;
1464 	rc.l.fline = line;
1465 	fwrite( (char *)&rc, sizeof(rc), 1, stdout );
1466 #ifdef FLEXNAMES
1467 	rc.l.name = exname(p->sname);
1468 	fwrite( rc.l.name, strlen(rc.l.name)+1, 1, stdout );
1469 #endif
1470 	}
1471 int proflg;
1472 int gdebug;
1473