From 6839d8afb14e008b686d8c2322ed785d37f23af3 Mon Sep 17 00:00:00 2001 From: dick Date: Tue, 20 Sep 1988 16:44:27 +0000 Subject: [PATCH] introduction of lint source code, governed by ifdef LINT --- lang/cem/cemcom/LLlex.c | 14 + lang/cem/cemcom/LintPars | 139 +++++ lang/cem/cemcom/Makefile | 191 +++++- lang/cem/cemcom/Parameters | 4 + lang/cem/cemcom/Resolve | 2 +- lang/cem/cemcom/blocks.c | 5 + lang/cem/cemcom/ch7.c | 5 + lang/cem/cemcom/code.c | 22 + lang/cem/cemcom/conversion.c | 5 + lang/cem/cemcom/declar.g | 19 + lang/cem/cemcom/def.str | 6 + lang/cem/cemcom/error.c | 74 +++ lang/cem/cemcom/eval.c | 5 + lang/cem/cemcom/expr.c | 5 + lang/cem/cemcom/expression.g | 5 + lang/cem/cemcom/field.c | 5 + lang/cem/cemcom/idf.c | 22 + lang/cem/cemcom/ival.g | 8 + lang/cem/cemcom/l_class.h | 21 + lang/cem/cemcom/l_comment.c | 129 ++++ lang/cem/cemcom/l_dummy.c | 63 ++ lang/cem/cemcom/l_ev_ord.c | 118 ++++ lang/cem/cemcom/l_lint.c | 350 +++++++++++ lang/cem/cemcom/l_lint.h | 17 + lang/cem/cemcom/l_misc.c | 155 +++++ lang/cem/cemcom/l_outdef.c | 414 +++++++++++++ lang/cem/cemcom/l_outdef.str | 31 + lang/cem/cemcom/l_state.str | 73 +++ lang/cem/cemcom/l_states.c | 1102 ++++++++++++++++++++++++++++++++++ lang/cem/cemcom/main.c | 19 + lang/cem/cemcom/options.c | 44 +- lang/cem/cemcom/program.g | 29 + lang/cem/cemcom/stack.c | 12 + lang/cem/cemcom/statement.g | 99 +++ lang/cem/cemcom/util.c | 3 + 35 files changed, 3199 insertions(+), 16 deletions(-) create mode 100644 lang/cem/cemcom/LintPars create mode 100644 lang/cem/cemcom/l_class.h create mode 100644 lang/cem/cemcom/l_comment.c create mode 100644 lang/cem/cemcom/l_dummy.c create mode 100644 lang/cem/cemcom/l_ev_ord.c create mode 100644 lang/cem/cemcom/l_lint.c create mode 100644 lang/cem/cemcom/l_lint.h create mode 100644 lang/cem/cemcom/l_misc.c create mode 100644 lang/cem/cemcom/l_outdef.c create mode 100644 lang/cem/cemcom/l_outdef.str create mode 100644 lang/cem/cemcom/l_state.str create mode 100644 lang/cem/cemcom/l_states.c diff --git a/lang/cem/cemcom/LLlex.c b/lang/cem/cemcom/LLlex.c index 9b6bbf322..21a74876b 100644 --- a/lang/cem/cemcom/LLlex.c +++ b/lang/cem/cemcom/LLlex.c @@ -5,6 +5,7 @@ /* $Header$ */ /* L E X I C A L A N A L Y Z E R */ +#include "lint.h" #include #include "nofloat.h" #include "idfsize.h" @@ -72,6 +73,9 @@ LLlex() 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 @@ -472,6 +476,10 @@ skipcomment() NoUnstack++; LoadChar(c); +#ifdef LINT + lint_comment(-2); + lint_comment(c); +#endif LINT do { while (c != '*') { if (class(c) == STNL) @@ -482,8 +490,14 @@ skipcomment() 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--; } diff --git a/lang/cem/cemcom/LintPars b/lang/cem/cemcom/LintPars new file mode 100644 index 000000000..4bfd2a9a0 --- /dev/null +++ b/lang/cem/cemcom/LintPars @@ -0,0 +1,139 @@ +!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 */ + + diff --git a/lang/cem/cemcom/Makefile b/lang/cem/cemcom/Makefile index 20f61dcf2..65050ad2f 100644 --- a/lang/cem/cemcom/Makefile +++ b/lang/cem/cemcom/Makefile @@ -28,6 +28,8 @@ OLIBS = $(INPLIB) $(EMMESOLIB) $(EMOLIB) $(EMKLIB) $(PRTLIB) $(STRLIB) \ $(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 @@ -66,7 +68,8 @@ CSRC = main.c idf.c declarator.c decspecs.c struct.c \ 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\ @@ -74,7 +77,8 @@ COBJ = main.o idf.o declarator.o decspecs.o struct.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 @@ -82,16 +86,18 @@ GOBJ = char.o symbol2str.o next.o 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 \ @@ -99,7 +105,7 @@ GHSRC = botch_free.h dataflow.h debug.h density.h errout.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) @@ -111,6 +117,12 @@ GENERATED = tab tokenfile.g Lpars.h LLfiles LL.output lint.out \ OBJ = $(COBJ) $(LOBJ) $(GOBJ) SRC = $(CSRC) $(LCSRC) $(GCSRC) +LINT = /usr/bin/lint +LINTFLAGS = + +MYLINT = ../lint +MYLINTFLAGS = #-xh + #EXCLEXCLEXCLEXCL .SUFFIXES: .str .h @@ -135,6 +147,11 @@ CEmain: Cfiles 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 @@ -162,6 +179,10 @@ lint: Cfiles 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' @@ -208,6 +229,9 @@ switch.h: make.allocd 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 @@ -234,8 +258,15 @@ $(CURRDIR)/cemain: $(OBJ) $(CURRDIR)/Makefile $(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 @@ -249,6 +280,7 @@ main.o: idf.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 @@ -276,6 +308,7 @@ idf.o: idf.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 @@ -305,9 +338,12 @@ declarator.o: target_sizes.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 @@ -325,6 +361,7 @@ struct.o: field.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 @@ -348,6 +385,7 @@ expr.o: file_info.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 @@ -365,6 +403,7 @@ ch7.o: def.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 @@ -401,7 +440,6 @@ cstoper.o: target_sizes.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 @@ -427,8 +465,10 @@ code.o: def.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 @@ -450,6 +490,7 @@ dumpidf.o: expr.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 @@ -461,10 +502,12 @@ dumpidf.o: type.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 @@ -479,6 +522,7 @@ field.o: expr.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 @@ -507,6 +551,7 @@ LLlex.o: file_info.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 @@ -575,6 +620,7 @@ options.o: class.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 @@ -610,6 +656,7 @@ stack.o: debug.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 @@ -625,6 +672,7 @@ type.o: arith.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 @@ -640,6 +688,7 @@ ch7mon.o: def.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 @@ -651,6 +700,7 @@ label.o: def.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 @@ -670,6 +720,7 @@ eval.o: expr.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 @@ -700,6 +751,7 @@ switch.o: switch.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 @@ -710,6 +762,7 @@ conversion.o: type.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 @@ -723,6 +776,7 @@ blocks.o: align.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 @@ -730,10 +784,116 @@ blocks.o: spec_arith.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 @@ -742,8 +902,11 @@ declar.o: expr.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 @@ -763,7 +926,10 @@ statement.o: def.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 @@ -773,10 +939,12 @@ statement.o: type.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 @@ -793,7 +961,9 @@ program.o: def.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 @@ -804,6 +974,7 @@ ival.o: LLlex.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 @@ -811,8 +982,10 @@ ival.o: expr.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 diff --git a/lang/cem/cemcom/Parameters b/lang/cem/cemcom/Parameters index 153888bdb..226c44716 100644 --- a/lang/cem/cemcom/Parameters +++ b/lang/cem/cemcom/Parameters @@ -1,3 +1,7 @@ +!File: lint.h +#undef LINT 1 /* if defined, 'lint' is produced */ + + !File: pathlength.h #define PATHLENGTH 1024 /* max. length of path to file */ diff --git a/lang/cem/cemcom/Resolve b/lang/cem/cemcom/Resolve index 6e19e0fe7..95334d1bd 100755 --- a/lang/cem/cemcom/Resolve +++ b/lang/cem/cemcom/Resolve @@ -12,7 +12,7 @@ esac PW=`pwd` options= case $1 in -main|emain) +main|emain|lnt) target=$PW/$1 ;; omain) diff --git a/lang/cem/cemcom/blocks.c b/lang/cem/cemcom/blocks.c index e7282acc7..1684995d4 100644 --- a/lang/cem/cemcom/blocks.c +++ b/lang/cem/cemcom/blocks.c @@ -5,6 +5,9 @@ /* $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 #include #include "arith.h" @@ -161,3 +164,5 @@ copy_loop(sz, src, dst) } #endif STB +#endif LINT + diff --git a/lang/cem/cemcom/ch7.c b/lang/cem/cemcom/ch7.c index 3fd3919ee..597debca4 100644 --- a/lang/cem/cemcom/ch7.c +++ b/lang/cem/cemcom/ch7.c @@ -5,6 +5,7 @@ /* $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" @@ -218,6 +219,10 @@ ch7cast(expp, oper, tp) 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 diff --git a/lang/cem/cemcom/code.c b/lang/cem/cemcom/code.c index fea6ff8b4..40b48e2ce 100644 --- a/lang/cem/cemcom/code.c +++ b/lang/cem/cemcom/code.c @@ -5,6 +5,7 @@ /* $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 #include "botch_free.h" #include @@ -29,6 +30,10 @@ #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; @@ -49,6 +54,7 @@ static int pro_id; extern char options[]; extern char *symbol2str(); +#ifndef LINT init_code(dst_file) char *dst_file; { @@ -64,6 +70,8 @@ init_code(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) @@ -262,6 +270,7 @@ end_proc(fbytes) 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); @@ -273,6 +282,8 @@ end_proc(fbytes) 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 @@ -466,6 +477,7 @@ loc_init(expr, id) } else { /* not embraced */ ch7cast(&expr, '=', tp); /* may modify expr */ +#ifndef LINT { struct value vl; @@ -475,6 +487,9 @@ loc_init(expr, id) vl.vl_value = (arith)0; store_val(&vl, tp); } +#else LINT + id->id_def->df_set = 1; +#endif LINT free_expression(expr); } } @@ -522,6 +537,9 @@ formal_cvt(df) } } +#ifdef LINT +/*ARGSUSED*/ +#endif LINT code_expr(expr, val, code, tlbl, flbl) struct expr *expr; label tlbl, flbl; @@ -530,9 +548,13 @@ code_expr(expr, val, code, 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: diff --git a/lang/cem/cemcom/conversion.c b/lang/cem/cemcom/conversion.c index 903f2454a..2e17b85a7 100644 --- a/lang/cem/cemcom/conversion.c +++ b/lang/cem/cemcom/conversion.c @@ -5,6 +5,9 @@ /* $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 #include "arith.h" @@ -149,3 +152,5 @@ convtype(tp) return 0; } +#endif LINT + diff --git a/lang/cem/cemcom/declar.g b/lang/cem/cemcom/declar.g index 2a6e5a51f..718b673f5 100644 --- a/lang/cem/cemcom/declar.g +++ b/lang/cem/cemcom/declar.g @@ -6,6 +6,7 @@ /* DECLARATION SYNTAX PARSER */ { +#include "lint.h" #include #include "nobitfield.h" #include "debug.h" @@ -24,6 +25,11 @@ #include "expr.h" #include "sizes.h" #include "level.h" +#ifdef LINT +#include "l_lint.h" +#include "l_state.h" +#endif LINT + extern char options[]; } @@ -158,6 +164,9 @@ init_declarator(register struct decspecs *ds;) { 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) @@ -166,6 +175,9 @@ init_declarator(register struct decspecs *ds;) ] ] { +#ifdef LINT + add_auto(Dc.dc_idf); +#endif LINT remove_declarator(&Dc); } ; @@ -193,6 +205,9 @@ initializer(struct idf *idf; int sc;) */ ] { +#ifdef LINT + lint_statement(); +#endif LINT if (globalflag) { struct expr ex; code_declaration(idf, &ex, level, sc); @@ -208,6 +223,10 @@ initializer(struct idf *idf; int 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); diff --git a/lang/cem/cemcom/def.str b/lang/cem/cemcom/def.str index 3c30fb659..8d719f2c8 100644 --- a/lang/cem/cemcom/def.str +++ b/lang/cem/cemcom/def.str @@ -5,6 +5,7 @@ /* $Header$ */ /* IDENTIFIER DEFINITION DESCRIPTOR */ +#include "lint.h" struct def { /* for ordinary tags */ struct def *next; @@ -21,6 +22,11 @@ struct def { /* for ordinary tags */ 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; }; diff --git a/lang/cem/cemcom/error.c b/lang/cem/cemcom/error.c index 68f4bd76c..3aef50d8d 100644 --- a/lang/cem/cemcom/error.c +++ b/lang/cem/cemcom/error.c @@ -9,6 +9,7 @@ #include #include +#include "lint.h" #include "nopp.h" #include "errout.h" #include "debug.h" @@ -34,6 +35,10 @@ 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 @@ -110,6 +115,54 @@ expr_warning(va_alist) /* expr, fmt, args */ 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 @@ -186,9 +239,11 @@ _error(class, fn, ln, ap) /* _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 *); @@ -215,7 +270,11 @@ _error(class, fn, ln, ap) /* the remark */ switch (class) { case WARNING: +#ifndef LINT remark = "(warning)"; +#else LINT + remark = 0; +#endif LINT break; case ERROR: @@ -233,6 +292,7 @@ _error(class, fn, ln, ap) /*NOTREACHED*/; } +#ifndef LINT if (ln == last_ln && fn && last_fn && strcmp(fn, last_fn) == 0) { /* we've seen this place before */ e_seen++; @@ -249,6 +309,20 @@ _error(class, fn, ln, ap) 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); diff --git a/lang/cem/cemcom/eval.c b/lang/cem/cemcom/eval.c index f28278ac2..04264e1a0 100644 --- a/lang/cem/cemcom/eval.c +++ b/lang/cem/cemcom/eval.c @@ -5,6 +5,9 @@ /* $Header$ */ /* EXPRESSION-CODE GENERATOR */ +#include "lint.h" +#ifndef LINT + #include "nofloat.h" #include #include @@ -969,3 +972,5 @@ load_cst(val, siz) } } +#endif LINT + diff --git a/lang/cem/cemcom/expr.c b/lang/cem/cemcom/expr.c index 5b8d8ef76..21b8815cd 100644 --- a/lang/cem/cemcom/expr.c +++ b/lang/cem/cemcom/expr.c @@ -5,6 +5,7 @@ /* $Header$ */ /* EXPRESSION TREE HANDLING */ +#include "lint.h" #include "nofloat.h" #include "botch_free.h" #include @@ -181,7 +182,9 @@ idf2expr(expr) 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; @@ -196,12 +199,14 @@ idf2expr(expr) 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; diff --git a/lang/cem/cemcom/expression.g b/lang/cem/cemcom/expression.g index d26ed5f87..a22c18797 100644 --- a/lang/cem/cemcom/expression.g +++ b/lang/cem/cemcom/expression.g @@ -6,6 +6,7 @@ /* EXPRESSION SYNTAX PARSER */ { +#include "lint.h" #include "arith.h" #include "LLlex.h" #include "type.h" @@ -207,6 +208,10 @@ conditional_expression(struct expr **expp;) #endif ch7bin(&e1, ':', e2); opnd2test(expp, '?'); +#ifdef LINT + if (is_cp_cst(*expp)) + hwarning("condition in ?: is constant"); +#endif LINT ch7bin(expp, '?', e1); } ]? diff --git a/lang/cem/cemcom/field.c b/lang/cem/cemcom/field.c index 0555e2829..3b944310b 100644 --- a/lang/cem/cemcom/field.c +++ b/lang/cem/cemcom/field.c @@ -5,6 +5,9 @@ /* $Header$ */ /* BITFIELD EXPRESSION EVALUATOR */ +#include "lint.h" +#ifndef LINT + #include "nobitfield.h" #ifndef NOBITFIELD @@ -174,3 +177,5 @@ eval_field(expr, code) } #endif NOBITFIELD +#endif LINT + diff --git a/lang/cem/cemcom/idf.c b/lang/cem/cemcom/idf.c index 4a1a8018c..3d5e47bfe 100644 --- a/lang/cem/cemcom/idf.c +++ b/lang/cem/cemcom/idf.c @@ -5,6 +5,7 @@ /* $Header$ */ /* IDENTIFIER FIDDLING & SYMBOL TABLE HANDLING */ +#include "lint.h" #include #include "nofloat.h" #include "debug.h" @@ -266,6 +267,22 @@ declare_idf(ds, dc, lvl) } #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 ) @@ -326,6 +343,11 @@ declare_idf(ds, dc, 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); diff --git a/lang/cem/cemcom/ival.g b/lang/cem/cemcom/ival.g index 88fd557a5..82a371e5e 100644 --- a/lang/cem/cemcom/ival.g +++ b/lang/cem/cemcom/ival.g @@ -6,6 +6,7 @@ /* CODE FOR THE INITIALISATION OF GLOBAL VARIABLES */ { +#include "lint.h" #include "nofloat.h" #include #include "debug.h" @@ -27,6 +28,10 @@ #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) @@ -48,6 +53,9 @@ initial_value(register struct type **tpp; register struct expr **expp;) : [ assignment_expression(expp) { +#ifdef LINT + pre_lint_expr(*expp, RVAL, USED); +#endif LINT if ((*expp)->ex_type->tp_fund == ARRAY) array2pointer(*expp); if (tpp) { diff --git a/lang/cem/cemcom/l_class.h b/lang/cem/cemcom/l_class.h new file mode 100644 index 000000000..2a77e546f --- /dev/null +++ b/lang/cem/cemcom/l_class.h @@ -0,0 +1,21 @@ +/* + * (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 */ + diff --git a/lang/cem/cemcom/l_comment.c b/lang/cem/cemcom/l_comment.c new file mode 100644 index 000000000..fd5b21a2c --- /dev/null +++ b/lang/cem/cemcom/l_comment.c @@ -0,0 +1,129 @@ +/* + * (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 + +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 diff --git a/lang/cem/cemcom/l_dummy.c b/lang/cem/cemcom/l_dummy.c new file mode 100644 index 000000000..ef4f8f941 --- /dev/null +++ b/lang/cem/cemcom/l_dummy.c @@ -0,0 +1,63 @@ +/* + *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; {} diff --git a/lang/cem/cemcom/l_ev_ord.c b/lang/cem/cemcom/l_ev_ord.c new file mode 100644 index 000000000..810c5c9e5 --- /dev/null +++ b/lang/cem/cemcom/l_ev_ord.c @@ -0,0 +1,118 @@ +/* + * (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 /* 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 diff --git a/lang/cem/cemcom/l_lint.c b/lang/cem/cemcom/l_lint.c new file mode 100644 index 000000000..6f6be686c --- /dev/null +++ b/lang/cem/cemcom/l_lint.c @@ -0,0 +1,350 @@ +/* + * (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 /* 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 diff --git a/lang/cem/cemcom/l_lint.h b/lang/cem/cemcom/l_lint.h new file mode 100644 index 000000000..3a59bfac4 --- /dev/null +++ b/lang/cem/cemcom/l_lint.h @@ -0,0 +1,17 @@ +/* + * (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 */ + diff --git a/lang/cem/cemcom/l_misc.c b/lang/cem/cemcom/l_misc.c new file mode 100644 index 000000000..84e68d764 --- /dev/null +++ b/lang/cem/cemcom/l_misc.c @@ -0,0 +1,155 @@ +/* + * (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 /* 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 */ +{ + /* 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; + } + } + } + + /* 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 diff --git a/lang/cem/cemcom/l_outdef.c b/lang/cem/cemcom/l_outdef.c new file mode 100644 index 000000000..8df435154 --- /dev/null +++ b/lang/cem/cemcom/l_outdef.c @@ -0,0 +1,414 @@ +/* + * (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 +#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 diff --git a/lang/cem/cemcom/l_outdef.str b/lang/cem/cemcom/l_outdef.str new file mode 100644 index 000000000..9f768c292 --- /dev/null +++ b/lang/cem/cemcom/l_outdef.str @@ -0,0 +1,31 @@ +/* + * (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; +}; diff --git a/lang/cem/cemcom/l_state.str b/lang/cem/cemcom/l_state.str new file mode 100644 index 000000000..82633253d --- /dev/null +++ b/lang/cem/cemcom/l_state.str @@ -0,0 +1,73 @@ +/* + * (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 */ + diff --git a/lang/cem/cemcom/l_states.c b/lang/cem/cemcom/l_states.c new file mode 100644 index 000000000..e9d445221 --- /dev/null +++ b/lang/cem/cemcom/l_states.c @@ -0,0 +1,1102 @@ +/* + * (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 /* 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 diff --git a/lang/cem/cemcom/main.c b/lang/cem/cemcom/main.c index 71b520b8e..b8104bf1b 100644 --- a/lang/cem/cemcom/main.c +++ b/lang/cem/cemcom/main.c @@ -5,6 +5,7 @@ /* $Header$ */ /* MAIN PROGRAM */ +#include "lint.h" #include "nofloat.h" #include #include "nopp.h" @@ -95,6 +96,9 @@ main(argc, argv) 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 @@ -130,7 +134,10 @@ compile(argc, argv) 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']; @@ -139,14 +146,17 @@ compile(argc, argv) 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; @@ -154,8 +164,14 @@ compile(argc, argv) 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; } @@ -185,8 +201,11 @@ compile(argc, argv) #endif NOPP #endif DEBUG { +#ifndef LINT init_code(destination && strcmp(destination, "-") != 0 ? destination : 0); +#endif LINT + /* compile the source text */ C_program(); diff --git a/lang/cem/cemcom/options.c b/lang/cem/cemcom/options.c index ec61dc11d..e873061e1 100644 --- a/lang/cem/cemcom/options.c +++ b/lang/cem/cemcom/options.c @@ -5,6 +5,7 @@ /* $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 #include "nofloat.h" @@ -29,6 +30,10 @@ extern int inc_total; #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(); @@ -45,13 +50,18 @@ next_option: /* to allow combined one-char options */ 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 @@ -59,16 +69,28 @@ next_option: /* to allow combined one-char options */ 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 @@ -180,6 +202,14 @@ 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; @@ -209,6 +239,7 @@ deleted, is now a debug-flag break; } +#ifndef LINT case 'V' : /* set object sizes and alignment requirements */ #ifdef NOCROSS warning("-V option ignored"); @@ -294,6 +325,7 @@ deleted, is now a debug-flag break; } #endif NOCROSS +#endif LINT } } diff --git a/lang/cem/cemcom/program.g b/lang/cem/cemcom/program.g index ebeeada63..64a1158cc 100644 --- a/lang/cem/cemcom/program.g +++ b/lang/cem/cemcom/program.g @@ -45,6 +45,7 @@ %start If_expr, control_if_expression; { +#include "lint.h" #include "nopp.h" #include "arith.h" #include "LLlex.h" @@ -56,6 +57,10 @@ #include "code.h" #include "expr.h" #include "def.h" +#ifdef LINT +#include "l_state.h" +#endif LINT + #ifndef NOPP extern arith ifval; #endif NOPP @@ -121,6 +126,9 @@ external_definition 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} @@ -156,6 +164,12 @@ non_function(register struct decspecs *ds; register struct declarator *dc;) { 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 } [ ',' @@ -171,6 +185,9 @@ function(struct decspecs *ds; struct declarator *dc;) } : { 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); @@ -180,11 +197,23 @@ function(struct decspecs *ds; struct declarator *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 } ; diff --git a/lang/cem/cemcom/stack.c b/lang/cem/cemcom/stack.c index aee78b94b..3be2dece2 100644 --- a/lang/cem/cemcom/stack.c +++ b/lang/cem/cemcom/stack.c @@ -5,6 +5,7 @@ /* $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 #include @@ -51,6 +52,9 @@ stack_level() { 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) @@ -96,6 +100,10 @@ unstack_level() 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. */ @@ -168,6 +176,10 @@ unstack_world() */ register struct stack_entry *se = local_level->sl_entry; +#ifdef LINT + lint_global_level(local_level); +#endif LINT + open_name_list(); while (se) { diff --git a/lang/cem/cemcom/statement.g b/lang/cem/cemcom/statement.g index 05e4eb204..601473615 100644 --- a/lang/cem/cemcom/statement.g +++ b/lang/cem/cemcom/statement.g @@ -8,6 +8,7 @@ { #include +#include "lint.h" #include "debug.h" #include "botch_free.h" @@ -20,6 +21,11 @@ #include "code.h" #include "stack.h" #include "def.h" +#ifdef LINT +#include "l_lint.h" +#include "l_state.h" +#endif LINT + extern int level; } @@ -31,6 +37,9 @@ extern int level; /* 9 */ statement { +#ifdef LINT + lint_statement(); +#endif LINT } : %if (AHEAD != ':') @@ -57,12 +66,18 @@ statement BREAK { code_break(); +#ifdef LINT + lint_break_stmt(); +#endif LINT } ';' | CONTINUE { code_continue(); +#ifdef LINT + lint_continue_stmt(); +#endif LINT } ';' | @@ -104,6 +119,9 @@ label grz: printf("A labelled statement\n"); } */ +#ifdef LINT + lint_label(); +#endif LINT define_label(idf); C_df_ilb((label)idf->id_def->df_address); } @@ -126,6 +144,9 @@ if_statement /* 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); } @@ -136,21 +157,33 @@ if_statement 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 } ] ; @@ -176,10 +209,17 @@ while_statement 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 } } ')' @@ -189,6 +229,9 @@ while_statement C_df_ilb(l_break); unstack_stmt(); free_expression(expr); +#ifdef LINT + end_loop_stmt(); +#endif LINT } ; @@ -202,6 +245,9 @@ do_statement DO { C_df_ilb(l_body); stack_stmt(l_break, l_continue); +#ifdef LINT + start_loop_stmt(DO, 1, 1); +#endif LINT } statement WHILE @@ -215,9 +261,15 @@ do_statement 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); } @@ -235,6 +287,9 @@ for_statement 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 @@ -257,10 +312,17 @@ for_statement 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 } } ]? @@ -268,9 +330,15 @@ for_statement 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, @@ -294,10 +362,22 @@ switch_statement 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); } @@ -311,6 +391,9 @@ case_statement CASE constant_expression(&expr) { +#ifdef LINT + lint_case_stmt(0); +#endif LINT code_case(expr); free_expression(expr); } @@ -322,6 +405,9 @@ default_statement : DEFAULT { +#ifdef LINT + lint_case_stmt(1); +#endif LINT code_default(); } ':' @@ -336,13 +422,23 @@ return_statement [ 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 } ] ';' @@ -358,6 +454,9 @@ jump { apply_label(idf); C_bra((label)idf->id_def->df_address); +#ifdef LINT + lint_jump_stmt(idf); +#endif LINT } ; diff --git a/lang/cem/cemcom/util.c b/lang/cem/cemcom/util.c index 5426fccbc..b51cf68d6 100644 --- a/lang/cem/cemcom/util.c +++ b/lang/cem/cemcom/util.c @@ -16,6 +16,7 @@ #include #include +#include "lint.h" #include "util.h" #include "use_tmp.h" #include "regcount.h" @@ -224,6 +225,7 @@ StoreLocal(off, sz) } } +#ifndef LINT AddrLocal(off) arith off; { @@ -232,3 +234,4 @@ AddrLocal(off) if (p) p->t_regtype = -1; C_lal(off); } +#endif LINT -- 2.34.1