Commit | Line | Data |
---|---|---|
13d26355 | 1 | #ifndef lint |
ca67e7b4 | 2 | static char sccsid[] = "@(#)lint.c 1.14 (Berkeley) 12/11/87"; |
13d26355 RH |
3 | #endif lint |
4 | ||
7184b3eb | 5 | # include "pass1.h" |
13d26355 | 6 | |
7184b3eb | 7 | # include "lmanifest.h" |
13d26355 RH |
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 | ||
476534cd KB |
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 */ | |
13d26355 RH |
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 ); | |
476534cd | 105 | strforget(); |
13d26355 RH |
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 ){ | |
bbc65794 EW |
119 | if( !zflag && dimtab[p->sizoff+1] < 0 ){ |
120 | /* never defined */ | |
13d26355 RH |
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 | } | |
d44c5e20 PN |
144 | /* no statics in libraries */ |
145 | if( Cflag ) break; | |
13d26355 RH |
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; | |
bbc65794 | 170 | int j, k=0, l=0; |
13d26355 RH |
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 ){ | |
bbc65794 EW |
179 | k = dimtab[i]; |
180 | l = X_NONAME | stab[j].suse; | |
13d26355 RH |
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 | } | |
bbc65794 EW |
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 | } | |
13d26355 RH |
199 | } |
200 | } | |
201 | ||
202 | t->extra = k; | |
bbc65794 | 203 | t->extra1 = l; |
13d26355 RH |
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 | ||
476534cd | 217 | strforget(); |
13d26355 | 218 | retlab = 1; |
d44c5e20 | 219 | |
13d26355 RH |
220 | cfp = &stab[curftn]; |
221 | ||
d44c5e20 PN |
222 | /* if creating library, don't do static functions */ |
223 | if( Cflag && cfp->sclass == STATIC ) return; | |
224 | ||
13d26355 | 225 | /* if variable number of arguments, only print the ones which will be checked */ |
6b3507db | 226 | if( vaflag >= 0 ){ |
13d26355 RH |
227 | if( n < vaflag ) werror( "declare the VARARGS arguments you want checked!" ); |
228 | else n = vaflag; | |
229 | } | |
230 | fsave( ftitle ); | |
6b3507db DS |
231 | if( cfp->sclass == STATIC ) outdef( cfp, LST, vaflag>=0?~n:n ); |
232 | else outdef( cfp, libflag?LIB:LDI, vaflag>=0?~n:n ); | |
13d26355 RH |
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; | |
bbc65794 | 240 | t.extra1 = 0; |
13d26355 RH |
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); | |
bbc65794 | 287 | t.extra1 = 0; |
13d26355 | 288 | |
7184b3eb | 289 | if( !astype( &t, p->fn.csiz ) ) { |
13d26355 RH |
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; | |
d44c5e20 PN |
410 | |
411 | fsave( ftitle ); | |
d105ff1f | 412 | if (!nflag) |
476534cd | 413 | doform(p, sp, acount); |
d44c5e20 PN |
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; | |
13d26355 RH |
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 | } | |
d44c5e20 | 433 | outdef( sp, lty, acount ); |
13d26355 RH |
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 ){ | |
bbc65794 | 454 | if( !ISARY(q->stype ) && !ISFTN(q->stype) && q->stype!=STRTY && q->stype!=UNIONTY ){ |
13d26355 RH |
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( p->tn.lval == 0 ){ | |
469 | lnp->lid = id; | |
470 | lnp->flgs = (uses&VALADDR)?0:((uses&VALSET)?VALSET:VALUSED); | |
471 | if( ++lnp >= &lnames[LNAMES] ) --lnp; | |
472 | } | |
473 | } | |
474 | return; | |
475 | ||
476 | } | |
477 | ||
478 | /* recurse, going down the right side first if we can */ | |
479 | ||
480 | switch( optype(p->in.op) ){ | |
481 | ||
482 | case BITYPE: | |
483 | np1 = lnp; | |
484 | lprt( p->in.right, down2, use2 ); | |
485 | case UTYPE: | |
486 | np2 = lnp; | |
487 | lprt( p->in.left, down1, use1 ); | |
488 | } | |
489 | ||
490 | if( optype(p->in.op) == BITYPE ){ | |
491 | if( p->in.op == ASSIGN && p->in.left->in.op == NAME ){ /* special case for a = .. a .. */ | |
492 | lmerge( np1, np2, 0 ); | |
493 | } | |
494 | else lmerge( np1, np2, p->in.op != COLON ); | |
495 | /* look for assignments to fields, and complain */ | |
496 | if( p->in.op == ASSIGN && p->in.left->in.op == FLD && p->in.right->in.op == ICON ) fldcon( p ); | |
497 | } | |
498 | ||
499 | } | |
500 | ||
501 | lmerge( np1, np2, flag ) struct lnm *np1, *np2; { | |
502 | /* np1 and np2 point to lists of lnm members, for the two sides | |
503 | * of a binary operator | |
504 | * flag is 1 if commutation is possible, 0 otherwise | |
505 | * lmerge returns a merged list, starting at np1, resetting lnp | |
506 | * it also complains, if appropriate, about side effects | |
507 | */ | |
508 | ||
509 | register struct lnm *npx, *npy; | |
510 | ||
511 | for( npx = np2; npx < lnp; ++npx ){ | |
512 | ||
513 | /* is it already there? */ | |
514 | for( npy = np1; npy < np2; ++npy ){ | |
515 | if( npx->lid == npy->lid ){ /* yes */ | |
516 | if( npx->flgs == 0 || npx->flgs == (VALSET|VALUSED) ) | |
517 | ; /* do nothing */ | |
518 | else if( (npx->flgs|npy->flgs)== (VALSET|VALUSED) || | |
519 | (npx->flgs&npy->flgs&VALSET) ){ | |
520 | #ifndef FLEXNAMES | |
521 | if( flag ) werror( "%.8s evaluation order undefined", stab[npy->lid].sname ); | |
522 | #else | |
523 | if( flag ) werror( "%s evaluation order undefined", stab[npy->lid].sname ); | |
524 | #endif | |
525 | } | |
526 | if( npy->flgs == 0 ) npx->flgs = 0; | |
527 | else npy->flgs |= npx->flgs; | |
528 | goto foundit; | |
529 | } | |
530 | } | |
531 | ||
532 | /* not there: update entry */ | |
533 | np2->lid = npx->lid; | |
534 | np2->flgs = npx->flgs; | |
535 | ++np2; | |
536 | ||
537 | foundit: ; | |
538 | } | |
539 | ||
540 | /* all finished: merged list is at np1 */ | |
541 | lnp = np2; | |
542 | } | |
543 | ||
544 | efcode(){ | |
545 | /* code for the end of a function */ | |
546 | register struct symtab *cfp; | |
547 | ||
548 | cfp = &stab[curftn]; | |
d44c5e20 PN |
549 | if( retstat & RETVAL && !(Cflag && cfp->sclass==STATIC) ) |
550 | outdef( cfp, LRV, DECTY ); | |
13d26355 RH |
551 | if( !vflag ){ |
552 | vflag = argflag; | |
553 | argflag = 0; | |
554 | } | |
555 | if( retstat == RETVAL+NRETVAL ) | |
556 | #ifndef FLEXNAMES | |
557 | werror( "function %.8s has return(e); and return;", cfp->sname); | |
558 | #else | |
559 | werror( "function %s has return(e); and return;", cfp->sname); | |
560 | #endif | |
561 | } | |
562 | ||
563 | aocode(p) struct symtab *p; { | |
564 | /* called when automatic p removed from stab */ | |
565 | register struct symtab *cfs; | |
566 | cfs = &stab[curftn]; | |
567 | if(p->suse>0 && !(p->sflags&(SMOS|STAG)) ){ | |
568 | if( p->sclass == PARAM ){ | |
569 | #ifndef FLEXNAMES | |
570 | if( vflag ) werror( "argument %.8s unused in function %.8s", | |
571 | #else | |
572 | if( vflag ) werror( "argument %s unused in function %s", | |
573 | #endif | |
574 | p->sname, | |
575 | cfs->sname ); | |
576 | } | |
577 | else { | |
578 | #ifndef FLEXNAMES | |
579 | if( p->sclass != TYPEDEF ) werror( "%.8s unused in function %.8s", | |
580 | #else | |
581 | if( p->sclass != TYPEDEF ) werror( "%s unused in function %s", | |
582 | #endif | |
583 | p->sname, cfs->sname ); | |
584 | } | |
585 | } | |
586 | ||
587 | if( p->suse < 0 && (p->sflags & (SSET|SREF|SMOS)) == SSET && | |
588 | !ISARY(p->stype) && !ISFTN(p->stype) ){ | |
589 | ||
590 | #ifndef FLEXNAMES | |
591 | werror( "%.8s set but not used in function %.8s", p->sname, cfs->sname ); | |
592 | #else | |
593 | werror( "%s set but not used in function %s", p->sname, cfs->sname ); | |
594 | #endif | |
595 | } | |
596 | ||
597 | if( p->stype == STRTY || p->stype == UNIONTY || p->stype == ENUMTY ){ | |
bbc65794 | 598 | if( !zflag && dimtab[p->sizoff+1] < 0 ) |
13d26355 | 599 | #ifndef FLEXNAMES |
bbc65794 | 600 | werror( "structure %.8s never defined", p->sname ); |
13d26355 | 601 | #else |
bbc65794 | 602 | werror( "structure %s never defined", p->sname ); |
13d26355 RH |
603 | #endif |
604 | } | |
605 | ||
606 | } | |
607 | ||
608 | defnam( p ) register struct symtab *p; { | |
609 | /* define the current location as the name p->sname */ | |
610 | ||
d44c5e20 | 611 | if( p->sclass == STATIC && (p->slevel>1 || Cflag) ) return; |
13d26355 | 612 | |
bbc65794 EW |
613 | if( !ISFTN( p->stype ) ) |
614 | if( p->sclass == STATIC ) outdef( p, LST, USUAL ); | |
615 | else outdef( p, libflag?LIB:LDI, USUAL ); | |
13d26355 RH |
616 | } |
617 | ||
618 | zecode( n ){ | |
619 | /* n integer words of zeros */ | |
620 | OFFSZ temp; | |
621 | temp = n; | |
622 | inoff += temp*SZINT; | |
623 | ; | |
624 | } | |
625 | ||
626 | andable( p ) NODE *p; { /* p is a NAME node; can it accept & ? */ | |
627 | register r; | |
628 | ||
629 | if( p->in.op != NAME ) cerror( "andable error" ); | |
630 | ||
631 | if( (r = p->tn.rval) < 0 ) return(1); /* labels are andable */ | |
632 | ||
633 | if( stab[r].sclass == AUTO || stab[r].sclass == PARAM ) return(0); | |
634 | #ifndef FLEXNAMES | |
635 | if( stab[r].sclass == REGISTER ) uerror( "can't take & of %.8s", stab[r].sname ); | |
636 | #else | |
637 | if( stab[r].sclass == REGISTER ) uerror( "can't take & of %s", stab[r].sname ); | |
638 | #endif | |
639 | return(1); | |
640 | } | |
641 | ||
642 | NODE * | |
643 | clocal(p) NODE *p; { | |
644 | ||
645 | /* this is called to do local transformations on | |
646 | an expression tree preparitory to its being | |
647 | written out in intermediate code. | |
648 | */ | |
649 | ||
650 | /* the major essential job is rewriting the | |
651 | automatic variables and arguments in terms of | |
652 | REG and OREG nodes */ | |
653 | /* conversion ops which are not necessary are also clobbered here */ | |
654 | /* in addition, any special features (such as rewriting | |
655 | exclusive or) are easily handled here as well */ | |
656 | ||
657 | register o; | |
658 | register unsigned t, tl; | |
a72909f3 | 659 | int s; |
13d26355 RH |
660 | |
661 | switch( o = p->in.op ){ | |
476534cd KB |
662 | case NAME: |
663 | { | |
664 | extern int didstr, subscr; | |
665 | extern NODE * strnodes[]; | |
666 | ||
667 | if (didstr) { | |
668 | didstr = 0; | |
669 | strnodes[subscr] = p; | |
670 | } | |
671 | } | |
672 | break; | |
13d26355 RH |
673 | |
674 | case SCONV: | |
675 | case PCONV: | |
676 | if( p->in.left->in.type==ENUMTY ){ | |
677 | p->in.left = pconvert( p->in.left ); | |
678 | } | |
679 | /* assume conversion takes place; type is inherited */ | |
680 | t = p->in.type; | |
681 | tl = p->in.left->in.type; | |
c1881ef2 | 682 | if( aflag && (tl==LONG||tl==ULONG) && (t!=LONG&&t!=ULONG&&t!=UNDEF) ){ |
13d26355 RH |
683 | werror( "long assignment may lose accuracy" ); |
684 | } | |
685 | if( aflag>=2 && (tl!=LONG&&tl!=ULONG) && (t==LONG||t==ULONG) && p->in.left->in.op != ICON ){ | |
686 | werror( "assignment to long may sign-extend incorrectly" ); | |
687 | } | |
688 | if( ISPTR(tl) && ISPTR(t) ){ | |
689 | tl = DECREF(tl); | |
690 | t = DECREF(t); | |
691 | switch( ISFTN(t) + ISFTN(tl) ){ | |
692 | ||
693 | case 0: /* neither is a function pointer */ | |
694 | if( talign(t,p->fn.csiz) > talign(tl,p->in.left->fn.csiz) ){ | |
695 | if( hflag||pflag ) werror( "possible pointer alignment problem" ); | |
696 | } | |
697 | break; | |
698 | ||
699 | case 1: | |
700 | werror( "questionable conversion of function pointer" ); | |
701 | ||
702 | case 2: | |
703 | ; | |
704 | } | |
705 | } | |
706 | p->in.left->in.type = p->in.type; | |
707 | p->in.left->fn.cdim = p->fn.cdim; | |
708 | p->in.left->fn.csiz = p->fn.csiz; | |
709 | p->in.op = FREE; | |
710 | return( p->in.left ); | |
711 | ||
712 | case PVCONV: | |
713 | case PMCONV: | |
714 | if( p->in.right->in.op != ICON ) cerror( "bad conversion"); | |
715 | p->in.op = FREE; | |
716 | return( buildtree( o==PMCONV?MUL:DIV, p->in.left, p->in.right ) ); | |
717 | ||
a72909f3 DS |
718 | case RS: |
719 | case LS: | |
720 | case ASG RS: | |
721 | case ASG LS: | |
722 | if( p->in.right->in.op != ICON ) | |
723 | break; | |
724 | s = p->in.right->tn.lval; | |
725 | if( s < 0 ) | |
726 | werror( "negative shift" ); | |
727 | else | |
728 | if( s >= dimtab[ p->fn.csiz ] ) | |
729 | werror( "shift greater than size of object" ); | |
730 | break; | |
731 | ||
13d26355 RH |
732 | } |
733 | ||
734 | return(p); | |
735 | } | |
736 | ||
737 | NODE * | |
738 | offcon( off, t, d, s ) OFFSZ off; TWORD t;{ /* make a structure offset node */ | |
739 | register NODE *p; | |
740 | p = bcon(0); | |
741 | p->tn.lval = off/SZCHAR; | |
742 | return(p); | |
743 | } | |
744 | ||
745 | noinit(){ | |
746 | /* storage class for such as "int a;" */ | |
747 | return( pflag ? EXTDEF : EXTERN ); | |
748 | } | |
749 | ||
750 | ||
751 | cinit( p, sz ) NODE *p; { /* initialize p into size sz */ | |
6b3507db DS |
752 | register int id; |
753 | ||
13d26355 RH |
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; | |
cd93e144 | 786 | static int stripping = 0; |
13d26355 | 787 | |
cd93e144 RH |
788 | if (stripping) |
789 | return(s); | |
790 | stripping++; | |
13d26355 | 791 | for( p=x; *s; ++s ){ |
cd93e144 | 792 | if( *s != '"' ){ |
13d26355 RH |
793 | #ifndef FLEXNAMES |
794 | /* PATCHED by ROBERT HENRY on 8Jul80 to fix 14 character file name bug */ | |
795 | if( p >= &x[LFNM] ) | |
d44c5e20 PN |
796 | #else |
797 | if( p >= &x[BUFSIZ] ) | |
13d26355 | 798 | #endif |
d44c5e20 | 799 | cerror( "filename too long" ); |
13d26355 RH |
800 | *p++ = *s; |
801 | } | |
802 | } | |
cd93e144 | 803 | stripping = 0; |
13d26355 RH |
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 | |
7e84ad26 | 816 | if( strncmp( s, fsname.f.fn, LFNM ) ) |
13d26355 | 817 | #else |
7e84ad26 | 818 | if (fsname.f.fn == NULL || strcmp(s, fsname.f.fn)) |
13d26355 | 819 | #endif |
7e84ad26 | 820 | { |
13d26355 RH |
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 | |
d44c5e20 PN |
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 | } | |
13d26355 RH |
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 */ | |
cd93e144 RH |
842 | if( f == 'u' && nerrors > 1 ) |
843 | --nerrors; /* don't get "too many errors" */ | |
844 | fprintf( stderr, "%s(%d): ", strip(ftitle), lineno); | |
13d26355 RH |
845 | } |
846 | ||
847 | /* a number of dummy routines, unneeded by lint */ | |
848 | ||
849 | branch(n){;} | |
850 | defalign(n){;} | |
851 | deflab(n){;} | |
476534cd KB |
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 | ||
d105ff1f | 873 | if (nflag || strapped) |
476534cd KB |
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 | ||
d105ff1f | 1116 | if (nflag || strapped) |
476534cd KB |
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 | */ | |
d105ff1f KB |
1142 | /* |
1143 | ** For now, ALWAYS use "portable" table, rather than doing this: | |
1144 | ** basep = pflag ? ip->ptable : ip->btable; | |
1145 | */ | |
1146 | basep = ip->ptable; | |
476534cd KB |
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 | ||
13d26355 RH |
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 | ||
476534cd KB |
1297 | main(argc, argv) |
1298 | int argc; | |
1299 | char **argv; | |
1300 | { | |
1301 | extern char *optarg; | |
1302 | extern int optind; | |
1303 | int ch; | |
13d26355 | 1304 | |
6b3507db | 1305 | while ((ch = getopt(argc,argv,"C:D:I:U:LX:Pabchnpuvxz")) != EOF) |
476534cd KB |
1306 | switch((char)ch) { |
1307 | case 'C': | |
1308 | Cflag = 1; | |
1309 | libname = optarg; | |
d44c5e20 | 1310 | continue; |
476534cd KB |
1311 | case 'D': /* #define */ |
1312 | case 'I': /* include path */ | |
1313 | case 'U': /* #undef */ | |
6b3507db | 1314 | case 'X': /* debugging, done in first pass */ |
476534cd | 1315 | case 'P': /* debugging, done in second pass */ |
d44c5e20 | 1316 | break; |
d44c5e20 PN |
1317 | case 'L': |
1318 | libflag = 1; | |
476534cd KB |
1319 | /*FALLTHROUGH*/ |
1320 | case 'v': /* unused arguments in functions */ | |
d44c5e20 | 1321 | vflag = 0; |
476534cd KB |
1322 | break; |
1323 | case 'a': /* long to int assignment */ | |
d44c5e20 | 1324 | ++aflag; |
476534cd KB |
1325 | break; |
1326 | case 'b': /* unreached break statements */ | |
1327 | brkflag = 1; | |
1328 | break; | |
1329 | case 'c': /* questionable casts */ | |
1330 | cflag = 1; | |
1331 | break; | |
1332 | case 'h': /* heuristics */ | |
1333 | hflag = 1; | |
1334 | break; | |
1335 | case 'n': /* standard library check */ | |
1336 | nflag = 1; | |
1337 | break; | |
1338 | case 'p': /* IBM & GCOS portability */ | |
1339 | pflag = 1; | |
1340 | break; | |
1341 | case 'u': /* 2nd pass: undefined or unused */ | |
1342 | break; | |
1343 | case 'x': /* unused externs */ | |
1344 | xflag = 1; | |
1345 | break; | |
1346 | case 'z': /* use of undefined structures */ | |
bbc65794 | 1347 | zflag = 1; |
476534cd KB |
1348 | break; |
1349 | case '?': | |
d44c5e20 | 1350 | default: |
476534cd KB |
1351 | fputs("usage: lint [-C lib] [-D def] [-I include] [-U undef] [-Labchnpuvx] file ...\n",stderr); |
1352 | exit(1); | |
1353 | } | |
13d26355 | 1354 | |
476534cd | 1355 | if (!pflag) { /* set sizes to sizes of target machine */ |
13d26355 RH |
1356 | # ifdef gcos |
1357 | SZCHAR = ALCHAR = 9; | |
1358 | # else | |
1359 | SZCHAR = ALCHAR = 8; | |
1360 | # endif | |
1361 | SZINT = ALINT = sizeof(int)*SZCHAR; | |
1362 | SZFLOAT = ALFLOAT = sizeof(float)*SZCHAR; | |
1363 | SZDOUBLE = ALDOUBLE = sizeof(double)*SZCHAR; | |
1364 | SZLONG = ALLONG = sizeof(long)*SZCHAR; | |
1365 | SZSHORT = ALSHORT = sizeof(short)*SZCHAR; | |
1366 | SZPOINT = ALPOINT = sizeof(int *)*SZCHAR; | |
1367 | ALSTRUCT = ALINT; | |
1368 | /* now, fix some things up for various machines (I wish we had "alignof") */ | |
1369 | ||
1370 | # ifdef pdp11 | |
1371 | ALLONG = ALDOUBLE = ALFLOAT = ALINT; | |
476534cd | 1372 | # endif |
13d26355 RH |
1373 | # ifdef ibm |
1374 | ALSTRUCT = ALCHAR; | |
476534cd | 1375 | # endif |
13d26355 | 1376 | } |
476534cd KB |
1377 | return(mainp1(argc,argv)); |
1378 | } | |
13d26355 RH |
1379 | |
1380 | ctype( type ) unsigned type; { /* are there any funny types? */ | |
1381 | return( type ); | |
1382 | } | |
1383 | ||
1384 | commdec( i ){ | |
1385 | /* put out a common declaration */ | |
bbc65794 EW |
1386 | if( stab[i].sclass == STATIC ) outdef( &stab[i], LST, USUAL ); |
1387 | else outdef( &stab[i], libflag?LIB:LDC, USUAL ); | |
13d26355 RH |
1388 | } |
1389 | ||
1390 | isitfloat ( s ) char *s; { | |
1391 | /* s is a character string; | |
1392 | if floating point is implemented, set dcon to the value of s */ | |
1393 | /* lint version | |
1394 | */ | |
1395 | dcon = atof( s ); | |
dfa87255 | 1396 | return( DCON ); |
13d26355 RH |
1397 | } |
1398 | ||
1399 | fldcon( p ) register NODE *p; { | |
1400 | /* p is an assignment of a constant to a field */ | |
1401 | /* check to see if the assignment is going to overflow, or otherwise cause trouble */ | |
1402 | register s; | |
1403 | CONSZ v; | |
1404 | ||
1405 | if( !hflag & !pflag ) return; | |
1406 | ||
1407 | s = UPKFSZ(p->in.left->tn.rval); | |
1408 | v = p->in.right->tn.lval; | |
1409 | ||
1410 | switch( p->in.left->in.type ){ | |
1411 | ||
1412 | case CHAR: | |
1413 | case INT: | |
1414 | case SHORT: | |
1415 | case LONG: | |
1416 | case ENUMTY: | |
1417 | if( v>=0 && (v>>(s-1))==0 ) return; | |
1418 | werror( "precision lost in assignment to (possibly sign-extended) field" ); | |
1419 | default: | |
1420 | return; | |
1421 | ||
1422 | case UNSIGNED: | |
1423 | case UCHAR: | |
1424 | case USHORT: | |
1425 | case ULONG: | |
1426 | if( v<0 || (v>>s)!=0 ) werror( "precision lost in field assignment" ); | |
1427 | ||
1428 | return; | |
1429 | } | |
1430 | ||
1431 | } | |
1432 | ||
1433 | outdef( p, lty, mode ) struct symtab *p; { | |
1434 | /* output a definition for the second pass */ | |
1435 | /* if mode is > USUAL, it is the number of args */ | |
1436 | char *fname; | |
1437 | TWORD t; | |
1438 | int line; | |
1439 | static union rec rc; | |
1440 | ||
1441 | if( mode == NOFILE ){ | |
1442 | fname = "???"; | |
1443 | line = p->suse; | |
1444 | } | |
1445 | else if( mode == SVLINE ){ | |
1446 | fname = ftitle; | |
1447 | line = -p->suse; | |
1448 | } | |
1449 | else { | |
1450 | fname = ftitle; | |
1451 | line = lineno; | |
1452 | } | |
1453 | fsave( fname ); | |
1454 | #ifndef FLEXNAMES | |
1455 | strncpy( rc.l.name, exname(p->sname), LCHNM ); | |
1456 | #endif | |
1457 | rc.l.decflag = lty; | |
1458 | t = p->stype; | |
1459 | if( mode == DECTY ) t = DECREF(t); | |
1460 | rc.l.type.aty = t; | |
1461 | rc.l.type.extra = 0; | |
bbc65794 | 1462 | rc.l.type.extra1 = 0; |
13d26355 RH |
1463 | astype( &rc.l.type, p->sizoff ); |
1464 | rc.l.nargs = (mode>USUAL) ? mode : 0; | |
1465 | rc.l.fline = line; | |
1466 | fwrite( (char *)&rc, sizeof(rc), 1, stdout ); | |
1467 | #ifdef FLEXNAMES | |
1468 | rc.l.name = exname(p->sname); | |
1469 | fwrite( rc.l.name, strlen(rc.l.name)+1, 1, stdout ); | |
1470 | #endif | |
1471 | } | |
1472 | int proflg; | |
1473 | int gdebug; |