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