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: }