📄 lint.c
字号:
#ifndef lintstatic char *sccsid = "@(#)lint.c 4.2 (ULTRIX) 12/9/87";#endif lint/************************************************************************ * * * Copyright (c) 1984 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//************************************************************************ * Modification History * * * * David Metsky, 2-Jul-87, 2.4(2.2) * 003 Made it OK to do a greater than of an unsigned number against * * 0. * * * * Lu Anne Van de Pas, 13-Mar-86, 2.0 * * 002 Added functions cvtfloat and cvtdouble to distinguish between * * double and float constants. * * David L. Ballenger, 14-Nov-1984, 1.2 * * 001 Add definitions of ALSTACK so that code shared with PCC will * * work * * * ************************************************************************/# 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 ALSTACK = 32;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 to check precision of assignments */int zflag = 0; /* no 'structure never defined' error */int Cflag = 0; /* filter out certain output, for generating libraries */char *libname = 0; /* name of the library we're generating */ /* flags for the "outdef" function */# define USUAL (-101)# define DECTY (-102)# define NOFILE (-103)# define SVLINE (-104)# define LNAMES 250struct lnm { short lid, flgs; } lnames[LNAMES], *lnp;contx( p, down, pl, pr ) register NODE *p; register *pl, *pr; { *pl = *pr = VAL; switch( p->in.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->in.op) ) break; if( p->in.op == UNARY MUL && ( p->in.type == STRTY || p->in.type == UNIONTY || p->in.type == UNDEF) ) { /* struct x f( ); main( ) { (void) f( ); } * the the cast call appears as U* UNDEF */ 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( !zflag && dimtab[p->sizoff+1] < 0 ){ /* never defined */#ifndef FLEXNAMES if( hflag ) werror( "struct/union %.8s never defined", p->sname );#else if( hflag ) werror( "struct/union %s never defined", p->sname );#endif } } switch( p->sclass ){ case STATIC: if( p->suse > 0 ){ k = lineno; lineno = p->suse;#ifndef FLEXNAMES uerror( "static variable %.8s unused",#else uerror( "static variable %s unused",#endif p->sname ); lineno = k; break; } /* no statics in libraries */ if( Cflag ) 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 ){ outdef( p, LDX, NOFILE ); } case EXTDEF: if( p->suse < 0 ){ /* used */ outdef( p, LUM, SVLINE ); } break; } } } exit( 0 ); }astype( t, i ) ATYPE *t; { TWORD tt; int j, k=0, l=0; if( (tt=BTYPE(t->aty))==STRTY || tt==UNIONTY ){ if( i<0 || i>= DIMTABSZ-3 ){ werror( "lint's little mind is blown" ); } else { j = dimtab[i+3]; if( j<0 || j>SYMTSZ ){ k = dimtab[i]; l = X_NONAME | stab[j].suse; } else { if( stab[j].suse <= 0 ) {#ifndef FLEXNAMES werror( "no line number for %.8s",#else werror( "no line number for %s",#endif stab[j].sname ); } else { k = dimtab[i];#ifdef FLEXNAMES l = hashstr(stab[j].sname);#else l = hashstr(stab[j].sname, LCHNM);#endif } } } t->extra = k; t->extra1 = l; return( 1 ); } else return( 0 ); }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; static ATYPE t; retlab = 1; cfp = &stab[curftn]; /* if creating library, don't do static functions */ if( Cflag && cfp->sclass == STATIC ) return; /* 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; } fsave( ftitle ); if( cfp->sclass == STATIC ) outdef( cfp, LST, vaflag>=0?-n:n ); else outdef( cfp, libflag?LIB:LDI, vaflag>=0?-n:n ); vaflag = -1; /* output the arguments */ if( n ){ for( i=0; i<n; ++i ) { t.aty = stab[a[i]].stype; t.extra = 0; t.extra1 = 0; if( !astype( &t, stab[a[i]].sizoff ) ) { switch( t.aty ){ case ULONG: break; case CHAR: case SHORT: t.aty = INT; break; case UCHAR: case USHORT: case UNSIGNED: t.aty = UNSIGNED; break; } } fwrite( (char *)&t, sizeof(ATYPE), 1, stdout ); } } }ctargs( p ) NODE *p; { /* count arguments; p points to at least one */ /* the arguemnts are a tower of commas to the left */ register c; c = 1; /* count the rhs */ while( p->in.op == CM ){ ++c; p = p->in.left; } return( c ); }lpta( p ) NODE *p; { static ATYPE t; if( p->in.op == CM ){ lpta( p->in.left ); p = p->in.right; } t.aty = p->in.type; t.extra = (p->in.op==ICON); t.extra1 = 0; if( !astype( &t, p->in.csiz ) ) { switch( t.aty ){ case CHAR: case SHORT: t.aty = INT; case LONG: case ULONG: case INT: case UNSIGNED: break; case UCHAR: case USHORT: t.aty = UNSIGNED; break; case FLOAT: t.aty = DOUBLE; t.extra = 0; break; default: t.extra = 0; break; } } fwrite( (char *)&t, sizeof(ATYPE), 1, stdout ); }# define VALSET 1# define VALUSED 2# define VALASGOP 4# define VALADDR 8lprt( 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->in.op == ASSIGN ) use1 = VALSET; else if( p->in.op == UNARY AND ) use1 = VALADDR; else if( asgop( p->in.op ) ){ /* =ops */ use1 = VALUSED|VALSET; if( down == EFF ) use1 |= VALASGOP; } /* print the lines for lint */ down2 = down1 = VAL; acount = 0; switch( p->in.op ){ case EQ: case NE: case GT: case GE: case LT: case LE: if( p->in.left->in.type == CHAR && p->in.right->in.op==ICON && p->in.right->tn.lval < 0 ){ werror( "nonportable character comparison" ); } if( (p->in.op==EQ || p->in.op==NE ) && ISUNSIGNED(p->in.left->in.type) && p->in.right->in.op == ICON ){ if( p->in.right->tn.lval < 0 && p->in.right->tn.rval == NONAME && !ISUNSIGNED(p->in.right->in.type) ){ werror( "comparison of unsigned with negative constant" ); } } break; case UGE: case ULT: if( p->in.right->in.op == ICON && p->in.right->tn.lval == 0 && p->in.right->tn.rval == NONAME ){ werror( "unsigned comparison with 0?" ); break; } case ULE: 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 ){ werror( "degenerate unsigned comparison" ); } break; case UGT: /* 003 - dnm */ 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 ){ 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->in.left, down1, use1 ); np2 = lnp; lprt( p->in.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->in.right ); case UNARY CALL: case UNARY STCALL: case UNARY FORTCALL: if( p->in.left->in.op == ICON && (id=p->in.left->tn.rval) != NONAME ){ /* used to be &name */ struct symtab *sp = &stab[id]; int lty; fsave( ftitle ); /* * if we're generating a library -C then * we don't want to output references to functions */ if( Cflag ) break; /* if a function used in an effects context is * cast to type void then consider its value * to have been disposed of properly * thus a call of type undef in an effects * context is construed to be used in a value * context */ if ((down == EFF) && (p->in.type != UNDEF)) { lty = LUE; } else if (down == EFF) { lty = LUV | LUE; } else { lty = LUV; } outdef( sp, lty, acount ); if( acount ) { lpta( p->in.right ); } } break; case ICON: /* look for &name case */ if( (id = p->tn.rval) >= 0 && id != NONAME ){ q = &stab[id]; q->sflags |= (SREF|SSET); q->suse = -lineno; } return; case NAME: if( (id = p->tn.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 && q->stype!=UNIONTY ){#ifndef FLEXNAMES werror( "%.8s may be used before set", q->sname );#else werror( "%s may be used before set", q->sname );#endif 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->tn.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->in.op) ){ case BITYPE: np1 = lnp; lprt( p->in.right, down2, use2 ); case UTYPE: np2 = lnp; lprt( p->in.left, down1, use1 ); } if( optype(p->in.op) == BITYPE ){ if( p->in.op == ASSIGN && p->in.left->in.op == NAME ){ /* special case for a = .. a .. */ lmerge( np1, np2, 0 ); } else lmerge( np1, np2, p->in.op != COLON ); /* look for assignments to fields, and complain */ if( p->in.op == ASSIGN && p->in.left->in.op == FLD && p->in.right->in.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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -