Преглед на файлове

introduction of lint source code, governed by ifdef LINT

dick преди 36 години
родител
ревизия
5844159c7b

+ 14 - 0
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	<alloc.h>
 #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--;
 }

+ 139 - 0
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 */
+
+

+ 182 - 9
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

+ 4 - 0
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		*/
 

+ 1 - 1
lang/cem/cemcom/Resolve

@@ -12,7 +12,7 @@ esac
 PW=`pwd`
 options=
 case $1 in
-main|emain)
+main|emain|lnt)
 	target=$PW/$1
 	;;
 omain)

+ 5 - 0
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 <em.h>
 #include <em_reg.h>
 #include "arith.h"
@@ -161,3 +164,5 @@ copy_loop(sz, src, dst)
 }
 #endif STB
 
+#endif	LINT
+

+ 5 - 0
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

+ 22 - 0
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	<em.h>
 #include	"botch_free.h"
 #include	<alloc.h>
@@ -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:

+ 5 - 0
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	<em.h>
 #include	"arith.h"
@@ -149,3 +152,5 @@ convtype(tp)
 	return 0;
 }
 
+#endif	LINT
+

+ 19 - 0
lang/cem/cemcom/declar.g

@@ -6,6 +6,7 @@
 /*	DECLARATION SYNTAX PARSER	*/
 
 {
+#include	"lint.h"
 #include	<alloc.h>
 #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);

+ 6 - 0
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;
 };

+ 74 - 0
lang/cem/cemcom/error.c

@@ -9,6 +9,7 @@
 #include	<system.h>
 #include	<em.h>
 
+#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);

+ 5 - 0
lang/cem/cemcom/eval.c

@@ -5,6 +5,9 @@
 /* $Header$ */
 /* EXPRESSION-CODE GENERATOR */
 
+#include	"lint.h"
+#ifndef	LINT
+
 #include	"nofloat.h"
 #include	<em.h>
 #include	<em_reg.h>
@@ -969,3 +972,5 @@ load_cst(val, siz)
 	}
 }
 
+#endif	LINT
+

+ 5 - 0
lang/cem/cemcom/expr.c

@@ -5,6 +5,7 @@
 /* $Header$ */
 /* EXPRESSION TREE HANDLING */
 
+#include	"lint.h"
 #include	"nofloat.h"
 #include	"botch_free.h"
 #include	<alloc.h>
@@ -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;

+ 5 - 0
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);
 		}
 	]?

+ 5 - 0
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
+

+ 22 - 0
lang/cem/cemcom/idf.c

@@ -5,6 +5,7 @@
 /* $Header$ */
 /*	IDENTIFIER  FIDDLING & SYMBOL TABLE HANDLING	*/
 
+#include	"lint.h"
 #include	<em_reg.h>
 #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);

+ 8 - 0
lang/cem/cemcom/ival.g

@@ -6,6 +6,7 @@
 /* CODE FOR THE INITIALISATION OF GLOBAL VARIABLES */
 
 {
+#include	"lint.h"
 #include	"nofloat.h"
 #include	<em.h>
 #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) {

+ 21 - 0
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 */
+

+ 129 - 0
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	<ctype.h>
+
+check_pseudo(buf, i)
+	char *buf;
+{
+/* Look if the i characters in buf are aequivalent with one of the
+ * strings N_OTREACHED, V_ARARGS[n], A_RGSUSED, L_INTLIBRARY
+ * (the u_nderscores are there to not confuse (UNIX) lint)
+ */
+	buf[i++] = '\0';
+	if (!strcmp(buf, "NOTREACHED"))
+		set_not_reached();
+	else if (!strcmp(buf, "ARGSUSED"))
+		set_argsused(1);
+	else if (!strcmp(buf, "LINTLIBRARY"))
+		set_lintlib();
+	else if (!strncmp(buf, "VARARGS", 7)) {
+		if (i == 8)
+			set_varargs(0);
+		else if (i == 9 && isdigit(buf[7]))
+			set_varargs(atoi(&buf[7]));
+	}
+}
+
+#endif	LINT

+ 63 - 0
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; {}

+ 118 - 0
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	<alloc.h>	/* for st_free */
+#include	"arith.h"	/* definition arith */
+#include	"label.h"	/* definition label */
+#include	"expr.h"
+#include	"idf.h"
+#include	"def.h"
+#include	"code.h"	/* RVAL etc */
+#include	"LLlex.h"
+#include	"Lpars.h"
+#include	"stack.h"
+#include	"type.h"
+#include	"level.h"
+#include	"nofloat.h"
+#include	"l_lint.h"
+#include	"l_state.h"
+
+extern char *symbol2str();
+
+check_and_merge(espp, esp, com_oper)
+	struct expr_state **espp, *esp;
+{
+/* Checks for undefined evaluation orders in case of a commutative operator.
+ * In addition the sets of used and set variables of both expressions are
+ * united.
+ * *espp will be pointing to this new list. esp is used for this list.
+ */
+	register struct expr_state **pp, *p1, *p2;
+
+	for (p1 = *espp; p1; p1 = p1->next) {
+		p2 = esp;
+		pp = &esp;
+		while (p2) {
+			if (	/* p1 and p2 are the same */
+				p1->es_idf == p2->es_idf
+			&&	p1->es_offset == p2->es_offset
+			) {
+				if (com_oper)
+					check_ev_order(p1, p2, com_oper);
+				p1->es_used |= p2->es_used;
+				p1->es_set |= p2->es_set;
+				*pp = p2->next;
+				free_expr_state(p2);
+				p2 = *pp;
+			}
+			else {
+				pp = &p2->next;
+				p2 = p2->next;
+			}
+		}
+	}
+	/* The rest of the list esp is pointing to, is put in front of the list
+	 * *espp is now pointing to.
+	 * *espp will be pointing to this new list.
+	 */
+	if (!esp)
+		return;
+	p1 = *espp;
+	*espp = esp;
+	while (esp->next)
+		esp = esp->next;
+	esp->next = p1;
+}
+
+check_ev_order(esp1, esp2, com_oper)
+	struct expr_state *esp1, *esp2;
+{
+	if (	(esp1->es_used && esp2->es_set)
+	||	(esp1->es_set && esp2->es_used)
+	||	(esp1->es_set && esp2->es_set)
+	) {
+		warning("result of %s depends on evaluation order on %s",
+			symbol2str(com_oper),
+			esp1->es_idf->id_text);
+	}
+}
+
+add_expr_state(value, to_state, espp)
+	struct value value;
+	struct expr_state **espp;
+{
+	register struct expr_state *esp = *espp;
+
+	if (value.vl_class != Name) {
+		crash("(add_expr_state) invalid vl_class");
+		/*NOTREACHED*/
+	}
+	while (	esp
+	&&	!(	esp->es_idf == value.vl_data.vl_idf
+		&&	esp->es_offset == value.vl_value
+		)
+	) {
+		esp = esp->next;
+	}
+	if (!esp) {	/* create new expr_state */
+		esp = new_expr_state();
+		esp->es_idf = value.vl_data.vl_idf;
+		esp->es_offset = value.vl_value;
+		esp->next = *espp;
+		*espp = esp;
+	}
+	if (to_state == SET)
+		esp->es_set = 1;
+	else	/* USED */
+		esp->es_used = 1;
+}
+
+#endif	LINT

+ 350 - 0
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	<alloc.h>	/* for st_free */
+#include	"arith.h"	/* definition arith */
+#include	"label.h"	/* definition label */
+#include	"expr.h"
+#include	"idf.h"
+#include	"def.h"
+#include	"code.h"	/* RVAL etc */
+#include	"LLlex.h"
+#include	"Lpars.h"
+#include	"stack.h"
+#include	"type.h"
+#include	"level.h"
+#include	"nofloat.h"
+#include	"l_lint.h"
+#include	"l_state.h"
+#include	"l_outdef.h"
+
+extern char options[128];
+extern char *symbol2str();
+
+struct expr_state *lint_expr();
+
+lint_init()
+{
+/* Allocate some memory for the global stack_bottom
+ * and some other initializations
+ */
+
+	extern struct lint_stack_entry stack_bottom;
+
+	stack_bottom.ls_current = new_state();
+}
+
+pre_lint_expr(expr, val, used)
+	struct expr *expr;
+{
+/* Introduced to dispose the returned expression states */
+
+	register struct expr_state *esp;
+
+	esp = lint_expr(expr, val, used);
+	free_expr_states(esp);
+}
+
+free_expr_states(esp)
+	register struct expr_state *esp;
+{
+	register struct expr_state *esp2;
+
+	while (esp) {
+		esp2 = esp;
+		esp = esp->next;
+		free_expr_state(esp2);
+	}
+}
+
+struct expr_state *
+lint_expr(expr, val, used)
+	register struct expr *expr;
+{
+/* Main function to process an expression tree.
+ * It returns a structure containing information about which variables
+ * are set and which are used in the expression.
+ * In addition it sets 'used' and 'set' fields of the corresponding
+ * variables in the current state.
+ * If the value of an operation without side-effects is not used,
+ * a warning is given.
+ */
+	struct expr_state *esp1 = 0, *esp2 = 0;
+
+	if (used == IGNORED) {
+		expr_ignored(expr);
+	}
+
+	switch (expr->ex_class) {
+	case Value:
+		switch (expr->VL_CLASS) {
+		case Const:
+		case Label:
+			return(0);
+
+		case Name:
+		{
+			register struct idf *idf = expr->VL_IDF;
+
+			if (!idf || !idf->id_def)
+				return(0);
+
+			if (	val == LVAL
+			||	(	val == RVAL
+				&&	expr->ex_type->tp_fund == POINTER
+				&&	!expr->ex_lvalue
+				)
+			) {
+				change_state(idf, SET);
+				idf->id_def->df_file =
+					Salloc(dot.tk_file,
+						strlen(dot.tk_file) + 1);
+				idf->id_def->df_line = dot.tk_line;
+			}
+			if (val == RVAL) {
+				change_state(idf, USED);
+				add_expr_state(expr->EX_VALUE, USED, &esp1);
+			}
+			return(esp1);
+		}
+
+		default:
+			crash("(lint_expr) bad value class\n");
+			/* NOTREACHED */
+		}
+
+	case Oper:
+	{
+		register int oper = expr->OP_OPER;
+		register struct expr *left = expr->OP_LEFT;
+		register struct expr *right = expr->OP_RIGHT;
+
+		switch (oper) {
+		case '=':
+		case PLUSAB:
+		case MINAB:
+		case TIMESAB:
+		case DIVAB:
+		case MODAB:
+		case LEFTAB:
+		case RIGHTAB:
+		case ANDAB:
+		case XORAB:
+		case ORAB:
+			lint_conversion(oper, right->ex_type, left->ex_type);
+			/* for cases like i += l; */
+			esp1 = lint_expr(right, RVAL, USED);
+			if (oper != '=') {
+				/* i += 1; is interpreted as i = i + 1; */
+				esp2 = lint_expr(left, RVAL, USED);
+				check_and_merge(&esp1, esp2, oper);
+			}
+			esp2 = lint_expr(left, LVAL, USED);
+			/* for cases like i = i + 1; and i not set, this
+			** order is essential
+			*/
+			check_and_merge(&esp1, esp2, oper);
+			if (	left->ex_class == Value
+			&&	left->VL_CLASS == Name
+			) {
+				add_expr_state(left->EX_VALUE, SET, &esp1);
+			}
+			return(esp1);
+
+		case POSTINCR:
+		case POSTDECR:
+		case PLUSPLUS:
+		case MINMIN:
+			/* i++; is parsed as i = i + 1;
+			 * This isn't quite correct :
+			 * The first statement doesn't USE i,
+			 * the second does.
+			 */
+			esp1 = lint_expr(left, RVAL, USED);
+			esp2 = lint_expr(left, LVAL, USED);
+			check_and_merge(&esp1, esp2, oper);
+			if (	left->ex_class == Value
+			&&	left->VL_CLASS == Name
+			) {
+				add_expr_state(left->EX_VALUE, SET, &esp1);
+				add_expr_state(left->EX_VALUE, USED, &esp1);
+			}
+			return(esp1);
+
+		case '-':
+		case '*':
+			if (left == 0)	/* unary */
+				return(lint_expr(right, RVAL, USED));
+			esp1 = lint_expr(left, RVAL, USED);
+			esp2 = lint_expr(right, RVAL, USED);
+			check_and_merge(&esp1, esp2, oper);
+			return(esp1);
+
+		case '(':
+			if (right != 0) {
+				/* function call with parameters */
+				register struct expr *ex = right;
+
+				while (	ex->ex_class == Oper
+				&&	ex->OP_OPER == PARCOMMA
+				) {
+					esp2 = lint_expr(ex->OP_RIGHT, RVAL,
+							 USED);
+					check_and_merge(&esp1, esp2, oper);
+					ex = ex->OP_LEFT;
+				}
+				esp2 = lint_expr(ex, RVAL, USED);
+				check_and_merge(&esp1, esp2, oper);
+			}
+			if (	left->ex_class == Value
+			&&	left->VL_CLASS == Name
+			) {
+				fill_outcall(expr,
+					expr->ex_type->tp_fund == VOID ?
+					VOIDED : used
+				);
+				outcall();
+				left->VL_IDF->id_def->df_used = 1;
+			}
+			else {
+				esp2 = lint_expr(left, val, USED);
+				check_and_merge(&esp1, esp2, oper);
+			}
+			return(esp1);
+
+		case '.':
+			return(lint_expr(left, val, USED));
+
+		case ARROW:
+			return(lint_expr(left, RVAL, USED));
+
+		case '~':
+		case '!':
+			return(lint_expr(right, RVAL, USED));
+
+		case '?':
+			esp1 = lint_expr(left, RVAL, USED);
+			esp2 = lint_expr(right->OP_LEFT, RVAL, USED);
+			check_and_merge(&esp1, esp2, 0);
+			esp2 = lint_expr(right->OP_RIGHT, RVAL, USED);
+			check_and_merge(&esp1, esp2, 0);
+			return(esp1);
+
+		case INT2INT:
+		case INT2FLOAT:
+		case FLOAT2INT:
+		case FLOAT2FLOAT:
+			lint_conversion(oper, right->ex_type, left->ex_type);
+			return(lint_expr(right, RVAL, USED));
+
+		case '<':
+		case '>':
+		case LESSEQ:
+		case GREATEREQ:
+		case EQUAL:
+		case NOTEQUAL:
+			lint_relop(left, right, oper);
+			lint_relop(right, left, 
+				oper == '<' ? '>' :
+				oper == '>' ? '<' :
+				oper == LESSEQ ? GREATEREQ :
+				oper == GREATEREQ ? LESSEQ :
+				oper
+			);
+			/*FALLTHROUGH*/
+		case '+':
+		case '/':
+		case '%':
+		case ',':
+		case LEFT:
+		case RIGHT:
+		case '&':
+		case '|':
+		case '^':
+		case OR:
+		case AND:
+			esp1 = lint_expr(left, RVAL,
+						oper == ',' ? IGNORED : USED);
+			esp2 = lint_expr(right, RVAL,
+						oper == ',' ? used : USED);
+			if (oper == OR || oper == AND || oper == ',')
+				check_and_merge(&esp1, esp2, 0);
+			else
+				check_and_merge(&esp1, esp2, oper);
+			return(esp1);
+
+		default:
+			return(0);	/* for initcomma */
+		}
+	}
+
+	default:
+		return(0);
+	}
+}
+
+expr_ignored(expr)
+	struct expr *expr;
+{
+	switch (expr->ex_class) {
+	case Oper:
+		switch (expr->OP_OPER) {
+		case '=':
+		case TIMESAB:
+		case DIVAB:
+		case MODAB:
+		case LEFTAB:
+		case RIGHTAB:
+		case ANDAB:
+		case XORAB:
+		case ORAB:
+		case AND:			/* doubtful but useful */
+		case OR:			/* doubtful but useful */
+		case '(':
+		case '?':
+		case ',':
+			break;
+
+		case PLUSAB:
+		case MINAB:
+		case POSTINCR:
+		case POSTDECR:
+		case PLUSPLUS:
+		case MINMIN:
+			/* may hide the operator * */
+			if (	/* operation on a pointer */
+				expr->OP_TYPE->tp_fund == POINTER
+			&&	/* the result is dereferenced, e.g. *p++; */
+				expr->ex_type == expr->OP_TYPE->tp_up
+			) {
+				hwarning("result of * ignored");
+			}
+			break;
+
+		default:
+			hwarning("result of %s ignored",
+						symbol2str(expr->OP_OPER));
+			break;
+		}
+		break;
+
+	case Value:
+		hwarning("identifier as statement");
+		break;
+
+	case String:
+	case Float:
+		hwarning("constant as statement");
+		break;
+	}
+}
+
+#endif	LINT

+ 17 - 0
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 */
+

+ 155 - 0
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	<alloc.h>	/* for st_free */
+#include	"arith.h"	/* definition arith */
+#include	"label.h"	/* definition label */
+#include	"expr.h"
+#include	"idf.h"
+#include	"def.h"
+#include	"code.h"	/* RVAL etc */
+#include	"LLlex.h"
+#include	"Lpars.h"
+#include	"stack.h"
+#include	"type.h"
+#include	"level.h"
+#include	"nofloat.h"
+#include	"l_state.h"
+
+extern char *symbol2str();
+extern struct type *func_type;
+
+lint_conversion(oper, from_type, to_type)
+	struct type *from_type, *to_type;
+{
+	register int from = from_type->tp_fund;
+	register int to = to_type->tp_fund;
+
+	switch (oper) {
+	case RETURN:	/* not really an oper, but it works */
+	case INT2INT:
+	case '=':
+	case PLUSAB:
+	case MINAB:
+	case TIMESAB:
+	case DIVAB:
+	case MODAB:
+	case LEFTAB:
+	case RIGHTAB:
+	case ANDAB:
+	case XORAB:
+	case ORAB:
+		if (	(from == LONG && to != LONG)
+		||	(from == DOUBLE && to != DOUBLE)
+		) {
+			awarning("conversion from %s to %s may lose accuracy",
+				symbol2str(from), symbol2str(to));
+		}
+	}
+}
+
+lint_ret_conv(from_type)
+	struct type *from_type;
+{
+	lint_conversion(RETURN, from_type, func_type);
+}
+
+lint_ptr_conv(from, to)
+	short from, to;
+{
+/* X -> X ok			-- this includes struct -> struct, of any size
+ * X -> CHAR ok
+ * DOUBLE -> X ok
+ * FLOAT -> LONG -> INT -> SHORT  ok
+ */
+	if (from == to)
+		return;
+
+	if (to == CHAR)
+		return;
+
+	if (from == DOUBLE)
+		return;
+
+	switch (from) {
+	case FLOAT:
+		switch (to) {
+		case LONG:
+		case INT:
+		case SHORT:
+			return;
+		}
+		break;
+	case LONG:
+		switch (to) {
+		case INT:
+		case SHORT:
+			return;
+		}
+		break;
+	case INT:
+		switch (to) {
+		case SHORT:
+			return;
+		}
+		break;
+	}
+
+	if (from == CHAR) {
+		hwarning("pointer to char may not align correctly for a %s",
+			symbol2str(to));
+	}
+	else {
+		warning("pointer to %s may not align correctly for a %s",
+			symbol2str(from), symbol2str(to));
+	}
+}
+
+lint_relop(left, right, oper)
+	struct expr *left, *right;
+	int oper;	/* '<', '>', LESSEQ, GREATEREQ, EQUAL, NOTEQUAL */
+{
+	/* <unsigned> <relop> <neg-const|0> is doubtful */
+	if (	left->ex_type->tp_unsigned
+	&&	right->ex_class == Value
+	&&	right->VL_CLASS == Const
+	) {
+		if (right->VL_VALUE < 0) {
+			warning("unsigned compared to negative constant");
+		}
+		if (right->VL_VALUE == 0) {
+			switch (oper) {
+			case '<':
+				warning("unsigned < 0 will always fail");
+				break;
+
+			case LESSEQ:
+				warning("unsigned <= 0 is probably wrong");
+				break;
+
+			case GREATEREQ:
+				warning("unsigned >= 0 will always succeed");
+				break;
+			}
+		}
+	}
+
+	/* <char> <relop> <neg-const> is undefined */
+	if (	left->ex_type->tp_fund == CHAR
+	&&	right->ex_class == Value
+	&&	right->VL_CLASS == Const
+	&&	(right->VL_VALUE < 0 || right->VL_VALUE > 127)
+	) {
+		warning("character compared to negative constant");
+	}
+}
+
+#endif	LINT

+ 414 - 0
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	<alloc.h>
+#include	"arith.h"
+#include	"type.h"
+#include	"LLlex.h"
+#include	"Lpars.h"
+#include	"stack.h"
+#include	"def.h"
+#include	"struct.h"
+#include	"field.h"
+#include	"idf.h"
+#include	"level.h"
+#include	"label.h"
+#include	"expr.h"
+#include	"l_lint.h"
+#include	"l_outdef.h"
+#include	"l_class.h"
+
+extern char *symbol2str();
+
+extern int f_VARARGSn, LINTLIB;
+int stat_number = 9999;			/* static scope number */
+struct outdef OutDef, OutCall;
+
+lint_declare_idf(idf, sc)
+	struct idf *idf;
+	int sc;
+{
+	register struct def *def = idf->id_def;
+	register int is_function = def->df_type->tp_fund == FUNCTION;
+
+	if (level == L_GLOBAL) {
+		lint_ext_def(idf, sc);
+		if (is_function)
+			def2decl(sc);
+		if (sc != TYPEDEF)
+			outdef();
+	}
+	else
+	if (level >= L_LOCAL && sc != STATIC && is_function) {
+		local_EFDC(idf);
+	}
+}
+
+lint_ext_def(idf, sc)
+	struct idf *idf;
+{
+/* At this place the following fields of the outputdefinition can be
+ * filled:
+ *		name, stat_number, class, file, line, type.
+ * For variable definitions and declarations this will be all.
+ * For functions the fields nrargs and argtps are filled after parsing
+ * the arguments.
+ * The returns-field is known at the end of the function definition.
+ * sc indicates the storage class defined by the declaration specifier.
+ */
+	register struct def *def = idf->id_def;
+	register struct type *type = def->df_type;
+
+	OutDef.od_name = idf->id_text;
+	OutDef.od_statnr = (sc == STATIC ? stat_number : 0);
+
+	switch (type->tp_fund) {
+	case ERRONEOUS:
+		OutDef.od_class = XXDF;
+		break;
+	case FUNCTION:
+		/* For the moment assume it will be a definition.
+		 * If no compound_statement follows, it is a declaration,
+		 * in which case the class will be adjusted by def2decl().
+		 */
+		OutDef.od_class = (sc == STATIC ? SFDF : EFDF);
+		break;
+	default:	/* a variable */
+		OutDef.od_class =
+			sc == EXTERN ? EVDC :
+			sc == STATIC ? SVDF : EVDF;
+		break;
+	}
+	OutDef.od_file = def->df_file;
+	OutDef.od_line = def->df_line;
+	OutDef.od_type = (type->tp_fund == FUNCTION ? type->tp_up : type);
+	OutDef.od_valreturned = NORETURN;
+}
+
+def2decl(sc)
+	int sc;
+{
+/* It was assumed we were parsing a function definition.
+ * There was no compound statement following, so actually it was a
+ * declaration. This function updates the class.
+ */
+	OutDef.od_class = (sc == STATIC ? XXDF : EFDC);
+}
+
+set_od_valreturned(n)
+{
+	OutDef.od_valreturned = n;
+}
+
+local_EFDC(idf)
+	struct idf *idf;
+{
+	struct outdef od;
+
+	od.od_class = EFDC;
+	od.od_statnr = 0;
+	od.od_name = idf->id_text;
+	od.od_file = idf->id_def->df_file;
+	od.od_line = idf->id_def->df_line;
+	od.od_type = idf->id_def->df_type->tp_up;
+	output_def(&od);
+	/* The other fields are not used for this class. */
+}
+
+lint_formals()
+{
+/* Make a list of tp_entries containing the types of the formal
+ * parameters of the function definition currently parsed.
+ */
+	register struct stack_entry *se = stack_level_of(L_FORMAL1)->sl_entry;
+	register struct tp_entry **hook = &OutDef.od_entry;
+
+	OutDef.od_nrargs = 0;
+	while (se) {
+		register struct type *type = se->se_idf->id_def->df_type;
+		register struct tp_entry *te = new_tp_entry();
+
+		switch (type->tp_fund) {
+		/*	Do the conversions on the formals that could not be
+			done in declare_idf().
+			It is, unfortunately, impossible not to do them,
+			since the corresponding actuals will have been
+			converted to generate proper code and we do not
+			want to duplicate the whole of expression handling
+			for lint.
+		*/
+		case CHAR:
+		case SHORT:
+			type = int_type;
+			break;
+		case FLOAT:
+			type = double_type;
+			break;
+		}
+		te->te_type = type;
+		te->te_class = !Const;
+		*hook = te;
+		hook = &te->next;
+
+		OutDef.od_nrargs++;
+		se = se->next;
+	}
+	if (f_VARARGSn > OutDef.od_nrargs) {
+		warning("VARARGS%d function has only %d arguments",
+			f_VARARGSn, OutDef.od_nrargs);
+		f_VARARGSn = OutDef.od_nrargs;
+	}
+}
+
+output_use(idf)
+	struct idf *idf;
+{
+/* Output the usage-definition of the variable described by idf.
+ */
+	OutDef.od_name = idf->id_text;
+	OutDef.od_statnr = (idf->id_def->df_sc == STATIC ? stat_number : 0);
+	OutDef.od_class = VU;
+	OutDef.od_file = FileName;
+	OutDef.od_line = LineNumber;
+	OutDef.od_type = idf->id_def->df_type;
+	outdef();
+}
+
+outdef()
+{
+	output_def(&OutDef);
+}
+
+outcall()
+{
+	output_def(&OutCall);
+}
+
+output_def(od)
+	struct outdef *od;
+{
+/* As the types are output the tp_entries are removed, because they
+ * are then not needed anymore.
+ */
+	if (od->od_class == XXDF)
+		return;
+
+	if (LINTLIB) {
+		switch (od->od_class) {
+		case EFDF:
+			od->od_class = LFDF;
+			break;
+		case EVDF:
+			od->od_class = LVDF;
+			break;
+		case SFDF:
+			/* remove tp_entries */
+			while (od->od_entry) {
+				register struct tp_entry *tmp = od->od_entry;
+				od->od_entry = od->od_entry->next;
+				free_tp_entry(tmp);
+			}
+			return;
+		default:
+			return;
+		}
+	}
+	printf("%s:%d:%c", od->od_name, od->od_statnr, od->od_class);
+	switch (od->od_class) {
+	case EFDF:
+	case SFDF:
+	case LFDF:
+		if (f_VARARGSn != -1) {
+			printf(":%d", -1 - f_VARARGSn);
+			outtypes(od->od_entry, f_VARARGSn);
+		}
+		else {
+			printf(":%d", od->od_nrargs);
+			outtypes(od->od_entry, od->od_nrargs);
+		}
+		od->od_entry = 0;
+		printf(":%d", od->od_valreturned);
+		break;
+	case FC:
+		printf(":%d", od->od_nrargs);
+		outtypes(od->od_entry, od->od_nrargs);
+		od->od_entry = 0;
+		printf(":%d", od->od_valused);
+		break;
+	case EVDF:
+	case SVDF:
+	case LVDF:
+	case EFDC:
+	case EVDC:
+	case IFDC:
+	case VU:
+		break;
+	default:
+		crash("(output_def) illegal class");
+		/*NOTREACHED*/
+	}
+	printf(":");
+	outtype(od->od_type);
+	printf(":%u:%s\n", od->od_line, od->od_file);
+}
+
+outtypes(te, n)
+	struct tp_entry *te;
+{
+/* Output n types in the tp_entry-list and remove all the entries */
+
+	register struct tp_entry *tmp;
+
+	while (n--) {
+		if (!te) {
+			crash("(outtypes) not enough tp_entries");
+			/*NOTREACHED*/
+		}
+		printf(":");
+		if (te->te_class == Const && te->te_value >= 0) {
+			/* constant non-negative actual parameter */
+			printf("+");
+		}
+		outtype(te->te_type);
+		if (te->te_type->tp_fund == FUNCTION) {
+			/* UGLY PATCH !!! ??? */
+			/*	function names as operands are sometimes
+				FUNCTION and sometimes POINTER to FUNCTION,
+				depending on opaque circumstances.  E.g., in
+					f(main, main);
+				the first main is PtF and the second is F.
+			*/
+			printf("*");
+		}
+		tmp = te;
+		te = te->next;
+		free_tp_entry(tmp);
+	}
+	/* remove the remaining entries */
+	while (te) {
+		tmp = te;
+		te = te->next;
+		free_tp_entry(tmp);
+	}
+}
+
+outtype(tp)
+	struct type *tp;
+{
+	switch (tp->tp_fund) {
+	case POINTER:
+		outtype(tp->tp_up);
+		printf("*");
+		break;
+
+	case ARRAY:
+		outtype(tp->tp_up);
+		printf("*");	/* compatible with [] */
+		break;
+
+	case FUNCTION:
+		outtype(tp->tp_up);
+		printf("()");
+		break;
+
+	case STRUCT:
+	case UNION:
+	case ENUM:
+		printf("%s %s", symbol2str(tp->tp_fund), tp->tp_idf->id_text);
+		break;
+
+	case CHAR:
+	case INT:
+	case SHORT:
+	case LONG:
+	case FLOAT:
+	case DOUBLE:
+	case VOID:
+	case ERRONEOUS:
+		if (tp->tp_unsigned)
+			printf("unsigned ");
+		printf("%s", symbol2str(tp->tp_fund));
+		break;
+	default:
+		crash("(outtype) illegal tp_fund");
+		/*NOTREACHED*/
+	}
+}
+
+implicit_func_decl(idf, file, line)
+	struct idf *idf;
+	char *file;
+	unsigned int line;
+{
+	struct outdef od;
+
+	od.od_class = IFDC;
+	od.od_statnr = 0;
+	od.od_name = idf->id_text;
+	od.od_file = file;
+	od.od_line = line;
+	od.od_type = idf->id_def->df_type->tp_up;
+	output_def(&od);
+	/* The other fields are not used for this class. */
+}
+
+fill_outcall(ex, used)
+	struct expr *ex;
+	int used;
+{
+	register struct idf *idf = ex->OP_LEFT->VL_IDF;
+	register struct def *def = idf->id_def;
+
+	if (def->df_sc == IMPLICIT) {
+		implicit_func_decl(idf, ex->ex_file, ex->ex_line);
+	}
+
+	OutCall.od_type = def->df_type->tp_up;
+	OutCall.od_statnr = (def->df_sc == STATIC ? stat_number : 0);
+	OutCall.od_class = FC;
+	OutCall.od_name = idf->id_text;
+	OutCall.od_file = ex->ex_file;
+	OutCall.od_line = ex->ex_line;
+	OutCall.od_entry = (struct tp_entry *)0;
+	OutCall.od_nrargs = 0;
+
+	if ((ex = ex->OP_RIGHT) != 0) {	/* function call with arguments */
+		/* store types of argument expressions in tp_entries */
+		while (ex->ex_class == Oper && ex->OP_OPER == PARCOMMA) {
+			fill_arg(ex->OP_RIGHT);
+			ex = ex->OP_LEFT;
+		}
+		fill_arg(ex);
+	}
+	OutCall.od_valused = used;	/* USED, IGNORED or VOIDED */
+}
+
+fill_arg(e)
+	struct expr *e;
+{
+	register struct tp_entry *te;
+
+	te = new_tp_entry();
+	te->te_type = e->ex_type;
+	if (is_cp_cst(e)) {
+		te->te_class = Const;
+		te->te_value = e->VL_VALUE;
+	}
+	else {
+		te->te_class = !Const;
+		te->te_value = (arith) 0;
+	}
+	te->next = OutCall.od_entry;
+	OutCall.od_entry = te;
+	OutCall.od_nrargs++;
+}
+
+#endif	LINT

+ 31 - 0
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;
+};

+ 73 - 0
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 */
+

+ 1102 - 0
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	<alloc.h>	/* for st_free */
+#include	"assert.h"
+#include	"arith.h"	/* definition arith */
+#include	"label.h"	/* definition label */
+#include	"expr.h"
+#include	"idf.h"
+#include	"def.h"
+#include	"code.h"	/* RVAL etc */
+#include	"LLlex.h"
+#include	"Lpars.h"
+#include	"stack.h"
+#include	"type.h"
+#include	"level.h"
+#include	"nofloat.h"
+#include	"l_lint.h"
+#include	"l_brace.h"
+#include	"l_state.h"
+#include	"l_outdef.h"
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+extern char *symbol2str();
+extern char *func_name;
+extern struct type *func_type;
+extern int func_notypegiven;
+extern char loptions[];
+extern int s_NOTREACHED;
+
+/* global variables for the lint_stack */
+struct lint_stack_entry stack_bottom;
+struct lint_stack_entry *top_ls = &stack_bottom;
+
+/* global variables for the brace stack */
+int brace_count;
+struct brace brace_bottom;
+struct brace *top_br = &brace_bottom;
+
+static print_autos();
+
+lint_start_local()
+{
+	register struct brace *br = new_brace();
+
+	brace_count++;
+	br->br_count = brace_count;
+	br->br_level = level;
+	br->next = top_br;
+	top_br = br;
+}	
+
+lint_local_level(stl)
+	struct stack_level *stl;
+{
+	if (s_NOTREACHED) {
+		top_ls->ls_current->st_notreached = 1;
+		s_NOTREACHED = 0;
+	}
+
+	if (top_ls->ls_class == CASE && level == top_ls->ls_level) {
+		lint_break_stmt();
+			/* To prevent a warning for the case
+			 *	switch (cond) {
+			 *	int i;
+			 *	case 0:
+			 *		i = 0;
+			 *		use(i);
+			 *	}
+			 */
+	}
+
+	check_autos();
+	end_brace(stl);
+}
+
+end_brace(stl)
+	struct stack_level *stl;
+{
+	/*	Check if static variables and labels are used and/or set.
+	*/
+	register struct stack_entry *se = stl->sl_entry;
+	register struct brace *br;
+
+	while (se) {
+		register struct idf *idf = se->se_idf;
+		register struct def *def = idf->id_def;
+
+		if (def) {
+			lint_1_local(idf, def);
+		}
+		se = se->next;
+	}
+
+	br = top_br;
+	top_br = br->next;
+	free_brace(br);
+}
+
+lint_1_local(idf, def)
+	struct idf *idf;
+	struct def *def;
+{
+	register int sc = def->df_sc;
+
+	if (	(sc == STATIC || sc == LABEL)
+	&&	!def->df_used
+	) {
+		def_warning(def, "%s %s declared but not used in function %s",
+			symbol2str(sc), idf->id_text, func_name);
+	}
+
+	if (	loptions['h']
+	&&	sc == AUTO
+	&&	!def->df_initialized
+	&&	def->df_firstbrace != 0
+	&&	def->df_minlevel != level
+	) {
+		register int diff = def->df_minlevel - level;
+
+		def_warning(def,
+			"local %s could be declared %d level%s deeper",
+			idf->id_text, diff, (diff == 1 ? "" : "s")
+		);
+	}
+}
+
+lint_global_level(stl)
+	struct stack_level *stl;
+{
+	register struct stack_entry *se = stl->sl_entry;
+
+	ASSERT(level == L_GLOBAL);
+	while (se) {
+		register struct idf *idf = se->se_idf;
+		register struct def *def = idf->id_def;
+
+		if (def) {
+			lint_1_global(idf, def);
+		}
+		se = se->next;
+	}
+}
+
+lint_1_global(idf, def)
+	struct idf *idf;
+	struct def *def;
+{
+	register int sc = def->df_sc;
+	register int fund = def->df_type->tp_fund;
+
+	switch (sc) {
+	case STATIC:
+	case EXTERN:
+	case GLOBAL:
+	case IMPLICIT:
+		if (fund == ERRONEOUS)
+			break;
+
+		if (def->df_set || def->df_used) {
+			/* Output a line to the intermediate file for
+			 * used external variables (including functions)
+			 */
+			output_use(idf);
+		}
+		else {
+			if (sc == STATIC) {
+				if (def->df_set) {
+					def_warning(def,
+						"%s %s %s set but not used",
+						symbol2str(sc),
+						symbol2str(fund),
+						idf->id_text);
+				}
+				else {
+					def_warning(def,
+						"%s %s %s not used anywhere",
+						symbol2str(sc),
+						symbol2str(fund),
+						idf->id_text);
+				}
+			}
+			if (loptions['x']) {
+				register char *fn = def->df_file;
+
+				if (	(sc == EXTERN || sc == GLOBAL)
+				&&	def->df_alloc == 0
+				&&	!def->df_set
+				&&	!def->df_initialized
+				&&	strcmp(&fn[strlen(fn)-2], ".c") == 0
+				) {
+					def_warning(def,
+						"%s %s %s not used anywhere",
+						symbol2str(sc),
+						symbol2str(fund),
+						idf->id_text);
+				}
+			}
+		}
+		break;
+	}
+}
+
+change_state(idf, to_state)
+	struct idf *idf;
+{
+/* Changes the state of the variable identified by idf in the current state
+ * on top of the stack.
+ * For non-automatic variables, the fields in the def-descriptor are set too.
+ */
+	register struct def *def = idf->id_def;
+	register struct auto_def *a = top_ls->ls_current->st_auto_list;
+
+	if (def) {
+		if (to_state == SET)
+			def->df_set = 1;
+		else
+			def->df_used = 1;
+
+		if (def->df_firstbrace == 0) {
+			def->df_firstbrace = brace_count;
+			def->df_minlevel = level;
+		}
+		else {
+			register struct brace *br = top_br;
+
+			/*	find the smallest brace range from which
+				firstbrace is visible
+			*/
+			while (br && br->br_count > def->df_firstbrace) {
+				br = br->next;
+			}
+			ASSERT(br && def->df_minlevel >= br->br_level);
+			def->df_minlevel = br->br_level;
+		}
+	}
+
+	while(a && a->ad_idf != idf)
+		a = a->next;
+	if (a == 0)	/* identifier not in list */
+		return;
+
+	if (to_state == SET) {
+		a->ad_maybe_set = 0;
+		a->ad_set = 1;
+		return;
+	}
+	/* else to_state == USED */
+	if (!a->ad_set) {
+		warning("%s%s uninitialized", idf->id_text,
+			(a->ad_maybe_set ? " possibly" : "")
+		);
+		a->ad_maybe_set = 0;
+		a->ad_set = 1;	/* one warning */
+	}
+	a->ad_used = 1;
+}
+
+extern struct stack_level *local_level;
+
+add_auto(idf)	/* to current state on top of lint_stack */
+	struct idf *idf;
+{
+/* Check if idf's definition is really an auto (or register).
+ * It could be a static or extern too.
+ * Watch out for register formal parameters.
+ */
+	register struct def *def = idf->id_def;
+	register struct auto_def *a;
+
+	if (!def)
+		return;
+	switch (def->df_sc) {
+	case AUTO:
+	case REGISTER:
+		if (def->df_level < L_LOCAL)
+			return;		/* a register formal */
+		a = new_auto_def();
+		a->ad_idf = idf;
+		a->ad_def = idf->id_def;
+		a->ad_used = def->df_used;
+		a->ad_set = def->df_set;
+		a->next = top_ls->ls_current->st_auto_list;
+		top_ls->ls_current->st_auto_list = a;
+	}
+}
+
+check_autos()
+{
+/* Before leaving a block remove the auto_defs of the automatic
+ * variables on this level and check if they are used
+ */
+	register struct auto_def *a1 = top_ls->ls_current->st_auto_list;
+	register struct auto_def *a2;
+
+	if (a1 && a1->ad_def->df_level > level) {
+		crash("(check_autos) corrupt level in st_auto_list");
+		/*NOTREACHED*/
+	}
+	while (a1 && a1->ad_def->df_level == level) {
+		a2 = a1;
+		a1 = a1->next;
+		if (!a2->ad_used) {
+			if (a2->ad_set || a2->ad_maybe_set) {
+				def_warning(a2->ad_def,
+					"%s set but not used in function %s",
+					a2->ad_idf->id_text, func_name);
+			}
+			else {
+				def_warning(a2->ad_def,
+					"%s neither set nor used in function %s",
+					a2->ad_idf->id_text, func_name);
+			}
+		}
+		free_auto_def(a2);
+	}
+	top_ls->ls_current->st_auto_list = a1;
+}
+
+check_args_used()
+{
+	register struct stack_entry *se = local_level->sl_entry;
+	extern int f_ARGSUSED;
+
+	if (level != L_FORMAL1) {
+		crash("(check_args_used) invalid level %d", level);
+		/*NOTREACHED*/
+	}
+	while (se) {
+		register struct def *def = se->se_idf->id_def;
+
+		if (def && !def->df_used && !loptions['v'] && !f_ARGSUSED) {
+			def_warning(def, "argument %s not used in function %s",
+					se->se_idf->id_text, func_name);
+		}
+		se = se->next;
+	}
+}
+
+struct auto_def *
+copy_st_auto_list(from_al, lvl)
+	struct auto_def *from_al;
+{
+	struct auto_def *start = 0;
+	register struct auto_def **hook = &start;
+
+	while (from_al && from_al->ad_def->df_level > lvl) {
+		from_al = from_al->next;
+	}
+	while (from_al) {
+		register struct auto_def *a = new_auto_def();
+
+		*hook = a;
+		*a = *from_al;
+		hook = &a->next;
+		from_al = from_al->next;
+	}
+
+	return(start);
+}
+
+free_st_auto_list(au)
+	register struct auto_def *au;
+{
+	register struct auto_def *a;
+
+	while (au) {
+		a = au;
+		au = au->next;
+		free_auto_def(a);
+	}
+}
+
+struct state *
+copy_state(from_st, lvl)
+	struct state *from_st;
+{
+/* Memory for the struct state and the struct auto_defs is allocated
+ * by this function
+ */
+	register struct state *st = new_state();
+
+	st->st_auto_list = copy_st_auto_list(from_st->st_auto_list, lvl);
+	st->st_notreached = from_st->st_notreached;
+	st->st_warned = from_st->st_warned;
+	return(st);
+}
+
+static
+Free_state(stp)
+	struct state **stp;
+{
+/* This function also frees the list of auto_defs
+ */
+	free_st_auto_list((*stp)->st_auto_list);
+	free_state(*stp);
+	*stp = 0;
+}
+
+remove_settings(state, lvl)
+	struct state *state;
+{
+/* The state of all variables on this level are set to 'not set' and
+ * 'not maybe set'. (I think you have to read this twice.)
+ */
+	register struct auto_def *a = state->st_auto_list;
+
+	while (a && a->ad_def->df_level == lvl) {
+		a->ad_set = a->ad_maybe_set = 0;
+		a = a->next;
+	}
+}
+
+
+/******** M E R G E ********/
+
+/* modes for merging */
+#define	NORMAL		0
+#define	CASE_BREAK	1
+#define	USE_ONLY	2
+
+struct auto_def *
+merge_autos(a1, a2, lvl, mode)
+	struct auto_def *a1, *a2;
+	int mode;
+{
+/* Returns a pointer to the result.
+ * a1 is left unchanged.
+ * a2 is used to create this result.
+ * The fields are set as follows:
+ *	a1_set + a2_set		-> set
+ *		+ a?_maybe_set	-> maybe set
+ *		ELSE		-> NOT set && NOT maybe set
+ *	*	+ a?_used	-> used
+ *
+ * For mode == CASE_BREAK:
+ * First a2 is taken as the result, then
+ * variables NOT set in a2 and set or maybe set in a1 become 'maybe set'
+ *
+ * For mode == USE_ONLY:
+ * Start with a2 as the result.
+ * Variables used in a1 become used in a2.
+ * The rest of the result is not changed.
+ */
+	register struct auto_def *a;
+
+	while (a1 && a1->ad_def->df_level > lvl) {
+		a1 = a1->next;
+	}
+	while (a2 && a2->ad_def->df_level > lvl) {
+		a = a2;
+		a2 = a2->next;
+		free_auto_def(a);
+	}
+	a = a2;	/* pointer to the result */
+	while (a1) {
+		if (!a2) {
+			crash("(merge_autos) a1 longer than a2");
+			/*NOTREACHED*/
+		}
+		if (a1->ad_idf != a2->ad_idf) {
+			crash("(merge_autos) identifiers should be the same %s %s",
+				a1->ad_idf->id_text, a2->ad_idf->id_text);
+			/*NOTREACHED*/
+		}
+
+		if (a1->ad_used)
+			a2->ad_used = 1;
+
+		if (mode != USE_ONLY) {
+			if (	(	!a2->ad_set
+				&&	(a1->ad_set || a1->ad_maybe_set)
+				)
+			||	(	mode == NORMAL
+				&&	!a1->ad_set
+				&&	(a2->ad_set || a2->ad_maybe_set)
+				)
+			) {
+				a2->ad_set = 0;
+				a2->ad_maybe_set = 1;
+			}
+		}
+
+		a1 = a1->next;
+		a2 = a2->next;
+	}
+	if (a2) {
+		crash("(merge_autos) a2 longer than a1");
+		/*NOTREACHED*/
+	}
+	return(a);
+}
+
+merge_states(st1, st2, lvl, mode)
+	struct state *st1, *st2;
+	int mode;
+{
+/* st2 becomes the result.
+ * st1 is left unchanged.
+ * The resulting state is the state the program gets in if st1 OR st2
+ * becomes the state. (E.g. the states at the end of an if-part and an
+ * end-part are merged by this function.)
+ */
+	if (st1->st_notreached) {
+		if (mode == NORMAL || st2->st_notreached) {
+			st2->st_auto_list =
+				merge_autos(st1->st_auto_list,
+					st2->st_auto_list, lvl, USE_ONLY);
+		}
+	}
+	else if (st2->st_notreached) {
+		register struct auto_def *tmp = st2->st_auto_list;
+
+		st2->st_auto_list = copy_st_auto_list(st1->st_auto_list, lvl);
+		st2->st_notreached = 0;
+		st2->st_warned = 0;
+		st2->st_auto_list = merge_autos(tmp, st2->st_auto_list,
+							lvl, USE_ONLY);
+		free_st_auto_list(tmp);
+	}
+	else {
+		st2->st_auto_list =
+			merge_autos(st1->st_auto_list, st2->st_auto_list,
+				lvl, mode);
+	}
+}
+
+
+/******** L I N T   S T A C K   S E A R C H I N G ********/
+
+/* The next four find-functions search the lint_stack for an entry.
+ * The letters mean : w: WHILE; d: DO; f: FOR; s: SWITCH; c: CASE.
+ */
+
+struct lint_stack_entry *
+find_wdf()
+{
+	register struct lint_stack_entry *lse = top_ls;
+
+	while (lse != &stack_bottom) {
+		switch (lse->ls_class)
+		case WHILE:
+		case DO:
+		case FOR:
+			return(lse);
+		lse = lse->ls_previous;
+	}
+	return(0);
+}
+
+struct lint_stack_entry *
+find_wdfc()
+{
+	register struct lint_stack_entry *lse = top_ls;
+
+	while (lse != &stack_bottom) {
+		switch (lse->ls_class)
+		case WHILE:
+		case DO:
+		case FOR:
+		case CASE:
+			return(lse);
+		lse = lse->ls_previous;
+	}
+	return(0);
+}
+
+struct lint_stack_entry *
+find_cs()
+{
+	register struct lint_stack_entry *lse = top_ls;
+
+	while (lse != &stack_bottom) {
+		switch (lse->ls_class)
+		case CASE:
+		case SWITCH:
+			return(lse);
+		lse = lse->ls_previous;
+	}
+	return(0);
+}
+
+/******** A C T I O N S ********/
+
+start_if_part()
+{
+/* Push a new stack entry on the lint_stack with class == IF
+ * copy the ls_current to the top of this stack
+ */
+	register struct lint_stack_entry *lse = new_lint_stack_entry();
+
+	lse->ls_class = IF;
+	lse->ls_current = copy_state(top_ls->ls_current, level);
+	lse->ls_level = level;
+	lint_push(lse);
+}
+
+start_else_part()
+{
+/* Move ls_current to LS_IF_STATE
+ * ls_current of the stack entry one below is copied to ls_current.
+ */
+	if (s_NOTREACHED) {
+		top_ls->ls_current->st_notreached = 1;
+		s_NOTREACHED = 0;
+	}
+	top_ls->LS_IF_STATE = top_ls->ls_current;
+	/* this is the reason why ls_current is a pointer */
+	top_ls->ls_current = copy_state(top_ls->ls_previous->ls_current,
+								level);
+	top_ls->ls_level = level;
+}
+
+end_if_else_stmt()
+{
+	Free_state(&top_ls->ls_previous->ls_current);
+	merge_states(top_ls->LS_IF_STATE, top_ls->ls_current,
+					top_ls->ls_level, NORMAL);
+	Free_state(&top_ls->LS_IF_STATE);
+	top_ls->ls_previous->ls_current = top_ls->ls_current;
+	lint_pop();
+}
+
+end_if_stmt()
+{
+/* No else-part met; merge ls_current with ls_current of previous
+ * stack entry
+ */
+	merge_states(top_ls->ls_current, top_ls->ls_previous->ls_current,
+						top_ls->ls_level, NORMAL);
+	Free_state(&top_ls->ls_current);
+	lint_pop();
+}
+
+start_loop_stmt(looptype, const, cond)
+{
+/* If const, the condition is constant and given in cond */
+	register struct lint_stack_entry *lse = new_lint_stack_entry();
+
+	lse->ls_class = looptype;
+	lse->ls_current = copy_state(top_ls->ls_current, level);
+	lse->ls_level = level;
+	if (const && !cond) {
+		/* while (0) | for (;0;) */
+		hwarning("condition in %s statement is constant",
+						symbol2str(looptype));
+		lse->ls_current->st_notreached = 1;
+	}
+	if (const && cond) {
+		/* while (1) | for (;;) | do */
+		/*	omitting the copy for LS_END will force this loop
+			to be treated as a do loop
+		*/
+		top_ls->ls_current->st_notreached = 1;
+	}
+	else {
+		lse->LS_END = copy_state(top_ls->ls_current, level);
+	}
+	lint_push(lse);
+}
+
+end_loop_stmt()
+{
+	register struct lint_stack_entry *prev_ls = top_ls->ls_previous;
+
+	lint_continue_stmt();
+	top_ls->LS_END->st_notreached = prev_ls->ls_current->st_notreached;
+	top_ls->LS_END->st_warned = prev_ls->ls_current->st_warned;
+	Free_state(&top_ls->ls_current);
+	Free_state(&prev_ls->ls_current);
+	prev_ls->ls_current = top_ls->LS_END;
+	lint_pop();
+}
+
+end_do_stmt(const, cond)
+{
+	end_loop_stmt();
+	if (const)
+		hwarning("constant do condition");
+	if (const && cond && top_ls->ls_current->st_notreached) {
+		/* no break met; this is really an endless loop */
+	}
+	else {
+		top_ls->ls_current->st_notreached = 0;
+	}
+}
+
+cont_break_merge(lse)
+	struct lint_stack_entry *lse;
+{
+	/* merge for continue and break statements */
+	if (lse->LS_END) {
+		merge_states(top_ls->ls_current, lse->LS_END,
+						lse->ls_level, NORMAL);
+	}
+	else {
+		lse->LS_END = copy_state(top_ls->ls_current, lse->ls_level);
+	}
+}
+
+lint_continue_stmt()
+{
+	register struct lint_stack_entry *lse = find_wdf();
+
+	if (!lse)
+		return;		/* not inside a loop statement */
+
+	cont_break_merge(lse);
+	top_ls->ls_current->st_notreached = 1;
+}
+
+start_switch_part()
+{
+/* ls_current of a SWITCH entry has different meaning from ls_current of
+ * other entries. It keeps track of which variables are used in all
+ * following case parts. (Needed for variables declared in a compound
+ * switch-block.)
+ */
+	register struct lint_stack_entry *lse = new_lint_stack_entry();
+
+	lse->ls_class = SWITCH;
+	lse->ls_current = copy_state(top_ls->ls_current, level);
+	lse->ls_level = level;
+	lse->LS_CASE = copy_state(top_ls->ls_current, level);
+	lse->ls_current->st_notreached = 1;
+	top_ls->ls_current->st_notreached = 1;
+	lint_push(lse);
+}
+
+end_switch_stmt()
+{
+	if (top_ls->ls_class == CASE) {
+		/* no break after last case or default */
+		lint_break_stmt();	/* introduce break */
+	}
+
+	if (!top_ls->LS_DEFAULT_MET) {
+		top_ls->ls_current->st_notreached = 0;
+		if (top_ls->LS_BREAK) {
+			merge_states(top_ls->ls_current, top_ls->LS_BREAK,
+						top_ls->ls_level, NORMAL);
+			Free_state(&top_ls->ls_current);
+		}
+		else {
+			top_ls->LS_BREAK = top_ls->ls_current;
+		}
+	}
+	else {
+		Free_state(&top_ls->ls_current);
+	}
+
+	if (top_ls->LS_BREAK) {
+		merge_states(top_ls->LS_CASE, top_ls->LS_BREAK,
+						top_ls->ls_level, CASE_BREAK);
+		Free_state(&top_ls->LS_CASE);
+	}
+	else {
+		top_ls->LS_BREAK = top_ls->LS_CASE;
+	}
+
+	top_ls->LS_BREAK->st_notreached =
+			top_ls->ls_previous->ls_current->st_notreached;
+				/* yack */
+	Free_state(&top_ls->ls_previous->ls_current);
+
+	if (!top_ls->LS_DEFAULT_MET)
+		top_ls->LS_BREAK->st_notreached = 0;
+	top_ls->ls_previous->ls_current = top_ls->LS_BREAK;
+
+	lint_pop();
+}
+
+lint_case_stmt(dflt)
+{
+/* A default statement is just a special case statement */
+
+	register struct lint_stack_entry *lse;
+	register struct lint_stack_entry *cs_entry = find_cs();
+
+	if (!cs_entry)
+		return;		/* not inside switch */
+	if (cs_entry != top_ls) {
+		warning("%s statement in strange context",
+			dflt ? "default" : "case");
+		return;
+	}
+	if (cs_entry->ls_class == SWITCH) {
+		if (dflt) {
+			cs_entry->LS_DEFAULT_MET = 1;
+		}
+		lse = new_lint_stack_entry();
+		lse->ls_class = CASE;
+		lse->ls_current = copy_state(top_ls->ls_current, level);
+		remove_settings(lse->ls_current, level);
+		lse->ls_level = level;
+		lint_push(lse);
+	}
+	else {
+		ASSERT(cs_entry->ls_class == CASE);
+		if (dflt) {
+			cs_entry->ls_previous->LS_DEFAULT_MET = 1;
+		}
+		merge_states(top_ls->ls_current, top_ls->ls_previous->LS_CASE,
+				top_ls->ls_previous->ls_level, NORMAL);
+		merge_states(top_ls->ls_current,
+				top_ls->ls_previous->ls_current,
+				top_ls->ls_previous->ls_level, NORMAL);
+		Free_state(&top_ls->ls_current);
+		top_ls->ls_current =
+			copy_state(top_ls->ls_previous->ls_current,
+					top_ls->ls_previous->ls_level);
+		remove_settings(top_ls->ls_current, top_ls->ls_level);
+	}
+}
+
+lint_break_stmt()
+{
+	register struct lint_stack_entry *lse = find_wdfc();
+
+	if (!lse)
+		return;
+
+	switch (lse->ls_class) {
+	case WHILE:
+	case FOR:
+	case DO:
+		/* loop break */
+		lse->ls_previous->ls_current->st_notreached = 0;
+		cont_break_merge(lse);
+		break;
+
+	case CASE:
+		/* case break */
+		if (!top_ls->ls_current->st_notreached) {
+			lse->ls_previous->ls_previous->ls_current->st_notreached = 0;
+		}
+		merge_states(lse->ls_current, lse->ls_previous->ls_current,
+					lse->ls_previous->ls_level, NORMAL);
+		if (lse->ls_previous->LS_BREAK) {
+			merge_states(top_ls->ls_current, lse->ls_previous->LS_BREAK,
+					lse->ls_previous->ls_level, NORMAL);
+		}
+		else {
+			lse->ls_previous->LS_BREAK = copy_state(top_ls->ls_current,
+						 lse->ls_previous->ls_level);
+		}
+		if (lse == top_ls) {
+			Free_state(&lse->ls_current);
+			lint_pop();
+		}
+		break;
+	default:
+		/* bad break */
+		crash("find_wdfc() returned invalid entry");
+		/*NOTREACHED*/
+	}
+	top_ls->ls_current->st_notreached = 1;
+}
+
+lint_start_function()
+{
+	lint_return_stmt(-1);	/* initialization */
+	move_ARG2f();
+	move_VAR2f();
+}
+
+lint_end_function()
+{
+	extern struct outdef OutDef;
+	register int fund = func_type->tp_fund;
+
+	if (	OutDef.od_valreturned == NOVALRETURNED
+	&&	!func_notypegiven
+	&&	fund != VOID
+	) {
+		warning("function %s declared %s%s but no value returned",
+			func_name,
+			(func_type->tp_unsigned && fund != POINTER) ?
+				"unsigned " : "",
+			 symbol2str(fund)
+		);
+	}
+	/* write the function definition record */
+	outdef();
+
+	/* At this stage it is possible that stack_bottom.ls_current is
+	 * pointing to a state with a list of auto_defs.
+	 * These auto_defs must be freed and the state must be filled
+	 * with zeros.
+	 */
+	if (top_ls != &stack_bottom) {
+		crash("(lint_end_function) top_ls != &stack_bottom");
+		/*NOTREACHED*/
+	}
+	if (top_ls->ls_current->st_auto_list != 0)
+		free_st_auto_list(top_ls->ls_current->st_auto_list);
+	top_ls->ls_current->st_auto_list = 0;
+	top_ls->ls_current->st_notreached = 0;
+	top_ls->ls_current->st_warned = 0;
+}
+
+lint_return_stmt(e)
+	int e;
+{
+/* The statics of this function are initialized by calling it with e = -1. */
+
+	static int ret_e;
+				/*-1	no return met yet
+				 * 0	return; met
+				 * 1	return with expression met
+				 */
+	static int warned;
+
+	switch (e) {
+	case -1:
+		ret_e = -1;
+		warned = 0;
+		return;
+	case 0:
+		if (top_ls->ls_current->st_notreached)
+			break;
+		if (ret_e == 1 && !warned) {
+			warning("function %s does not always return a value",
+				func_name);
+			warned = 1;
+		}
+		else
+			ret_e = 0;
+		break;
+	case 1:
+		if (top_ls->ls_current->st_notreached)
+			break;
+		if (ret_e == 0 && !warned) {
+			warning("function %s does not always return a value",
+				func_name);
+			warned = 1;
+		}
+		else
+			ret_e = 1;
+		break;
+	}
+	if (!top_ls->ls_current->st_notreached)
+		set_od_valreturned(e);
+	top_ls->ls_current->st_notreached = 1;
+}
+
+lint_jump_stmt(idf)
+	struct idf *idf;
+{
+	top_ls->ls_current->st_notreached = 1;
+	if (!idf->id_def)
+		return;
+	idf->id_def->df_used = 1;
+}
+
+lint_label()
+{
+/*	When meeting a label, we should take the intersection of all
+	settings at all goto's leading this way, but this cannot reasonably
+	be done.  So we assume that the user knows what he is doing and set
+	all automatic variables to set.
+*/
+	register struct auto_def *a = top_ls->ls_current->st_auto_list;
+
+	hwarning("all auto variables assumed initialized at label");
+	while (a) {
+		a->ad_maybe_set = 0;
+		a->ad_set = 1;
+		a = a->next;
+	}
+}
+
+lint_statement()
+{
+/* Check if this statement can be reached
+ */
+	if (s_NOTREACHED) {
+		top_ls->ls_current->st_notreached = 1;
+		s_NOTREACHED = 0;
+	}
+	if (DOT == '{' || DOT == ';')
+		return;
+	if (top_ls->ls_current->st_warned)
+		return;
+	if (top_ls->ls_current->st_notreached) {
+		if (DOT != CASE && DOT != DEFAULT && AHEAD != ':') {
+			if (DOT != BREAK || !loptions['b'])
+				warning("statement cannot be reached");
+			top_ls->ls_current->st_warned = 1;
+		}
+		else {
+			top_ls->ls_current->st_notreached = 0;
+			top_ls->ls_current->st_warned = 0;
+		}
+	}
+}
+
+lint_push(lse)
+	struct lint_stack_entry *lse;
+{
+	lse->ls_previous = top_ls;
+	top_ls->next = lse;
+	top_ls = lse;
+}
+
+lint_pop()
+{
+	top_ls = top_ls->ls_previous;
+	free_lint_stack_entry(top_ls->next);
+}
+
+
+/* FOR DEBUGGING */
+
+print_lint_stack()
+{
+	register struct lint_stack_entry *lse = top_ls;
+
+	while (lse) {
+		print("  |-------------- level %d ------------\n",
+					lse->ls_level);
+		print("  |cur: ");
+		if (lse->ls_current) {
+			print_autos(lse->ls_current->st_auto_list);
+			print("  |st_notreached == %d\n",
+				lse->ls_current->st_notreached);
+		}
+		else
+			print("\n");
+		print("  |class == %s\n",
+			lse->ls_class ? symbol2str(lse->ls_class) : "{");
+		switch (lse->ls_class) {
+		case SWITCH:
+			print("  |LS_BREAK: ");
+			if (lse->LS_BREAK) {
+				print_autos(lse->LS_BREAK->st_auto_list);
+				print("  |st_notreached == %d\n",
+					lse->LS_BREAK->st_notreached);
+			}
+			else
+				print("\n");
+			print("  |LS_CASE:  ");
+			if (lse->LS_CASE) {
+				print_autos(lse->LS_CASE->st_auto_list);
+				print("  |st_notreached == %d\n",
+					lse->LS_CASE->st_notreached);
+			}
+			else
+				print("\n");
+			break;
+		case DO:
+		case WHILE:
+		case FOR:
+			print("  |LS_END:  ");
+			if (lse->LS_END) {
+				print_autos(lse->LS_END->st_auto_list);
+				print("  |st_notreached == %d\n",
+					lse->LS_END->st_notreached);
+			}
+			else
+				print("\n");
+			break;
+		case IF:
+			print("  |LS_IF_STATE: ");
+			if (lse->LS_IF_STATE) {
+				print_autos(lse->LS_IF_STATE->st_auto_list);
+				print("  |st_notreached == %d\n",
+					lse->LS_IF_STATE->st_notreached);
+			}
+			else
+				print("\n");
+			break;
+		default:
+			break;
+		}
+		lse = lse->ls_previous;
+	}
+	print("  |--------------\n\n");
+}
+
+static
+print_autos(a)
+	register struct auto_def *a;
+{
+	while (a) {
+		print("%s", a->ad_idf->id_text);
+		print("(l=%d)", a->ad_def->df_level);
+		print("(U%dS%dM%d) ", a->ad_used, a->ad_set, a->ad_maybe_set);
+		a = a->next;
+	}
+	print("\n");
+}
+#endif	LINT

+ 19 - 0
lang/cem/cemcom/main.c

@@ -5,6 +5,7 @@
 /* $Header$ */
 /* MAIN PROGRAM */
 
+#include	"lint.h"
 #include	"nofloat.h"
 #include	<system.h>
 #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();
 

+ 38 - 6
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	<alloc.h>
 #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
 	}
 }
 

+ 29 - 0
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
 	}
 ;

+ 12 - 0
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	<system.h>
 #include	<em.h>
@@ -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)	{

+ 99 - 0
lang/cem/cemcom/statement.g

@@ -8,6 +8,7 @@
 {
 #include	<em.h>
 
+#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
 		}
 ;
 

+ 3 - 0
lang/cem/cemcom/util.c

@@ -16,6 +16,7 @@
 #include	<alloc.h>
 #include	<em_mes.h>
 
+#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