📄 lint.c
字号:
#ifndef lintstatic char sccsid[] = "@(#)lint.c 1.1 92/07/30 SMI"; /* from S5R2 1.7 */#endif#ident "@(#)RELEASE lint1 4.1"/* lint.c * This file contains the major functions for the first pass of lint * * There are basically two types of functions in this file: * functions called directly by the portable C compiler and other * (lint) functions. * * lint functions: * =============== * astype hashes a struct/union line number to ensure uniqueness * ctargs count arguments of a function * fldcon check assignment of a constant to a field * fsave write out a new filename to the intermediate file * lmerge * lprt * lpta * main driver routine for the first pass (lint1) * outdef write info out to the intermediate file * strip strip a filename down to its basename * where print location of an error * * pcc interface routines: * ======================= * andable returns 1 if a node can accept the & operator * aocode called when an automatic is removed from symbol table * asmout called to put an "asm" into the output * bfcode emit code for beginning of function * branch dummy, unused by lint * cinit * clocal do local transformations on the tree * commdec put out a common declaration * ctype dummy for lint * defalign dummy, unused by lint * deflab dummy, unused by lint * defname * ecode emit code for tree (lint processing for whole tree) * efcode emit code for end of function * ejobcode end of job processing * exname create external name * fldal check field alignment * fldty check field type * isitfloat * noinit return storage class for uninitialized objects * offcon make structure offset node * prtdcon * zecode create arg integer words of zero */# include "cpass1.h"# include "messages.h"#ifndef CXREF# include "lerror.h"#endif# include "lmanifest.h"# include <ctype.h># include <signal.h># define VAL 0# define EFF 1#if CXREFextern int ddebug, idebug, bdebug, tdebug, edebug, xdebug;int blocknos[20]; /* CXREF */int blockptr = 0; /* CXREF */int nextblock = 1; /* CXREF */#endifint vflag = 1; /* tell about unused argments */#if CXREFint xflag = 0; /* tell about unused externals */#else/* 28 feb 80 reverse sense of xflag */int xflag = 1; /* tell about unused externals */#endifint 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 */#if CXREFint aflag = 0; /* used to check precision of assignments */#else/* 28 feb 80 reverse sense of aflag */int aflag = 1; /* used to check precision of assignments */int zflag = 0; /* no 'structure never defined' error */int Cflag = 0; /* filter out certain output, for generating libraries */#endif#if CXREFchar *flabel = "xxx";int filecount = 0;#endif#ifndef CXREF# ifdef sparc int host = sparcAL; int target = sparcAL;# endif# ifdef mc68000 int host = mc68020AL; int target = mc68020AL;# endif# ifdef i386 int host = i386AL; int target = i386AL;# endif char sourcename[ BUFSIZ + 1 ] = ""; char *libname = 0; /* name of the library we're generating */ char *builtin_va_alist_name;extern struct alignment altable[];extern struct alignment portalign; /* flags for the "outdef" function */# define USUAL (-101)# define DECTY (-102)# define NOFILE (-103) /* somewhat of a misnomer */# define SVLINE (-104)# define LNAMES 250#else /* CXREF */# define LNAMES 100#endifstruct lnm { int lid; short flgs; } lnames[LNAMES], *lnp;/* contx - check context of node * contx is called for each node during tree walk (fwalk); * it complains about nodes that have null effect. * VAL is passed to a child if that child's value is used * EFF is passed to a child if that child is used in an effects context * * arguments: * p - node pointer * down - value passed down from ancestor * pl, pr - pointers to values to be passed down to descendants */contx( p, down, pl, pr ) register NODE *p; register *pl, *pr;{ *pl = *pr = VAL; switch( p->in.op ){ /* left side of ANDAND, OROR, and QUEST always evaluated for value (value determines if right side is to be evaluated) */ case ANDAND: case OROR: case QUEST: *pr = down; break; /* left side and right side treated identically */ case SCONV: case PCONV: case COLON: *pr = *pl = down; break; /* comma operator uses left side for effect */ 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: /* assignment ops are OK */ if( asgop(p->in.op) ) break; /* struct x f( ); main( ) { (void) f( ); } * the cast call appears as U* TVOID */ if( p->in.op == UNARY MUL && ( p->in.type == STRTY || p->in.type == UNIONTY || p->in.type == TVOID) ) break; /* the compiler does this... */ /* found a null effect ... */ if( down == EFF && hflag && p->in.type != TVOID ) WERROR( MESSAGE( 86 ) ); }}#ifndef CXREF/* ecode - compile code for node */ecode( p ) NODE *p;{ fwalk( p, contx, EFF ); /* do a preorder tree walk */ lnp = lnames; /* initialize pointer to start of array */ lprt( p, EFF, 0, 0 );}ejobcode( flag ){ /* called after processing each job */ /* flag is nonzero if errors were detected */ register k; register struct symtab *p; int i; extern hdrclose( ), unbuffer( ); for (i=0; i<SYMTSZ; ++i) { for (p=stab[i]; p!=NULL; p=p->next) { if( p->stype == STRTY || p->stype == UNIONTY || p->stype == ENUMTY){ if( !zflag && dimtab[p->sizoff+1] < 0 ){ if( hflag ){ if (p->stype == ENUMTY) /* "enum %s never defined" */ WERROR( MESSAGE( 104 ), p->sname ); else /* "struct/union %s never defined" */ WERROR( MESSAGE( 102 ), p->sname ); } } } switch( p->sclass ){ case STATIC: if( p->suse > 0 ){ k = lineno; lineno = p->suse; if (ISFTN(p->stype)) /* "static function %s unused" */ UERROR( MESSAGE( 141 ), p->sname ); else /* "static variable %s unused" */ UERROR( MESSAGE( 101 ), 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; } } } hdrclose( ); unbuffer( ); exit( 0 );}/* astype - hash a struct/union/enum line number to ensure uniqueness */astype( t, i ) ATYPE *t;{ TWORD tt; struct symtab *s; int k=0, l=0; if( (tt=BTYPE(t->aty))==STRTY || tt==UNIONTY || tt==ENUMTY ) { if( i<0 || i>= curdim-3 ) uerror( "lint's little mind is blown" ); else { s = STP(dimtab[i+3]); if( s == NULL ) { k = dimtab[i]; l = X_NONAME; } else { if( s->suse <= 0 ) uerror( "no line number for %s", s->sname ); else { k = dimtab[i]; l = hashstr(s->sname); /* XXX - -p, 8 chars? */ } } } t->extra = k; t->extra1 = l; return( 1 ); } else return( 0 );}/* bfcode - handle the beginning of a function */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 = STP(curftn); if (cfp == NULL) return; /* 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 ) uerror( "declare the VARARGS arguments you want checked!" ); else n = vaflag; } else { /* look for varargs cookie ourselves */ for ( i=0; i<n; ++i) { if (STP(a[i])->sname == builtin_va_alist_name){ /* make sure it looks legal */ if ( i != n - 1 ) uerror("there are parameters after va_alist"); vaflag = n = i; break; } } } fsave( ftitle ); outdef( cfp, cfp->sclass==STATIC? LDS : (libflag?LIB:LDI), vaflag >= 0 ? -(n + 1) : n ); vaflag = -1; /* output the arguments */ if( n ) for( i=0; i<n; ++i ) { register struct symtab *s; s = STP(a[i]); if (s == NULL) { bzero((char *)&t, sizeof(t)); } else { t.aty = s->stype; t.extra = 0; t.extra1 = 0; if( !astype( &t, s->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 - count arguments; p points to at least one */ctargs( p ) NODE *p;{ /* the arguments 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 */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; if (p->in.op==ICON) { t.extra = 1; t.extra1 = p->tn.lval; } else { t.extra = t.extra1 = 0; } if( !astype( &t, p->fn.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 8#define STASG_LEFT 1#define STASG_RIGHT 2lprt( p, down, uses, stasg ) register NODE *p;{ register struct symtab *q; register acount; register down1, down2; register use1, use2; register struct lnm *np1, *np2; extern char *htmpname; /* 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 ) && p->in.op != STASG ){ /* =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: if( ISUNSIGNED(p->in.left->in.type) && p->in.right->in.op == ICON && p->in.right->tn.lval < 0 && p->in.right->tn.rval == NONAME && !ISUNSIGNED(p->in.right->in.type) ) /* "comparison of unsigned with negative constant" */ WERROR( MESSAGE( 21 ) ); goto charchk; 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) /* "nonportable character comparison" */ WERROR(MESSAGE(82)); charchk: if (p->in.left->in.type == CHAR && p->in.right->in.op==ICON && p->in.right->tn.lval < 0) /* "nonportable character comparison" */ WERROR( MESSAGE( 82 ) ); break; case UGE: case ULT: if( p->in.right->in.op == ICON && p->in.right->tn.lval == 0 && p->in.right->tn.rval == NONAME ) { /* "degenerate unsigned comparison" */ WERROR( MESSAGE( 30 ) ); break; } case UGT: case ULE: if ( ISUNSIGNED(p->in.left->in.type) && p->in.right->in.op == ICON && p->in.right->tn.rval == NONAME ) { /* given the "usual arithmetic conversions", which */ /* apply to relational operators, can this ever */ /* happen? */ if (!ISUNSIGNED( p->in.right->in.type ) && p->in.right->tn.lval < 0 ) /* "comparison of unsigned with negative constant" */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -