Переглянути джерело

version using input module and detecting preprocessor loops

ceriel 38 роки тому
батько
коміт
bd0740dc42

+ 15 - 5
lang/cem/cemcom/LLlex.c

@@ -21,9 +21,6 @@
 /* Data about the token yielded */
 struct token dot, ahead, aside;
 
-unsigned int LineNumber = 0;	/* current LineNumber	*/
-char *FileName = 0;		/* current filename	*/
-
 int ReplaceMacros = 1;		/* replacing macros			*/
 int EoiForNewline = 0;		/* return EOI upon encountering newline	*/
 int PreProcKeys = 0;		/* return preprocessor key		*/
@@ -31,6 +28,7 @@ int AccFileSpecifier = 0;	/* return filespecifier <...>		*/
 int AccDefined = 0;		/* accept "defined(...)"		*/
 int UnknownIdIsZero = 0;	/* interpret unknown id as integer 0	*/
 int SkipEscNewline = 0;		/* how to interpret backslash-newline	*/
+int Unstacked = 0;		/* an unstack is done 			*/
 
 #define MAX_LL_DEPTH	2
 
@@ -102,21 +100,28 @@ GetToken(ptok)
 	char buf[(IDFSIZE > NUMSIZE ? IDFSIZE : NUMSIZE) + 1];
 	register int ch, nch;
 
+	if (! LineNumber) goto firstline;
 again:	/* rescan the input after an error or replacement	*/
+#ifndef NOPP
+	if (Unstacked) EnableMacros();
+#endif
 	LoadChar(ch);
 go_on:	/* rescan, the following character has been read	*/
 	if ((ch & 0200) && ch != EOI) /* stop on non-ascii character */
 		fatal("non-ascii '\\%03o' read", ch & 0377);
 	switch (class(ch)) {	/* detect character class	*/
 	case STNL:		/* newline, vertical space or formfeed	*/
+firstline:
 		LineNumber++;			/* also at vs and ff	*/
 		if (EoiForNewline)	/* called in control line	*/
 			/*	a newline in a control line indicates the
 				end-of-information of the line.
 			*/
 			return ptok->tk_symb = EOI;
-		while (LoadChar(ch), ch == '#') /* a control line follows */
+		while (LoadChar(ch), ch == '#') { /* a control line follows */
 			domacro();
+			if (!LineNumber) goto firstline;
+		}
 			/*	We have to loop here, because in
 				`domacro' the nl, vt or ff is read. The
 				character following it may again be a `#'.
@@ -253,6 +258,9 @@ go_on:	/* rescan, the following character has been read	*/
 		hash = STARTHASH();
 		do	{			/* read the identifier	*/
 			if (++pos < idfsize) {
+#ifndef NOPP
+				if (Unstacked) EnableMacros();
+#endif
 				*tg++ = ch;
 				hash = ENHASH(hash, ch, pos);
 			}
@@ -485,8 +493,10 @@ string_token(nm, stop_char, plen)
 		}
 		if (ch == '\\') {
 			LoadChar(ch);
-			if (ch == '\n')
+			if (ch == '\n') {
 				LineNumber++;
+				continue;
+			}
 			ch = quoted(ch);
 		}
 		str[pos++] = ch;

+ 2 - 2
lang/cem/cemcom/LLlex.h

@@ -7,6 +7,7 @@
 */
 
 #include "nofloat.h"
+#include "file_info.h"
 
 /* the structure of a token:	*/
 struct token	{
@@ -42,8 +43,6 @@ struct token	{
 #endif NOFLOAT
 
 extern struct token dot, ahead, aside;
-extern unsigned int LineNumber;	/* "LLlex.c"	*/
-extern char *FileName;		/* "LLlex.c"	*/
 
 extern int ReplaceMacros;	/* "LLlex.c"	*/
 extern int EoiForNewline;	/* "LLlex.c"	*/
@@ -52,6 +51,7 @@ extern int AccFileSpecifier;	/* "LLlex.c"	*/
 extern int AccDefined;		/* "LLlex.c"	*/
 extern int UnknownIdIsZero;	/* "LLlex.c"	*/
 extern int SkipEscNewline;	/* "LLlex.c"	*/
+extern int Unstacked;		/* "LLlex.c"	*/
 
 extern int NoUnstack;		/* buffer.c	*/
 

+ 43 - 41
lang/cem/cemcom/Makefile.erik

@@ -17,21 +17,23 @@ EMELIB = $(EM)/modules/lib/libeme.a
 STRLIB = $(EM)/modules/lib/libstr.a
 PRTLIB = $(EM)/modules/lib/libprint.a
 EMMESLIB = $(EM)/modules/lib/libem_mes.a
+INPLIB = $(EM)/modules/lib/libinput.a
 #CH3LIB = $(EM)/modules/lib/libch3.a
 CH3LIB =
-LIBS = $(CH3LIB) $(EMMESLIB) $(EMKLIB) $(PRTLIB) $(STRLIB) $(SYSLIB)
-ELIBS = $(CH3LIB) $(EMMESLIB) $(EMELIB) $(PRTLIB) $(STRLIB) $(SYSLIB)
-LIB_INCLUDES = $(EM)/modules/h
-EM_INCLUDES = $(EM)/h
+LIBS = $(INPLIB) $(CH3LIB) $(EMMESLIB) $(EMKLIB) $(PRTLIB) $(STRLIB) $(SYSLIB)
+ELIBS = $(INPLIB) $(CH3LIB) $(EMMESLIB) $(EMELIB) $(PRTLIB) $(STRLIB) $(SYSLIB)
+LIB_INCLUDES = -I$(EM)/modules/h -I$(EM)/modules/pkg
+EM_INCLUDES = -I$(EM)/h
 SYSLLIB = $(EM)/modules/lib/llib-lsys.ln
 EMKLLIB = $(EM)/modules/lib/llib-lemk.ln
 EMELLIB = $(EM)/modules/lib/llib-leme.ln
 STRLLIB = $(EM)/modules/lib/llib-lstr.ln
 PRTLLIB = $(EM)/modules/lib/llib-lprint.ln
 EMMESLLIB = $(EM)/modules/lib/llib-lmes.ln
+INPLLIB = $(EM)/modules/lib/llib-linput.ln
 CH3LLIB = $(EM)/modules/lib/llib-lch3.ln
 LINTLIBS =
-#LINTLIBS = $(CH3LLIB) $(EMMESLLIB) $(EMKLLIB) $(PRTLLIB) $(STRLLIB) $(SYSLLIB)
+#LINTLIBS = $(CH3LLIB) $(INPLLIB) $(EMMESLLIB) $(EMKLLIB) $(PRTLLIB) $(STRLLIB) $(SYSLLIB)
 
 # Where to install the compiler and its driver
 CEMCOM = $(DESTINATION)/cemcom
@@ -48,7 +50,7 @@ GEN = $(EM)/bin/LLgen
 GENOPTIONS = -vv
 
 # Special #defines during compilation
-CDEFS =	$(MAP) -I$(EM_INCLUDES) -I$(LIB_INCLUDES)
+CDEFS =	$(MAP) $(EM_INCLUDES) $(LIB_INCLUDES)
 CFLAGS = $(CDEFS) $(COPTIONS) -O#	# we cannot pass the COPTIONS to lint!
 
 # Grammar files and their objects
@@ -77,7 +79,7 @@ GSRC =	char.c symbol2str.c next.c \
 GHSRC =	botch_free.h dataflow.h debug.h density.h errout.h \
 	idepth.h idfsize.h ifdepth.h inputtype.h inumlength.h lapbuf.h \
 	maxincl.h myalloc.h nobitfield.h nofloat.h nopp.h \
-	nparams.h numsize.h parbufsize.h pathlength.h predefine.h \
+	nparams.h numsize.h parbufsize.h pathlength.h \
 	strsize.h target_sizes.h textsize.h use_tmp.h spec_arith.h static.h
 
 # Other generated files, for 'make clean' only
@@ -206,47 +208,47 @@ sim:	cfiles
 	$(SIM) $(SIMFLAGS) `sources $(COBJ)` $(GSRC) $(LSRC)
 
 #AUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTO
-LLlex.o: LLlex.h Lpars.h alloc.h arith.h assert.h class.h debug.h def.h idf.h idfsize.h input.h nofloat.h nopp.h numsize.h sizes.h spec_arith.h strsize.h
-LLmessage.o: LLlex.h Lpars.h alloc.h arith.h idf.h nofloat.h nopp.h spec_arith.h
-Lpars.o: Lpars.h
-alloc.o: alloc.h assert.h debug.h myalloc.h
-arith.o: Lpars.h alloc.h arith.h botch_free.h expr.h field.h idf.h label.h mes.h nobitfield.h nofloat.h nopp.h spec_arith.h storage.h type.h
-blocks.o: arith.h atw.h nofloat.h sizes.h spec_arith.h
+main.o: LLlex.h Lpars.h alloc.h arith.h debug.h declar.h file_info.h idf.h input.h inputtype.h level.h maxincl.h myalloc.h nobitfield.h nofloat.h nopp.h spec_arith.h specials.h target_sizes.h tokenname.h type.h use_tmp.h
+idf.o: LLlex.h Lpars.h align.h alloc.h arith.h assert.h botch_free.h debug.h declar.h decspecs.h def.h file_info.h idf.h idfsize.h label.h level.h nobitfield.h nofloat.h nopp.h sizes.h spec_arith.h specials.h stack.h storage.h struct.h type.h
+declarator.o: Lpars.h alloc.h arith.h botch_free.h declar.h expr.h idf.h label.h nobitfield.h nofloat.h nopp.h sizes.h spec_arith.h storage.h type.h
+decspecs.o: Lpars.h arith.h decspecs.h def.h level.h nobitfield.h nofloat.h spec_arith.h type.h
+struct.o: LLlex.h Lpars.h align.h arith.h assert.h botch_free.h debug.h def.h field.h file_info.h idf.h level.h nobitfield.h nofloat.h nopp.h sizes.h spec_arith.h stack.h storage.h struct.h type.h
+expr.o: LLlex.h Lpars.h alloc.h arith.h botch_free.h declar.h decspecs.h def.h expr.h file_info.h idf.h label.h level.h nobitfield.h nofloat.h nopp.h sizes.h spec_arith.h storage.h type.h
 ch7.o: Lpars.h arith.h assert.h debug.h def.h expr.h idf.h label.h nobitfield.h nofloat.h nopp.h spec_arith.h struct.h type.h
 ch7bin.o: Lpars.h arith.h botch_free.h expr.h idf.h label.h nobitfield.h nofloat.h nopp.h spec_arith.h storage.h struct.h type.h
-ch7mon.o: Lpars.h arith.h botch_free.h def.h expr.h idf.h label.h nobitfield.h nofloat.h nopp.h spec_arith.h storage.h type.h
-char.o: class.h
-code.o: LLlex.h Lpars.h alloc.h arith.h assert.h atw.h botch_free.h code.h dataflow.h debug.h declar.h decspecs.h def.h expr.h idf.h label.h level.h mes.h nobitfield.h nofloat.h nopp.h sizes.h spec_arith.h specials.h stack.h stmt.h storage.h type.h use_tmp.h
-conversion.o: Lpars.h arith.h nobitfield.h nofloat.h sizes.h spec_arith.h type.h
 cstoper.o: Lpars.h arith.h assert.h debug.h expr.h idf.h label.h nobitfield.h nofloat.h nopp.h sizes.h spec_arith.h target_sizes.h type.h
-dataflow.o: dataflow.h
-declar.o: LLlex.h Lpars.h arith.h debug.h declar.h decspecs.h def.h expr.h field.h idf.h label.h nobitfield.h nofloat.h nopp.h sizes.h spec_arith.h storage.h struct.h type.h
-declarator.o: Lpars.h alloc.h arith.h botch_free.h declar.h expr.h idf.h label.h nobitfield.h nofloat.h nopp.h sizes.h spec_arith.h storage.h type.h
-decspecs.o: Lpars.h arith.h decspecs.h def.h level.h nobitfield.h nofloat.h spec_arith.h type.h
-domacro.o: LLlex.h Lpars.h alloc.h arith.h assert.h botch_free.h class.h debug.h idf.h idfsize.h ifdepth.h input.h interface.h macro.h nofloat.h nopp.h nparams.h parbufsize.h spec_arith.h storage.h textsize.h
+arith.o: Lpars.h alloc.h arith.h botch_free.h expr.h field.h idf.h label.h mes.h nobitfield.h nofloat.h nopp.h spec_arith.h storage.h type.h
+alloc.o: alloc.h assert.h debug.h myalloc.h
+code.o: LLlex.h Lpars.h alloc.h arith.h assert.h atw.h botch_free.h code.h dataflow.h debug.h declar.h decspecs.h def.h expr.h file_info.h idf.h label.h level.h mes.h nobitfield.h nofloat.h nopp.h sizes.h spec_arith.h specials.h stack.h stmt.h storage.h type.h use_tmp.h
 dumpidf.o: Lpars.h arith.h debug.h def.h expr.h field.h idf.h label.h nobitfield.h nofloat.h nopp.h spec_arith.h stack.h static.h struct.h type.h
-error.o: LLlex.h arith.h debug.h errout.h expr.h label.h nofloat.h nopp.h spec_arith.h tokenname.h use_tmp.h
-eval.o: Lpars.h align.h arith.h assert.h atw.h code.h dataflow.h debug.h def.h expr.h idf.h label.h level.h mes.h nobitfield.h nofloat.h nopp.h sizes.h spec_arith.h stack.h type.h
-expr.o: LLlex.h Lpars.h alloc.h arith.h botch_free.h declar.h decspecs.h def.h expr.h idf.h label.h level.h nobitfield.h nofloat.h nopp.h sizes.h spec_arith.h storage.h type.h
-expression.o: LLlex.h Lpars.h arith.h expr.h idf.h label.h nobitfield.h nofloat.h nopp.h spec_arith.h type.h
+error.o: LLlex.h arith.h debug.h errout.h expr.h file_info.h label.h nofloat.h nopp.h spec_arith.h tokenname.h use_tmp.h
 field.o: Lpars.h arith.h assert.h code.h debug.h expr.h field.h idf.h label.h nobitfield.h nofloat.h nopp.h sizes.h spec_arith.h type.h
-idf.o: LLlex.h Lpars.h align.h alloc.h arith.h assert.h botch_free.h debug.h declar.h decspecs.h def.h idf.h idfsize.h label.h level.h nobitfield.h nofloat.h nopp.h sizes.h spec_arith.h specials.h stack.h storage.h struct.h type.h
-init.o: alloc.h class.h idf.h interface.h macro.h nopp.h predefine.h
-input.o: LLlex.h alloc.h arith.h assert.h debug.h idepth.h input.h inputtype.h interface.h nofloat.h nopp.h pathlength.h spec_arith.h static.h
-ival.o: Lpars.h align.h arith.h assert.h class.h debug.h def.h expr.h field.h idf.h label.h level.h nobitfield.h nofloat.h nopp.h sizes.h spec_arith.h struct.h type.h
-label.o: Lpars.h arith.h def.h idf.h label.h level.h nobitfield.h nofloat.h nopp.h spec_arith.h type.h
-main.o: LLlex.h Lpars.h alloc.h arith.h debug.h declar.h idf.h input.h inputtype.h level.h maxincl.h myalloc.h nobitfield.h nofloat.h nopp.h spec_arith.h specials.h target_sizes.h tokenname.h type.h use_tmp.h
+tokenname.o: LLlex.h Lpars.h arith.h file_info.h idf.h nofloat.h nopp.h spec_arith.h tokenname.h
+LLlex.o: LLlex.h Lpars.h alloc.h arith.h assert.h class.h debug.h def.h file_info.h idf.h idfsize.h input.h nofloat.h nopp.h numsize.h sizes.h spec_arith.h strsize.h
+LLmessage.o: LLlex.h Lpars.h alloc.h arith.h file_info.h idf.h nofloat.h nopp.h spec_arith.h
+input.o: file_info.h input.h inputtype.h nopp.h
+domacro.o: LLlex.h Lpars.h alloc.h arith.h assert.h botch_free.h class.h debug.h file_info.h idf.h idfsize.h ifdepth.h input.h interface.h macro.h nofloat.h nopp.h nparams.h parbufsize.h spec_arith.h storage.h textsize.h
+replace.o: LLlex.h alloc.h arith.h assert.h class.h debug.h file_info.h idf.h input.h interface.h macro.h nofloat.h nopp.h pathlength.h spec_arith.h static.h strsize.h
+init.o: alloc.h class.h idf.h interface.h macro.h nopp.h
 options.o: align.h arith.h class.h idf.h idfsize.h macro.h maxincl.h nobitfield.h nofloat.h nopp.h sizes.h spec_arith.h storage.h use_tmp.h
-program.o: LLlex.h Lpars.h alloc.h arith.h code.h declar.h decspecs.h def.h expr.h idf.h label.h nobitfield.h nofloat.h nopp.h spec_arith.h type.h
-replace.o: LLlex.h alloc.h arith.h assert.h class.h debug.h idf.h input.h interface.h macro.h nofloat.h nopp.h pathlength.h spec_arith.h static.h strsize.h
 scan.o: class.h idf.h input.h interface.h lapbuf.h macro.h nopp.h nparams.h
-skip.o: LLlex.h arith.h class.h input.h interface.h nofloat.h nopp.h spec_arith.h
+skip.o: LLlex.h arith.h class.h file_info.h input.h interface.h nofloat.h nopp.h spec_arith.h
 stack.o: Lpars.h alloc.h arith.h botch_free.h debug.h def.h idf.h level.h mes.h nobitfield.h nofloat.h nopp.h spec_arith.h stack.h storage.h struct.h type.h use_tmp.h
-statement.o: LLlex.h Lpars.h arith.h botch_free.h code.h debug.h def.h expr.h idf.h label.h nobitfield.h nofloat.h nopp.h spec_arith.h stack.h storage.h type.h
-storage.o: alloc.h assert.h botch_free.h debug.h storage.h
-struct.o: LLlex.h Lpars.h align.h arith.h assert.h botch_free.h debug.h def.h field.h idf.h level.h nobitfield.h nofloat.h nopp.h sizes.h spec_arith.h stack.h storage.h struct.h type.h
+type.o: Lpars.h align.h alloc.h arith.h def.h idf.h nobitfield.h nofloat.h nopp.h sizes.h spec_arith.h storage.h type.h
+ch7mon.o: Lpars.h arith.h botch_free.h def.h expr.h idf.h label.h nobitfield.h nofloat.h nopp.h spec_arith.h storage.h type.h
+label.o: Lpars.h arith.h def.h idf.h label.h level.h nobitfield.h nofloat.h nopp.h spec_arith.h type.h
+eval.o: Lpars.h align.h arith.h assert.h atw.h code.h dataflow.h debug.h def.h expr.h idf.h label.h level.h mes.h nobitfield.h nofloat.h nopp.h sizes.h spec_arith.h stack.h type.h
 switch.o: Lpars.h arith.h assert.h botch_free.h code.h debug.h density.h expr.h idf.h label.h nobitfield.h nofloat.h nopp.h spec_arith.h storage.h switch.h type.h
-symbol2str.o: Lpars.h
+storage.o: alloc.h assert.h botch_free.h debug.h storage.h
+ival.o: Lpars.h align.h arith.h assert.h class.h debug.h def.h expr.h field.h idf.h label.h level.h nobitfield.h nofloat.h nopp.h sizes.h spec_arith.h struct.h type.h
+conversion.o: Lpars.h arith.h nobitfield.h nofloat.h sizes.h spec_arith.h type.h
+blocks.o: arith.h atw.h label.h nofloat.h sizes.h spec_arith.h stack.h
+dataflow.o: dataflow.h
 tokenfile.o: Lpars.h
-tokenname.o: LLlex.h Lpars.h arith.h idf.h nofloat.h nopp.h spec_arith.h tokenname.h
-type.o: Lpars.h align.h alloc.h arith.h def.h idf.h nobitfield.h nofloat.h nopp.h sizes.h spec_arith.h storage.h type.h
+declar.o: LLlex.h Lpars.h arith.h debug.h declar.h decspecs.h def.h expr.h field.h file_info.h idf.h label.h nobitfield.h nofloat.h nopp.h sizes.h spec_arith.h storage.h struct.h type.h
+statement.o: LLlex.h Lpars.h arith.h botch_free.h code.h debug.h def.h expr.h file_info.h idf.h label.h nobitfield.h nofloat.h nopp.h spec_arith.h stack.h storage.h type.h
+expression.o: LLlex.h Lpars.h arith.h expr.h file_info.h idf.h label.h nobitfield.h nofloat.h nopp.h spec_arith.h type.h
+program.o: LLlex.h Lpars.h alloc.h arith.h code.h declar.h decspecs.h def.h expr.h file_info.h idf.h label.h nobitfield.h nofloat.h nopp.h spec_arith.h type.h
+Lpars.o: Lpars.h
+char.o: class.h
+symbol2str.o: Lpars.h

+ 1 - 5
lang/cem/cemcom/Parameters

@@ -42,10 +42,6 @@
 #define	DENSITY	2	/* see switch.[ch] for an explanation		*/
 
 
-!File: predefine.h
-#define	PREDEFINE	"vax,VAX,BSD4_1,bsd4_1"
-
-
 !File: lapbuf.h
 #define	LAPBUF	4096	/* size of macro actual parameter buffer	*/
 
@@ -115,7 +111,7 @@
 
 
 !File: inputtype.h
-#undef READ_IN_ONE	1	/* read input file in one	*/
+#undef INP_READ_IN_ONE	1	/* read input file in one	*/
 
 
 !File: nopp.h

+ 50 - 31
lang/cem/cemcom/domacro.c

@@ -24,6 +24,7 @@
 #include	"storage.h"
 
 IMPORT char *inctable[];	/* list of include directories		*/
+IMPORT char *getwdir();
 PRIVATE char ifstack[IFDEPTH];	/* if-stack: the content of an entry is	*/
 				/* 1 if a corresponding ELSE has been	*/
 				/* encountered.				*/
@@ -223,6 +224,7 @@ do_include()
 	/*	do_include() performs the inclusion of a file.
 	*/
 	char *filenm;
+	char *result;
 	int tok;
 	struct token tk;
 
@@ -235,8 +237,17 @@ do_include()
 	}
 	AccFileSpecifier = 0;
 	SkipRestOfLine();
-	if (filenm && !InsertFile(filenm, &inctable[tok == FILESPECIFIER]))
-		lexerror("cannot find include file \"%s\"", filenm);
+	inctable[0] = WorkingDir;
+	if (filenm) {
+		if (!InsertFile(filenm, &inctable[tok==FILESPECIFIER],&result)){
+			lexerror("cannot find include file \"%s\"", filenm);
+		}
+		else {
+			WorkingDir = getwdir(result);
+			FileName = result;
+			LineNumber = 0;
+		}
+	}
 }
 
 PRIVATE
@@ -341,35 +352,31 @@ do_if()
 PRIVATE
 do_ifdef(how)
 {
-	struct idf *id;
+	register struct idf *id;
 
 	/*	how == 1 : ifdef; how == 0 : ifndef
 	*/
 	push_if();
-	if (id = GetIdentifier()) {
-		if (
-			(how && !(id && id->id_macro))
-		||
-			(!how && id && id->id_macro)
-		) /* this id is not defined	*/
-			skip_block();
-		else
-			SkipRestOfLine();
-	}
-	else {
+	if (!(id = GetIdentifier()))
 		lexerror("illegal #ifdef construction");
+
+	/* The next test is a shorthand for:
+		(how && !id->id_macro) || (!how && id->id_macro)
+	*/
+	if (how ^ (id && id->id_macro != 0))
+		skip_block();
+	else
 		SkipRestOfLine();
-	}
 }
 
 PRIVATE
 do_undef()
 {
-	struct idf *id;
+	register struct idf *id;
 
 	/* Forget a macro definition.	*/
 	if (id = GetIdentifier()) {
-		if (id && id->id_macro) { /* forget the macro */
+		if (id->id_macro) { /* forget the macro */
 			free_macro(id->id_macro);
 			id->id_macro = (struct macro *) 0;
 		} /* else: don't complain */
@@ -406,14 +413,15 @@ getparams(buf, parbuf)
 		Note that the '(' has already been eaten.
 		The names of the formal parameters are stored into parbuf.
 	*/
-	register count = 0;
-	register c;
+	register char **pbuf = &buf[0];
+	register int c;
 	register char *ptr = &parbuf[0];
+	register char **pbuf2;
 
 	LoadChar(c);
 	c = skipspaces(c);
 	if (c == ')') {		/* no parameters: #define name()	*/
-		buf[0] = (char *) 0;
+		*pbuf = (char *) 0;
 		return 0;
 	}
 	for (;;) {		/* eat the formal parameter list	*/
@@ -421,7 +429,7 @@ getparams(buf, parbuf)
 			lexerror("#define: bad formal parameter");
 			return -1;
 		}
-		buf[count++] = ptr;	/* name of the formal	*/
+		*pbuf = ptr;	/* name of the formal	*/
 		*ptr++ = c;
 		if (ptr >= &parbuf[PARBUFSIZE])
 			fatal("formal parameter buffer overflow");
@@ -432,10 +440,22 @@ getparams(buf, parbuf)
 				fatal("formal parameter buffer overflow");
 		} while (in_idf(c));
 		*(ptr - 1) = '\0';	/* mark end of the name		*/
+
+		/*	Check if this formal parameter is already used.
+			Usually, macros do not have many parameters, so ...
+		*/
+		for (pbuf2 = pbuf - 1; pbuf2 >= &buf[0]; pbuf2--) {
+			if (!strcmp(*pbuf2, *pbuf)) {
+				warning("formal parameter \"%s\" already used",
+					*pbuf);
+			}
+		}
+
+		pbuf++;
 		c = skipspaces(c);
 		if (c == ')') {	/* end of the formal parameter list	*/
-			buf[count] = (char *) 0;
-			return count;
+			*pbuf = (char *) 0;
+			return pbuf - buf;
 		}
 		if (c != ',') {
 			lexerror("#define: bad formal parameter list");
@@ -444,11 +464,12 @@ getparams(buf, parbuf)
 		LoadChar(c);
 		c = skipspaces(c);
 	}
+	/*NOTREACHED*/
 }
 
 EXPORT
 macro_def(id, text, nformals, length, flags)
-	struct idf *id;
+	register struct idf *id;
 	char *text;
 {
 	register struct macro *newdef = id->id_macro;
@@ -456,15 +477,12 @@ macro_def(id, text, nformals, length, flags)
 	/*	macro_def() puts the contents and information of a macro
 		definition into a structure and stores it into the symbol
 		table entry belonging to the name of the macro.
-		A warning is given if the definition overwrites another
-		(unless predefined!)
+		A warning is given if the definition overwrites another.
 	*/
 	if (newdef) {		/* is there a redefinition?	*/
-		if ((newdef->mc_flag & PREDEF) == 0) {
-			if (macroeq(newdef->mc_text, text))
-				return;
-			lexwarning("redefine \"%s\"", id->id_text);
-		} /* else: overwrite pre-definition	*/
+		if (macroeq(newdef->mc_text, text))
+			return;
+		lexwarning("redefine \"%s\"", id->id_text);
 	}
 	else
 		id->id_macro = newdef = new_macro();
@@ -472,6 +490,7 @@ macro_def(id, text, nformals, length, flags)
 	newdef->mc_nps  = nformals;	/* nr of formals	*/
 	newdef->mc_length = length;	/* length of repl. text	*/
 	newdef->mc_flag = flags;	/* special flags	*/
+	newdef->mc_count = 0;
 }
 
 PRIVATE int

+ 14 - 0
lang/cem/cemcom/file_info.h

@@ -0,0 +1,14 @@
+/* $Header$ */
+/* F I L E   I N F O R M A T I O N   S T R U C T U R E */
+
+struct file_info {
+	unsigned int	fil_lino;
+	char		*fil_name;
+	char		*fil_wdir;
+};
+
+#define LineNumber	finfo.fil_lino
+#define FileName	finfo.fil_name
+#define WorkingDir	finfo.fil_wdir
+
+extern struct file_info finfo;	/* input.c */

+ 1 - 33
lang/cem/cemcom/init.c

@@ -5,7 +5,6 @@
 
 #ifndef NOPP
 #include	<system.h>
-#include	"predefine.h"	/* UF */
 #include	"alloc.h"
 #include	"class.h"
 #include	"macro.h"
@@ -57,10 +56,7 @@ init_pp()
 	}
 
 	/*	Initialize __DATE__, __FILE__ and __LINE__ macro
-		definitions.  The compile-time specified predefined macros
-		are also predefined:  if this file is compiled with
-		-DPREDEFINE="vax,pdp", the macro definitions "vax" and
-		"pdp" are predefined macros.
+		definitions.
 	*/
 	/* __DATE__	*/
 	clock = sys_time();
@@ -77,33 +73,5 @@ init_pp()
 
 	/* defined(??) */
 	macro_def(str2idf("defined"), "", 1, 1, FUNC);
-
-#ifdef	PREDEFINE
-	{
-		/*	PREDEFINE is a compile-time defined string
-			containing a number of identifiers to be
-			predefined at the host machine (for example
-			-DPREDEFINE="vax,unix,pmds").
-		*/
-		register char *s = PREDEFINE;
-		register char *id;
-		char c;
-
-		for (;;)	{
-			while (*s && class(*s++) != STIDF);
-			if (*s)	{
-				/* gobble identifier */
-				id = s - 1;
-				while (in_idf(*s++));
-				c = *--s;
-				*s = '\0';
-				macro_def(str2idf(id), "1", -1, 1, PREDEF);
-				*s = c;
-			}
-			else
-				break;
-		}
-	}
-#endif	PREDEFINE
 }
 #endif NOPP

+ 27 - 437
lang/cem/cemcom/input.c

@@ -1,427 +1,18 @@
 /* $Header$ */
-/*	INPUT AND BUFFER HANDLING MODULE	*/
 
-/*
-	[input.c input.h]
-	Input buffering module: this module contains the routines that
-	offers an input buffering mechanism to the user.
-
-	This module exports the following objects:
-	InsertFile() :	suspend input from current buffer and obtain the
-			next input characters from the specified file
-	InsertText() :	suspend input from current buffer and take the
-			specified text as stream of input characters
-	LoadChar() :	(defined in input.h) read next character from
-			the input ; LoadChar() invokes loadbuf() on
-			encounting a ASCII NUL character
-	NoUnstack :	if set to non-zero:
-			loadbuf() reports "unexpected EOF" on encounting
-			the end-of-file or end-of-stacked-text.
-	
-	Imported objects are:
-	IDEPTH, DEBUG, READ_IN_ONE, PATHLENGTH: compile-time parameters
-	Malloc(), Salloc(): memory allocation routines
-	fatal(), lexerror(): exception handling
-	FileName, LineNumber, WorkingDir: input trace for lexical analyser
-
-	READ_IN_ONE DEFINED: every input file is read into memory completely
-		and made an input buffer
-	READ_IN_ONE NOT DEFINED: the input from files is buffered in
-		a fixed length input buffer
-*/
-
-#include	<system.h>
-#include	"nopp.h"
-#include	"inputtype.h"
-#include	"interface.h"
-#include	"arith.h"
-#include	"LLlex.h"
-#include	"input.h"
-#include	"alloc.h"
-
-#ifndef NOPP
-#include	"idepth.h"
-#include	"debug.h"
-#include	"pathlength.h"
-#include	"assert.h"
-#include	"static.h"
-#endif NOPP
-
-EXPORT char *ipp = 0;		/* input pointer	*/
-EXPORT int NoUnstack = 0;	/* if 1: report EOF	*/
-
-#ifndef READ_IN_ONE
-PRIVATE File *FilDes = 0;	/* current input medium	*/
-#endif READ_IN_ONE
+#include "inputtype.h"
+#include "file_info.h"
+#include "input.h"
+#define INP_TYPE	struct file_info
+#define INP_VAR		finfo
+struct file_info	finfo;
+#include <inp_pkg.body>
+#include "nopp.h"
 
 #ifndef NOPP
-struct buffer_header	{
-	char *bh_name;	/* file name where the text comes from	*/
-	unsigned int bh_lineno;
-			/* current lineno in file		*/
-	long bh_size;	/* = strlen (text), should be unsigned	*/
-	char *bh_text;	/* pointer to buffer containing text	*/
-	char *bh_ipp;	/* current read pointer (= stacked ipp)	*/
-	char *bh_wdir;	/* directory of current file		*/
-	File *bh_fp;	/* needed for files if !READ_IN_ONE	*/
-};
-
-PRIVATE struct buffer_header instack[IDEPTH];	/* stack of input media	*/
-PRIVATE struct buffer_header *head  = 0;	/* current input buffer	*/
-
-IMPORT char **WorkingDir;	/* name of current working directory	*/
-#else NOPP
-long isize;
-char ibuf[BUFSIZ + 1];
-#endif NOPP
-
-#ifdef READ_IN_ONE
-/*	readfile() creates a buffer in which the text of the file
-	is situated.  A pointer to the start of this text is
-	returned.  *size is initialized with the buffer length.
-	Note that the file input buffer is prepared for the
-	preprocessor by inserting a '\n' in the beginning of the
-	text and appending a '\n' at the end of the text.  The
-	file text start at position 1 of the input buffer. This is
-	done to allow pushback.
-*/
-
-PRIVATE char *
-readfile(filename, size)
-	char *filename;
-	long *size;
-{
-	File *fp;		/* filedescriptor for `filename'	*/
-	char *cbuf;		/* pointer to buffer to be returned	*/
-	int tmp;
-	long sys_filesize();
-
-	if (sys_open(filename, OP_READ, &fp) == 0) /* can't open this file */
-		return (char *) 0;
-	if ((*size = sys_filesize(filename)) == -1L)
-		fatal("(readfile) cannot get size of file");
-	/* allocate enough space to store contents of the file		*/
-	cbuf = Malloc(*size + 2);
-	if (sys_read(fp, cbuf + 1, (int) *size, &tmp) == 0 || tmp != *size)
-		fatal("(readfile) bad read");
-	(*size)++;		/* keep book of the size!	*/
-	sys_close(fp);		/* filedes no longer needed	*/
-	cbuf[0] = '\0';		/* allow pushback of first char	*/
-	cbuf[*size] = '\0';	/* invoke loadbuf() at end	*/
-	return cbuf;
-}
-#endif READ_IN_ONE
-
-#ifndef NOPP
-#ifndef READ_IN_ONE
-/*	Input buffer supplying routines: pushbuf() and popbuf()
-*/
-PRIVATE char *bufstack[IDEPTH] = 0;
-PRIVATE bufstptr = 0;
-
-PRIVATE char *
-pushbuf()
-{
-	if (bufstptr >= IDEPTH)
-		fatal("ran out of input buffers");
-	if (bufstack[bufstptr] == 0) {
-		bufstack[bufstptr] = Malloc(BUFSIZ + 4);
-	}
-	return bufstack[bufstptr++];
-}
-
-PRIVATE
-popbuf()
-{
-	bufstptr--;
-	ASSERT(bufstptr >= 0);
-}
-#endif READ_IN_ONE
-#endif NOPP
-
-#ifndef NOPP
-/*	Input buffer administration: push_bh() and pop_bh()
-*/
-PRIVATE struct buffer_header *
-push_bh()
-{
-	if (head) {
-		if (head >= &instack[IDEPTH - 1])
-			fatal("too many nested input texts");
-		head->bh_ipp = ipp;
-		head->bh_lineno = LineNumber;
-		head++;
-	}
-	else
-		head = &instack[0];
-
-	return head;
-}
-#endif NOPP
-
-#ifndef NOPP
-/*	pop_bh() uncovers the previous inputbuffer on the stack
-	of headers.  0 is returned if there are no more
-	inputbuffers on the stack, 1 is returned in the other case.
-*/
-PRIVATE int
-pop_bh()
-{
-	File *pfp = head->bh_fp;
-
-	if (NoUnstack) {
-		lexerror("unexpected EOF");
-	}
-
-	if (head <= &instack[0])	{	/* no more entries	*/
-		head = (struct buffer_header *) 0;
-		return 0;
-	}
-
-	ipp = (--head)->bh_ipp; /* restore the previous input pointer	*/
-
-	if (pfp != 0)	{		/* unstack a file	*/
-#ifndef READ_IN_ONE
-		closefile(pfp);
-		popbuf();		/* free last buffer	*/
-#endif READ_IN_ONE
-		LineNumber = head->bh_lineno;
-		FileName = head->bh_name;
-		*WorkingDir = head->bh_wdir;
-	}
-
-#ifndef READ_IN_ONE
-	FilDes = head->bh_fp;
-#endif READ_IN_ONE
-
-	return 1;
-}
-#endif NOPP
-
-#ifndef READ_IN_ONE
-/*	low level IO routines: openfile(), readblock() and closefile()
-*/
-
-PRIVATE File *
-openfile(filename)
-	char *filename;
-{
-	File *fp;
-
-	if (filename == 0)
-		return STDIN;
-	if (sys_open(filename, OP_READ, &fp) == 0)
-		return (File *)0;
-	return fp;
-}
-
-PRIVATE
-closefile(fp)
-	File *fp;
-{
-	if (fp != STDIN)
-		sys_close(fp);
-}
-
-PRIVATE int
-readblock(fp, buf)
-	File *fp;
-	char buf[];
-{
-	int n;
-
-	if (sys_read(fp, &buf[1], BUFSIZ, &n) == 0)
-		fatal("(readblock) bad read");
-	buf[0] = buf[n + 1] = '\0';
-	return n;
-}
-#endif READ_IN_ONE
-
-/*	Interface routines : InsertFile(), InsertText() and loadbuf()
-*/
-
-EXPORT int
-InsertFile(filnam, table)
-	char *filnam;
-	char *table[];
-{
-	char *mk_filename(), *newfn;
-	char *strcpy();
-	File *openfile();
-
-#ifdef READ_IN_ONE
-	char *readfile(), *text;
-	long size;
-#else READ_IN_ONE
-	File *fp = 0;
-#endif READ_IN_ONE
-
-#ifdef READ_IN_ONE
-	if (!filnam)
-		return 0;
-#endif READ_IN_ONE
-
-#ifndef NOPP
-	if (table == 0 || filnam[0] == '/') {	/* don't look in the table! */
-#endif NOPP
-#ifdef READ_IN_ONE
-		text = readfile(filnam, &size);
-#else READ_IN_ONE
-		fp = openfile(filnam);
-		if (filnam == 0)
-			filnam = "standard input";
-#endif READ_IN_ONE
-#ifndef NOPP
-	}
-	else {
-		ASSERT(filnam != 0);
-		while (*table) {	/* look in the directory table	*/
-			newfn = mk_filename(*table++, filnam);
-#ifdef READ_IN_ONE
-			if (text = readfile(newfn, &size))
-#else READ_IN_ONE
-			if ((fp = openfile(newfn)) != 0)
-#endif READ_IN_ONE
-			{
-				/* free filnam ??? */
-				filnam = Salloc(newfn, strlen(newfn) + 1);
-				break;
-			}
-		}
-	}
-#endif NOPP
-
-#ifdef READ_IN_ONE
-	if (text)
-#else READ_IN_ONE
-	if (fp != 0)
-#endif READ_IN_ONE
-#ifndef NOPP
-	{
-		struct buffer_header *push_bh();
-		register struct buffer_header *bh = push_bh();
-
-		setwdir(WorkingDir, filnam);
-		bh->bh_lineno = LineNumber = 0;
-		bh->bh_name = FileName = filnam;
-		bh->bh_wdir = *WorkingDir;
-#ifdef READ_IN_ONE
-		bh->bh_size = size;
-		bh->bh_fp = STDIN;		/* this is a file */
-		ipp = bh->bh_text = text;
-#else READ_IN_ONE
-		bh->bh_size = readblock(fp, ipp = bh->bh_text = pushbuf()) + 1;
-		FilDes = bh->bh_fp = fp;
-#endif READ_IN_ONE
-		bh->bh_text[0] = '\n';	/* wake up pp if '#' comes first */
-		return 1;
-	}
-#else NOPP
-	{
-		LineNumber = 0;
-		FileName = filnam;
-#ifdef READ_IN_ONE
-		isize = size;
-		ipp = text;
-#else READ_IN_ONE
-		isize = readblock(FilDes = fp, ipp = &ibuf[0]) + 1;
-#endif READ_IN_ONE
-		ibuf[0] = '\n';
-		return 1;
-	}
-#endif NOPP
-	return 0;
-}
-
-#ifndef NOPP
-EXPORT
-InsertText(text, length)
-	char *text;
-{
-	struct buffer_header *push_bh();
-	register struct buffer_header *bh = push_bh();
-
-	bh->bh_name = FileName;
-	bh->bh_lineno = LineNumber;
-	bh->bh_size = (long) length;
-	bh->bh_text = text;
-	bh->bh_wdir = *WorkingDir;
-	bh->bh_fp = 0;	/* this is not a file !	*/
-	ipp = text + 1;
-#ifndef READ_IN_ONE
-	FilDes = 0;
-#endif READ_IN_ONE
-}
-#endif NOPP
-
-/*	loadbuf() is called if LoadChar meets a '\0' character
-	which may be the end-of-buffer mark of the current input
-	buffer.  The '\0' could be genuine although not likely.
-	Note: this routine is exported due to its occurence in the definition
-	of LoadChar [input.h], that is defined as a macro.
-*/
-EXPORT int
-loadbuf()
-{
-#ifndef NOPP
-	if (!head) /* stack exhausted, EOF on sourcefile	*/
-		return EOI;
-#endif NOPP
-	
-#ifndef NOPP
-	if (ipp < &(head->bh_text[head->bh_size]))
-#else NOPP
-	if (ipp < &ibuf[isize])
-#endif NOPP
-		return '\0'; /* a genuine '\0' character has been seen	*/
-
-#ifndef READ_IN_ONE
-#ifndef NOPP
-	if (	FilDes != 0
-	&&	(head->bh_size = readblock(FilDes, head->bh_text)) > 0
-	)
-		return ipp = &(head->bh_text[1]), *ipp++;
-#else NOPP
-	if (FilDes != 0 && (isize = readblock(FilDes, &ibuf[0])) > 0)
-		return ipp = &ibuf[1], *ipp++;
-#endif NOPP
-#endif READ_IN_ONE
-
-#ifdef NOPP
-	if (NoUnstack)
-		lexerror("unexpected EOF");
-#ifndef READ_IN_ONE
-	closefile(FilDes);
-#endif READ_IN_ONE
-#endif NOPP
-
-#ifndef NOPP
-	if (pop_bh())
-		return *ipp ? *ipp++ : loadbuf();
-#endif NOPP
-	ipp = &"\0\0"[1];
-	return EOI;
-}
-
-/*	Some miscellaneous routines : setwdir() and mk_filename()
-*/
-
-#ifndef NOPP
-/*	setwdir() updates *wdir according to the old working
-	directory (*wdir) and the filename fn, which may contain
-	some path name.  The algorithm used here is:
-	setwdir(DIR, FILE):
-		if (FILE == "/***")
-			*DIR = "/"
-		else
-		if (contains(FILE, '/'))
-			*DIR = directory(FILE)
-		else
-			*DIR remains unchanged
-*/
-PRIVATE
-setwdir(wdir, fn)
-	char *fn, **wdir;
+char *
+getwdir(fn)
+	char *fn;
 {
 	register char *p;
 	char *strrindex();
@@ -433,32 +24,31 @@ setwdir(wdir, fn)
 	}
 
 	if (fn[0] == '\0' || (fn[0] == '/' && p == &fn[0])) /* absolute path */
-		*wdir = "/";
+		return "";
 	else
 	if (p) {
 		*p = '\0';
-		*wdir = Salloc(fn, p - &fn[0] + 1);
+		fn = Salloc(fn, p - &fn[0] + 1);
 		*p = '/';
+		return fn;
 	}
+	else return ".";
 }
 #endif NOPP
 
-#ifndef NOPP
-/*	mk_filename() concatenates a dir and filename.
-*/
-GSTATIC char path[PATHLENGTH];
+int	NoUnstack;
 
-PRIVATE char *
-mk_filename(dir, file)
-	register char *dir, *file;
+AtEoIT()
 {
-	register char *dst = &path[0];
+#ifndef NOPP
+	if (NoUnstack) lexerror("unexpected EOF");
+	DoUnstack();
+#endif NOPP
+	return 0;
+}
 
-	if (!(dir[0] == '.' && dir[1] == '\0')) {
-		while (*dst++ = *dir++);
-		*(dst - 1) = '/';
-	}
-	while (*dst++ = *file++);
-	return &path[0];
+AtEoIF()
+{
+	if (NoUnstack) lexerror("unexpected EOF");
+	return 0;
 }
-#endif NOPP

+ 1 - 11
lang/cem/cemcom/input.h

@@ -1,13 +1,3 @@
 /* $Header$ */
-/* INPUT PRIMITIVES */
 
-#define	LoadChar(dest)	((dest = *ipp++) || (dest = loadbuf()))
-#define	PushBack()	(ipp--)
-				
-/*	EOF may be defined as -1 in most programs but the character -1 may
-	be expanded to the int -1 which causes troubles at the indexing in
-	the class or boolean arrays.
-*/
-#define	EOI	(0200)
-			
-extern char *ipp;
+#include <inp_pkg.spec>

+ 3 - 2
lang/cem/cemcom/macro.str

@@ -9,7 +9,7 @@
 */
 #define NOFLAG		0		/* no special flags	*/
 #define	FUNC		01		/* function attached    */
-#define	PREDEF		02		/* predefined macro	*/
+#define NOREPLACE	02		/* don't replace	*/
 
 #define	FORMALP 0200	/* mask for creating macro formal parameter	*/
 
@@ -21,8 +21,9 @@
 struct macro	{
 	struct macro *next;
 	char *	mc_text;	/* the replacement text		*/
-	int	mc_nps;	/* number of formal parameters	*/
+	int	mc_nps;		/* number of formal parameters	*/
 	int	mc_length;	/* length of replacement text	*/
+	int	mc_count;	/* # of "concurrent" invocations*/
 	char	mc_flag;	/* marking this macro		*/
 };
 

+ 12 - 9
lang/cem/cemcom/main.c

@@ -34,7 +34,7 @@ char *inctable[MAXINCL] = {		/* list for includes	*/
 	0
 };
 
-char **WorkingDir = &inctable[0];
+extern char *getwdir();
 #endif NOPP
 
 struct sp_id special_ids[] =	{
@@ -90,19 +90,17 @@ main(argc, argv)
 #endif NOPP
 
 	/*	Note: source file "-" indicates that the source is supplied
-		as standard input.  This is only allowed if READ_IN_ONE is
+		as standard input.  This is only allowed if INP_READ_IN_ONE is
 		not defined!
 	*/
-#ifdef READ_IN_ONE
+#ifdef INP_READ_IN_ONE
 	while (argc > 1 && *argv[1] == '-')
-#else READ_IN_ONE
+#else INP_READ_IN_ONE
 	while (argc > 1 && *argv[1] == '-' && argv[1][1] != '\0')
-#endif READ_IN_ONE
+#endif INP_READ_IN_ONE
 	{
 		char *par = &argv[1][1];
 
-		if (*par == '-')
-			par++;
 		do_option(par);
 		argc--, argv++;
 	}
@@ -139,6 +137,7 @@ compile(argc, argv)
 #ifdef USE_TMP
 	char tmpf[256];
 #endif
+	char *result;
 
 #ifndef NOPP
 	int pp_only = options['E'] || options['P'];
@@ -172,11 +171,15 @@ compile(argc, argv)
 
 	if (destination && strcmp(destination, "-") == 0)
 		destination = 0;
-	if (!InsertFile(source, (char **) 0)) /* read the source file	*/
+	if (!InsertFile(source, (char **) 0, &result)) /* read the source file	*/
 		fatal("%s: no source file %s\n", prog_name, 
 			source ? source : "stdin");
 	init();
-	/* FileName = source; /* needed ???	*/
+	FileName = source;
+	LineNumber = 0;
+#ifndef NOPP
+	WorkingDir = getwdir(source);
+#endif NOPP
 	PushLex();
 
 #ifndef NOPP

+ 9 - 1
lang/cem/cemcom/options.c

@@ -34,7 +34,10 @@ do_option(text)
 	switch(*text++)	{
 
 	default:
-		options[text[-1]] = 1;	/* flags, debug options etc.	*/
+		fatal("illegal option: %c", *--text);
+
+	case '-':
+		options[*text] = 1;	/* flags, debug options etc.	*/
 		break;
 
 	case 'C' :	/* E option + comment output		*/
@@ -105,6 +108,7 @@ do_option(text)
 				new = tmp;
 			}
 		}
+		else inctable[inc_pos] = 0;
 #else NOPP
 		warning("-I option ignored");
 #endif NOPP
@@ -135,6 +139,10 @@ do_option(text)
 #endif NOPP
 		break;
 
+	case 'R':
+		options['R'] = 1;
+		break;
+
 #ifdef USE_TMP
 	case 'T' :
 		if (*text)

+ 58 - 19
lang/cem/cemcom/replace.c

@@ -21,9 +21,11 @@
 char *strcpy(), *strcat();
 char *long2str();
 
+PRIVATE struct macro	*ReplaceList;	/* list of currently active macros */
+
 EXPORT int
 replace(idef)
-	struct idf *idef;
+	register struct idf *idef;
 {
 	/*	replace() is called by the lexical analyzer to perform
 		macro replacement.  "idef" is the description of the
@@ -34,14 +36,18 @@ replace(idef)
 		replace() returns 1 if the replacement succeeded and 0 if
 		some error has occurred.
 	*/
+	register struct macro *mac = idef->id_macro;
 	register char c;
-	register char flags = idef->id_macro->mc_flag;
 	char **actpars, **getactuals();
 	char *reptext, *macro2buffer();
 	int size;
 
-	if (idef->id_macro->mc_nps != -1) {	/* with parameter list	*/
-		if (flags & FUNC) {
+	if (mac->mc_flag & NOREPLACE) {
+		lexwarning("macro %s is recursive", idef->id_text);
+		return 0;
+	}
+	if (mac->mc_nps != -1) {	/* with parameter list	*/
+		if (mac->mc_flag & FUNC) {
 					/* must be "defined".
 					   Unfortunately, the next assertion
 					   will not compile ...
@@ -50,6 +56,12 @@ replace(idef)
 			if (! AccDefined)
 				return 0;
 		}
+		if (++mac->mc_count > 100) {
+			/* 100 must be some number in Parameters */
+			lexwarning("macro %s is assumed recursive",
+				    idef->id_text);
+			return 0;
+		}
 		LoadChar(c);
 		c = skipspaces(c);
 		if (c != '(') {		/* no replacement if no ()	*/
@@ -59,23 +71,27 @@ replace(idef)
 			return 0;
 		}
 		actpars = getactuals(idef);	/* get act.param. list	*/
-		if (flags & FUNC) {
+		if (mac->mc_flag & FUNC) {
 			struct idf *param = str2idf(*actpars);
 
 			if (param->id_macro) 
-				reptext = "\0001";
+				reptext = "1";
 			else
-				reptext = "\0000";
-			InsertText(reptext, 2);
+				reptext = "0";
+			InsertText(reptext, 1);
+			mac->next = ReplaceList;
+			ReplaceList = mac;
 			return 1;
 		}
 	}
-	if ((flags & PREDEF) && (UnknownIdIsZero == 0)) /* don't replace */
-		return 0;
-	if (flags & FUNC) 	/* this macro leads to special action	*/
+	if (mac->mc_flag & FUNC) /* this macro leads to special action	*/
 		macro_func(idef);
+	if (mac->mc_nps <= 0)
+		mac->mc_flag |= NOREPLACE;
 	reptext = macro2buffer(idef, actpars, &size); /* create input buffer */
 	InsertText(reptext, size);
+	mac->next = ReplaceList;
+	ReplaceList = mac;
 	return 1;
 }
 
@@ -83,24 +99,26 @@ GSTATIC char FilNamBuf[PATHLENGTH];
 
 PRIVATE
 macro_func(idef)
-	struct idf *idef;
+	register struct idf *idef;
 {
 	/*	macro_func() performs the special actions needed with some
 		macros.  These macros are __FILE__ and __LINE__ which
 		replacement texts must be evaluated at the time they are
 		used.
 	*/
+	register struct macro *mac = idef->id_macro;
+
 	switch (idef->id_text[2]) { /* This switch is very blunt... */
 	case 'F' :			/* __FILE__	*/
 		FilNamBuf[0] = '"';
 		strcpy(&FilNamBuf[1], FileName);
 		strcat(FilNamBuf, "\"");
-		idef->id_macro->mc_text = FilNamBuf;
-		idef->id_macro->mc_length = strlen(FilNamBuf);
+		mac->mc_text = FilNamBuf;
+		mac->mc_length = strlen(FilNamBuf);
 		break;
 	case 'L' :			/* __LINE__	*/
-		idef->id_macro->mc_text = long2str((long)LineNumber, 10);
-		idef->id_macro->mc_length = 1;
+		mac->mc_text = long2str((long)LineNumber, 10);
+		mac->mc_length = 1;
 		break;
 	default :
 		crash("(macro_func)");
@@ -125,10 +143,9 @@ macro2buffer(idef, actpars, siztext)
 	*/
 	register int size = 8;
 	register char *text = Malloc(size);
-	register pos = 0;
+	register int pos = 0;
 	register char *ptr = idef->id_macro->mc_text;
 
-	text[pos++] = '\0';			/* allow pushback	*/
 	while (*ptr) {
 		if (*ptr & FORMALP) {	/* non-asc formal param. mark	*/
 			register int n = *ptr++ & 0177;
@@ -138,7 +155,7 @@ macro2buffer(idef, actpars, siztext)
 			/*	copy the text of the actual parameter
 				into the replacement text
 			*/
-			for (p = actpars[n - 1]; *p; p++) {
+			for (p = actpars[n - 1]; p && *p; p++) {
 				text[pos++] = *p;
 				if (pos == size)
 					text = Srealloc(text, size += RSTRSIZE);
@@ -154,4 +171,26 @@ macro2buffer(idef, actpars, siztext)
 	*siztext = pos;
 	return text;
 }
+
+EXPORT
+DoUnstack()
+{
+	Unstacked++;
+}
+
+EXPORT
+EnableMacros()
+{
+	register struct macro *p = ReplaceList;
+
+	ASSERT(Unstacked > 0);
+	while (Unstacked > 0) {
+		ASSERT(p != 0);
+		p->mc_flag &= ~NOREPLACE;
+		p->mc_count = 0;
+		p = p->next;
+		Unstacked--;
+	}
+	ReplaceList = p;
+}
 #endif NOPP