/* $Header$ */
/* L E X I C A L A N A L Y Z E R */
+#include "lint.h"
#include <alloc.h>
#include "nofloat.h"
#include "idfsize.h"
ASIDE = 0;
}
else { /* read ahead and return the old one */
+#ifdef LINT
+ move_NOT2s();
+#endif LINT
dot = ahead;
/* the following test is performed due to the dual
task of LLlex(): it is also called for parsing the
NoUnstack++;
LoadChar(c);
+#ifdef LINT
+ lint_comment(-2);
+ lint_comment(c);
+#endif LINT
do {
while (c != '*') {
if (class(c) == STNL)
return;
}
LoadChar(c);
+#ifdef LINT
+ lint_comment(c);
+#endif LINT
} /* last Character seen was '*' */
LoadChar(c);
+#ifdef LINT
+ lint_comment(c);
+#endif LINT
} while (c != '/');
NoUnstack--;
}
--- /dev/null
+!File: lint.h
+#define LINT 1 /* if defined, 'lint' is produced */
+
+
+!File: pathlength.h
+#define PATHLENGTH 1024 /* max. length of path to file */
+
+
+!File: errout.h
+#define ERROUT STDERR /* file pointer for writing messages */
+#define MAXERR_LINE 5 /* maximum number of error messages given
+ on the same input line. */
+
+
+!File: idfsize.h
+#define IDFSIZE 64 /* maximum significant length of an identifier */
+
+
+!File: numsize.h
+#define NUMSIZE 256 /* maximum length of a numeric constant */
+
+
+!File: nparams.h
+#define NPARAMS 32 /* maximum number of parameters of macros */
+
+
+!File: ifdepth.h
+#define IFDEPTH 256 /* maximum number of nested if-constructions */
+
+
+!File: density.h
+#define DENSITY 2 /* see switch.[ch] for an explanation */
+
+
+!File: lapbuf.h
+#define LAPBUF 4096 /* size of macro actual parameter buffer */
+
+
+!File: strsize.h
+#define ISTRSIZE 32 /* minimum number of bytes allocated for
+ storing a string */
+#define RSTRSIZE 8 /* step size in enlarging the memory for
+ the storage of a string */
+
+
+!File: target_sizes.h
+#define MAXSIZE 8 /* the maximum of the SZ_* constants */
+
+/* target machine sizes */
+#define SZ_CHAR (arith)1
+#define SZ_SHORT (arith)2
+#define SZ_WORD (arith)4
+#define SZ_INT (arith)4
+#define SZ_LONG (arith)4
+#ifndef NOFLOAT
+#define SZ_FLOAT (arith)4
+#define SZ_DOUBLE (arith)8
+#endif NOFLOAT
+#define SZ_POINTER (arith)4
+
+/* target machine alignment requirements */
+#define AL_CHAR 1
+#define AL_SHORT SZ_SHORT
+#define AL_WORD SZ_WORD
+#define AL_INT SZ_WORD
+#define AL_LONG SZ_WORD
+#ifndef NOFLOAT
+#define AL_FLOAT SZ_WORD
+#define AL_DOUBLE SZ_WORD
+#endif NOFLOAT
+#define AL_POINTER SZ_WORD
+#define AL_STRUCT 1
+#define AL_UNION 1
+
+
+!File: botch_free.h
+#undef BOTCH_FREE 1 /* when defined, botch freed memory, as a check */
+
+
+!File: dataflow.h
+#undef DATAFLOW 1 /* produce some compile-time xref */
+
+
+!File: debug.h
+#undef DEBUG 1 /* perform various self-tests */
+
+
+!File: use_tmp.h
+#undef USE_TMP 1 /* collect exa, exp, ina and inp commands
+ and let them precede the rest of
+ the generated compact code */
+
+
+!File: parbufsize.h
+#define PARBUFSIZE 1024
+
+
+!File: textsize.h
+#define ITEXTSIZE 8 /* 1st piece of memory for repl. text */
+#define RTEXTSIZE 8 /* stepsize for enlarging repl.text */
+
+
+!File: inputtype.h
+#define INP_READ_IN_ONE 1 /* read input file in one */
+
+
+!File: nopp.h
+#undef NOPP 1 /* if NOT defined, use built-int preprocessor */
+
+
+!File: nobitfield.h
+#undef NOBITFIELD 1 /* if NOT defined, implement bitfields */
+
+
+!File: spec_arith.h
+/* describes internal compiler arithmetics */
+#undef SPECIAL_ARITHMETICS /* something different from native long */
+
+
+!File: static.h
+#define GSTATIC /* for large global "static" arrays */
+
+
+!File: nofloat.h
+#undef NOFLOAT 1 /* if NOT defined, floats are implemented */
+
+
+!File: noRoption.h
+#undef NOROPTION 1 /* if NOT defined, R option is implemented */
+
+
+!File: nocross.h
+#undef NOCROSS 1 /* if NOT defined, cross compiler */
+
+
+!File: regcount.h
+#undef REGCOUNT 1 /* count occurrences for register messages */
+
+
$(ALLOCLIB) $(MALLOC) $(SYSLIB)
CELIBS = $(INPLIB) $(EMMESCELIB) $(EMCELIB) $(PRTLIB) $(STRLIB) \
$(ALLOCLIB) $(MALLOC) $(SYSLIB)
+LLIBS = $(INPLIB) $(EMMESLIB) $(PRTLIB) $(STRLIB) \
+ $(ALLOCLIB) $(MALLOC) $(SYSLIB)
LIB_INCLUDES = -I$(EMHOME)/modules/h -I$(EMHOME)/modules/pkg
EM_INCLUDES = -I$(EMHOME)/h
SYSLLIB = $(EMHOME)/modules/lib/llib-lsystem.ln
input.c domacro.c replace.c init.c options.c \
scan.c skip.c stack.c type.c ch7mon.c label.c eval.c \
switch.c conversion.c util.c \
- blocks.c dataflow.c Version.c
+ blocks.c dataflow.c Version.c \
+ l_lint.c l_states.c l_misc.c l_ev_ord.c l_outdef.c l_comment.c l_dummy.c
COBJ = main.o idf.o declarator.o decspecs.o struct.o \
expr.o ch7.o ch7bin.o cstoper.o arith.o \
asm.o code.o dumpidf.o error.o field.o\
input.o domacro.o replace.o init.o options.o \
scan.o skip.o stack.o type.o ch7mon.o label.o eval.o \
switch.o conversion.o util.o \
- blocks.o dataflow.o Version.o
+ blocks.o dataflow.o Version.o \
+ l_lint.o l_states.o l_misc.o l_ev_ord.o l_outdef.o l_comment.o l_dummy.o
# Objects of other generated C files
GCSRC = char.c symbol2str.c next.c
STRSRC = code.str declar.str decspecs.str def.str expr.str field.str \
estack.str util.str \
- idf.str macro.str stack.str stmt.str struct.str switch.str type.str
+ idf.str macro.str stack.str stmt.str struct.str switch.str type.str \
+ l_brace.str l_state.str l_outdef.str
# generated source files
GHSTRSRC = code.h declar.h decspecs.h def.h expr.h field.h \
estack.h util.h \
- idf.h macro.h stack.h stmt.h struct.h switch.h type.h
+ idf.h macro.h stack.h stmt.h struct.h switch.h type.h \
+ l_brace.h l_state.h l_outdef.h
GSRC = $(GCSRC) $(GHSTRSRC)
# .h files generated by `make hfiles LLfiles'; PLEASE KEEP THIS UP-TO-DATE!
GHSRC = botch_free.h dataflow.h debug.h density.h errout.h \
- idfsize.h ifdepth.h inputtype.h lapbuf.h \
+ idfsize.h ifdepth.h inputtype.h lapbuf.h lint.h \
nobitfield.h nofloat.h nopp.h noRoption.h nocross.h \
nparams.h numsize.h parbufsize.h pathlength.h Lpars.h \
strsize.h target_sizes.h textsize.h use_tmp.h spec_arith.h static.h \
HSRC = LLlex.h align.h arith.h assert.h atw.h class.h \
input.h interface.h label.h level.h mes.h sizes.h specials.h \
- file_info.h tokenname.h
+ file_info.h tokenname.h l_lint.h
HFILES = $(HSRC) $(GHSRC) $(GHSTRSRC)
OBJ = $(COBJ) $(LOBJ) $(GOBJ)
SRC = $(CSRC) $(LCSRC) $(GCSRC)
+LINT = /usr/bin/lint
+LINTFLAGS =
+
+MYLINT = ../lint
+MYLINTFLAGS = #-xh
+
#EXCLEXCLEXCLEXCL
.SUFFIXES: .str .h
sh -c 'if $(CC) nmclash.c > /dev/null 2>&1 ; then make "EMHOME="$(EMHOME) "COPTIONS="-DCODE_EXPANDER $(CURRDIR)/cemain ; else EMHOME=$(EMHOME); export EMHOME; ./Resolve cemain ; fi'
@rm -f nmclash.o a.out *.o
+Lnt: Cfiles
+ sh -c 'if $(CC) nmclash.c > /dev/null 2>&1 ; then make "EMHOME="$(EMHOME) $(CURRDIR)/lnt ; else EMHOME=$(EMHOME); export EMHOME; ./Resolve lnt ; fi'
+ make "EMHOME="$(EMHOME) $(CURRDIR)/lnt
+ @rm -f nmclash.o a.out
+
install: Main
rm -f $(EMHOME)/lib/em_cemcom $(EMHOME)/man/em_cemcom.6
cp $(CURRDIR)/main $(EMHOME)/lib/em_cemcom
sh -c 'if $(CC) nmclash.c > /dev/null 2>&1 ; then make "EMHOME="$(EMHOME) Xlint ; else sh Resolve Xlint ; fi'
@rm -f nmclash.o a.out
+mylint: Cfiles
+ sh -c 'if $(CC) nmclash.c > /dev/null 2>&1 ; then make "EMHOME="$(EMHOME) Xmylint ; else sh Resolve Xmylint ; fi'
+ @rm -f nmclash.o a.out
+
longnames: $(SRC) $(HFILES)
sh -c 'if test -f longnames ; then : ; else touch longnames ; fi ; $(PRID) -l7 longnames $? > Xlongnames ; mv Xlongnames longnames'
type.h: make.allocd
estack.h: make.allocd
util.h: make.allocd
+l_brace.h: make.allocd
+l_state.h: make.allocd
+l_outdef.h: make.allocd
depend: Cfiles
sed '/^#AUTOAUTO/,$$d' Makefile >Makefile.new
$(CC) $(COPTIONS) $(LDFLAGS) $(OBJ) $(CELIBS) -o $(CURRDIR)/cemain
size $(CURRDIR)/cemain
-Xlint:
- lint $(CDEFS) $(LINTFLAGS) $(SRC)
+$(CURRDIR)/lnt: $(OBJ) $(CURRDIR)/Makefile
+ $(CC) $(COPTIONS) $(LDFLAGS) $(OBJ) $(LLIBS) -o $(CURRDIR)/lnt
+ size $(CURRDIR)/lnt
+
+Xlint: $(SRC)
+ $(LINT) $(CDEFS) $(LINTFLAGS) $(SRC)
+
+Xmylint: $(SRC)
+ $(MYLINT) $(CDEFS) $(MYLINTFLAGS) $(SRC)
#AUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTO
main.o: LLlex.h
main.o: input.h
main.o: inputtype.h
main.o: level.h
+main.o: lint.h
main.o: noRoption.h
main.o: nobitfield.h
main.o: nocross.h
idf.o: idfsize.h
idf.o: label.h
idf.o: level.h
+idf.o: lint.h
idf.o: noRoption.h
idf.o: nobitfield.h
idf.o: nocross.h
declarator.o: type.h
decspecs.o: Lpars.h
decspecs.o: arith.h
+decspecs.o: assert.h
+decspecs.o: debug.h
decspecs.o: decspecs.h
decspecs.o: def.h
decspecs.o: level.h
+decspecs.o: lint.h
decspecs.o: noRoption.h
decspecs.o: nobitfield.h
decspecs.o: nofloat.h
struct.o: file_info.h
struct.o: idf.h
struct.o: level.h
+struct.o: lint.h
struct.o: noRoption.h
struct.o: nobitfield.h
struct.o: nocross.h
expr.o: idf.h
expr.o: label.h
expr.o: level.h
+expr.o: lint.h
expr.o: noRoption.h
expr.o: nobitfield.h
expr.o: nocross.h
ch7.o: expr.h
ch7.o: idf.h
ch7.o: label.h
+ch7.o: lint.h
ch7.o: nobitfield.h
ch7.o: nofloat.h
ch7.o: nopp.h
cstoper.o: type.h
arith.o: Lpars.h
arith.o: arith.h
-arith.o: botch_free.h
arith.o: expr.h
arith.o: field.h
arith.o: idf.h
code.o: expr.h
code.o: file_info.h
code.o: idf.h
+code.o: l_lint.h
code.o: label.h
code.o: level.h
+code.o: lint.h
code.o: noRoption.h
code.o: nobitfield.h
code.o: nocross.h
dumpidf.o: field.h
dumpidf.o: idf.h
dumpidf.o: label.h
+dumpidf.o: lint.h
dumpidf.o: nobitfield.h
dumpidf.o: nofloat.h
dumpidf.o: nopp.h
error.o: LLlex.h
error.o: arith.h
error.o: debug.h
+error.o: def.h
error.o: errout.h
error.o: expr.h
error.o: file_info.h
error.o: label.h
+error.o: lint.h
error.o: nofloat.h
error.o: nopp.h
error.o: spec_arith.h
field.o: field.h
field.o: idf.h
field.o: label.h
+field.o: lint.h
field.o: nobitfield.h
field.o: nocross.h
field.o: nofloat.h
LLlex.o: idf.h
LLlex.o: idfsize.h
LLlex.o: input.h
+LLlex.o: lint.h
LLlex.o: nocross.h
LLlex.o: nofloat.h
LLlex.o: nopp.h
options.o: dataflow.h
options.o: idf.h
options.o: idfsize.h
+options.o: lint.h
options.o: macro.h
options.o: noRoption.h
options.o: nobitfield.h
stack.o: def.h
stack.o: idf.h
stack.o: level.h
+stack.o: lint.h
stack.o: mes.h
stack.o: noRoption.h
stack.o: nobitfield.h
type.o: botch_free.h
type.o: def.h
type.o: idf.h
+type.o: lint.h
type.o: nobitfield.h
type.o: nocross.h
type.o: nofloat.h
ch7mon.o: expr.h
ch7mon.o: idf.h
ch7mon.o: label.h
+ch7mon.o: lint.h
ch7mon.o: nobitfield.h
ch7mon.o: nofloat.h
ch7mon.o: nopp.h
label.o: idf.h
label.o: label.h
label.o: level.h
+label.o: lint.h
label.o: noRoption.h
label.o: nobitfield.h
label.o: nofloat.h
eval.o: idf.h
eval.o: label.h
eval.o: level.h
+eval.o: lint.h
eval.o: mes.h
eval.o: nobitfield.h
eval.o: nocross.h
switch.o: type.h
conversion.o: Lpars.h
conversion.o: arith.h
+conversion.o: lint.h
conversion.o: nobitfield.h
conversion.o: nocross.h
conversion.o: nofloat.h
util.o: Lpars.h
util.o: align.h
util.o: def.h
+util.o: lint.h
util.o: nocross.h
util.o: nofloat.h
util.o: regcount.h
blocks.o: arith.h
blocks.o: atw.h
blocks.o: label.h
+blocks.o: lint.h
blocks.o: nocross.h
blocks.o: nofloat.h
blocks.o: sizes.h
blocks.o: stack.h
blocks.o: target_sizes.h
dataflow.o: dataflow.h
+l_lint.o: LLlex.h
+l_lint.o: Lpars.h
+l_lint.o: arith.h
+l_lint.o: code.h
+l_lint.o: def.h
+l_lint.o: expr.h
+l_lint.o: file_info.h
+l_lint.o: idf.h
+l_lint.o: l_lint.h
+l_lint.o: l_outdef.h
+l_lint.o: l_state.h
+l_lint.o: label.h
+l_lint.o: level.h
+l_lint.o: lint.h
+l_lint.o: nobitfield.h
+l_lint.o: nofloat.h
+l_lint.o: nopp.h
+l_lint.o: spec_arith.h
+l_lint.o: stack.h
+l_lint.o: type.h
+l_states.o: LLlex.h
+l_states.o: Lpars.h
+l_states.o: arith.h
+l_states.o: assert.h
+l_states.o: code.h
+l_states.o: debug.h
+l_states.o: def.h
+l_states.o: expr.h
+l_states.o: file_info.h
+l_states.o: idf.h
+l_states.o: l_brace.h
+l_states.o: l_lint.h
+l_states.o: l_outdef.h
+l_states.o: l_state.h
+l_states.o: label.h
+l_states.o: level.h
+l_states.o: lint.h
+l_states.o: nobitfield.h
+l_states.o: nofloat.h
+l_states.o: nopp.h
+l_states.o: spec_arith.h
+l_states.o: stack.h
+l_states.o: type.h
+l_misc.o: LLlex.h
+l_misc.o: Lpars.h
+l_misc.o: arith.h
+l_misc.o: code.h
+l_misc.o: def.h
+l_misc.o: expr.h
+l_misc.o: file_info.h
+l_misc.o: idf.h
+l_misc.o: l_state.h
+l_misc.o: label.h
+l_misc.o: level.h
+l_misc.o: lint.h
+l_misc.o: nobitfield.h
+l_misc.o: nofloat.h
+l_misc.o: nopp.h
+l_misc.o: spec_arith.h
+l_misc.o: stack.h
+l_misc.o: type.h
+l_ev_ord.o: LLlex.h
+l_ev_ord.o: Lpars.h
+l_ev_ord.o: arith.h
+l_ev_ord.o: code.h
+l_ev_ord.o: def.h
+l_ev_ord.o: expr.h
+l_ev_ord.o: file_info.h
+l_ev_ord.o: idf.h
+l_ev_ord.o: l_lint.h
+l_ev_ord.o: l_state.h
+l_ev_ord.o: label.h
+l_ev_ord.o: level.h
+l_ev_ord.o: lint.h
+l_ev_ord.o: nobitfield.h
+l_ev_ord.o: nofloat.h
+l_ev_ord.o: nopp.h
+l_ev_ord.o: spec_arith.h
+l_ev_ord.o: stack.h
+l_ev_ord.o: type.h
+l_outdef.o: LLlex.h
+l_outdef.o: Lpars.h
+l_outdef.o: arith.h
+l_outdef.o: def.h
+l_outdef.o: expr.h
+l_outdef.o: field.h
+l_outdef.o: file_info.h
+l_outdef.o: idf.h
+l_outdef.o: l_class.h
+l_outdef.o: l_lint.h
+l_outdef.o: l_outdef.h
+l_outdef.o: label.h
+l_outdef.o: level.h
+l_outdef.o: lint.h
+l_outdef.o: nobitfield.h
+l_outdef.o: nofloat.h
+l_outdef.o: nopp.h
+l_outdef.o: spec_arith.h
+l_outdef.o: stack.h
+l_outdef.o: struct.h
+l_outdef.o: type.h
+l_comment.o: arith.h
+l_comment.o: l_state.h
+l_comment.o: lint.h
+l_comment.o: spec_arith.h
tokenfile.o: Lpars.h
declar.o: LLlex.h
declar.o: Lpars.h
declar.o: arith.h
+declar.o: code.h
declar.o: debug.h
declar.o: declar.h
declar.o: decspecs.h
declar.o: field.h
declar.o: file_info.h
declar.o: idf.h
+declar.o: l_lint.h
+declar.o: l_state.h
declar.o: label.h
declar.o: level.h
+declar.o: lint.h
declar.o: nobitfield.h
declar.o: nocross.h
declar.o: nofloat.h
statement.o: expr.h
statement.o: file_info.h
statement.o: idf.h
+statement.o: l_lint.h
+statement.o: l_state.h
statement.o: label.h
+statement.o: lint.h
statement.o: nobitfield.h
statement.o: nofloat.h
statement.o: nopp.h
expression.o: LLlex.h
expression.o: Lpars.h
expression.o: arith.h
+expression.o: code.h
expression.o: expr.h
expression.o: file_info.h
expression.o: idf.h
expression.o: label.h
+expression.o: lint.h
expression.o: noRoption.h
expression.o: nobitfield.h
expression.o: nofloat.h
program.o: expr.h
program.o: file_info.h
program.o: idf.h
+program.o: l_state.h
program.o: label.h
+program.o: lint.h
program.o: nobitfield.h
program.o: nofloat.h
program.o: nopp.h
ival.o: Lpars.h
ival.o: arith.h
ival.o: assert.h
+ival.o: code.h
ival.o: debug.h
ival.o: def.h
ival.o: estack.h
ival.o: field.h
ival.o: file_info.h
ival.o: idf.h
+ival.o: l_lint.h
ival.o: label.h
ival.o: level.h
+ival.o: lint.h
ival.o: noRoption.h
ival.o: nobitfield.h
ival.o: nocross.h
+!File: lint.h
+#undef LINT 1 /* if defined, 'lint' is produced */
+
+
!File: pathlength.h
#define PATHLENGTH 1024 /* max. length of path to file */
PW=`pwd`
options=
case $1 in
-main|emain)
+main|emain|lnt)
target=$PW/$1
;;
omain)
/* $Header$ */
/* B L O C K S T O R I N G A N D L O A D I N G */
+#include "lint.h"
+#ifndef LINT
+
#include <em.h>
#include <em_reg.h>
#include "arith.h"
}
#endif STB
+#endif LINT
+
/* $Header$ */
/* S E M A N T I C A N A L Y S I S -- C H A P T E R 7 RM */
+#include "lint.h"
#include "nofloat.h"
#include "debug.h"
#include "nobitfield.h"
if (oper != CAST)
expr_warning(*expp, "incompatible pointers in %s",
symbol2str(oper));
+#ifdef LINT
+ if (oper == CAST)
+ lint_ptr_conv(oldtp->tp_up->tp_fund, tp->tp_up->tp_fund);
+#endif LINT
(*expp)->ex_type = tp; /* free conversion */
}
else
/* $Header$ */
/* C O D E - G E N E R A T I N G R O U T I N E S */
+#include "lint.h"
#include <em.h>
#include "botch_free.h"
#include <alloc.h>
#include "assert.h"
#include "noRoption.h"
#include "file_info.h"
+#ifdef LINT
+#include "l_lint.h"
+#endif LINT
+
label lab_count = 1;
label datlab_count = 1;
extern char options[];
extern char *symbol2str();
+#ifndef LINT
init_code(dst_file)
char *dst_file;
{
C_insertpart(tmp_id = C_getid());
#endif USE_TMP
}
+#endif LINT
+
static struct string_cst *str_list = 0;
code_string(val, len, dlb)
if (return_expr_occurred) C_asp(-func_size);
C_df_ilb(return_label);
prc_exit();
+#ifndef LINT
if (return_expr_occurred) {
if (func_res_label != 0) {
C_lae_dlb(func_res_label, (arith)0);
C_ret(func_size);
}
else C_ret((arith) 0);
+#endif LINT
+
/* getting the number of "local" bytes is posponed until here,
because copying the function result in "func_res_label" may
need temporaries! However, local_level is now L_FORMAL2, because
}
else { /* not embraced */
ch7cast(&expr, '=', tp); /* may modify expr */
+#ifndef LINT
{
struct value vl;
vl.vl_value = (arith)0;
store_val(&vl, tp);
}
+#else LINT
+ id->id_def->df_set = 1;
+#endif LINT
free_expression(expr);
}
}
}
}
+#ifdef LINT
+/*ARGSUSED*/
+#endif LINT
code_expr(expr, val, code, tlbl, flbl)
struct expr *expr;
label tlbl, flbl;
generator. If line number trace is wanted, it generates a
lin instruction. EVAL() is called directly.
*/
+#ifndef LINT
if (! options['L']) /* profiling */
C_lin((arith)(expr->ex_line));
EVAL(expr, val, code, tlbl, flbl);
+#else LINT
+ pre_lint_expr(expr, RVAL, code ? USED : IGNORED);
+#endif LINT
}
/* The FOR/WHILE/DO/SWITCH stacking mechanism:
/* $Header$ */
/* C O N V E R S I O N - C O D E G E N E R A T O R */
+#include "lint.h"
+#ifndef LINT
+
#include "nofloat.h"
#include <em.h>
#include "arith.h"
return 0;
}
+#endif LINT
+
/* DECLARATION SYNTAX PARSER */
{
+#include "lint.h"
#include <alloc.h>
#include "nobitfield.h"
#include "debug.h"
#include "expr.h"
#include "sizes.h"
#include "level.h"
+#ifdef LINT
+#include "l_lint.h"
+#include "l_state.h"
+#endif LINT
+
extern char options[];
}
{
reject_params(&Dc);
declare_idf(ds, &Dc, level);
+#ifdef LINT
+ lint_declare_idf(Dc.dc_idf, ds->ds_sc);
+#endif LINT
}
[
initializer(Dc.dc_idf, ds->ds_sc)
]
]
{
+#ifdef LINT
+ add_auto(Dc.dc_idf);
+#endif LINT
remove_declarator(&Dc);
}
;
*/
]
{
+#ifdef LINT
+ lint_statement();
+#endif LINT
if (globalflag) {
struct expr ex;
code_declaration(idf, &ex, level, sc);
#ifdef DEBUG
print_expr("initializer-expression", expr);
#endif DEBUG
+#ifdef LINT
+ change_state(idf, SET);
+ pre_lint_expr(expr, RVAL, USED);
+#endif LINT
code_declaration(idf, expr, level, sc);
}
init_idf(idf);
/* $Header$ */
/* IDENTIFIER DEFINITION DESCRIPTOR */
+#include "lint.h"
struct def { /* for ordinary tags */
struct def *next;
char df_used; /* set if idf is used */
char *df_file; /* file containing the definition */
unsigned int df_line; /* line number of the definition */
+#ifdef LINT
+ char df_set;
+ int df_firstbrace; /* brace number of its first occurrence */
+ int df_minlevel; /* the lowest level needed for this def */
+#endif LINT
char df_formal_array; /* to warn if sizeof is taken */
arith df_address;
};
#include <system.h>
#include <em.h>
+#include "lint.h"
#include "nopp.h"
#include "errout.h"
#include "debug.h"
int err_occurred = 0;
extern char options[];
+#ifdef LINT
+extern char loptions[];
+#endif LINT
+
/* There are three general error-message functions:
lexerror() lexical and pre-processor error messages
error() syntactic and semantic error messages
va_end(ap);
}
+#ifdef LINT
+
+/*VARARGS*/
+def_warning(va_alist) /* def, fmt, args */
+ va_dcl
+{
+ va_list ap;
+
+ va_start(ap);
+ {
+ register struct def *def = va_arg(ap, struct def *);
+
+ _error(WARNING, def->df_file, def->df_line, ap);
+ }
+ va_end(ap);
+}
+
+
+/*VARARGS*/
+hwarning(va_alist) /* fmt, args */
+ va_dcl
+{
+ va_list ap;
+
+ va_start(ap);
+ {
+ if (loptions['h'])
+ _error(WARNING, dot.tk_file, dot.tk_line, ap);
+ }
+ va_end(ap);
+}
+
+/*VARARGS*/
+awarning(va_alist) /* fmt, args */
+ va_dcl
+{
+ va_list ap;
+
+ va_start(ap);
+ {
+ if (loptions['a'])
+ _error(WARNING, dot.tk_file, dot.tk_line, ap);
+ }
+ va_end(ap);
+}
+
+#endif LINT
+
/*VARARGS*/
lexerror(va_alist) /* fmt, args */
va_dcl
/* _error attempts to limit the number of error messages
for a given line to MAXERR_LINE.
*/
+#ifndef LINT
static char *last_fn = 0;
static unsigned int last_ln = 0;
static int e_seen = 0;
+#endif LINT
char *remark;
char *fmt = va_arg(ap, char *);
/* the remark */
switch (class) {
case WARNING:
+#ifndef LINT
remark = "(warning)";
+#else LINT
+ remark = 0;
+#endif LINT
break;
case ERROR:
/*NOTREACHED*/;
}
+#ifndef LINT
if (ln == last_ln && fn && last_fn && strcmp(fn, last_fn) == 0) {
/* we've seen this place before */
e_seen++;
last_ln = ln;
e_seen = 0;
}
+#endif LINT
+
+#ifdef LINT
+ if ( /* there is a file name */
+ fn
+ && /* the file name is global */
+ fn[0] == '/'
+ && /* it is not a .c file */
+ strcmp(&fn[strlen(fn)-2], ".c") != 0
+ ) {
+ /* we skip this message */
+ return;
+ }
+#endif LINT
if (fn)
fprint(ERROUT, "\"%s\", line %u: ", fn, ln);
/* $Header$ */
/* EXPRESSION-CODE GENERATOR */
+#include "lint.h"
+#ifndef LINT
+
#include "nofloat.h"
#include <em.h>
#include <em_reg.h>
}
}
+#endif LINT
+
/* $Header$ */
/* EXPRESSION TREE HANDLING */
+#include "lint.h"
#include "nofloat.h"
#include "botch_free.h"
#include <alloc.h>
expr->ex_type = error_type;
}
else {
+#ifndef LINT
def->df_used = 1;
+#endif LINT
expr->ex_type = def->df_type;
if (expr->ex_type == error_type)
expr->ex_flags |= EX_ERROR;
expr->VL_CLASS = Const;
expr->VL_VALUE = def->df_address;
}
+#ifndef LINT
else
if (def->df_sc == STATIC && def->df_level >= L_LOCAL) {
expr->VL_CLASS = Label;
expr->VL_LBL = def->df_address;
expr->VL_VALUE = (arith)0;
}
+#endif LINT
else {
expr->VL_CLASS = Name;
expr->VL_IDF = idf;
/* EXPRESSION SYNTAX PARSER */
{
+#include "lint.h"
#include "arith.h"
#include "LLlex.h"
#include "type.h"
#endif
ch7bin(&e1, ':', e2);
opnd2test(expp, '?');
+#ifdef LINT
+ if (is_cp_cst(*expp))
+ hwarning("condition in ?: is constant");
+#endif LINT
ch7bin(expp, '?', e1);
}
]?
/* $Header$ */
/* BITFIELD EXPRESSION EVALUATOR */
+#include "lint.h"
+#ifndef LINT
+
#include "nobitfield.h"
#ifndef NOBITFIELD
}
#endif NOBITFIELD
+#endif LINT
+
/* $Header$ */
/* IDENTIFIER FIDDLING & SYMBOL TABLE HANDLING */
+#include "lint.h"
#include <em_reg.h>
#include "nofloat.h"
#include "debug.h"
}
#endif
+#ifdef LINT
+ if ( def && def->df_level < lvl
+ && !(lvl == L_FORMAL2 || def->df_level == L_UNIVERSAL)
+ ) {
+ /* there is already a definition for this name
+ on a more global level
+ */
+ warning("%s is already defined as a %s",
+ idf->id_text,
+ def->df_level == L_GLOBAL ? "global" :
+ def->df_level == L_FORMAL2 ? "formal" :
+ "more global local"
+ );
+ }
+#endif LINT
+
if (def &&
( def->df_level == lvl ||
( lvl != L_GLOBAL && def->df_level > lvl )
newdef->df_sc = sc;
newdef->df_file = idf->id_file;
newdef->df_line = idf->id_line;
+#ifdef LINT
+ newdef->df_set = (type->tp_fund == ARRAY);
+ newdef->df_firstbrace = 0;
+#endif LINT
+
/* link it into the name list in the proper place */
idf->id_def = newdef;
update_ahead(idf);
/* CODE FOR THE INITIALISATION OF GLOBAL VARIABLES */
{
+#include "lint.h"
#include "nofloat.h"
#include <em.h>
#include "debug.h"
#include "noRoption.h"
#include "estack.h"
#include "code.h"
+#ifdef LINT
+#include "l_lint.h"
+#endif LINT
+
#define con_nullbyte() C_con_ucon("0", (arith)1)
#define aggregate_type(tp) ((tp)->tp_fund == ARRAY || (tp)->tp_fund == STRUCT)
[
assignment_expression(expp)
{
+#ifdef LINT
+ pre_lint_expr(*expp, RVAL, USED);
+#endif LINT
if ((*expp)->ex_type->tp_fund == ARRAY)
array2pointer(*expp);
if (tpp) {
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+
+/* Lint class constants */
+
+#define LFDF 'a' /* Library Function Definition */
+#define LVDF 'b' /* Library Variable Definition */
+#define EFDF 'c' /* External Function Definition */
+#define EVDF 'd' /* External Variable Definition */
+#define EFDC 'e' /* External Function Declaration */
+#define EVDC 'f' /* External Variable Declaration */
+#define IFDC 'g' /* Implicit Function Declaration */
+#define SFDF 'h' /* Static Function Definition */
+#define SVDF 'i' /* Static Variable Definition */
+#define FC 'j' /* Function Call */
+#define VU 'k' /* Variable Usage */
+#define XXDF 'l' /* Ignore Class */
+
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* Lint-specific comment handling */
+
+#include "lint.h"
+
+#ifdef LINT
+
+#include "arith.h"
+#include "l_state.h"
+
+static int NOTREACHED;
+static int VARARGSn = -1;
+static int ARGSUSED;
+int LINTLIB;
+
+int s_NOTREACHED;
+int f_VARARGSn;
+int f_ARGSUSED;
+
+set_not_reached()
+{
+ NOTREACHED = 1;
+}
+
+move_NOT2s()
+{
+ s_NOTREACHED = NOTREACHED;
+ NOTREACHED = 0;
+}
+
+set_varargs(n)
+{
+ VARARGSn = n;
+}
+
+move_VAR2f()
+{
+ f_VARARGSn = VARARGSn;
+ VARARGSn = -1;
+}
+
+set_argsused(n)
+{
+ ARGSUSED = n;
+}
+
+move_ARG2f()
+{
+ f_ARGSUSED = ARGSUSED;
+ ARGSUSED = 0;
+}
+
+set_lintlib()
+{
+ LINTLIB = 1;
+}
+
+#define IN_SPACE 0
+#define IN_WORD 1
+#define IN_COMMENT 2
+
+lint_comment(c)
+ int c;
+{
+/* This function is called with every character between /_* and *_/ (the
+ * _underscores are used because comment in C doesn't nest).
+ * It looks for pseudocomments.
+ * In this version it is allowed that 'keyword' is followed by rubbish.
+ * At the start of each comment the function should be initialized by
+ * calling it with c = -2.
+ * I am not sure if this way of information hiding is a good solution.
+ */
+ static int position; /* IN_SPACE, IN_WORD, IN_COMMENT */
+ static char buf[12];
+ static int i; /* next free position in buf */
+
+ if (c == -2) {
+ position = IN_SPACE;
+ i = 0;
+ return;
+ }
+ if (position == IN_COMMENT)
+ return;
+ if (position == IN_SPACE) {
+ if (c == ' ' || c == '\t')
+ return;
+ position = IN_WORD;
+ }
+ /* position == IN_WORD */
+ if (c == ' ' || c == '\t' || c == '*') {
+ position = IN_COMMENT;
+ check_pseudo(buf, i);
+ }
+ else
+ if (i < 12)
+ buf[i++] = (char)c;
+ else
+ position = IN_COMMENT;
+}
+
+#include <ctype.h>
+
+check_pseudo(buf, i)
+ char *buf;
+{
+/* Look if the i characters in buf are aequivalent with one of the
+ * strings N_OTREACHED, V_ARARGS[n], A_RGSUSED, L_INTLIBRARY
+ * (the u_nderscores are there to not confuse (UNIX) lint)
+ */
+ buf[i++] = '\0';
+ if (!strcmp(buf, "NOTREACHED"))
+ set_not_reached();
+ else if (!strcmp(buf, "ARGSUSED"))
+ set_argsused(1);
+ else if (!strcmp(buf, "LINTLIBRARY"))
+ set_lintlib();
+ else if (!strncmp(buf, "VARARGS", 7)) {
+ if (i == 8)
+ set_varargs(0);
+ else if (i == 9 && isdigit(buf[7]))
+ set_varargs(atoi(&buf[7]));
+ }
+}
+
+#endif LINT
--- /dev/null
+/*
+ *The following functions are hacked to null-functions (i.e. they
+ * do nothing). This needs another solution in the future.
+ */
+#include "arith.h"
+#include "label.h"
+
+C_close(){}
+int C_busy(){return 0;}
+
+
+/* More routines */
+/* ARGSUSED */
+CC_bhcst(ps_xxx,n,w,i) arith n,w; {}
+/* ARGSUSED */
+CC_crcst(ps_xxx,v) arith v; {}
+/* ARGSUSED */
+CC_crdlb(ps_xxx,v,s) label v; arith s; {}
+/* ARGSUSED */
+CC_crdnam(ps_xxx,v,s) char *v; arith s; {}
+/* ARGSUSED */
+CC_crfcon(ps_xxx,v,s) char *v; arith s; {}
+/* ARGSUSED */
+CC_cricon(ps_xxx,v,s) char *v; arith s; {}
+/* ARGSUSED */
+CC_crilb(ps_xxx,v) label v; {}
+/* ARGSUSED */
+CC_crpnam(ps_xxx,v) char *v; {}
+/* ARGSUSED */
+CC_crscon(ps_xxx,v,s) char *v; arith s; {}
+/* ARGSUSED */
+CC_crucon(ps_xxx,v,s) char *v; arith s; {}
+/* ARGSUSED */
+CC_cst(l) {}
+/* ARGSUSED */
+CC_dfdlb(l) label l; {}
+/* ARGSUSED */
+CC_dfdnam(s) char *s; {}
+/* ARGSUSED */
+CC_dfilb(l) label l; {}
+/* ARGSUSED */
+CC_end(l) arith l; {}
+CC_msend() {}
+/* ARGSUSED */
+CC_msstart(ms) {}
+/* ARGSUSED */
+CC_opcst(op_xxx,c) arith c; {}
+/* ARGSUSED */
+CC_opdlb(op_xxx,g,o) label g; arith o; {}
+/* ARGSUSED */
+CC_opilb(op_xxx,b) label b; {}
+/* ARGSUSED */
+CC_oppnam(op_xxx,p) char *p; {}
+/* ARGSUSED */
+CC_pronarg(s) char *s; {}
+/* ARGSUSED */
+CC_psdlb(ps_xxx,l) label l; {}
+/* ARGSUSED */
+CC_psdnam(ps_xxx,s) char *s; {}
+/* ARGSUSED */
+CC_pspnam(ps_xxx,s) char *s; {}
+/* ARGSUSED */
+CC_scon(v,s) char *s; {}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* Lint evaluation order checking */
+
+#include "lint.h"
+
+#ifdef LINT
+
+#include <alloc.h> /* for st_free */
+#include "arith.h" /* definition arith */
+#include "label.h" /* definition label */
+#include "expr.h"
+#include "idf.h"
+#include "def.h"
+#include "code.h" /* RVAL etc */
+#include "LLlex.h"
+#include "Lpars.h"
+#include "stack.h"
+#include "type.h"
+#include "level.h"
+#include "nofloat.h"
+#include "l_lint.h"
+#include "l_state.h"
+
+extern char *symbol2str();
+
+check_and_merge(espp, esp, com_oper)
+ struct expr_state **espp, *esp;
+{
+/* Checks for undefined evaluation orders in case of a commutative operator.
+ * In addition the sets of used and set variables of both expressions are
+ * united.
+ * *espp will be pointing to this new list. esp is used for this list.
+ */
+ register struct expr_state **pp, *p1, *p2;
+
+ for (p1 = *espp; p1; p1 = p1->next) {
+ p2 = esp;
+ pp = &esp;
+ while (p2) {
+ if ( /* p1 and p2 are the same */
+ p1->es_idf == p2->es_idf
+ && p1->es_offset == p2->es_offset
+ ) {
+ if (com_oper)
+ check_ev_order(p1, p2, com_oper);
+ p1->es_used |= p2->es_used;
+ p1->es_set |= p2->es_set;
+ *pp = p2->next;
+ free_expr_state(p2);
+ p2 = *pp;
+ }
+ else {
+ pp = &p2->next;
+ p2 = p2->next;
+ }
+ }
+ }
+ /* The rest of the list esp is pointing to, is put in front of the list
+ * *espp is now pointing to.
+ * *espp will be pointing to this new list.
+ */
+ if (!esp)
+ return;
+ p1 = *espp;
+ *espp = esp;
+ while (esp->next)
+ esp = esp->next;
+ esp->next = p1;
+}
+
+check_ev_order(esp1, esp2, com_oper)
+ struct expr_state *esp1, *esp2;
+{
+ if ( (esp1->es_used && esp2->es_set)
+ || (esp1->es_set && esp2->es_used)
+ || (esp1->es_set && esp2->es_set)
+ ) {
+ warning("result of %s depends on evaluation order on %s",
+ symbol2str(com_oper),
+ esp1->es_idf->id_text);
+ }
+}
+
+add_expr_state(value, to_state, espp)
+ struct value value;
+ struct expr_state **espp;
+{
+ register struct expr_state *esp = *espp;
+
+ if (value.vl_class != Name) {
+ crash("(add_expr_state) invalid vl_class");
+ /*NOTREACHED*/
+ }
+ while ( esp
+ && !( esp->es_idf == value.vl_data.vl_idf
+ && esp->es_offset == value.vl_value
+ )
+ ) {
+ esp = esp->next;
+ }
+ if (!esp) { /* create new expr_state */
+ esp = new_expr_state();
+ esp->es_idf = value.vl_data.vl_idf;
+ esp->es_offset = value.vl_value;
+ esp->next = *espp;
+ *espp = esp;
+ }
+ if (to_state == SET)
+ esp->es_set = 1;
+ else /* USED */
+ esp->es_used = 1;
+}
+
+#endif LINT
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* Lint main routines */
+
+#include "lint.h"
+
+#ifdef LINT
+
+#include <alloc.h> /* for st_free */
+#include "arith.h" /* definition arith */
+#include "label.h" /* definition label */
+#include "expr.h"
+#include "idf.h"
+#include "def.h"
+#include "code.h" /* RVAL etc */
+#include "LLlex.h"
+#include "Lpars.h"
+#include "stack.h"
+#include "type.h"
+#include "level.h"
+#include "nofloat.h"
+#include "l_lint.h"
+#include "l_state.h"
+#include "l_outdef.h"
+
+extern char options[128];
+extern char *symbol2str();
+
+struct expr_state *lint_expr();
+
+lint_init()
+{
+/* Allocate some memory for the global stack_bottom
+ * and some other initializations
+ */
+
+ extern struct lint_stack_entry stack_bottom;
+
+ stack_bottom.ls_current = new_state();
+}
+
+pre_lint_expr(expr, val, used)
+ struct expr *expr;
+{
+/* Introduced to dispose the returned expression states */
+
+ register struct expr_state *esp;
+
+ esp = lint_expr(expr, val, used);
+ free_expr_states(esp);
+}
+
+free_expr_states(esp)
+ register struct expr_state *esp;
+{
+ register struct expr_state *esp2;
+
+ while (esp) {
+ esp2 = esp;
+ esp = esp->next;
+ free_expr_state(esp2);
+ }
+}
+
+struct expr_state *
+lint_expr(expr, val, used)
+ register struct expr *expr;
+{
+/* Main function to process an expression tree.
+ * It returns a structure containing information about which variables
+ * are set and which are used in the expression.
+ * In addition it sets 'used' and 'set' fields of the corresponding
+ * variables in the current state.
+ * If the value of an operation without side-effects is not used,
+ * a warning is given.
+ */
+ struct expr_state *esp1 = 0, *esp2 = 0;
+
+ if (used == IGNORED) {
+ expr_ignored(expr);
+ }
+
+ switch (expr->ex_class) {
+ case Value:
+ switch (expr->VL_CLASS) {
+ case Const:
+ case Label:
+ return(0);
+
+ case Name:
+ {
+ register struct idf *idf = expr->VL_IDF;
+
+ if (!idf || !idf->id_def)
+ return(0);
+
+ if ( val == LVAL
+ || ( val == RVAL
+ && expr->ex_type->tp_fund == POINTER
+ && !expr->ex_lvalue
+ )
+ ) {
+ change_state(idf, SET);
+ idf->id_def->df_file =
+ Salloc(dot.tk_file,
+ strlen(dot.tk_file) + 1);
+ idf->id_def->df_line = dot.tk_line;
+ }
+ if (val == RVAL) {
+ change_state(idf, USED);
+ add_expr_state(expr->EX_VALUE, USED, &esp1);
+ }
+ return(esp1);
+ }
+
+ default:
+ crash("(lint_expr) bad value class\n");
+ /* NOTREACHED */
+ }
+
+ case Oper:
+ {
+ register int oper = expr->OP_OPER;
+ register struct expr *left = expr->OP_LEFT;
+ register struct expr *right = expr->OP_RIGHT;
+
+ switch (oper) {
+ case '=':
+ case PLUSAB:
+ case MINAB:
+ case TIMESAB:
+ case DIVAB:
+ case MODAB:
+ case LEFTAB:
+ case RIGHTAB:
+ case ANDAB:
+ case XORAB:
+ case ORAB:
+ lint_conversion(oper, right->ex_type, left->ex_type);
+ /* for cases like i += l; */
+ esp1 = lint_expr(right, RVAL, USED);
+ if (oper != '=') {
+ /* i += 1; is interpreted as i = i + 1; */
+ esp2 = lint_expr(left, RVAL, USED);
+ check_and_merge(&esp1, esp2, oper);
+ }
+ esp2 = lint_expr(left, LVAL, USED);
+ /* for cases like i = i + 1; and i not set, this
+ ** order is essential
+ */
+ check_and_merge(&esp1, esp2, oper);
+ if ( left->ex_class == Value
+ && left->VL_CLASS == Name
+ ) {
+ add_expr_state(left->EX_VALUE, SET, &esp1);
+ }
+ return(esp1);
+
+ case POSTINCR:
+ case POSTDECR:
+ case PLUSPLUS:
+ case MINMIN:
+ /* i++; is parsed as i = i + 1;
+ * This isn't quite correct :
+ * The first statement doesn't USE i,
+ * the second does.
+ */
+ esp1 = lint_expr(left, RVAL, USED);
+ esp2 = lint_expr(left, LVAL, USED);
+ check_and_merge(&esp1, esp2, oper);
+ if ( left->ex_class == Value
+ && left->VL_CLASS == Name
+ ) {
+ add_expr_state(left->EX_VALUE, SET, &esp1);
+ add_expr_state(left->EX_VALUE, USED, &esp1);
+ }
+ return(esp1);
+
+ case '-':
+ case '*':
+ if (left == 0) /* unary */
+ return(lint_expr(right, RVAL, USED));
+ esp1 = lint_expr(left, RVAL, USED);
+ esp2 = lint_expr(right, RVAL, USED);
+ check_and_merge(&esp1, esp2, oper);
+ return(esp1);
+
+ case '(':
+ if (right != 0) {
+ /* function call with parameters */
+ register struct expr *ex = right;
+
+ while ( ex->ex_class == Oper
+ && ex->OP_OPER == PARCOMMA
+ ) {
+ esp2 = lint_expr(ex->OP_RIGHT, RVAL,
+ USED);
+ check_and_merge(&esp1, esp2, oper);
+ ex = ex->OP_LEFT;
+ }
+ esp2 = lint_expr(ex, RVAL, USED);
+ check_and_merge(&esp1, esp2, oper);
+ }
+ if ( left->ex_class == Value
+ && left->VL_CLASS == Name
+ ) {
+ fill_outcall(expr,
+ expr->ex_type->tp_fund == VOID ?
+ VOIDED : used
+ );
+ outcall();
+ left->VL_IDF->id_def->df_used = 1;
+ }
+ else {
+ esp2 = lint_expr(left, val, USED);
+ check_and_merge(&esp1, esp2, oper);
+ }
+ return(esp1);
+
+ case '.':
+ return(lint_expr(left, val, USED));
+
+ case ARROW:
+ return(lint_expr(left, RVAL, USED));
+
+ case '~':
+ case '!':
+ return(lint_expr(right, RVAL, USED));
+
+ case '?':
+ esp1 = lint_expr(left, RVAL, USED);
+ esp2 = lint_expr(right->OP_LEFT, RVAL, USED);
+ check_and_merge(&esp1, esp2, 0);
+ esp2 = lint_expr(right->OP_RIGHT, RVAL, USED);
+ check_and_merge(&esp1, esp2, 0);
+ return(esp1);
+
+ case INT2INT:
+ case INT2FLOAT:
+ case FLOAT2INT:
+ case FLOAT2FLOAT:
+ lint_conversion(oper, right->ex_type, left->ex_type);
+ return(lint_expr(right, RVAL, USED));
+
+ case '<':
+ case '>':
+ case LESSEQ:
+ case GREATEREQ:
+ case EQUAL:
+ case NOTEQUAL:
+ lint_relop(left, right, oper);
+ lint_relop(right, left,
+ oper == '<' ? '>' :
+ oper == '>' ? '<' :
+ oper == LESSEQ ? GREATEREQ :
+ oper == GREATEREQ ? LESSEQ :
+ oper
+ );
+ /*FALLTHROUGH*/
+ case '+':
+ case '/':
+ case '%':
+ case ',':
+ case LEFT:
+ case RIGHT:
+ case '&':
+ case '|':
+ case '^':
+ case OR:
+ case AND:
+ esp1 = lint_expr(left, RVAL,
+ oper == ',' ? IGNORED : USED);
+ esp2 = lint_expr(right, RVAL,
+ oper == ',' ? used : USED);
+ if (oper == OR || oper == AND || oper == ',')
+ check_and_merge(&esp1, esp2, 0);
+ else
+ check_and_merge(&esp1, esp2, oper);
+ return(esp1);
+
+ default:
+ return(0); /* for initcomma */
+ }
+ }
+
+ default:
+ return(0);
+ }
+}
+
+expr_ignored(expr)
+ struct expr *expr;
+{
+ switch (expr->ex_class) {
+ case Oper:
+ switch (expr->OP_OPER) {
+ case '=':
+ case TIMESAB:
+ case DIVAB:
+ case MODAB:
+ case LEFTAB:
+ case RIGHTAB:
+ case ANDAB:
+ case XORAB:
+ case ORAB:
+ case AND: /* doubtful but useful */
+ case OR: /* doubtful but useful */
+ case '(':
+ case '?':
+ case ',':
+ break;
+
+ case PLUSAB:
+ case MINAB:
+ case POSTINCR:
+ case POSTDECR:
+ case PLUSPLUS:
+ case MINMIN:
+ /* may hide the operator * */
+ if ( /* operation on a pointer */
+ expr->OP_TYPE->tp_fund == POINTER
+ && /* the result is dereferenced, e.g. *p++; */
+ expr->ex_type == expr->OP_TYPE->tp_up
+ ) {
+ hwarning("result of * ignored");
+ }
+ break;
+
+ default:
+ hwarning("result of %s ignored",
+ symbol2str(expr->OP_OPER));
+ break;
+ }
+ break;
+
+ case Value:
+ hwarning("identifier as statement");
+ break;
+
+ case String:
+ case Float:
+ hwarning("constant as statement");
+ break;
+ }
+}
+
+#endif LINT
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* LINT FLAGS */
+
+#define USED 0
+#define IGNORED 1
+#define SET 2
+#define VOIDED 3
+
+/* for od_valreturned */
+#define NOVALRETURNED 0
+#define VALRETURNED 1
+#define NORETURN 2 /* end of function NOTREACHED */
+
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* Lint miscellaneous routines */
+
+#include "lint.h"
+
+#ifdef LINT
+
+#include <alloc.h> /* for st_free */
+#include "arith.h" /* definition arith */
+#include "label.h" /* definition label */
+#include "expr.h"
+#include "idf.h"
+#include "def.h"
+#include "code.h" /* RVAL etc */
+#include "LLlex.h"
+#include "Lpars.h"
+#include "stack.h"
+#include "type.h"
+#include "level.h"
+#include "nofloat.h"
+#include "l_state.h"
+
+extern char *symbol2str();
+extern struct type *func_type;
+
+lint_conversion(oper, from_type, to_type)
+ struct type *from_type, *to_type;
+{
+ register int from = from_type->tp_fund;
+ register int to = to_type->tp_fund;
+
+ switch (oper) {
+ case RETURN: /* not really an oper, but it works */
+ case INT2INT:
+ case '=':
+ case PLUSAB:
+ case MINAB:
+ case TIMESAB:
+ case DIVAB:
+ case MODAB:
+ case LEFTAB:
+ case RIGHTAB:
+ case ANDAB:
+ case XORAB:
+ case ORAB:
+ if ( (from == LONG && to != LONG)
+ || (from == DOUBLE && to != DOUBLE)
+ ) {
+ awarning("conversion from %s to %s may lose accuracy",
+ symbol2str(from), symbol2str(to));
+ }
+ }
+}
+
+lint_ret_conv(from_type)
+ struct type *from_type;
+{
+ lint_conversion(RETURN, from_type, func_type);
+}
+
+lint_ptr_conv(from, to)
+ short from, to;
+{
+/* X -> X ok -- this includes struct -> struct, of any size
+ * X -> CHAR ok
+ * DOUBLE -> X ok
+ * FLOAT -> LONG -> INT -> SHORT ok
+ */
+ if (from == to)
+ return;
+
+ if (to == CHAR)
+ return;
+
+ if (from == DOUBLE)
+ return;
+
+ switch (from) {
+ case FLOAT:
+ switch (to) {
+ case LONG:
+ case INT:
+ case SHORT:
+ return;
+ }
+ break;
+ case LONG:
+ switch (to) {
+ case INT:
+ case SHORT:
+ return;
+ }
+ break;
+ case INT:
+ switch (to) {
+ case SHORT:
+ return;
+ }
+ break;
+ }
+
+ if (from == CHAR) {
+ hwarning("pointer to char may not align correctly for a %s",
+ symbol2str(to));
+ }
+ else {
+ warning("pointer to %s may not align correctly for a %s",
+ symbol2str(from), symbol2str(to));
+ }
+}
+
+lint_relop(left, right, oper)
+ struct expr *left, *right;
+ int oper; /* '<', '>', LESSEQ, GREATEREQ, EQUAL, NOTEQUAL */
+{
+ /* <unsigned> <relop> <neg-const|0> is doubtful */
+ if ( left->ex_type->tp_unsigned
+ && right->ex_class == Value
+ && right->VL_CLASS == Const
+ ) {
+ if (right->VL_VALUE < 0) {
+ warning("unsigned compared to negative constant");
+ }
+ if (right->VL_VALUE == 0) {
+ switch (oper) {
+ case '<':
+ warning("unsigned < 0 will always fail");
+ break;
+
+ case LESSEQ:
+ warning("unsigned <= 0 is probably wrong");
+ break;
+
+ case GREATEREQ:
+ warning("unsigned >= 0 will always succeed");
+ break;
+ }
+ }
+ }
+
+ /* <char> <relop> <neg-const> is undefined */
+ if ( left->ex_type->tp_fund == CHAR
+ && right->ex_class == Value
+ && right->VL_CLASS == Const
+ && (right->VL_VALUE < 0 || right->VL_VALUE > 127)
+ ) {
+ warning("character compared to negative constant");
+ }
+}
+
+#endif LINT
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* Lint outdef construction */
+
+#include "lint.h"
+
+#ifdef LINT
+
+#include <alloc.h>
+#include "arith.h"
+#include "type.h"
+#include "LLlex.h"
+#include "Lpars.h"
+#include "stack.h"
+#include "def.h"
+#include "struct.h"
+#include "field.h"
+#include "idf.h"
+#include "level.h"
+#include "label.h"
+#include "expr.h"
+#include "l_lint.h"
+#include "l_outdef.h"
+#include "l_class.h"
+
+extern char *symbol2str();
+
+extern int f_VARARGSn, LINTLIB;
+int stat_number = 9999; /* static scope number */
+struct outdef OutDef, OutCall;
+
+lint_declare_idf(idf, sc)
+ struct idf *idf;
+ int sc;
+{
+ register struct def *def = idf->id_def;
+ register int is_function = def->df_type->tp_fund == FUNCTION;
+
+ if (level == L_GLOBAL) {
+ lint_ext_def(idf, sc);
+ if (is_function)
+ def2decl(sc);
+ if (sc != TYPEDEF)
+ outdef();
+ }
+ else
+ if (level >= L_LOCAL && sc != STATIC && is_function) {
+ local_EFDC(idf);
+ }
+}
+
+lint_ext_def(idf, sc)
+ struct idf *idf;
+{
+/* At this place the following fields of the outputdefinition can be
+ * filled:
+ * name, stat_number, class, file, line, type.
+ * For variable definitions and declarations this will be all.
+ * For functions the fields nrargs and argtps are filled after parsing
+ * the arguments.
+ * The returns-field is known at the end of the function definition.
+ * sc indicates the storage class defined by the declaration specifier.
+ */
+ register struct def *def = idf->id_def;
+ register struct type *type = def->df_type;
+
+ OutDef.od_name = idf->id_text;
+ OutDef.od_statnr = (sc == STATIC ? stat_number : 0);
+
+ switch (type->tp_fund) {
+ case ERRONEOUS:
+ OutDef.od_class = XXDF;
+ break;
+ case FUNCTION:
+ /* For the moment assume it will be a definition.
+ * If no compound_statement follows, it is a declaration,
+ * in which case the class will be adjusted by def2decl().
+ */
+ OutDef.od_class = (sc == STATIC ? SFDF : EFDF);
+ break;
+ default: /* a variable */
+ OutDef.od_class =
+ sc == EXTERN ? EVDC :
+ sc == STATIC ? SVDF : EVDF;
+ break;
+ }
+ OutDef.od_file = def->df_file;
+ OutDef.od_line = def->df_line;
+ OutDef.od_type = (type->tp_fund == FUNCTION ? type->tp_up : type);
+ OutDef.od_valreturned = NORETURN;
+}
+
+def2decl(sc)
+ int sc;
+{
+/* It was assumed we were parsing a function definition.
+ * There was no compound statement following, so actually it was a
+ * declaration. This function updates the class.
+ */
+ OutDef.od_class = (sc == STATIC ? XXDF : EFDC);
+}
+
+set_od_valreturned(n)
+{
+ OutDef.od_valreturned = n;
+}
+
+local_EFDC(idf)
+ struct idf *idf;
+{
+ struct outdef od;
+
+ od.od_class = EFDC;
+ od.od_statnr = 0;
+ od.od_name = idf->id_text;
+ od.od_file = idf->id_def->df_file;
+ od.od_line = idf->id_def->df_line;
+ od.od_type = idf->id_def->df_type->tp_up;
+ output_def(&od);
+ /* The other fields are not used for this class. */
+}
+
+lint_formals()
+{
+/* Make a list of tp_entries containing the types of the formal
+ * parameters of the function definition currently parsed.
+ */
+ register struct stack_entry *se = stack_level_of(L_FORMAL1)->sl_entry;
+ register struct tp_entry **hook = &OutDef.od_entry;
+
+ OutDef.od_nrargs = 0;
+ while (se) {
+ register struct type *type = se->se_idf->id_def->df_type;
+ register struct tp_entry *te = new_tp_entry();
+
+ switch (type->tp_fund) {
+ /* Do the conversions on the formals that could not be
+ done in declare_idf().
+ It is, unfortunately, impossible not to do them,
+ since the corresponding actuals will have been
+ converted to generate proper code and we do not
+ want to duplicate the whole of expression handling
+ for lint.
+ */
+ case CHAR:
+ case SHORT:
+ type = int_type;
+ break;
+ case FLOAT:
+ type = double_type;
+ break;
+ }
+ te->te_type = type;
+ te->te_class = !Const;
+ *hook = te;
+ hook = &te->next;
+
+ OutDef.od_nrargs++;
+ se = se->next;
+ }
+ if (f_VARARGSn > OutDef.od_nrargs) {
+ warning("VARARGS%d function has only %d arguments",
+ f_VARARGSn, OutDef.od_nrargs);
+ f_VARARGSn = OutDef.od_nrargs;
+ }
+}
+
+output_use(idf)
+ struct idf *idf;
+{
+/* Output the usage-definition of the variable described by idf.
+ */
+ OutDef.od_name = idf->id_text;
+ OutDef.od_statnr = (idf->id_def->df_sc == STATIC ? stat_number : 0);
+ OutDef.od_class = VU;
+ OutDef.od_file = FileName;
+ OutDef.od_line = LineNumber;
+ OutDef.od_type = idf->id_def->df_type;
+ outdef();
+}
+
+outdef()
+{
+ output_def(&OutDef);
+}
+
+outcall()
+{
+ output_def(&OutCall);
+}
+
+output_def(od)
+ struct outdef *od;
+{
+/* As the types are output the tp_entries are removed, because they
+ * are then not needed anymore.
+ */
+ if (od->od_class == XXDF)
+ return;
+
+ if (LINTLIB) {
+ switch (od->od_class) {
+ case EFDF:
+ od->od_class = LFDF;
+ break;
+ case EVDF:
+ od->od_class = LVDF;
+ break;
+ case SFDF:
+ /* remove tp_entries */
+ while (od->od_entry) {
+ register struct tp_entry *tmp = od->od_entry;
+ od->od_entry = od->od_entry->next;
+ free_tp_entry(tmp);
+ }
+ return;
+ default:
+ return;
+ }
+ }
+ printf("%s:%d:%c", od->od_name, od->od_statnr, od->od_class);
+ switch (od->od_class) {
+ case EFDF:
+ case SFDF:
+ case LFDF:
+ if (f_VARARGSn != -1) {
+ printf(":%d", -1 - f_VARARGSn);
+ outtypes(od->od_entry, f_VARARGSn);
+ }
+ else {
+ printf(":%d", od->od_nrargs);
+ outtypes(od->od_entry, od->od_nrargs);
+ }
+ od->od_entry = 0;
+ printf(":%d", od->od_valreturned);
+ break;
+ case FC:
+ printf(":%d", od->od_nrargs);
+ outtypes(od->od_entry, od->od_nrargs);
+ od->od_entry = 0;
+ printf(":%d", od->od_valused);
+ break;
+ case EVDF:
+ case SVDF:
+ case LVDF:
+ case EFDC:
+ case EVDC:
+ case IFDC:
+ case VU:
+ break;
+ default:
+ crash("(output_def) illegal class");
+ /*NOTREACHED*/
+ }
+ printf(":");
+ outtype(od->od_type);
+ printf(":%u:%s\n", od->od_line, od->od_file);
+}
+
+outtypes(te, n)
+ struct tp_entry *te;
+{
+/* Output n types in the tp_entry-list and remove all the entries */
+
+ register struct tp_entry *tmp;
+
+ while (n--) {
+ if (!te) {
+ crash("(outtypes) not enough tp_entries");
+ /*NOTREACHED*/
+ }
+ printf(":");
+ if (te->te_class == Const && te->te_value >= 0) {
+ /* constant non-negative actual parameter */
+ printf("+");
+ }
+ outtype(te->te_type);
+ if (te->te_type->tp_fund == FUNCTION) {
+ /* UGLY PATCH !!! ??? */
+ /* function names as operands are sometimes
+ FUNCTION and sometimes POINTER to FUNCTION,
+ depending on opaque circumstances. E.g., in
+ f(main, main);
+ the first main is PtF and the second is F.
+ */
+ printf("*");
+ }
+ tmp = te;
+ te = te->next;
+ free_tp_entry(tmp);
+ }
+ /* remove the remaining entries */
+ while (te) {
+ tmp = te;
+ te = te->next;
+ free_tp_entry(tmp);
+ }
+}
+
+outtype(tp)
+ struct type *tp;
+{
+ switch (tp->tp_fund) {
+ case POINTER:
+ outtype(tp->tp_up);
+ printf("*");
+ break;
+
+ case ARRAY:
+ outtype(tp->tp_up);
+ printf("*"); /* compatible with [] */
+ break;
+
+ case FUNCTION:
+ outtype(tp->tp_up);
+ printf("()");
+ break;
+
+ case STRUCT:
+ case UNION:
+ case ENUM:
+ printf("%s %s", symbol2str(tp->tp_fund), tp->tp_idf->id_text);
+ break;
+
+ case CHAR:
+ case INT:
+ case SHORT:
+ case LONG:
+ case FLOAT:
+ case DOUBLE:
+ case VOID:
+ case ERRONEOUS:
+ if (tp->tp_unsigned)
+ printf("unsigned ");
+ printf("%s", symbol2str(tp->tp_fund));
+ break;
+ default:
+ crash("(outtype) illegal tp_fund");
+ /*NOTREACHED*/
+ }
+}
+
+implicit_func_decl(idf, file, line)
+ struct idf *idf;
+ char *file;
+ unsigned int line;
+{
+ struct outdef od;
+
+ od.od_class = IFDC;
+ od.od_statnr = 0;
+ od.od_name = idf->id_text;
+ od.od_file = file;
+ od.od_line = line;
+ od.od_type = idf->id_def->df_type->tp_up;
+ output_def(&od);
+ /* The other fields are not used for this class. */
+}
+
+fill_outcall(ex, used)
+ struct expr *ex;
+ int used;
+{
+ register struct idf *idf = ex->OP_LEFT->VL_IDF;
+ register struct def *def = idf->id_def;
+
+ if (def->df_sc == IMPLICIT) {
+ implicit_func_decl(idf, ex->ex_file, ex->ex_line);
+ }
+
+ OutCall.od_type = def->df_type->tp_up;
+ OutCall.od_statnr = (def->df_sc == STATIC ? stat_number : 0);
+ OutCall.od_class = FC;
+ OutCall.od_name = idf->id_text;
+ OutCall.od_file = ex->ex_file;
+ OutCall.od_line = ex->ex_line;
+ OutCall.od_entry = (struct tp_entry *)0;
+ OutCall.od_nrargs = 0;
+
+ if ((ex = ex->OP_RIGHT) != 0) { /* function call with arguments */
+ /* store types of argument expressions in tp_entries */
+ while (ex->ex_class == Oper && ex->OP_OPER == PARCOMMA) {
+ fill_arg(ex->OP_RIGHT);
+ ex = ex->OP_LEFT;
+ }
+ fill_arg(ex);
+ }
+ OutCall.od_valused = used; /* USED, IGNORED or VOIDED */
+}
+
+fill_arg(e)
+ struct expr *e;
+{
+ register struct tp_entry *te;
+
+ te = new_tp_entry();
+ te->te_type = e->ex_type;
+ if (is_cp_cst(e)) {
+ te->te_class = Const;
+ te->te_value = e->VL_VALUE;
+ }
+ else {
+ te->te_class = !Const;
+ te->te_value = (arith) 0;
+ }
+ te->next = OutCall.od_entry;
+ OutCall.od_entry = te;
+ OutCall.od_nrargs++;
+}
+
+#endif LINT
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* Lint output definition */
+
+struct tp_entry {
+ struct tp_entry *next;
+ struct type *te_type;
+ int te_class; /* for constant parameters */
+ arith te_value;
+};
+
+/* ALLOCDEF "tp_entry" 10 */
+
+struct outdef {
+ char od_class;
+ int od_statnr;
+ char *od_name;
+ char *od_file;
+ unsigned int od_line;
+ int od_nrargs;
+ struct tp_entry *od_entry; /* a list of the types of the
+ * formal parameters */
+ int od_valreturned;
+ /* NOVALRETURNED, VALRETURNED, NORETURN; see l_lint.h */
+ int od_valused;
+ /* USED, IGNORED, SET, VOIDED; see l_lint.h */
+ struct type *od_type;
+};
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* Lint state stack */
+
+/* These datastructures are used to implement a stack on which the
+ * state of automatic variables (including register variables) is
+ * kept.
+ * In this way it is possible to account for the flow of
+ * control of the program.
+ */
+
+
+struct switch_states {
+ struct state *sws_case;
+ struct state *sws_break;
+ int sws_default_met;
+};
+
+struct lint_stack_entry {
+ struct lint_stack_entry *next;
+ struct lint_stack_entry *ls_previous;
+ short ls_class; /* IF, WHILE, DO, FOR, SWITCH, CASE */
+ int ls_level;
+ struct state *ls_current; /* used by all classes */
+ union {
+ struct state *u_if_state; /* used for IF-class */
+ struct state *u_end; /* used for loop-classes */
+ struct switch_states u_switch;
+ } ls_states; /* not used for CASE-class */
+};
+
+/* macros to access the union */
+#define LS_IF_STATE ls_states.u_if_state
+#define LS_END ls_states.u_end
+#define LS_CASE ls_states.u_switch.sws_case
+#define LS_BREAK ls_states.u_switch.sws_break
+#define LS_DEFAULT_MET ls_states.u_switch.sws_default_met
+
+/* ALLOCDEF "lint_stack_entry" 10 */
+
+struct state {
+ struct state *next; /* only used by memory allocator */
+ struct auto_def *st_auto_list;
+ int st_notreached; /* set if not reached */
+ int st_warned; /* set if warning issued */
+};
+
+/* ALLOCDEF "state" 15 */
+
+struct auto_def {
+ struct auto_def *next;
+ struct idf *ad_idf;
+ struct def *ad_def;
+ int ad_used;
+ int ad_set;
+ int ad_maybe_set;
+};
+
+/* ALLOCDEF "auto_def" 20 */
+
+struct expr_state {
+ struct expr_state *next;
+ struct idf *es_idf;
+ arith es_offset;
+ int es_used;
+ int es_set;
+};
+
+/* ALLOCDEF "expr_state" 20 */
+
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* Lint status checking */
+
+#include "lint.h"
+
+#ifdef LINT
+
+#include <alloc.h> /* for st_free */
+#include "assert.h"
+#include "arith.h" /* definition arith */
+#include "label.h" /* definition label */
+#include "expr.h"
+#include "idf.h"
+#include "def.h"
+#include "code.h" /* RVAL etc */
+#include "LLlex.h"
+#include "Lpars.h"
+#include "stack.h"
+#include "type.h"
+#include "level.h"
+#include "nofloat.h"
+#include "l_lint.h"
+#include "l_brace.h"
+#include "l_state.h"
+#include "l_outdef.h"
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+extern char *symbol2str();
+extern char *func_name;
+extern struct type *func_type;
+extern int func_notypegiven;
+extern char loptions[];
+extern int s_NOTREACHED;
+
+/* global variables for the lint_stack */
+struct lint_stack_entry stack_bottom;
+struct lint_stack_entry *top_ls = &stack_bottom;
+
+/* global variables for the brace stack */
+int brace_count;
+struct brace brace_bottom;
+struct brace *top_br = &brace_bottom;
+
+static print_autos();
+
+lint_start_local()
+{
+ register struct brace *br = new_brace();
+
+ brace_count++;
+ br->br_count = brace_count;
+ br->br_level = level;
+ br->next = top_br;
+ top_br = br;
+}
+
+lint_local_level(stl)
+ struct stack_level *stl;
+{
+ if (s_NOTREACHED) {
+ top_ls->ls_current->st_notreached = 1;
+ s_NOTREACHED = 0;
+ }
+
+ if (top_ls->ls_class == CASE && level == top_ls->ls_level) {
+ lint_break_stmt();
+ /* To prevent a warning for the case
+ * switch (cond) {
+ * int i;
+ * case 0:
+ * i = 0;
+ * use(i);
+ * }
+ */
+ }
+
+ check_autos();
+ end_brace(stl);
+}
+
+end_brace(stl)
+ struct stack_level *stl;
+{
+ /* Check if static variables and labels are used and/or set.
+ */
+ register struct stack_entry *se = stl->sl_entry;
+ register struct brace *br;
+
+ while (se) {
+ register struct idf *idf = se->se_idf;
+ register struct def *def = idf->id_def;
+
+ if (def) {
+ lint_1_local(idf, def);
+ }
+ se = se->next;
+ }
+
+ br = top_br;
+ top_br = br->next;
+ free_brace(br);
+}
+
+lint_1_local(idf, def)
+ struct idf *idf;
+ struct def *def;
+{
+ register int sc = def->df_sc;
+
+ if ( (sc == STATIC || sc == LABEL)
+ && !def->df_used
+ ) {
+ def_warning(def, "%s %s declared but not used in function %s",
+ symbol2str(sc), idf->id_text, func_name);
+ }
+
+ if ( loptions['h']
+ && sc == AUTO
+ && !def->df_initialized
+ && def->df_firstbrace != 0
+ && def->df_minlevel != level
+ ) {
+ register int diff = def->df_minlevel - level;
+
+ def_warning(def,
+ "local %s could be declared %d level%s deeper",
+ idf->id_text, diff, (diff == 1 ? "" : "s")
+ );
+ }
+}
+
+lint_global_level(stl)
+ struct stack_level *stl;
+{
+ register struct stack_entry *se = stl->sl_entry;
+
+ ASSERT(level == L_GLOBAL);
+ while (se) {
+ register struct idf *idf = se->se_idf;
+ register struct def *def = idf->id_def;
+
+ if (def) {
+ lint_1_global(idf, def);
+ }
+ se = se->next;
+ }
+}
+
+lint_1_global(idf, def)
+ struct idf *idf;
+ struct def *def;
+{
+ register int sc = def->df_sc;
+ register int fund = def->df_type->tp_fund;
+
+ switch (sc) {
+ case STATIC:
+ case EXTERN:
+ case GLOBAL:
+ case IMPLICIT:
+ if (fund == ERRONEOUS)
+ break;
+
+ if (def->df_set || def->df_used) {
+ /* Output a line to the intermediate file for
+ * used external variables (including functions)
+ */
+ output_use(idf);
+ }
+ else {
+ if (sc == STATIC) {
+ if (def->df_set) {
+ def_warning(def,
+ "%s %s %s set but not used",
+ symbol2str(sc),
+ symbol2str(fund),
+ idf->id_text);
+ }
+ else {
+ def_warning(def,
+ "%s %s %s not used anywhere",
+ symbol2str(sc),
+ symbol2str(fund),
+ idf->id_text);
+ }
+ }
+ if (loptions['x']) {
+ register char *fn = def->df_file;
+
+ if ( (sc == EXTERN || sc == GLOBAL)
+ && def->df_alloc == 0
+ && !def->df_set
+ && !def->df_initialized
+ && strcmp(&fn[strlen(fn)-2], ".c") == 0
+ ) {
+ def_warning(def,
+ "%s %s %s not used anywhere",
+ symbol2str(sc),
+ symbol2str(fund),
+ idf->id_text);
+ }
+ }
+ }
+ break;
+ }
+}
+
+change_state(idf, to_state)
+ struct idf *idf;
+{
+/* Changes the state of the variable identified by idf in the current state
+ * on top of the stack.
+ * For non-automatic variables, the fields in the def-descriptor are set too.
+ */
+ register struct def *def = idf->id_def;
+ register struct auto_def *a = top_ls->ls_current->st_auto_list;
+
+ if (def) {
+ if (to_state == SET)
+ def->df_set = 1;
+ else
+ def->df_used = 1;
+
+ if (def->df_firstbrace == 0) {
+ def->df_firstbrace = brace_count;
+ def->df_minlevel = level;
+ }
+ else {
+ register struct brace *br = top_br;
+
+ /* find the smallest brace range from which
+ firstbrace is visible
+ */
+ while (br && br->br_count > def->df_firstbrace) {
+ br = br->next;
+ }
+ ASSERT(br && def->df_minlevel >= br->br_level);
+ def->df_minlevel = br->br_level;
+ }
+ }
+
+ while(a && a->ad_idf != idf)
+ a = a->next;
+ if (a == 0) /* identifier not in list */
+ return;
+
+ if (to_state == SET) {
+ a->ad_maybe_set = 0;
+ a->ad_set = 1;
+ return;
+ }
+ /* else to_state == USED */
+ if (!a->ad_set) {
+ warning("%s%s uninitialized", idf->id_text,
+ (a->ad_maybe_set ? " possibly" : "")
+ );
+ a->ad_maybe_set = 0;
+ a->ad_set = 1; /* one warning */
+ }
+ a->ad_used = 1;
+}
+
+extern struct stack_level *local_level;
+
+add_auto(idf) /* to current state on top of lint_stack */
+ struct idf *idf;
+{
+/* Check if idf's definition is really an auto (or register).
+ * It could be a static or extern too.
+ * Watch out for register formal parameters.
+ */
+ register struct def *def = idf->id_def;
+ register struct auto_def *a;
+
+ if (!def)
+ return;
+ switch (def->df_sc) {
+ case AUTO:
+ case REGISTER:
+ if (def->df_level < L_LOCAL)
+ return; /* a register formal */
+ a = new_auto_def();
+ a->ad_idf = idf;
+ a->ad_def = idf->id_def;
+ a->ad_used = def->df_used;
+ a->ad_set = def->df_set;
+ a->next = top_ls->ls_current->st_auto_list;
+ top_ls->ls_current->st_auto_list = a;
+ }
+}
+
+check_autos()
+{
+/* Before leaving a block remove the auto_defs of the automatic
+ * variables on this level and check if they are used
+ */
+ register struct auto_def *a1 = top_ls->ls_current->st_auto_list;
+ register struct auto_def *a2;
+
+ if (a1 && a1->ad_def->df_level > level) {
+ crash("(check_autos) corrupt level in st_auto_list");
+ /*NOTREACHED*/
+ }
+ while (a1 && a1->ad_def->df_level == level) {
+ a2 = a1;
+ a1 = a1->next;
+ if (!a2->ad_used) {
+ if (a2->ad_set || a2->ad_maybe_set) {
+ def_warning(a2->ad_def,
+ "%s set but not used in function %s",
+ a2->ad_idf->id_text, func_name);
+ }
+ else {
+ def_warning(a2->ad_def,
+ "%s neither set nor used in function %s",
+ a2->ad_idf->id_text, func_name);
+ }
+ }
+ free_auto_def(a2);
+ }
+ top_ls->ls_current->st_auto_list = a1;
+}
+
+check_args_used()
+{
+ register struct stack_entry *se = local_level->sl_entry;
+ extern int f_ARGSUSED;
+
+ if (level != L_FORMAL1) {
+ crash("(check_args_used) invalid level %d", level);
+ /*NOTREACHED*/
+ }
+ while (se) {
+ register struct def *def = se->se_idf->id_def;
+
+ if (def && !def->df_used && !loptions['v'] && !f_ARGSUSED) {
+ def_warning(def, "argument %s not used in function %s",
+ se->se_idf->id_text, func_name);
+ }
+ se = se->next;
+ }
+}
+
+struct auto_def *
+copy_st_auto_list(from_al, lvl)
+ struct auto_def *from_al;
+{
+ struct auto_def *start = 0;
+ register struct auto_def **hook = &start;
+
+ while (from_al && from_al->ad_def->df_level > lvl) {
+ from_al = from_al->next;
+ }
+ while (from_al) {
+ register struct auto_def *a = new_auto_def();
+
+ *hook = a;
+ *a = *from_al;
+ hook = &a->next;
+ from_al = from_al->next;
+ }
+
+ return(start);
+}
+
+free_st_auto_list(au)
+ register struct auto_def *au;
+{
+ register struct auto_def *a;
+
+ while (au) {
+ a = au;
+ au = au->next;
+ free_auto_def(a);
+ }
+}
+
+struct state *
+copy_state(from_st, lvl)
+ struct state *from_st;
+{
+/* Memory for the struct state and the struct auto_defs is allocated
+ * by this function
+ */
+ register struct state *st = new_state();
+
+ st->st_auto_list = copy_st_auto_list(from_st->st_auto_list, lvl);
+ st->st_notreached = from_st->st_notreached;
+ st->st_warned = from_st->st_warned;
+ return(st);
+}
+
+static
+Free_state(stp)
+ struct state **stp;
+{
+/* This function also frees the list of auto_defs
+ */
+ free_st_auto_list((*stp)->st_auto_list);
+ free_state(*stp);
+ *stp = 0;
+}
+
+remove_settings(state, lvl)
+ struct state *state;
+{
+/* The state of all variables on this level are set to 'not set' and
+ * 'not maybe set'. (I think you have to read this twice.)
+ */
+ register struct auto_def *a = state->st_auto_list;
+
+ while (a && a->ad_def->df_level == lvl) {
+ a->ad_set = a->ad_maybe_set = 0;
+ a = a->next;
+ }
+}
+
+
+/******** M E R G E ********/
+
+/* modes for merging */
+#define NORMAL 0
+#define CASE_BREAK 1
+#define USE_ONLY 2
+
+struct auto_def *
+merge_autos(a1, a2, lvl, mode)
+ struct auto_def *a1, *a2;
+ int mode;
+{
+/* Returns a pointer to the result.
+ * a1 is left unchanged.
+ * a2 is used to create this result.
+ * The fields are set as follows:
+ * a1_set + a2_set -> set
+ * + a?_maybe_set -> maybe set
+ * ELSE -> NOT set && NOT maybe set
+ * * + a?_used -> used
+ *
+ * For mode == CASE_BREAK:
+ * First a2 is taken as the result, then
+ * variables NOT set in a2 and set or maybe set in a1 become 'maybe set'
+ *
+ * For mode == USE_ONLY:
+ * Start with a2 as the result.
+ * Variables used in a1 become used in a2.
+ * The rest of the result is not changed.
+ */
+ register struct auto_def *a;
+
+ while (a1 && a1->ad_def->df_level > lvl) {
+ a1 = a1->next;
+ }
+ while (a2 && a2->ad_def->df_level > lvl) {
+ a = a2;
+ a2 = a2->next;
+ free_auto_def(a);
+ }
+ a = a2; /* pointer to the result */
+ while (a1) {
+ if (!a2) {
+ crash("(merge_autos) a1 longer than a2");
+ /*NOTREACHED*/
+ }
+ if (a1->ad_idf != a2->ad_idf) {
+ crash("(merge_autos) identifiers should be the same %s %s",
+ a1->ad_idf->id_text, a2->ad_idf->id_text);
+ /*NOTREACHED*/
+ }
+
+ if (a1->ad_used)
+ a2->ad_used = 1;
+
+ if (mode != USE_ONLY) {
+ if ( ( !a2->ad_set
+ && (a1->ad_set || a1->ad_maybe_set)
+ )
+ || ( mode == NORMAL
+ && !a1->ad_set
+ && (a2->ad_set || a2->ad_maybe_set)
+ )
+ ) {
+ a2->ad_set = 0;
+ a2->ad_maybe_set = 1;
+ }
+ }
+
+ a1 = a1->next;
+ a2 = a2->next;
+ }
+ if (a2) {
+ crash("(merge_autos) a2 longer than a1");
+ /*NOTREACHED*/
+ }
+ return(a);
+}
+
+merge_states(st1, st2, lvl, mode)
+ struct state *st1, *st2;
+ int mode;
+{
+/* st2 becomes the result.
+ * st1 is left unchanged.
+ * The resulting state is the state the program gets in if st1 OR st2
+ * becomes the state. (E.g. the states at the end of an if-part and an
+ * end-part are merged by this function.)
+ */
+ if (st1->st_notreached) {
+ if (mode == NORMAL || st2->st_notreached) {
+ st2->st_auto_list =
+ merge_autos(st1->st_auto_list,
+ st2->st_auto_list, lvl, USE_ONLY);
+ }
+ }
+ else if (st2->st_notreached) {
+ register struct auto_def *tmp = st2->st_auto_list;
+
+ st2->st_auto_list = copy_st_auto_list(st1->st_auto_list, lvl);
+ st2->st_notreached = 0;
+ st2->st_warned = 0;
+ st2->st_auto_list = merge_autos(tmp, st2->st_auto_list,
+ lvl, USE_ONLY);
+ free_st_auto_list(tmp);
+ }
+ else {
+ st2->st_auto_list =
+ merge_autos(st1->st_auto_list, st2->st_auto_list,
+ lvl, mode);
+ }
+}
+
+
+/******** L I N T S T A C K S E A R C H I N G ********/
+
+/* The next four find-functions search the lint_stack for an entry.
+ * The letters mean : w: WHILE; d: DO; f: FOR; s: SWITCH; c: CASE.
+ */
+
+struct lint_stack_entry *
+find_wdf()
+{
+ register struct lint_stack_entry *lse = top_ls;
+
+ while (lse != &stack_bottom) {
+ switch (lse->ls_class)
+ case WHILE:
+ case DO:
+ case FOR:
+ return(lse);
+ lse = lse->ls_previous;
+ }
+ return(0);
+}
+
+struct lint_stack_entry *
+find_wdfc()
+{
+ register struct lint_stack_entry *lse = top_ls;
+
+ while (lse != &stack_bottom) {
+ switch (lse->ls_class)
+ case WHILE:
+ case DO:
+ case FOR:
+ case CASE:
+ return(lse);
+ lse = lse->ls_previous;
+ }
+ return(0);
+}
+
+struct lint_stack_entry *
+find_cs()
+{
+ register struct lint_stack_entry *lse = top_ls;
+
+ while (lse != &stack_bottom) {
+ switch (lse->ls_class)
+ case CASE:
+ case SWITCH:
+ return(lse);
+ lse = lse->ls_previous;
+ }
+ return(0);
+}
+
+/******** A C T I O N S ********/
+
+start_if_part()
+{
+/* Push a new stack entry on the lint_stack with class == IF
+ * copy the ls_current to the top of this stack
+ */
+ register struct lint_stack_entry *lse = new_lint_stack_entry();
+
+ lse->ls_class = IF;
+ lse->ls_current = copy_state(top_ls->ls_current, level);
+ lse->ls_level = level;
+ lint_push(lse);
+}
+
+start_else_part()
+{
+/* Move ls_current to LS_IF_STATE
+ * ls_current of the stack entry one below is copied to ls_current.
+ */
+ if (s_NOTREACHED) {
+ top_ls->ls_current->st_notreached = 1;
+ s_NOTREACHED = 0;
+ }
+ top_ls->LS_IF_STATE = top_ls->ls_current;
+ /* this is the reason why ls_current is a pointer */
+ top_ls->ls_current = copy_state(top_ls->ls_previous->ls_current,
+ level);
+ top_ls->ls_level = level;
+}
+
+end_if_else_stmt()
+{
+ Free_state(&top_ls->ls_previous->ls_current);
+ merge_states(top_ls->LS_IF_STATE, top_ls->ls_current,
+ top_ls->ls_level, NORMAL);
+ Free_state(&top_ls->LS_IF_STATE);
+ top_ls->ls_previous->ls_current = top_ls->ls_current;
+ lint_pop();
+}
+
+end_if_stmt()
+{
+/* No else-part met; merge ls_current with ls_current of previous
+ * stack entry
+ */
+ merge_states(top_ls->ls_current, top_ls->ls_previous->ls_current,
+ top_ls->ls_level, NORMAL);
+ Free_state(&top_ls->ls_current);
+ lint_pop();
+}
+
+start_loop_stmt(looptype, const, cond)
+{
+/* If const, the condition is constant and given in cond */
+ register struct lint_stack_entry *lse = new_lint_stack_entry();
+
+ lse->ls_class = looptype;
+ lse->ls_current = copy_state(top_ls->ls_current, level);
+ lse->ls_level = level;
+ if (const && !cond) {
+ /* while (0) | for (;0;) */
+ hwarning("condition in %s statement is constant",
+ symbol2str(looptype));
+ lse->ls_current->st_notreached = 1;
+ }
+ if (const && cond) {
+ /* while (1) | for (;;) | do */
+ /* omitting the copy for LS_END will force this loop
+ to be treated as a do loop
+ */
+ top_ls->ls_current->st_notreached = 1;
+ }
+ else {
+ lse->LS_END = copy_state(top_ls->ls_current, level);
+ }
+ lint_push(lse);
+}
+
+end_loop_stmt()
+{
+ register struct lint_stack_entry *prev_ls = top_ls->ls_previous;
+
+ lint_continue_stmt();
+ top_ls->LS_END->st_notreached = prev_ls->ls_current->st_notreached;
+ top_ls->LS_END->st_warned = prev_ls->ls_current->st_warned;
+ Free_state(&top_ls->ls_current);
+ Free_state(&prev_ls->ls_current);
+ prev_ls->ls_current = top_ls->LS_END;
+ lint_pop();
+}
+
+end_do_stmt(const, cond)
+{
+ end_loop_stmt();
+ if (const)
+ hwarning("constant do condition");
+ if (const && cond && top_ls->ls_current->st_notreached) {
+ /* no break met; this is really an endless loop */
+ }
+ else {
+ top_ls->ls_current->st_notreached = 0;
+ }
+}
+
+cont_break_merge(lse)
+ struct lint_stack_entry *lse;
+{
+ /* merge for continue and break statements */
+ if (lse->LS_END) {
+ merge_states(top_ls->ls_current, lse->LS_END,
+ lse->ls_level, NORMAL);
+ }
+ else {
+ lse->LS_END = copy_state(top_ls->ls_current, lse->ls_level);
+ }
+}
+
+lint_continue_stmt()
+{
+ register struct lint_stack_entry *lse = find_wdf();
+
+ if (!lse)
+ return; /* not inside a loop statement */
+
+ cont_break_merge(lse);
+ top_ls->ls_current->st_notreached = 1;
+}
+
+start_switch_part()
+{
+/* ls_current of a SWITCH entry has different meaning from ls_current of
+ * other entries. It keeps track of which variables are used in all
+ * following case parts. (Needed for variables declared in a compound
+ * switch-block.)
+ */
+ register struct lint_stack_entry *lse = new_lint_stack_entry();
+
+ lse->ls_class = SWITCH;
+ lse->ls_current = copy_state(top_ls->ls_current, level);
+ lse->ls_level = level;
+ lse->LS_CASE = copy_state(top_ls->ls_current, level);
+ lse->ls_current->st_notreached = 1;
+ top_ls->ls_current->st_notreached = 1;
+ lint_push(lse);
+}
+
+end_switch_stmt()
+{
+ if (top_ls->ls_class == CASE) {
+ /* no break after last case or default */
+ lint_break_stmt(); /* introduce break */
+ }
+
+ if (!top_ls->LS_DEFAULT_MET) {
+ top_ls->ls_current->st_notreached = 0;
+ if (top_ls->LS_BREAK) {
+ merge_states(top_ls->ls_current, top_ls->LS_BREAK,
+ top_ls->ls_level, NORMAL);
+ Free_state(&top_ls->ls_current);
+ }
+ else {
+ top_ls->LS_BREAK = top_ls->ls_current;
+ }
+ }
+ else {
+ Free_state(&top_ls->ls_current);
+ }
+
+ if (top_ls->LS_BREAK) {
+ merge_states(top_ls->LS_CASE, top_ls->LS_BREAK,
+ top_ls->ls_level, CASE_BREAK);
+ Free_state(&top_ls->LS_CASE);
+ }
+ else {
+ top_ls->LS_BREAK = top_ls->LS_CASE;
+ }
+
+ top_ls->LS_BREAK->st_notreached =
+ top_ls->ls_previous->ls_current->st_notreached;
+ /* yack */
+ Free_state(&top_ls->ls_previous->ls_current);
+
+ if (!top_ls->LS_DEFAULT_MET)
+ top_ls->LS_BREAK->st_notreached = 0;
+ top_ls->ls_previous->ls_current = top_ls->LS_BREAK;
+
+ lint_pop();
+}
+
+lint_case_stmt(dflt)
+{
+/* A default statement is just a special case statement */
+
+ register struct lint_stack_entry *lse;
+ register struct lint_stack_entry *cs_entry = find_cs();
+
+ if (!cs_entry)
+ return; /* not inside switch */
+ if (cs_entry != top_ls) {
+ warning("%s statement in strange context",
+ dflt ? "default" : "case");
+ return;
+ }
+ if (cs_entry->ls_class == SWITCH) {
+ if (dflt) {
+ cs_entry->LS_DEFAULT_MET = 1;
+ }
+ lse = new_lint_stack_entry();
+ lse->ls_class = CASE;
+ lse->ls_current = copy_state(top_ls->ls_current, level);
+ remove_settings(lse->ls_current, level);
+ lse->ls_level = level;
+ lint_push(lse);
+ }
+ else {
+ ASSERT(cs_entry->ls_class == CASE);
+ if (dflt) {
+ cs_entry->ls_previous->LS_DEFAULT_MET = 1;
+ }
+ merge_states(top_ls->ls_current, top_ls->ls_previous->LS_CASE,
+ top_ls->ls_previous->ls_level, NORMAL);
+ merge_states(top_ls->ls_current,
+ top_ls->ls_previous->ls_current,
+ top_ls->ls_previous->ls_level, NORMAL);
+ Free_state(&top_ls->ls_current);
+ top_ls->ls_current =
+ copy_state(top_ls->ls_previous->ls_current,
+ top_ls->ls_previous->ls_level);
+ remove_settings(top_ls->ls_current, top_ls->ls_level);
+ }
+}
+
+lint_break_stmt()
+{
+ register struct lint_stack_entry *lse = find_wdfc();
+
+ if (!lse)
+ return;
+
+ switch (lse->ls_class) {
+ case WHILE:
+ case FOR:
+ case DO:
+ /* loop break */
+ lse->ls_previous->ls_current->st_notreached = 0;
+ cont_break_merge(lse);
+ break;
+
+ case CASE:
+ /* case break */
+ if (!top_ls->ls_current->st_notreached) {
+ lse->ls_previous->ls_previous->ls_current->st_notreached = 0;
+ }
+ merge_states(lse->ls_current, lse->ls_previous->ls_current,
+ lse->ls_previous->ls_level, NORMAL);
+ if (lse->ls_previous->LS_BREAK) {
+ merge_states(top_ls->ls_current, lse->ls_previous->LS_BREAK,
+ lse->ls_previous->ls_level, NORMAL);
+ }
+ else {
+ lse->ls_previous->LS_BREAK = copy_state(top_ls->ls_current,
+ lse->ls_previous->ls_level);
+ }
+ if (lse == top_ls) {
+ Free_state(&lse->ls_current);
+ lint_pop();
+ }
+ break;
+ default:
+ /* bad break */
+ crash("find_wdfc() returned invalid entry");
+ /*NOTREACHED*/
+ }
+ top_ls->ls_current->st_notreached = 1;
+}
+
+lint_start_function()
+{
+ lint_return_stmt(-1); /* initialization */
+ move_ARG2f();
+ move_VAR2f();
+}
+
+lint_end_function()
+{
+ extern struct outdef OutDef;
+ register int fund = func_type->tp_fund;
+
+ if ( OutDef.od_valreturned == NOVALRETURNED
+ && !func_notypegiven
+ && fund != VOID
+ ) {
+ warning("function %s declared %s%s but no value returned",
+ func_name,
+ (func_type->tp_unsigned && fund != POINTER) ?
+ "unsigned " : "",
+ symbol2str(fund)
+ );
+ }
+ /* write the function definition record */
+ outdef();
+
+ /* At this stage it is possible that stack_bottom.ls_current is
+ * pointing to a state with a list of auto_defs.
+ * These auto_defs must be freed and the state must be filled
+ * with zeros.
+ */
+ if (top_ls != &stack_bottom) {
+ crash("(lint_end_function) top_ls != &stack_bottom");
+ /*NOTREACHED*/
+ }
+ if (top_ls->ls_current->st_auto_list != 0)
+ free_st_auto_list(top_ls->ls_current->st_auto_list);
+ top_ls->ls_current->st_auto_list = 0;
+ top_ls->ls_current->st_notreached = 0;
+ top_ls->ls_current->st_warned = 0;
+}
+
+lint_return_stmt(e)
+ int e;
+{
+/* The statics of this function are initialized by calling it with e = -1. */
+
+ static int ret_e;
+ /*-1 no return met yet
+ * 0 return; met
+ * 1 return with expression met
+ */
+ static int warned;
+
+ switch (e) {
+ case -1:
+ ret_e = -1;
+ warned = 0;
+ return;
+ case 0:
+ if (top_ls->ls_current->st_notreached)
+ break;
+ if (ret_e == 1 && !warned) {
+ warning("function %s does not always return a value",
+ func_name);
+ warned = 1;
+ }
+ else
+ ret_e = 0;
+ break;
+ case 1:
+ if (top_ls->ls_current->st_notreached)
+ break;
+ if (ret_e == 0 && !warned) {
+ warning("function %s does not always return a value",
+ func_name);
+ warned = 1;
+ }
+ else
+ ret_e = 1;
+ break;
+ }
+ if (!top_ls->ls_current->st_notreached)
+ set_od_valreturned(e);
+ top_ls->ls_current->st_notreached = 1;
+}
+
+lint_jump_stmt(idf)
+ struct idf *idf;
+{
+ top_ls->ls_current->st_notreached = 1;
+ if (!idf->id_def)
+ return;
+ idf->id_def->df_used = 1;
+}
+
+lint_label()
+{
+/* When meeting a label, we should take the intersection of all
+ settings at all goto's leading this way, but this cannot reasonably
+ be done. So we assume that the user knows what he is doing and set
+ all automatic variables to set.
+*/
+ register struct auto_def *a = top_ls->ls_current->st_auto_list;
+
+ hwarning("all auto variables assumed initialized at label");
+ while (a) {
+ a->ad_maybe_set = 0;
+ a->ad_set = 1;
+ a = a->next;
+ }
+}
+
+lint_statement()
+{
+/* Check if this statement can be reached
+ */
+ if (s_NOTREACHED) {
+ top_ls->ls_current->st_notreached = 1;
+ s_NOTREACHED = 0;
+ }
+ if (DOT == '{' || DOT == ';')
+ return;
+ if (top_ls->ls_current->st_warned)
+ return;
+ if (top_ls->ls_current->st_notreached) {
+ if (DOT != CASE && DOT != DEFAULT && AHEAD != ':') {
+ if (DOT != BREAK || !loptions['b'])
+ warning("statement cannot be reached");
+ top_ls->ls_current->st_warned = 1;
+ }
+ else {
+ top_ls->ls_current->st_notreached = 0;
+ top_ls->ls_current->st_warned = 0;
+ }
+ }
+}
+
+lint_push(lse)
+ struct lint_stack_entry *lse;
+{
+ lse->ls_previous = top_ls;
+ top_ls->next = lse;
+ top_ls = lse;
+}
+
+lint_pop()
+{
+ top_ls = top_ls->ls_previous;
+ free_lint_stack_entry(top_ls->next);
+}
+
+
+/* FOR DEBUGGING */
+
+print_lint_stack()
+{
+ register struct lint_stack_entry *lse = top_ls;
+
+ while (lse) {
+ print(" |-------------- level %d ------------\n",
+ lse->ls_level);
+ print(" |cur: ");
+ if (lse->ls_current) {
+ print_autos(lse->ls_current->st_auto_list);
+ print(" |st_notreached == %d\n",
+ lse->ls_current->st_notreached);
+ }
+ else
+ print("\n");
+ print(" |class == %s\n",
+ lse->ls_class ? symbol2str(lse->ls_class) : "{");
+ switch (lse->ls_class) {
+ case SWITCH:
+ print(" |LS_BREAK: ");
+ if (lse->LS_BREAK) {
+ print_autos(lse->LS_BREAK->st_auto_list);
+ print(" |st_notreached == %d\n",
+ lse->LS_BREAK->st_notreached);
+ }
+ else
+ print("\n");
+ print(" |LS_CASE: ");
+ if (lse->LS_CASE) {
+ print_autos(lse->LS_CASE->st_auto_list);
+ print(" |st_notreached == %d\n",
+ lse->LS_CASE->st_notreached);
+ }
+ else
+ print("\n");
+ break;
+ case DO:
+ case WHILE:
+ case FOR:
+ print(" |LS_END: ");
+ if (lse->LS_END) {
+ print_autos(lse->LS_END->st_auto_list);
+ print(" |st_notreached == %d\n",
+ lse->LS_END->st_notreached);
+ }
+ else
+ print("\n");
+ break;
+ case IF:
+ print(" |LS_IF_STATE: ");
+ if (lse->LS_IF_STATE) {
+ print_autos(lse->LS_IF_STATE->st_auto_list);
+ print(" |st_notreached == %d\n",
+ lse->LS_IF_STATE->st_notreached);
+ }
+ else
+ print("\n");
+ break;
+ default:
+ break;
+ }
+ lse = lse->ls_previous;
+ }
+ print(" |--------------\n\n");
+}
+
+static
+print_autos(a)
+ register struct auto_def *a;
+{
+ while (a) {
+ print("%s", a->ad_idf->id_text);
+ print("(l=%d)", a->ad_def->df_level);
+ print("(U%dS%dM%d) ", a->ad_used, a->ad_set, a->ad_maybe_set);
+ a = a->next;
+ }
+ print("\n");
+}
+#endif LINT
/* $Header$ */
/* MAIN PROGRAM */
+#include "lint.h"
#include "nofloat.h"
#include <system.h>
#include "nopp.h"
inc_max = 10;
init_pp(); /* initialise the preprocessor macros */
+#ifdef LINT
+ lint_init();
+#endif LINT
#endif NOPP
/* Note: source file "-" indicates that the source is supplied
char *argv[];
{
char *result;
+#ifndef LINT
register char *destination = 0;
+#endif LINT
+
#ifdef DEBUG
#ifndef NOPP
int pp_only = options['E'] || options['P'] || options['C'];
switch (argc) {
case 1:
+#ifndef LINT
#ifdef DEBUG
#ifndef NOPP
if (!pp_only)
#endif NOPP
#endif
fatal("%s: destination file not specified", prog_name);
+#endif LINT
break;
+#ifndef LINT
case 2:
destination = argv[1];
break;
nmlist = argv[2];
destination = argv[1];
break;
+#endif LINT
+
default:
+#ifndef LINT
fatal("use: %s source destination [namelist]", prog_name);
+#else LINT
+ fatal("use: %s source", prog_name);
+#endif LINT
break;
}
#endif NOPP
#endif DEBUG
{
+#ifndef LINT
init_code(destination && strcmp(destination, "-") != 0 ?
destination : 0);
+#endif LINT
+
/* compile the source text */
C_program();
/* $Header$ */
/* U S E R O P T I O N - H A N D L I N G */
+#include "lint.h"
#include "botch_free.h"
#include <alloc.h>
#include "nofloat.h"
#endif NOPP
char options[128]; /* one for every char */
+#ifdef LINT
+char loptions[128]; /* one for every char */
+#endif LINT
+
extern int idfsize;
static int txt2int();
break;
default:
+#ifndef LINT
fatal("illegal option: %c", opt);
+#else LINT
+ warning("illegal option: %c", opt);
+#endif LINT
break;
case '-':
options[*text++] = 1; /* flags, debug options etc. */
goto next_option;
+#ifndef LINT
#ifdef DATAFLOW
case 'd':
#endif DATAFLOW
case 'L' : /* no fil/lin */
case 'n': /* use no registers */
case 'w': /* no warnings will be given */
-#ifndef NOROPTION
- case 'R': /* strict version */
-#endif
options[opt] = 1;
goto next_option;
-#ifdef NOROPTION
- case 'R':
+#endif LINT
+
+#ifdef LINT
+ case 'h': /* heuristic tests */
+ case 'v': /* no complaints about unused arguments */
+ case 'a': /* check long->int int->long conversions */
+ case 'b': /* don't report unreachable break-statements */
+ case 'x': /* complain about unused extern declared variables */
+ case 'u': /* no "used but not defined"; for pass 2 */
+ loptions[opt] = 1;
+ goto next_option;
+#endif LINT
+
+ case 'R': /* strict version */
+#ifndef NOROPTION
+ options[opt] = 1;
+#else NOROPTION
warning("-R option not implemented");
+#endif NOROPTION
goto next_option;
-#endif
#ifdef ___XXX___
deleted, is now a debug-flag
break;
#endif ___XXX___
+#ifdef LINT
+ case 'S' : { /* -Sint : static scope number for lint */
+ extern int stat_number;
+ stat_number = txt2int(&text);
+ break;
+ }
+#endif LINT
+
case 'T' : {
#ifdef USE_TMP
extern char *C_tmpdir;
break;
}
+#ifndef LINT
case 'V' : /* set object sizes and alignment requirements */
#ifdef NOCROSS
warning("-V option ignored");
break;
}
#endif NOCROSS
+#endif LINT
}
}
%start If_expr, control_if_expression;
{
+#include "lint.h"
#include "nopp.h"
#include "arith.h"
#include "LLlex.h"
#include "code.h"
#include "expr.h"
#include "def.h"
+#ifdef LINT
+#include "l_state.h"
+#endif LINT
+
#ifndef NOPP
extern arith ifval;
#endif NOPP
declarator(&Dc)
{
declare_idf(&Ds, &Dc, level);
+#ifdef LINT
+ lint_ext_def(Dc.dc_idf, Ds.ds_sc);
+#endif LINT
}
[%if (Dc.dc_idf->id_def->df_type->tp_fund == FUNCTION)
/* int i (1) {2, 3}
{ code_declaration(dc->dc_idf, (struct expr *) 0, level, ds->ds_sc); }
]
{
+#ifdef LINT
+ if (dc->dc_idf->id_def->df_type->tp_fund == FUNCTION)
+ def2decl(ds->ds_sc);
+ if (dc->dc_idf->id_def->df_sc != TYPEDEF)
+ outdef();
+#endif LINT
}
[
','
}
:
{ register struct idf *idf = dc->dc_idf;
+#ifdef LINT
+ lint_start_function();
+#endif LINT
init_idf(idf);
stack_level(); /* L_FORMAL1 declarations */
declare_params(dc);
declaration*
{
declare_formals(&fbytes);
+#ifdef LINT
+ lint_formals();
+#endif LINT
}
compound_statement
{
end_proc(fbytes);
+#ifdef LINT
+ lint_return_stmt(0); /* implicit return at end of function */
+#endif LINT
unstack_level(); /* L_FORMAL2 declarations */
+#ifdef LINT
+ check_args_used();
+#endif LINT
unstack_level(); /* L_FORMAL1 declarations */
+#ifdef LINT
+ lint_end_function();
+#endif LINT
}
;
/* $Header$ */
/* S T A C K / U N S T A C K R O U T I N E S */
+#include "lint.h"
#include "nofloat.h"
#include <system.h>
#include <em.h>
stl->sl_level = ++level;
stl->sl_max_block = loclev->sl_max_block;
local_level = stl;
+#ifdef LINT
+ lint_start_local();
+#endif LINT
}
stack_idf(idf, stl)
dumpidftab("before unstackidfs", 0);
#endif DEBUG
+#ifdef LINT
+ lint_local_level(local_level);
+#endif LINT
+
/* The implementation below is more careful than strictly
necessary. Optimists may optimize it afterwards.
*/
*/
register struct stack_entry *se = local_level->sl_entry;
+#ifdef LINT
+ lint_global_level(local_level);
+#endif LINT
+
open_name_list();
while (se) {
{
#include <em.h>
+#include "lint.h"
#include "debug.h"
#include "botch_free.h"
#include "code.h"
#include "stack.h"
#include "def.h"
+#ifdef LINT
+#include "l_lint.h"
+#include "l_state.h"
+#endif LINT
+
extern int level;
}
/* 9 */
statement
{
+#ifdef LINT
+ lint_statement();
+#endif LINT
}
:
%if (AHEAD != ':')
BREAK
{
code_break();
+#ifdef LINT
+ lint_break_stmt();
+#endif LINT
}
';'
|
CONTINUE
{
code_continue();
+#ifdef LINT
+ lint_continue_stmt();
+#endif LINT
}
';'
|
grz: printf("A labelled statement\n");
}
*/
+#ifdef LINT
+ lint_label();
+#endif LINT
define_label(idf);
C_df_ilb((label)idf->id_def->df_address);
}
/* The comparison has been optimized
to a 0 or 1.
*/
+#ifdef LINT
+ hwarning("condition in if is constant");
+#endif LINT
if (expr->VL_VALUE == (arith)0) {
C_bra(l_false);
}
C_df_ilb(l_true);
}
free_expression(expr);
+#ifdef LINT
+ start_if_part();
+#endif LINT
}
')'
statement
[%prefer
ELSE
{
+#ifdef LINT
+ start_else_part();
+#endif LINT
C_bra(l_end);
C_df_ilb(l_false);
}
statement
{ C_df_ilb(l_end);
+#ifdef LINT
+ end_if_else_stmt();
+#endif LINT
}
|
empty
{ C_df_ilb(l_false);
+#ifdef LINT
+ end_if_stmt();
+#endif LINT
}
]
;
if (expr->VL_VALUE == (arith)0) {
C_bra(l_break);
}
+#ifdef LINT
+ start_loop_stmt(WHILE, 1,
+ expr->VL_VALUE != (arith)0);
+#endif LINT
}
else {
code_expr(expr, RVAL, TRUE, l_body, l_break);
C_df_ilb(l_body);
+#ifdef LINT
+ start_loop_stmt(WHILE, 0, 0);
+#endif LINT
}
}
')'
C_df_ilb(l_break);
unstack_stmt();
free_expression(expr);
+#ifdef LINT
+ end_loop_stmt();
+#endif LINT
}
;
DO
{ C_df_ilb(l_body);
stack_stmt(l_break, l_continue);
+#ifdef LINT
+ start_loop_stmt(DO, 1, 1);
+#endif LINT
}
statement
WHILE
if (expr->VL_VALUE == (arith)1) {
C_bra(l_body);
}
+#ifdef LINT
+ end_do_stmt(1, expr->VL_VALUE != (arith)0);
+#endif LINT
}
else {
code_expr(expr, RVAL, TRUE, l_body, l_break);
+#ifdef LINT
+ end_do_stmt(0, 0);
+#endif LINT
}
C_df_ilb(l_break);
}
label l_continue = text_label();
label l_body = text_label();
label l_test = text_label();
+#ifdef LINT
+ int const = 1, cond = 1; /* the default case */
+#endif LINT
}
:
FOR
if (e_test->VL_VALUE == (arith)0) {
C_bra(l_break);
}
+#ifdef LINT
+ const = 1,
+ cond = e_test->VL_VALUE != (arith)0;
+#endif LINT
}
else {
code_expr(e_test, RVAL, TRUE, l_body, l_break);
C_df_ilb(l_body);
+#ifdef LINT
+ const = 0, cond = 0;
+#endif LINT
}
}
]?
expression(&e_incr)?
')'
{
+#ifdef LINT
+ start_loop_stmt(FOR, const, cond);
+#endif LINT
}
statement
{
+#ifdef LINT
+ end_loop_stmt();
+#endif LINT
C_df_ilb(l_continue);
if (e_incr)
code_expr(e_incr, RVAL, FALSE,
expression(&expr)
{
code_startswitch(&expr);
+#ifdef LINT
+ start_switch_part();
+ /* the following is a trick to detect a constant
+ * expression in a switch
+ */
+ opnd2test(&expr, SWITCH);
+ if (is_cp_cst(expr))
+ hwarning("switch value is constant");
+#endif LINT
}
')'
statement
{
+#ifdef LINT
+ end_switch_stmt();
+#endif LINT
code_endswitch();
free_expression(expr);
}
CASE
constant_expression(&expr)
{
+#ifdef LINT
+ lint_case_stmt(0);
+#endif LINT
code_case(expr);
free_expression(expr);
}
:
DEFAULT
{
+#ifdef LINT
+ lint_case_stmt(1);
+#endif LINT
code_default();
}
':'
[
expression(&expr)
{
+#ifdef LINT
+ lint_ret_conv(expr->ex_type);
+#endif LINT
+
do_return_expr(expr);
free_expression(expr);
+#ifdef LINT
+ lint_return_stmt(1);
+#endif LINT
}
|
empty
{
do_return();
+#ifdef LINT
+ lint_return_stmt(0);
+#endif LINT
}
]
';'
{
apply_label(idf);
C_bra((label)idf->id_def->df_address);
+#ifdef LINT
+ lint_jump_stmt(idf);
+#endif LINT
}
;
#include <alloc.h>
#include <em_mes.h>
+#include "lint.h"
#include "util.h"
#include "use_tmp.h"
#include "regcount.h"
}
}
+#ifndef LINT
AddrLocal(off)
arith off;
{
if (p) p->t_regtype = -1;
C_lal(off);
}
+#endif LINT