/* these are appropriate for the -p flag */
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 */
contx( p
, down
, pl
, pr
) register NODE
*p
; register *pl
, *pr
; {
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" );
/* called after processing each job */
/* flag is nonzero if errors were detected */
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
);
uerror( "static variable %s unused",
/* 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
);
if( p
->suse
< 0 ){ /* used */
printf( "%.7s\t%03d\t%o\t%d\t", exname(p
->sname
), LUM
, p
->stype
, 0 );
fident( line
){ /* like ident, but lineno = line */
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 struct symtab
*cfp
;
/* if variable number of arguments, only print the ones which will be checked */
if( n
< vaflag
) werror( "declare the VARARGS arguments you want checked!" );
printf( "%.7s\t%03d\t%o\t%d\t", exname(cfp
->sname
), libflag
?LIB
:LDI
,
cfp
->stype
, vaflag
>=0?-n
:n
);
switch( t
= stab
[a
[i
]].stype
){
/* count arguments; p points to at least one */
/* the arguemnts are a tower of commasto the left */
c
= 1; /* count the rhs */
printf( "%o\t", DOUBLE
);
printf( "%o\t", p
->type
);
if( p
->op
== ICON
) printf( "%o<1\t", t
);
else printf( "%o\t", t
);
lprt( p
, down
, uses
) register NODE
*p
; {
register struct symtab
*q
;
register struct lnm
*np1
, *np2
;
/* first, set variables which are set... */
if( p
->op
== ASSIGN
) use1
= VALSET
;
else if( p
->op
== UNARY AND
) use1
= VALADDR
;
else if( asgop( p
->op
) ){ /* =ops */
if( down
== EFF
) use1
|= VALASGOP
;
/* print the lines for lint */
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" );
if( p
->right
->op
== ICON
&& p
->right
->lval
== 0 && p
->right
->rval
== NONAME
){
werror( "unsigned comparison with 0?" );
if( p
->right
->op
== ICON
&& p
->right
->lval
<= 0 && !ISUNSIGNED(p
->right
->type
) && p
->right
->rval
== NONAME
){
werror( "degenerate unsigned comparison" );
/* go recursively left, then right */
lprt( p
->left
, down1
, use1
);
lprt( p
->right
, down2
, use2
);
acount
= ctargs( p
->right
);
if( p
->left
->op
== ICON
&& (id
=p
->left
->rval
) != NONAME
){ /* used to be &name */
printf( "%.7s\t%03d\t%o\t%d\t",
DECREF(p
->left
->type
), acount
);
if( acount
) lpta( p
->right
);
/* look for &name case */
if( (id
= p
->rval
) >= 0 && id
!= NONAME
){
q
->sflags
|= (SREF
|SSET
);
if( (id
= p
->rval
) >= 0 && id
!= NONAME
){
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
);
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
);
lnp
->flgs
= (uses
&VALADDR
)?0:((uses
&VALSET
)?VALSET
:VALUSED
);
if( ++lnp
>= &lnames
[LNAMES
] ) --lnp
;
/* recurse, going down the right side first if we can */
lprt( p
->right
, down2
, use2
);
lprt( p
->left
, down1
, use1
);
if( optype(p
->op
) == BITYPE
){
if( p
->op
== ASSIGN
&& p
->left
->op
== NAME
){ /* special case for a = .. a .. */
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
* 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
) )
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
;
/* not there: update entry */
/* all finished: merged list is at np1 */
/* code for the end of a function */
register struct symtab
*cfp
;
printf( "%.7s\t%03d\t%o\t%d\t", exname(cfp
->sname
),
LRV
, DECREF( cfp
->stype
), 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
;
if(p
->suse
>0 && !(p
->sflags
&SMOS
) ){
if( p
->sclass
== PARAM
){
if( vflag
) werror( "argument %.7s unused in function %.7s",
if( p
->sclass
!= TYPEDEF
) werror( "%.7s unused in function %.7s",
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 );
/* n integer words of zeros */
andable( p
) NODE
*p
; { /* p is a NAME node; can it accept & ? */
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);
/* 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
/* 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 */
if( p
->left
->type
==ENUMTY
){
p
->left
= pconvert( p
->left
);
/* assume conversion takes place; type is inherited */
if( aflag
&& (tl
==LONG
||tl
==ULONG
) && (t
!=LONG
&&t
!=ULONG
) ){
werror( "long assignment may lose accuracy" );
if( ISPTR(tl
) && ISPTR(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" );
werror( "questionable conversion of function pointer" );
if( p
->right
->op
!= ICON
) cerror( "bad conversion");
return( buildtree( o
==PMCONV
?MUL
:DIV
, p
->left
, p
->right
) );
offcon( off
, t
, d
, s
) OFFSZ off
; TWORD t
;{ /* make a structure offset node */
/* storage class for such as "int a;" */
return( pflag
? EXTDEF
: EXTERN
);
cinit( p
, sz
) NODE
*p
; { /* initialize p into size sz */
if( p
->left
->op
== ICON
) return;
if( p
->left
->op
== NAME
&& p
->left
->type
== MOE
) return;
uerror( "illegal initialization" );
/* make a name look like an external name in the local machine */
if( isupper(*p
) ) aa
[i
] = tolower( *p
);
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 */
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" );
main( argc
, argv
) char *argv
[]; {
for( p
=argv
[1]; *p
; ++p
){
case 'L': /* produced by driver program */
/* for the moment, -s triggers -h */
case 'u': /* done in second pass */
case 'n': /* done in shell script */
werror( "option %c now default: see `man 6 lint'", *p
);
uerror( "illegal option: %c", *p
);
if( !pflag
){ /* set sizes to sizes of target machine */
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
;
/* now, fix some things up for various machines (I wish we had "alignof") */
ALLONG
= ALDOUBLE
= ALFLOAT
= ALINT
;
return( mainp1( argc
, argv
) );
ctype( type
) unsigned type
; { /* are there any funny types? */
/* put out a common declaration */
register struct symtab
*p
;
printf( "%.7s\t%03d\t%o\t%d\t", exname(p
->sname
), libflag
?LIB
:LDC
, p
->stype
, 0 );
isitfloat ( s
) char *s
; {
/* s is a character string;
if floating point is implemented, set dcon to the value of s */
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 */
if( !hflag
& !pflag
) return;
s
= UPKFSZ(p
->left
->rval
);
if( v
>=0 && (v
>>(s
-1))==0 ) return;
werror( "precision lost in assignment to (possibly sign-extended) field" );
if( v
<0 || (v
>>s
)!=0 ) werror( "precision lost in field assignment" );