home *** CD-ROM | disk | FTP | other *** search
- # include "mfile1"
-
- # include "lmanifest"
-
- # include <ctype.h>
-
- # define VAL 0
- # define EFF 1
-
- /* these are appropriate for the -p flag */
- int SZCHAR = 8;
- int SZINT = 16;
- int SZFLOAT = 32;
- int SZDOUBLE = 64;
- int SZLONG = 32;
- int SZSHORT = 16;
- int SZPOINT = 16;
- int ALCHAR = 8;
- int ALINT = 16;
- int ALFLOAT = 32;
- int ALDOUBLE = 64;
- int ALLONG = 32;
- int ALSHORT = 16;
- int ALPOINT = 16;
- int ALSTRUCT = 16;
-
- int vflag = 1; /* tell about unused argments */
- int xflag = 0; /* tell about unused externals */
- int argflag = 0; /* used to turn off complaints about arguments */
- int libflag = 0; /* used to generate library descriptions */
- int vaflag = -1; /* used to signal functions with a variable number of args */
- int aflag = 0; /* used th check precision of assignments */
-
- char *flabel = "xxx";
-
- # define LNAMES 100
-
- struct lnm {
- short lid, flgs;
- } lnames[LNAMES], *lnp;
-
- contx( p, down, pl, pr ) register NODE *p; register *pl, *pr; {
-
- *pl = *pr = VAL;
- switch( p->op ){
-
- case ANDAND:
- case OROR:
- case QUEST:
- *pr = down;
- break;
-
- case SCONV:
- case PCONV:
- case COLON:
- *pr = *pl = down;
- break;
-
- case COMOP:
- *pl = EFF;
- *pr = down;
-
- case FORCE:
- case INIT:
- case UNARY CALL:
- case STCALL:
- case UNARY STCALL:
- case CALL:
- case UNARY FORTCALL:
- case FORTCALL:
- case CBRANCH:
- break;
-
- default:
- if( asgop(p->op) ) break;
- if( p->op == UNARY MUL && ( p->type == STRTY || p->type == UNIONTY) ) {
- break; /* the compiler does this... */
- }
- if( down == EFF && hflag ) werror( "null effect" );
-
- }
- }
-
- ecode( p ) NODE *p; {
- /* compile code for p */
-
- fwalk( p, contx, EFF );
- lnp = lnames;
- lprt( p, EFF, 0 );
- }
-
- ejobcode( flag ){
- /* called after processing each job */
- /* flag is nonzero if errors were detected */
- register k;
- register struct symtab *p;
-
- for( p=stab; p< &stab[SYMTSZ]; ++p ){
-
- if( p->stype != TNULL ) {
-
- if( p->stype == STRTY || p->stype == UNIONTY ){
- if( dimtab[p->sizoff+1] < 0 ){ /* never defined */
- if( hflag ) werror( "struct/union %.7s never defined", p->sname );
- }
- }
-
- switch( p->sclass ){
-
- case STATIC:
- if( p->suse > 0 ){
- k = lineno;
- lineno = p->suse;
- uerror( "static variable %s unused",
- p->sname );
- lineno = k;
- break;
- }
-
- case EXTERN:
- case USTATIC:
- /* with the xflag, worry about externs not used */
- /* the filename may be wrong here... */
- if( xflag && p->suse >= 0 && !libflag ){
- printf( "%.7s\t%03d\t%o\t%d\t", p->sname, LDX, p->stype, 0 );
- /* we don't really know the file number; we know only the line
- number, so we put only that out */
- printf( "\"???\"\t%d\t%s\n", p->suse, flabel );
- }
-
- case EXTDEF:
- if( p->suse < 0 ){ /* used */
- printf( "%.7s\t%03d\t%o\t%d\t", exname(p->sname), LUM, p->stype, 0 );
- fident( -p->suse );
- }
- break;
- }
-
- }
-
- }
- exit( 0 );
- }
-
- fident( line ){ /* like ident, but lineno = line */
- register temp;
- temp = lineno;
- lineno = line;
- ident();
- lineno = temp;
- }
-
- ident(){ /* write out file and line identification */
- printf( "%s\t%d\t%s\n", ftitle, lineno, flabel );
- }
-
- bfcode( a, n ) int a[]; {
- /* code for the beginning of a function; a is an array of
- indices in stab for the arguments; n is the number */
- /* this must also set retlab */
- register i;
- register struct symtab *cfp;
- register unsigned t;
-
- retlab = 1;
- cfp = &stab[curftn];
-
- /* if variable number of arguments, only print the ones which will be checked */
- if( vaflag > 0 ){
- if( n < vaflag ) werror( "declare the VARARGS arguments you want checked!" );
- else n = vaflag;
- }
- printf( "%.7s\t%03d\t%o\t%d\t", exname(cfp->sname), libflag?LIB:LDI,
- cfp->stype, vaflag>=0?-n:n );
- vaflag = -1;
-
- for( i=0; i<n; ++i ) {
- switch( t = stab[a[i]].stype ){
-
- case ULONG:
- break;
-
- case CHAR:
- case SHORT:
- t = INT;
- break;
-
- case UCHAR:
- case USHORT:
- case UNSIGNED:
- t = UNSIGNED;
- break;
-
- }
-
- printf( "%o\t", t );
- }
- ident();
- }
-
- ctargs( p ) NODE *p; {
- /* count arguments; p points to at least one */
- /* the arguemnts are a tower of commasto the left */
- register c;
- c = 1; /* count the rhs */
- while( p->op == CM ){
- ++c;
- p = p->left;
- }
- return( c );
- }
-
- lpta( p ) NODE *p; {
- TWORD t;
-
- if( p->op == CM ){
- lpta( p->left );
- p = p->right;
- }
- switch( t = p->type ){
-
- case CHAR:
- case SHORT:
- t = INT;
- case LONG:
- case ULONG:
- case INT:
- case UNSIGNED:
- break;
-
- case UCHAR:
- case USHORT:
- t = UNSIGNED;
- break;
-
- case FLOAT:
- printf( "%o\t", DOUBLE );
- return;
-
- default:
- printf( "%o\t", p->type );
- return;
- }
-
- if( p->op == ICON ) printf( "%o<1\t", t );
- else printf( "%o\t", t );
- }
-
- # define VALSET 1
- # define VALUSED 2
- # define VALASGOP 4
- # define VALADDR 8
-
- lprt( p, down, uses ) register NODE *p; {
- register struct symtab *q;
- register id;
- register acount;
- register down1, down2;
- register use1, use2;
- register struct lnm *np1, *np2;
-
- /* first, set variables which are set... */
-
- use1 = use2 = VALUSED;
- if( p->op == ASSIGN ) use1 = VALSET;
- else if( p->op == UNARY AND ) use1 = VALADDR;
- else if( asgop( p->op ) ){ /* =ops */
- use1 = VALUSED|VALSET;
- if( down == EFF ) use1 |= VALASGOP;
- }
-
-
- /* print the lines for lint */
-
- down2 = down1 = VAL;
- acount = 0;
-
- switch( p->op ){
-
- case EQ:
- case NE:
- case GT:
- case GE:
- case LT:
- case LE:
- if( p->left->type == CHAR && p->right->op==ICON && p->right->lval < 0 ){
- werror( "nonportable character comparison" );
- }
- if( (p->op==EQ || p->op==NE ) && ISUNSIGNED(p->left->type) && p->right->op == ICON ){
- if( p->right->lval < 0 && p->right->rval == NONAME && !ISUNSIGNED(p->right->type) ){
- werror( "comparison of unsigned with negative constant" );
- }
- }
- break;
-
- case UGE:
- case ULT:
- if( p->right->op == ICON && p->right->lval == 0 && p->right->rval == NONAME ){
- werror( "unsigned comparison with 0?" );
- break;
- }
- case UGT:
- case ULE:
- if( p->right->op == ICON && p->right->lval <= 0 && !ISUNSIGNED(p->right->type) && p->right->rval == NONAME ){
- werror( "degenerate unsigned comparison" );
- }
- break;
-
- case COMOP:
- down1 = EFF;
-
- case ANDAND:
- case OROR:
- case QUEST:
- down2 = down;
- /* go recursively left, then right */
- np1 = lnp;
- lprt( p->left, down1, use1 );
- np2 = lnp;
- lprt( p->right, down2, use2 );
- lmerge( np1, np2, 0 );
- return;
-
- case SCONV:
- case PCONV:
- case COLON:
- down1 = down2 = down;
- break;
-
- case CALL:
- case STCALL:
- case FORTCALL:
- acount = ctargs( p->right );
- case UNARY CALL:
- case UNARY STCALL:
- case UNARY FORTCALL:
- if( p->left->op == ICON && (id=p->left->rval) != NONAME ){ /* used to be &name */
- printf( "%.7s\t%03d\t%o\t%d\t",
- exname(stab[id].sname),
- down==EFF ? LUE : LUV,
- DECREF(p->left->type), acount );
- if( acount ) lpta( p->right );
- ident();
- }
- break;
-
- case ICON:
- /* look for &name case */
- if( (id = p->rval) >= 0 && id != NONAME ){
- q = &stab[id];
- q->sflags |= (SREF|SSET);
- }
- return;
-
- case NAME:
- if( (id = p->rval) >= 0 && id != NONAME ){
- q = &stab[id];
- if( (uses&VALUSED) && !(q->sflags&SSET) ){
- if( q->sclass == AUTO || q->sclass == REGISTER ){
- if( !ISARY(q->stype ) && !ISFTN(q->stype) && q->stype!=STRTY ){
- werror( "%.7s may be used before set", q->sname );
- q->sflags |= SSET;
- }
- }
- }
- if( uses & VALASGOP ) break; /* not a real use */
- if( uses & VALSET ) q->sflags |= SSET;
- if( uses & VALUSED ) q->sflags |= SREF;
- if( uses & VALADDR ) q->sflags |= (SREF|SSET);
- if( p->lval == 0 ){
- lnp->lid = id;
- lnp->flgs = (uses&VALADDR)?0:((uses&VALSET)?VALSET:VALUSED);
- if( ++lnp >= &lnames[LNAMES] ) --lnp;
- }
- }
- return;
-
- }
-
- /* recurse, going down the right side first if we can */
-
- switch( optype(p->op) ){
-
- case BITYPE:
- np1 = lnp;
- lprt( p->right, down2, use2 );
- case UTYPE:
- np2 = lnp;
- lprt( p->left, down1, use1 );
- }
-
- if( optype(p->op) == BITYPE ){
- if( p->op == ASSIGN && p->left->op == NAME ){ /* special case for a = .. a .. */
- lmerge( np1, np2, 0 );
- }
- else lmerge( np1, np2, p->op != COLON );
- /* look for assignments to fields, and complain */
- if( p->op == ASSIGN && p->left->op == FLD && p->right->op == ICON ) fldcon( p );
- }
-
- }
-
- lmerge( np1, np2, flag ) struct lnm *np1, *np2; {
- /* np1 and np2 point to lists of lnm members, for the two sides
- * of a binary operator
- * flag is 1 if commutation is possible, 0 otherwise
- * lmerge returns a merged list, starting at np1, resetting lnp
- * it also complains, if appropriate, about side effects
- */
-
- register struct lnm *npx, *npy;
-
- for( npx = np2; npx < lnp; ++npx ){
-
- /* is it already there? */
- for( npy = np1; npy < np2; ++npy ){
- if( npx->lid == npy->lid ){ /* yes */
- if( npx->flgs == 0 || npx->flgs == (VALSET|VALUSED) )
- ; /* do nothing */
- else if( (npx->flgs|npy->flgs)== (VALSET|VALUSED) ||
- (npx->flgs&npy->flgs&VALSET) ){
- if( flag ) werror( "%.8s evaluation order undefined", stab[npy->lid].sname );
- }
- if( npy->flgs == 0 ) npx->flgs = 0;
- else npy->flgs |= npx->flgs;
- goto foundit;
- }
- }
-
- /* not there: update entry */
- np2->lid = npx->lid;
- np2->flgs = npx->flgs;
- ++np2;
-
- foundit: ;
- }
-
- /* all finished: merged list is at np1 */
- lnp = np2;
- }
-
- efcode(){
- /* code for the end of a function */
- register struct symtab *cfp;
-
- cfp = &stab[curftn];
- if( retstat & RETVAL ){
- printf( "%.7s\t%03d\t%o\t%d\t", exname(cfp->sname),
- LRV, DECREF( cfp->stype), 0 );
- ident();
- }
- if( !vflag ){
- vflag = argflag;
- argflag = 0;
- }
- if( retstat == RETVAL+NRETVAL )
- werror( "function %.8s has return(e); and return;", cfp->sname);
- }
-
- aocode(p) struct symtab *p; {
- /* called when automatic p removed from stab */
- register struct symtab *cfs;
- cfs = &stab[curftn];
- if(p->suse>0 && !(p->sflags&SMOS) ){
- if( p->sclass == PARAM ){
- if( vflag ) werror( "argument %.7s unused in function %.7s",
- p->sname,
- cfs->sname );
- }
- else {
- if( p->sclass != TYPEDEF ) werror( "%.7s unused in function %.7s",
- p->sname, cfs->sname );
- }
- }
-
- if( p->suse < 0 && (p->sflags & (SSET|SREF|SMOS)) == SSET &&
- !ISARY(p->stype) && !ISFTN(p->stype) ){
-
- werror( "%.7s set but not used in function %.7s", p->sname, cfs->sname );
- }
-
- if( p->stype == STRTY || p->stype == UNIONTY || p->stype == ENUMTY ){
- if( dimtab[p->sizoff+1] < 0 ) werror( "structure %.7s never defined", p->sname );
- }
-
- }
-
- defnam( p ) register struct symtab *p; {
- /* define the current location as the name p->sname */
-
- if( p->sclass == STATIC && p->slevel>1 ) return;
-
- if( !ISFTN( p->stype ) ){
- printf( "%.7s\t%03d\t%o\t%d\t",
- exname(p->sname), libflag?LIB:LDI, p->stype, 0 );
- ident();
- }
- }
-
- zecode( n ){
- /* n integer words of zeros */
- OFFSZ temp;
- temp = n;
- inoff += temp*SZINT;
- ;
- }
-
- andable( p ) NODE *p; { /* p is a NAME node; can it accept & ? */
- register r;
-
- if( p->op != NAME ) cerror( "andable error" );
-
- if( (r = p->rval) < 0 ) return(1); /* labels are andable */
-
- if( stab[r].sclass == AUTO || stab[r].sclass == PARAM ) return(0);
- return(1);
- }
-
- NODE *
- clocal(p) NODE *p; {
-
- /* this is called to do local transformations on
- an expression tree preparitory to its being
- written out in intermediate code.
- */
-
- /* the major essential job is rewriting the
- automatic variables and arguments in terms of
- REG and OREG nodes */
- /* conversion ops which are not necessary are also clobbered here */
- /* in addition, any special features (such as rewriting
- exclusive or) are easily handled here as well */
-
- register o;
- register unsigned t, tl;
-
- switch( o = p->op ){
-
- case SCONV:
- case PCONV:
- if( p->left->type==ENUMTY ){
- p->left = pconvert( p->left );
- }
- /* assume conversion takes place; type is inherited */
- t = p->type;
- tl = p->left->type;
- if( aflag && (tl==LONG||tl==ULONG) && (t!=LONG&&t!=ULONG) ){
- werror( "long assignment may lose accuracy" );
- }
- if( ISPTR(tl) && ISPTR(t) ){
- tl = DECREF(tl);
- t = DECREF(t);
- switch( ISFTN(t) + ISFTN(tl) ){
-
- case 0: /* neither is a function pointer */
- if( talign(t,p->csiz) > talign(tl,p->left->csiz) ){
- if( hflag||pflag ) werror( "possible pointer alignment problem" );
- }
- break;
-
- case 1:
- werror( "questionable conversion of function pointer" );
-
- case 2:
- ;
- }
- }
- p->left->type = p->type;
- p->left->cdim = p->cdim;
- p->left->csiz = p->csiz;
- p->op = FREE;
- return( p->left );
-
- case PVCONV:
- case PMCONV:
- if( p->right->op != ICON ) cerror( "bad conversion");
- p->op = FREE;
- return( buildtree( o==PMCONV?MUL:DIV, p->left, p->right ) );
-
- }
-
- return(p);
- }
-
- NODE *
- offcon( off, t, d, s ) OFFSZ off; TWORD t;{ /* make a structure offset node */
- register NODE *p;
- p = bcon(0);
- p->lval = off/SZCHAR;
- return(p);
- }
-
- noinit(){
- /* storage class for such as "int a;" */
- return( pflag ? EXTDEF : EXTERN );
- }
-
-
- cinit( p, sz ) NODE *p; { /* initialize p into size sz */
- inoff += sz;
- if( p->op == INIT ){
- if( p->left->op == ICON ) return;
- if( p->left->op == NAME && p->left->type == MOE ) return;
- }
- uerror( "illegal initialization" );
- }
-
- char *
- exname( p ) char *p; {
- /* make a name look like an external name in the local machine */
- static char aa[8];
- register int i;
-
- if( !pflag ) return(p);
- for( i=0; i<6; ++i ){
- if( isupper(*p ) ) aa[i] = tolower( *p );
- else aa[i] = *p;
- if( *p ) ++p;
- }
- aa[6] = '\0';
- return( aa );
- }
-
- where(f){ /* print true location of error */
- if( f == 'u' && nerrors>1 ) --nerrors; /* don't get "too many errors" */
- fprintf( stderr, "%s, line %d: ", ftitle, lineno );
- }
-
- /* a number of dummy routines, unneeded by lint */
-
- branch(n){;}
- defalign(n){;}
- deflab(n){;}
- bycode(t,i){;}
- cisreg(t){return(1);} /* everyting is a register variable! */
-
- fldty(p) struct symtab *p; {
- ; /* all types are OK here... */
- }
-
- fldal(t) unsigned t; { /* field alignment... */
- if( t == ENUMTY ) return( ALCHAR ); /* this should be thought through better... */
- if( ISPTR(t) ){ /* really for the benefit of honeywell (and someday IBM) */
- if( pflag ) uerror( "nonportable field type" );
- }
- else uerror( "illegal field type" );
- return(ALINT);
- }
-
- main( argc, argv ) char *argv[]; {
- char *p;
-
- /* handle options */
-
- for( p=argv[1]; *p; ++p ){
-
- switch( *p ){
-
- case '-':
- continue;
-
- case 'L': /* produced by driver program */
- flabel = p;
- goto break2;
-
- case '\0':
- break;
-
- case 'b':
- brkflag = 1;
- continue;
-
- case 'p':
- pflag = 1;
- continue;
-
- case 'c':
- cflag = 1;
- continue;
-
- case 's':
- /* for the moment, -s triggers -h */
-
- case 'h':
- hflag = 1;
- continue;
-
- case 'v':
- vflag = 0;
- continue;
-
- case 'x':
- xflag = 1;
- continue;
-
- case 'a':
- aflag = 1;
- case 'u': /* done in second pass */
- case 'n': /* done in shell script */
- continue;
-
- case 't':
- werror( "option %c now default: see `man 6 lint'", *p );
- continue;
-
- default:
- uerror( "illegal option: %c", *p );
- continue;
-
- }
- }
-
- break2:
- if( !pflag ){ /* set sizes to sizes of target machine */
- # ifdef gcos
- SZCHAR = ALCHAR = 9;
- # else
- SZCHAR = ALCHAR = 8;
- # endif
- SZINT = ALINT = sizeof(int)*SZCHAR;
- SZFLOAT = ALFLOAT = sizeof(float)*SZCHAR;
- SZDOUBLE = ALDOUBLE = sizeof(double)*SZCHAR;
- SZLONG = ALLONG = sizeof(long)*SZCHAR;
- SZSHORT = ALSHORT = sizeof(short)*SZCHAR;
- SZPOINT = ALPOINT = sizeof(int *)*SZCHAR;
- ALSTRUCT = ALINT;
- /* now, fix some things up for various machines (I wish we had "alignof") */
-
- # ifdef pdp11
- ALLONG = ALDOUBLE = ALFLOAT = ALINT;
- #endif
- # ifdef ibm
- ALSTRUCT = ALCHAR;
- #endif
- }
-
- return( mainp1( argc, argv ) );
- }
-
- ctype( type ) unsigned type; { /* are there any funny types? */
- return( type );
- }
-
- commdec( i ){
- /* put out a common declaration */
- register struct symtab *p;
- p = &stab[i];
- printf( "%.7s\t%03d\t%o\t%d\t", exname(p->sname), libflag?LIB:LDC, p->stype, 0 );
- ident();
- }
-
- isitfloat ( s ) char *s; {
- /* s is a character string;
- if floating point is implemented, set dcon to the value of s */
- /* lint version
- */
- dcon = atof( s );
- return( FCON );
- }
-
- fldcon( p ) register NODE *p; {
- /* p is an assignment of a constant to a field */
- /* check to see if the assignment is going to overflow, or otherwise cause trouble */
- register s;
- CONSZ v;
-
- if( !hflag & !pflag ) return;
-
- s = UPKFSZ(p->left->rval);
- v = p->right->lval;
-
- switch( p->left->type ){
-
- case CHAR:
- case INT:
- case SHORT:
- case LONG:
- case ENUMTY:
- if( v>=0 && (v>>(s-1))==0 ) return;
- werror( "precision lost in assignment to (possibly sign-extended) field" );
- default:
- return;
-
- case UNSIGNED:
- case UCHAR:
- case USHORT:
- case ULONG:
- if( v<0 || (v>>s)!=0 ) werror( "precision lost in field assignment" );
-
- return;
- }
-
- }
-