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