Bell 32V development
[unix-history] / usr / src / cmd / lint / lpass2.c
# include "lmanifest"
# include "manifest"
# define USED 01
# define VUSED 02
# define EUSED 04
# define RVAL 010
# define VARARGS 0100
typedef struct { TWORD aty; int extra; } atype;
struct line {
char name[8];
int decflag;
atype type;
int nargs;
atype atyp[50];
int fline;
char file[100];
}
l1,
l2,
*pd, /* pointer to line having definition */
*pc, /* pointer to current line read */
*p3; /* used for swapping pc and pd */
int uses = USED;
int hflag = 0;
int pflag = 0;
int xflag = 0;
int uflag = 1;
main( argc, argv ) char *argv[]; {
register char *p;
/* first argument is - options */
if( argc>=2 && argv[1][0] == '-' ){
for( p=argv[1]; *p; ++p ){
switch( *p ){
case 'h':
hflag = 1;
break;
case 'p':
pflag = 1;
break;
case 'x':
xflag = 1;
break;
case 'u':
uflag = 0;
break;
}
}
}
pd = &l1;
pc = &l2;
pd->name[0] = '\0' ;
pd->fline = 0;
pd->file[0] = '\0';
pd->decflag = LDI;
/* main loop: read a line;
if same as last line, check compatibility
if not same as last line, becomes df.
*/
for(;;){
lread();
if( steq(pc->name, pd->name) ) chkcompat();
else {
lastone();
setuse();
p3=pc;
pc = pd;
pd = p3;
}
}
}
lread(){ /* read a line into pc */
register i, n;
getnam( pc->name );
pc->decflag = rdin10();
rdinty( &pc->type );
n = pc->nargs = rdin10();
if( n<0 ) n = -n;
for( i=0; i<n; ++i ){
rdinty( &pc->atyp[i] );
}
getnam( pc->file );
pc->fline = rdin10();
while( getchar() != '\n' ) ; /* VOID */
}
rdin10(){
register val, c, s;
val = 0;
s = 1;
while( (c=getchar()) != '\t' ){
if( c <= 0 ) error( "unexpected EOF" );
else if( c == '-' ) {
s = -1;
continue;
}
else if( c<'0' || c>'9' ) {
error("rotten digit: %o\n", c );
}
val = val*10 + c - '0';
}
return( val*s );
}
rdinty( p ) atype *p; {
register val, c, s;
val = 0;
s = 1;
while( (c=getchar()) != '\t' && c!= '<' ){
if( c <= 0 ) error( "unexpected EOF" );
else if( c == '-' ) {
s = -1;
continue;
}
else if( c<'0' || c>'7' ) {
error("rotten digit: %o\n", c );
}
val = (val<<3) + c - '0';
}
p->aty = val*s;
if( c == '<' ) p->extra = rdin10();
else p->extra = 0;
}
getnam(p) char *p; {
register c;
while( (c=getchar()) != '\t' ){
if( c == '\n' ) error( "rotten name\n" );
if( c <= 0 ) cleanup();
*p++ = c;
}
*p = '\0';
}
/* VARARGS */
error( s, a ) char *s; {
fprintf( stderr, "pass 2 error: " );
fprintf( stderr, s, a );
fprintf( stderr, "\n" );
exit(1);
}
steq(p,q) char *p,*q; { /* check that the p and q names are the same */
while( *p == *q ){
if( *p == 0 ) return(1);
++p;
++q;
}
return(0);
}
chkcompat(){
/* are the types, etc. in pc and pd compatible */
register int i;
setuse();
/* argument check */
if( pd->decflag & (LDI|LIB|LUV|LUE) ){
if( pc->decflag & (LUV|LIB|LUE) ){
if( pd->nargs != pc->nargs ){
if( !(uses&VARARGS) ){
printf( "%.7s: variable # of args.", pd->name );
viceversa();
}
if( pc->nargs > pd->nargs ) pc->nargs = pd->nargs;
if( !(pd->decflag & (LDI|LIB) ) ) {
pd->nargs = pc->nargs;
uses |= VARARGS;
}
}
for( i=0; i<pc->nargs; ++i ){
if( chktype(&pd->atyp[i], &pc->atyp[i]) ){
printf( "%.7s, arg. %d used inconsistently",
pd->name, i+1 );
viceversa();
}
}
}
}
if( (pd->decflag&(LDI|LIB|LUV)) && pc->decflag==LUV ){
if( chktype( &pc->type, &pd->type ) ){
printf( "%.7s value used inconsistently", pd->name );
viceversa();
}
}
/* check for multiple declaration */
if( (pd->decflag&LDI) && (pc->decflag&(LDI|LIB)) ){
printf( "%.7s multiply declared", pd->name );
viceversa();
}
/* do a bit of checking of definitions and uses... */
if( (pd->decflag & (LDI|LIB|LDX|LDC)) && (pc->decflag & (LDX|LDC)) && pd->type.aty != pc->type.aty ){
printf( "%.7s value declared inconsistently", pd->name );
viceversa();
}
/* better not call functions which are declared to be structure or union returning */
if( (pd->decflag & (LDI|LIB|LDX|LDC)) && (pc->decflag & LUE) && pd->type.aty != pc->type.aty ){
/* only matters if the function returns union or structure */
TWORD ty;
ty = pd->type.aty;
if( ISFTN(ty) && ((ty = DECREF(ty))==STRTY || ty==UNIONTY ) ){
printf( "%.7s function value type must be declared before use", pd->name );
viceversa();
}
}
if( pflag && pd->decflag==LDX && pc->decflag == LUM && !ISFTN(pd->type.aty) ){
/* make the external declaration go away */
/* in effect, it was used without being defined */
/* swap pc and pd */
p3 = pc;
pc = pd;
pd = p3;
}
}
viceversa(){
/* print out file comparison */
printf( " %s(%d) :: %s(%d)\n", pd->file, pd->fline, pc->file, pc->fline );
}
/* messages for defintion/use */
char *
mess[2][2] = {
"",
"%.7s used( %s(%d) ), but not defined\n",
"%.7s defined( %s(%d) ), but never used\n",
"%.7s declared( %s(%d) ), but never used or defined\n"
};
lastone(){
/* called when pc and pd are at last different */
register nu, nd;
nu = nd = 0;
if( !(uses&USED) && pd->decflag != LIB ) {
if( !steq(pd->name,"main") )
nu = 1;
}
if( !ISFTN(pd->type.aty) ){
switch( pd->decflag ){
case LIB:
nu = nd = 0; /* don't complain about uses on libraries */
break;
case LDX:
if( !xflag ) break;
case LUV:
case LUE:
case LUM:
nd = 1;
}
}
if( uflag && ( nu || nd ) ) printf( mess[nu][nd], pd->name, pd->file, pd->fline );
if( (uses&(RVAL+EUSED)) == (RVAL+EUSED) ){
printf( "%.7s returns value which is %s ignored\n", pd->name,
uses&VUSED ? "sometimes" : "always" );
}
if( (uses&(RVAL+VUSED)) == (VUSED) && (pd->decflag&(LDI|LIB)) ){
printf( "%.7s value is used, but none returned\n", pd->name );
}
/* clean up pc, in preparation for the next thing */
uses = 0;
if( pc->nargs < 0 ){
pc->nargs = -pc->nargs;
uses = VARARGS;
}
}
cleanup(){ /* call lastone and die gracefully */
lastone();
exit(0);
}
setuse(){ /* check new type to ensure that it is used */
switch( pc->decflag ){
case LRV:
uses |= RVAL;
return;
case LUV:
uses |= VUSED+USED;
return;
case LUE:
uses |= EUSED+USED;
return;
case LUM:
uses |= USED;
return;
}
}
chktype( pt1, pt2 ) register atype *pt1, *pt2; {
/* check the two type words to see if they are compatible */
/* for the moment, enums are turned into ints, and should be checked as such */
if( pt1->aty == ENUMTY ) pt1->aty = INT;
if( pt2->aty == ENUMTY ) pt2->aty = INT;
if( pt2->extra ){ /* constant passed in */
if( pt1->aty == UNSIGNED && pt2->aty == INT ) return( 0 );
else if( pt1->aty == ULONG && pt2->aty == LONG ) return( 0 );
}
else if( pt1->extra ){ /* for symmetry */
if( pt2->aty == UNSIGNED && pt1->aty == INT ) return( 0 );
else if( pt2->aty == ULONG && pt1->aty == LONG ) return( 0 );
}
return( pt1->aty != pt2->aty );
}