|
|
researchv10 Norman
# include "manifest"
# include "lint.h"
# define USED 01
# define VUSED 02
# define EUSED 04
# define RVAL 010
# define VARARGS 0100
# define NSZ 2048
# define TYSZ 3500
# define FSZ 250
# define NTY 50
typedef struct sty STYPE;
struct sty { ATYPE t; STYPE *next; };
typedef struct sym {
#ifndef FLEXNAMES
char name[LCHNM];
#else
char *name;
#endif
short nargs;
int decflag;
int fline;
STYPE symty;
int fno;
int use;
} STAB;
STAB stab[NSZ];
STAB *find();
STYPE tary[TYSZ];
STYPE *tget();
#ifndef FLEXNAMES
char fnm[FSZ][LFNM];
#else
char *fnm[FSZ];
#endif
#ifdef FLEXNAMES
char *getstr();
#endif
int tfree; /* used to allocate types */
int ffree; /* used to save filenames */
struct ty atyp[NTY];
/* r is where all the input ends up */
union rec r;
int hflag = 0;
int pflag = 0;
int xflag = 0;
int uflag = 1;
int ddddd = 0;
int cfno; /* current file number */
#ifdef FMTARGS
FILE *stmpfile; /* string tmp file pointer */
char *stmpname; /* string tmp file name */
#endif
main( argc, argv ) char *argv[]; {
register char *p;
/* first argument is intermediate file */
/* second argument is - options */
#ifdef FMTARGS
fmtinit();
#endif
for( ; argc>2 && argv[argc-1][0] == '-' ; --argc ){
for( p=argv[argc-1]; *p; ++p ){
switch( *p ){
case 'h':
hflag = 1;
break;
case 'p':
pflag = 1;
break;
case 'x':
xflag = 1;
break;
case 'X':
ddddd = 1;
break;
case 'u':
uflag = 0;
break;
#ifdef FMTARGS
case 'S':
for (stmpname = p + 1; p[1]; p++);
if (!(stmpfile = fopen (stmpname, "r"))) {
error ("%s: can't open", stmpname);
exit (1);
}
break;
#endif
}
}
}
if( argc < 2 || !freopen( argv[1], "r", stdin ) ){
error( "cannot open intermediate file" );
exit( 1 );
}
mloop( LDI|LIB );
rewind( stdin );
mloop( LDC|LDX );
rewind( stdin );
mloop( LRV|LUV|LUE|LUM );
cleanup();
return(0);
}
mloop( m ){
/* do the main loop */
register STAB *q;
while( lread(m) ){
q = find();
if( q->decflag ) chkcompat(q);
else setuse(q);
}
}
lread(m){ /* read a line into r.l */
register n;
for(;;) {
if( fread( (char *)&r, sizeof(r), 1, stdin ) <= 0 ) return(0);
if( r.l.decflag & LFN ){
/* new filename */
#ifdef FLEXNAMES
r.f.fn = getstr();
#endif
setfno( r.f.fn );
continue;
}
#ifdef FLEXNAMES
r.l.name = getstr();
#endif
n = r.l.nargs;
if( n<0 ) n = -n;
if( n ){
if( n>=NTY ) error( "more than %d args?", n );
fread( (char *)atyp, sizeof(ATYPE), n, stdin );
}
if( ( r.l.decflag & m ) ) return( 1 );
}
}
setfno( s ) char *s; {
/* look up current file names */
/* first, strip backwards to the beginning or to the first / */
int i;
/* now look up s */
for( i=0; i<ffree; ++i ){
#ifndef FLEXNAMES
if( !strncmp( s, fnm[i], LFNM ) ){
#else
if (fnm[i] == s){
#endif
cfno = i;
return;
}
}
/* make a new entry */
if( ffree >= FSZ ) error( "more than %d files", FSZ );
#ifndef FLEXNAMES
strncpy( fnm[ffree], s, LFNM );
#else
fnm[ffree] = s;
#endif
cfno = ffree++;
}
/* VARARGS */
error( s, a ) char *s; {
#ifndef FLEXNAMES
fprintf( stderr, "pass 2 error:(file %.*s) ", LFNM, fnm[cfno] );
#else
fprintf( stderr, "pass 2 error:(file %s) ", fnm[cfno] );
#endif
fprintf( stderr, s, a );
fprintf( stderr, "\n" );
exit(1);
}
STAB *
find(){
/* for this to work, NSZ should be a power of 2 */
register h=0;
#ifndef FLEXNAMES
{ register char *p, *q;
for( h=0,p=r.l.name,q=p+LCHNM; *p&&p<q; ++p) {
h = (h<<1)+ *p;
if( h>=NSZ ){
h = (h+1)&(NSZ-1);
}
}
}
#else
h = ((int)r.l.name)%NSZ;
#endif
{ register STAB *p, *q;
for( p=q= &stab[h]; q->decflag; ){
/* this call to strncmp should be taken out... */
#ifndef FLEXNAMES
if( !strncmp( r.l.name, q->name, LCHNM)) return(q);
#else
if (r.l.name == q->name) return (q);
#endif
if( ++q >= &stab[NSZ] ) q = stab;
if( q == p ) error( "too many names defined" );
}
#ifndef FLEXNAMES
strncpy( q->name, r.l.name, LCHNM );
#else
q->name = r.l.name;
#endif
return( q );
}
}
STYPE *
tget(){
if( tfree >= TYSZ ){
error( "too many types needed" );
}
return( &tary[tfree++] );
}
chkcompat(q) STAB *q; {
/* are the types, etc. in r.l and q compatible */
register int i;
STYPE *qq;
setuse(q);
/* argument check */
if( q->decflag & (LDI|LIB|LUV|LUE) ){
if( r.l.decflag & (LUV|LIB|LUE) ){
#ifdef FMTARGS
if (q->decflag & (LPF|LSF)) {
fmtcheck (q);
if(r.l.nargs > q->nargs)
r.l.nargs = q->nargs;
q->use |= VARARGS;
}
#endif
if( q->nargs != r.l.nargs ){
if( !(q->use&VARARGS) ){
#ifndef FLEXNAMES
printf( "%.8s: variable # of args.", q->name );
#else
printf( "%s: variable # of args.", q->name );
#endif
viceversa(q);
}
if( r.l.nargs > q->nargs ) r.l.nargs = q->nargs;
if( !(q->decflag & (LDI|LIB) ) ) {
q->nargs = r.l.nargs;
q->use |= VARARGS;
}
}
for( i=0,qq=q->symty.next; i<r.l.nargs; ++i,qq=qq->next){
if( chktype( &qq->t, &atyp[i] ) ){
#ifndef FLEXNAMES
printf( "%.8s, arg. %d used inconsistently",
#else
printf( "%s, arg. %d used inconsistently",
#endif
q->name, i+1 );
viceversa(q);
}
}
}
}
if( (q->decflag&(LDI|LIB|LUV)) && r.l.decflag==LUV ){
if( chktype( &r.l.type, &q->symty.t ) ){
#ifndef FLEXNAMES
printf( "%.8s value used inconsistently", q->name );
#else
printf( "%s value used inconsistently", q->name );
#endif
viceversa(q);
}
}
/* check for multiple declaration */
if( (q->decflag&LDI) && (r.l.decflag&(LDI|LIB)) ){
#ifndef FLEXNAMES
printf( "%.8s multiply declared", q->name );
#else
printf( "%s multiply declared", q->name );
#endif
viceversa(q);
}
/* do a bit of checking of definitions and uses... */
if( (q->decflag & (LDI|LIB|LDX|LDC|LUM)) && (r.l.decflag & (LDX|LDC|LUM)) && q->symty.t.aty != r.l.type.aty ){
#ifndef FLEXNAMES
printf( "%.8s value declared inconsistently", q->name );
#else
printf( "%s value declared inconsistently", q->name );
#endif
viceversa(q);
}
/* better not call functions which are declared to be structure or union returning */
if( (q->decflag & (LDI|LIB|LDX|LDC)) && (r.l.decflag & LUE) && q->symty.t.aty != r.l.type.aty ){
/* only matters if the function returns union or structure */
TWORD ty;
ty = q->symty.t.aty;
if( ISFTN(ty) && ((ty = DECREF(ty))==STRTY || ty==UNIONTY ) ){
#ifndef FLEXNAMES
printf( "%.8s function value type must be declared before use", q->name );
#else
printf( "%s function value type must be declared before use", q->name );
#endif
viceversa(q);
}
}
if( pflag && q->decflag==LDX && r.l.decflag == LUM && !ISFTN(q->symty.t.aty) ){
/* make the external declaration go away */
/* in effect, it was used without being defined */
}
}
viceversa(q) STAB *q; {
/* print out file comparison */
#ifndef FLEXNAMES
printf( " %.*s(%d) :: %.*s(%d)\n",
LFNM, fnm[q->fno], q->fline,
LFNM, fnm[cfno], r.l.fline );
#else
printf( " %s(%d) :: %s(%d)\n",
fnm[q->fno], q->fline,
fnm[cfno], r.l.fline );
#endif
}
/* messages for defintion/use */
char *
mess[2][2] ={
"",
#ifndef FLEXNAMES
"%.8s used( %.*s(%d) ), but not defined\n",
"%.8s defined( %.*s(%d) ), but never used\n",
"%.8s declared( %.*s(%d) ), but never used or defined\n"
#else
"%s used( %s(%d) ), but not defined\n",
"%s defined( %s(%d) ), but never used\n",
"%s declared( %s(%d) ), but never used or defined\n"
#endif
};
lastone(q) STAB *q; {
register nu, nd, uses;
if( ddddd ) pst(q);
nu = nd = 0;
uses = q->use;
#ifdef FMTARGS
/* not needed anymore, right? */
q->decflag &= ~(LPF|LSF);
#endif
if( !(uses&USED) && q->decflag != LIB ) {
#ifndef FLEXNAMES
if( strncmp(q->name,"main",7) )
#else
if (strcmp(q->name, "main"))
#endif
nu = 1;
}
if( !ISFTN(q->symty.t.aty) ){
switch( q->decflag ){
case LIB:
nu = nd = 0; /* don't complain about uses on libraries */
break;
case LDX:
if( !xflag ) break;
case LUV:
case LUE:
/* 01/04/80 */ case LUV | LUE:
case LUM:
nd = 1;
}
}
if( uflag && ( nu || nd ) ) printf( mess[nu][nd],
#ifndef FLEXNAMES
q->name, LFNM, fnm[q->fno], q->fline );
#else
q->name, fnm[q->fno], q->fline );
#endif
if( (uses&(RVAL+EUSED)) == (RVAL+EUSED) ){
#ifndef FLEXNAMES
printf( "%.8s returns value which is %s ignored\n", q->name,
#else
printf( "%s returns value which is %s ignored\n", q->name,
#endif
uses&VUSED ? "sometimes" : "always" );
}
if( (uses&(RVAL+VUSED)) == (VUSED) && (q->decflag&(LDI|LIB)) ){
#ifndef FLEXNAMES
printf( "%.8s value is used, but none returned\n", q->name );
#else
printf( "%s value is used, but none returned\n", q->name );
#endif
}
}
cleanup(){ /* call lastone and die gracefully */
STAB *q;
for( q=stab; q< &stab[NSZ]; ++q ){
if( q->decflag ) lastone(q);
}
exit(0);
}
setuse(q) STAB *q; { /* check new type to ensure that it is used */
if( !q->decflag ){ /* new one */
q->decflag = r.l.decflag;
q->symty.t = r.l.type;
if( r.l.nargs < 0 ){
q->nargs = -r.l.nargs;
q->use = VARARGS;
}
else {
q->nargs = r.l.nargs;
q->use = 0;
}
q->fline = r.l.fline;
q->fno = cfno;
if( q->nargs ){
int i;
STYPE *qq;
for( i=0,qq= &q->symty; i<q->nargs; ++i,qq=qq->next ){
qq->next = tget();
qq->next->t = atyp[i];
}
}
}
switch( r.l.decflag ){
case LRV:
q->use |= RVAL;
return;
case LUV:
q->use |= VUSED+USED;
return;
case LUE:
q->use |= EUSED+USED;
return;
/* 01/04/80 */ case LUV | LUE:
case LUM:
q->use |= USED;
return;
}
}
chktype( pt1, pt2 ) register ATYPE *pt1, *pt2; {
TWORD t;
/* 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( (t=BTYPE(pt1->aty)==STRTY) || t==UNIONTY ){
return( pt1->aty!=pt2->aty || (
pt1->extra!=pt2->extra ) );
}
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 );
}
struct tb { int m; char * nm };
ptb( v, tp ) struct tb *tp; {
/* print a value from the table */
int flag;
flag = 0;
for( ; tp->m; ++tp ){
if( v&tp->m ){
if( flag++ ) putchar( '|' );
printf( "%s", tp->nm );
}
}
}
pst( q ) STAB *q; {
/* give a debugging output for q */
static struct tb dfs[] = {
LDI, "LDI",
LIB, "LIB",
LDC, "LDC",
LDX, "LDX",
LRV, "LRV",
LUV, "LUV",
LUE, "LUE",
LUM, "LUM",
#ifdef FMTARGS
LPF, "printf-like",
LSF, "scanf-like",
#endif
0, "" };
static struct tb us[] = {
USED, "USED",
VUSED, "VUSED",
EUSED, "EUSED",
RVAL, "RVAL",
VARARGS, "VARARGS",
0, 0,
};
#ifndef FLEXNAMES
printf( "%.8s (", q->name );
#else
printf( "%s (", q->name );
#endif
ptb( q->decflag, dfs );
printf( "), use= " );
ptb( q->use, us );
printf( ", line %d, nargs=%d\n", q->fline, q->nargs );
}
#ifdef FLEXNAMES
pty( t, name ) TWORD t; {
static char * tnames[] = {
"void", "farg", "char", "short",
"int", "long", "float", "double",
"struct xxx", "union %s", "enum", "moety",
"unsigned char", "unsigned short", "unsigned", "unsigned long",
"?", "?"
};
printf( "%s ", tnames[BTYPE(t)] );
pty1( t, name, (8 * sizeof (int) - BTSHIFT) / TSHIFT );
}
pty1( t, name, level ) TWORD t; {
register TWORD u;
if( level < 0 ){
printf( "%s", name );
return;
}
u = t >> level * TSHIFT;
if( ISPTR(u) ){
printf( "*" );
pty1( t, name, level-1 );
}
else if( ISFTN(u) ){
if( level > 0 && ISPTR(u << TSHIFT) ){
printf( "(" );
pty1( t, name, level-1 );
printf( ")()" );
}
else {
pty1( t, name, level-1 );
printf( "()" );
}
}
else if( ISARY(u) ){
if( level > 0 && ISPTR(u << TSHIFT) ){
printf( "(" );
pty1( t, name, level-1 );
printf( ")[]" );
}
else {
pty1( t, name, level-1 );
printf( "[]" );
}
}
else {
pty1( t, name, level-1 );
}
}
char *
getstr()
{
char buf[BUFSIZ];
register char *cp = buf;
register int c;
if (feof(stdin) || ferror(stdin))
return("");
while ((c = getchar()) > 0)
*cp++ = c;
if (c < 0) {
fprintf(stderr, "pass 2 error: intermediate file format error (getstr)");
exit(1);
}
*cp++ = 0;
return (hash(buf));
}
#define NSAVETAB 4096
char *savetab;
int saveleft;
char *
savestr(cp)
register char *cp;
{
register int len;
len = strlen(cp) + 1;
if (len > saveleft) {
saveleft = NSAVETAB;
if (len > saveleft)
saveleft = len;
savetab = (char *)malloc(saveleft);
if (savetab == 0) {
fprintf(stderr, "pass 2 error: ran out of memory (savestr)");
exit(1);
}
}
strncpy(savetab, cp, len);
cp = savetab;
savetab += len;
saveleft -= len;
return (cp);
}
/*
* The definition for the segmented hash tables.
*/
#define MAXHASH 20
#define HASHINC 1013
struct ht {
char **ht_low;
char **ht_high;
int ht_used;
} htab[MAXHASH];
char *
hash(s)
char *s;
{
register char **h;
register i;
register char *cp;
struct ht *htp;
int sh;
/*
* The hash function is a modular hash of
* the sum of the characters with the sum
* doubled before each successive character
* is added.
*/
cp = s;
i = 0;
while (*cp)
i = i*2 + *cp++;
sh = (i&077777) % HASHINC;
cp = s;
/*
* There are as many as MAXHASH active
* hash tables at any given point in time.
* The search starts with the first table
* and continues through the active tables
* as necessary.
*/
for (htp = htab; htp < &htab[MAXHASH]; htp++) {
if (htp->ht_low == 0) {
register char **hp =
(char **) calloc(sizeof (char **), HASHINC);
if (hp == 0) {
fprintf(stderr, "pass 2 error: ran out of memory (hash)");
exit(1);
}
htp->ht_low = hp;
htp->ht_high = htp->ht_low + HASHINC;
}
h = htp->ht_low + sh;
/*
* quadratic rehash increment
* starts at 1 and incremented
* by two each rehash.
*/
i = 1;
do {
if (*h == 0) {
if (htp->ht_used > (HASHINC * 3)/4)
break;
htp->ht_used++;
*h = savestr(cp);
return (*h);
}
if (**h == *cp && strcmp(*h, cp) == 0)
return (*h);
h += i;
i += 2;
if (h >= htp->ht_high)
h -= HASHINC;
} while (i < HASHINC);
}
fprintf(stderr, "pass 2 error: ran out of hash tables");
exit(1);
}
char *tstrbuf[1];
#endif
# ifdef FMTARGS
#define FMTSIZE 256
char *getfmt();
static char pftab[256], /* printf */
pfltab[128], /* printf %l? */
sftab[256], /* scanf */
sfhtab[128], /* scanf %h? */
sfltab[128]; /* scanf %l? */
typedef struct {
char *fm_s; /* format characters of interest */
char fm_ty; /* expected arg type for fm_c */
char fm_lty; /* expected type if preceded by `l' */
char fm_hty; /* expected type if preceded by `h' */
} Fmtinit;
static Fmtinit pinit[] = {
{ "dox", INT, LONG },
{ "efgEG", DOUBLE },
{ "c", INT },
{ "s", CHAR+PTR },
#ifdef USGFMT
{ "uX", INT, LONG },
#else
{ "DOX", LONG },
{ "u", UNSIGNED, ULONG },
#endif
{ 0 }
};
static Fmtinit sinit[] = {
{ "dox", INT+PTR, LONG+PTR, SHORT+PTR },
{ "efg", FLOAT+PTR, DOUBLE+PTR },
{ "cs[", CHAR+PTR },
#ifdef USGFMT
{ "u", UNSIGNED+PTR, ULONG+PTR, USHORT+PTR },
#else
{ "DOX", LONG+PTR },
{ "EFG", DOUBLE+PTR },
#endif
{ 0 }
};
chkprintf (q, arg, fmt)
STAB *q;
register int arg;
register char *fmt;
{
register int c, d;
register TWORD ty;
while (c = *fmt++) {
if (c != '%' || (c = *fmt++) == '%')
continue;
for (; c=='-' || c=='+' || c=='#' || c==' '; c = *fmt++);
if (c == '*') {
fmtarg (q, arg++, INT, '*', 0);
c = *fmt++;
}
else for (; c >= '0' && c <= '9'; c = *fmt++);
if (c == '.')
if ((c = *fmt++) == '*') {
fmtarg (q, arg++, INT, '*', 0);
c = *fmt++;
}
else for (; c >= '0' && c <= '9'; c = *fmt++);
ty = pftab[c];
if (c == 'l' && pftab[c = *fmt++]) {
d = 'l';
ty = pfltab[c];
}
else d = 0;
if (ty)
fmtarg (q, arg++, ty, c, d);
else goto bad;
}
if (arg < r.l.nargs)
fmterror (q, "too many args for format");
return;
bad:
fmterror (q, "malformed format string");
return;
}
chkscanf (q, arg, fmt)
STAB *q;
register int arg;
register char *fmt;
{
register int c, d = 0, suppress;
TWORD ty;
while (c = *fmt++) {
if (c != '%' || (c = *fmt++) == '%')
continue;
if (suppress = (c == '*'))
c = *fmt++;
for (; c >= '0' && c <= '9'; c = *fmt++);
ty = sftab[c];
if (c == '[') {
if ((c = *fmt++) == '^')
c = *fmt++;
if (c == ']')
c = *fmt++;
for (; c && c != ']'; c = *fmt++);
if (c != ']')
goto bad;
c = '[';
}
d = 0;
if (c == 'l' || c == 'h') {
d = c;
if (sftab[c = *fmt++])
ty = fmt[-2] == 'l' ? sfltab[c] : sfhtab[c];
}
if (!ty)
goto bad;
else if (!suppress)
fmtarg (q, arg++, ty, c, d);
}
if (arg < r.l.nargs)
fmterror (q, "too many args for format");
return;
bad:
fmterror (q, "malformed format string");
return;
}
fmtarg (q, arg, ty, c, d)
STAB *q;
char c, d;
int arg;
TWORD ty;
{
char buf[16];
TWORD ty2;
if (arg >= r.l.nargs) {
if (arg == r.l.nargs)
fmterror (q, "too few args for format");
return;
}
#define deunsign(x) (ISUNSIGNED(BTYPE(x))?((x)&~BTMASK|DEUNSIGN(BTYPE(x))):(x))
ty = deunsign (ty);
ty2 = deunsign (atyp[arg].aty);
if (ty == ty2) /* fat chance ... */
return;
if (sizeof (int) == sizeof (long))
if ((ty & TMASK) == (ty2 & TMASK))
if (BTYPE (ty) == INT && BTYPE (ty2) == LONG ||
BTYPE (ty) == LONG && BTYPE (ty2) == INT)
return;
prflex (q->name);
printf (": %%%.1s%c for ", &d, c);
sprintf (buf, "arg %d", arg+1);
pty (atyp[arg].aty, buf);
viceversa (q);
return;
}
fmtcheck (q)
STAB *q;
{
char *fmt;
int arg = q->nargs;
if (r.l.nargs < arg) /* somebody else will complain */
return;
if (arg < 1) /* should've been caught in pass 1 */
return;
if (!(fmt = getfmt (atyp+arg-1)))
return;
if (q->decflag & LPF)
chkprintf (q, arg, fmt);
else if (q->decflag & LSF)
chkscanf (q, arg, fmt);
return;
}
fmterror (q, msg)
STAB *q;
char *msg;
{
prflex (q->name);
printf (": %s", msg);
viceversa (q);
}
int
fmtinit()
{
char *s;
int i;
for (i = 0; s = pinit[i].fm_s; i++)
for (; *s; s++) {
pftab[*s] = pinit[i].fm_ty;
pfltab[*s] = pinit[i].fm_lty;
}
for (i = 0; s = sinit[i].fm_s; i++)
for (; *s; s++) {
sftab[*s] = sinit[i].fm_ty;
sfhtab[*s] = sinit[i].fm_hty;
sfltab[*s] = sinit[i].fm_lty;
}
return;
}
char *
getfmt (a)
register ATYPE *a;
{
static char fmt[FMTSIZE];
register char *s = fmt;
register int c;
if (a->straddr <= 0)
return (0); /* not a string constant */
if (fseek (stmpfile, a->straddr, 0))
error ("cannot fseek string file");
while ((c = fgetc (stmpfile)) != EOF && c && s < fmt+FMTSIZE-1)
*s++ = c;
*s = '\0';
return (fmt);
}
prflex (name)
char *name;
{
#ifdef FLEXNAMES
printf ("%s", name);
#else
printf ("%.8s", name);
#endif
}
# endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.