Ver código fonte

Initial revision

ceriel 35 anos atrás
pai
commit
3ca38fbe2e
100 arquivos alterados com 21759 adições e 0 exclusões
  1. 101 0
      lang/cem/cemcom.ansi/.distr
  2. 145 0
      lang/cem/cemcom.ansi/BigPars
  3. 777 0
      lang/cem/cemcom.ansi/LLlex.c
  4. 69 0
      lang/cem/cemcom.ansi/LLlex.h
  5. 59 0
      lang/cem/cemcom.ansi/LLmessage.c
  6. 145 0
      lang/cem/cemcom.ansi/LintPars
  7. 1091 0
      lang/cem/cemcom.ansi/Makefile
  8. 718 0
      lang/cem/cemcom.ansi/Makefile.erik
  9. 67 0
      lang/cem/cemcom.ansi/Resolve
  10. 145 0
      lang/cem/cemcom.ansi/SmallPars
  11. 8 0
      lang/cem/cemcom.ansi/Version.c
  12. 35 0
      lang/cem/cemcom.ansi/align.h
  13. 575 0
      lang/cem/cemcom.ansi/arith.c
  14. 28 0
      lang/cem/cemcom.ansi/arith.h
  15. 16 0
      lang/cem/cemcom.ansi/asm.c
  16. 24 0
      lang/cem/cemcom.ansi/assert.h
  17. 10 0
      lang/cem/cemcom.ansi/atw.h
  18. 168 0
      lang/cem/cemcom.ansi/blocks.c
  19. 230 0
      lang/cem/cemcom.ansi/cem.1
  20. 764 0
      lang/cem/cemcom.ansi/cem.c
  21. 79 0
      lang/cem/cemcom.ansi/cemcom.1
  22. 540 0
      lang/cem/cemcom.ansi/ch7.c
  23. 350 0
      lang/cem/cemcom.ansi/ch7bin.c
  24. 166 0
      lang/cem/cemcom.ansi/ch7mon.c
  25. 74 0
      lang/cem/cemcom.ansi/char.tab
  26. 44 0
      lang/cem/cemcom.ansi/class.h
  27. 657 0
      lang/cem/cemcom.ansi/code.c
  28. 22 0
      lang/cem/cemcom.ansi/code.str
  29. 158 0
      lang/cem/cemcom.ansi/conversion.c
  30. 237 0
      lang/cem/cemcom.ansi/cstoper.c
  31. 37 0
      lang/cem/cemcom.ansi/dataflow.c
  32. 696 0
      lang/cem/cemcom.ansi/declar.g
  33. 44 0
      lang/cem/cemcom.ansi/declar.str
  34. 126 0
      lang/cem/cemcom.ansi/declarator.c
  35. 197 0
      lang/cem/cemcom.ansi/decspecs.c
  36. 20 0
      lang/cem/cemcom.ansi/decspecs.str
  37. 40 0
      lang/cem/cemcom.ansi/def.str
  38. 688 0
      lang/cem/cemcom.ansi/domacro.c
  39. 512 0
      lang/cem/cemcom.ansi/dumpidf.c
  40. 355 0
      lang/cem/cemcom.ansi/error.c
  41. 21 0
      lang/cem/cemcom.ansi/estack.str
  42. 994 0
      lang/cem/cemcom.ansi/eval.c
  43. 536 0
      lang/cem/cemcom.ansi/expr.c
  44. 116 0
      lang/cem/cemcom.ansi/expr.str
  45. 375 0
      lang/cem/cemcom.ansi/expression.g
  46. 181 0
      lang/cem/cemcom.ansi/field.c
  47. 16 0
      lang/cem/cemcom.ansi/field.str
  48. 20 0
      lang/cem/cemcom.ansi/file_info.h
  49. 736 0
      lang/cem/cemcom.ansi/idf.c
  50. 52 0
      lang/cem/cemcom.ansi/idf.str
  51. 95 0
      lang/cem/cemcom.ansi/init.c
  52. 64 0
      lang/cem/cemcom.ansi/input.c
  53. 15 0
      lang/cem/cemcom.ansi/input.h
  54. 8 0
      lang/cem/cemcom.ansi/interface.h
  55. 700 0
      lang/cem/cemcom.ansi/ival.g
  56. 28 0
      lang/cem/cemcom.ansi/l_brace.str
  57. 21 0
      lang/cem/cemcom.ansi/l_class.h
  58. 211 0
      lang/cem/cemcom.ansi/l_comment.c
  59. 15 0
      lang/cem/cemcom.ansi/l_comment.h
  60. 74 0
      lang/cem/cemcom.ansi/l_dummy.c
  61. 107 0
      lang/cem/cemcom.ansi/l_ev_ord.c
  62. 442 0
      lang/cem/cemcom.ansi/l_lint.c
  63. 18 0
      lang/cem/cemcom.ansi/l_lint.h
  64. 395 0
      lang/cem/cemcom.ansi/l_misc.c
  65. 546 0
      lang/cem/cemcom.ansi/l_outdef.c
  66. 47 0
      lang/cem/cemcom.ansi/l_outdef.str
  67. 74 0
      lang/cem/cemcom.ansi/l_state.str
  68. 1131 0
      lang/cem/cemcom.ansi/l_states.c
  69. 74 0
      lang/cem/cemcom.ansi/label.c
  70. 28 0
      lang/cem/cemcom.ansi/label.h
  71. 23 0
      lang/cem/cemcom.ansi/level.h
  72. 60 0
      lang/cem/cemcom.ansi/macro.str
  73. 406 0
      lang/cem/cemcom.ansi/main.c
  74. 8 0
      lang/cem/cemcom.ansi/make.allocd
  75. 35 0
      lang/cem/cemcom.ansi/make.hfiles
  76. 3 0
      lang/cem/cemcom.ansi/make.next
  77. 38 0
      lang/cem/cemcom.ansi/make.tokcase
  78. 11 0
      lang/cem/cemcom.ansi/make.tokfile
  79. 246 0
      lang/cem/cemcom.ansi/mcomm.c
  80. 8 0
      lang/cem/cemcom.ansi/mes.h
  81. 9 0
      lang/cem/cemcom.ansi/nmclash.c
  82. 28 0
      lang/cem/cemcom.ansi/options
  83. 356 0
      lang/cem/cemcom.ansi/options.c
  84. 74 0
      lang/cem/cemcom.ansi/pragma.c
  85. 222 0
      lang/cem/cemcom.ansi/program.g
  86. 442 0
      lang/cem/cemcom.ansi/proto.c
  87. 17 0
      lang/cem/cemcom.ansi/proto.str
  88. 677 0
      lang/cem/cemcom.ansi/replace.c
  89. 39 0
      lang/cem/cemcom.ansi/replace.str
  90. 237 0
      lang/cem/cemcom.ansi/scan.c
  91. 33 0
      lang/cem/cemcom.ansi/sizes.h
  92. 69 0
      lang/cem/cemcom.ansi/skip.c
  93. 18 0
      lang/cem/cemcom.ansi/specials.h
  94. 279 0
      lang/cem/cemcom.ansi/stack.c
  95. 34 0
      lang/cem/cemcom.ansi/stack.str
  96. 472 0
      lang/cem/cemcom.ansi/statement.g
  97. 15 0
      lang/cem/cemcom.ansi/stb.c
  98. 14 0
      lang/cem/cemcom.ansi/stmt.str
  99. 499 0
      lang/cem/cemcom.ansi/struct.c
  100. 30 0
      lang/cem/cemcom.ansi/struct.str

+ 101 - 0
lang/cem/cemcom.ansi/.distr

@@ -0,0 +1,101 @@
+Version.c
+Makefile
+Resolve
+nmclash.c
+LLlex.c
+LLlex.h
+LLmessage.c
+SmallPars
+BigPars
+LintPars
+align.h
+arith.c
+arith.h
+asm.c
+assert.h
+atw.h
+blocks.c
+cem.1
+cem.c
+cemcom.1
+ch7.c
+ch7bin.c
+ch7mon.c
+char.tab
+class.h
+code.c
+code.str
+conversion.c
+cstoper.c
+dataflow.c
+declar.g
+declar.str
+declarator.c
+decspecs.c
+decspecs.str
+def.str
+domacro.c
+dumpidf.c
+error.c
+estack.str
+eval.c
+expr.c
+expr.str
+expression.g
+field.c
+field.str
+file_info.h
+idf.c
+idf.str
+init.c
+input.c
+input.h
+interface.h
+ival.g
+l_brace.str
+l_class.h
+l_comment.c
+l_dummy.c
+l_ev_ord.c
+l_lint.c
+l_lint.h
+l_misc.c
+l_outdef.c
+l_outdef.str
+l_state.str
+l_states.c
+label.c
+label.h
+level.h
+macro.str
+main.c
+make.allocd
+make.hfiles
+make.next
+make.tokcase
+make.tokfile
+mcomm.c
+mes.h
+options
+options.c
+program.g
+replace.c
+scan.c
+sizes.h
+skip.c
+specials.h
+stack.c
+stack.str
+statement.g
+stb.c
+stmt.str
+struct.c
+struct.str
+switch.c
+switch.str
+tokenname.c
+tokenname.h
+type.c
+type.str
+util.str
+util.c

+ 145 - 0
lang/cem/cemcom.ansi/BigPars

@@ -0,0 +1,145 @@
+!File: lint.h
+#undef	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	16	/* 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
+#define DATAFLOW	1	/* produce some compile-time xref	*/
+
+
+!File: debug.h
+#undef DEBUG		1	/* perform various self-tests		*/
+
+
+!File: use_tmp.h
+#define PREPEND_SCOPES	1	/* collect exa, exp, ina and inp commands
+					and if USE_TMP is defined let them
+					precede the rest of the generated
+					compact code	*/
+#define USE_TMP		1	/* use C_insertpart, C_endpart mechanism
+					to generate EM-code in the order needed
+					for the code-generators. If not defined,
+					the old-style peephole optimizer is
+					needed.	*/
+
+
+!File: parbufsize.h
+#define PARBUFSIZE	1024
+
+
+!File: textsize.h
+#define ITEXTSIZE	32	/* 1st piece of memory for repl. text	*/
+#define RTEXTSIZE	16	/* 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 */
+
+

+ 777 - 0
lang/cem/cemcom.ansi/LLlex.c

@@ -0,0 +1,777 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $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"
+#include	"numsize.h"
+#include	"debug.h"
+#include	"strsize.h"
+#include	"nopp.h"
+#include	"input.h"
+#include	"arith.h"
+#include	"def.h"
+#include	"macro.h"
+#include	"idf.h"
+#include	"LLlex.h"
+#include	"Lpars.h"
+#include	"class.h"
+#include	"assert.h"
+#include	"sizes.h"
+
+/* Data about the token yielded */
+struct token dot, ahead, aside;
+
+#ifndef NOPP
+int ReplaceMacros = 1;		/* replacing macros			*/
+int AccDefined = 0;		/* accept "defined(...)"		*/
+int UnknownIdIsZero = 0;	/* interpret unknown id as integer 0	*/
+int Unstacked = 0;		/* an unstack is done 			*/
+#endif
+int AccFileSpecifier = 0;	/* return filespecifier <...>		*/
+int EoiForNewline = 0;		/* return EOI upon encountering newline	*/
+int File_Inserted = 0;		/* a file has just been inserted	*/
+int LexSave = 0;		/* last character read by GetChar	*/
+#define MAX_LL_DEPTH	2
+
+static struct token LexStack[MAX_LL_DEPTH];
+static LexSP = 0;
+
+/*	In PushLex() the actions are taken in order to initialise or
+	re-initialise the lexical scanner.
+	E.g. at the invocation of a sub-parser that uses LLlex(), the
+	state of the current parser should be saved.
+*/
+PushLex()
+{
+	ASSERT(LexSP < 2);
+	ASSERT(ASIDE == 0);	/* ASIDE = 0;	*/
+	GetToken(&ahead);
+	LexStack[LexSP++] = dot;
+}
+
+PopLex()
+{
+	ASSERT(LexSP > 0);
+	dot = LexStack[--LexSP];
+}
+
+int
+LLlex()
+{
+	/*	LLlex() plays the role of Lexical Analyzer for the C parser.
+		The look-ahead and putting aside of tokens are taken into
+		account.
+	*/
+	if (ASIDE) {	/* a token is put aside		*/
+		dot = aside;
+		ASIDE = 0;
+	}
+	else {		/* read ahead and return the old one	*/
+#ifdef	LINT
+		lint_comment_ahead();
+#endif	LINT
+		dot = ahead;
+		/*	the following test is performed due to the dual
+			task of LLlex(): it is also called for parsing the
+			restricted constant expression following a #if or
+			#elif.  The newline character causes EOF to be
+			returned in this case to stop the LLgen parsing task.
+		*/
+		if (DOT != EOI)
+			GetToken(&ahead);
+		else
+			DOT = EOF;
+	}
+	return DOT;
+}
+
+
+char	*string_token();
+arith	char_constant();
+
+
+int
+GetToken(ptok)
+	register struct token *ptok;
+{
+	/*	LexToken() is the actual token recognizer. It calls the
+		control line interpreter if it encounters a "\n{w}*#"
+		combination. Macro replacement is also performed if it is
+		needed.
+	*/
+	char buf[(IDFSIZE > NUMSIZE ? IDFSIZE : NUMSIZE) + 1];
+	register int ch, nch;
+
+	if (File_Inserted) {
+		File_Inserted = 0;
+		goto firstline;
+	}
+
+again:	/* rescan the input after an error or replacement	*/
+	ch = GetChar();
+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);
+	/* keep track of the place of the token in the file	*/
+	ptok->tk_file = FileName;
+	ptok->tk_line = LineNumber;
+
+	switch (class(ch)) {	/* detect character class	*/
+	case STNL:		/* newline, vertical space or formfeed	*/
+firstline:
+		LineNumber++;			/* also at vs and ff	*/
+		ptok->tk_file = FileName;
+		ptok->tk_line = LineNumber;
+		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 ((ch = GetChar()), (ch == '#' || class(ch) == STSKIP)) {
+			/* blanks are allowed before hashes */
+			if (ch == '#') {
+				/* a control line follows */
+				domacro();
+				if (File_Inserted) {
+					File_Inserted = 0;
+					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 `#'.
+			*/
+		goto go_on;
+	case STSKIP:		/* just skip the skip characters	*/
+		goto again;
+	case STGARB:		/* garbage character			*/
+		if (040 < ch && ch < 0177)
+			lexerror("garbage char %c", ch);
+		else
+			lexerror("garbage char \\%03o", ch);
+		goto again;
+	case STSIMP:	/* a simple character, no part of compound token*/
+		if (ch == '/') { /* probably the start of comment	*/
+			ch = GetChar();
+			if (ch == '*') { /* start of comment */
+				skipcomment();
+				goto again;
+			}
+			else {
+				UnGetChar();
+				ch = '/';	/* restore ch	*/
+			}
+		}
+		return ptok->tk_symb = ch;
+	case STCOMP:	/* maybe the start of a compound token		*/
+		nch = GetChar();		/* character lookahead	*/
+		switch (ch) {
+		case '!':
+			if (nch == '=')
+				return ptok->tk_symb = NOTEQUAL;
+			UnGetChar();
+			return ptok->tk_symb = ch;
+		case '&':
+			if (nch == '&')
+				return ptok->tk_symb = AND;
+			UnGetChar();
+			return ptok->tk_symb = ch;
+		case '+':
+			if (nch == '+')
+				return ptok->tk_symb = PLUSPLUS;
+			UnGetChar();
+			return ptok->tk_symb = ch;
+		case '-':
+			if (nch == '-')
+				return ptok->tk_symb = MINMIN;
+			if (nch == '>')
+				return ptok->tk_symb = ARROW;
+			UnGetChar();
+			return ptok->tk_symb = ch;
+		case '<':
+			if (AccFileSpecifier) {
+				UnGetChar();	/* pushback nch */
+				ptok->tk_bts = string_token("file specifier",
+							'>', &(ptok->tk_len));
+				return ptok->tk_symb = FILESPECIFIER;
+			}
+			if (nch == '<')
+				return ptok->tk_symb = LEFT;
+			if (nch == '=')
+				return ptok->tk_symb = LESSEQ;
+			UnGetChar();
+			return ptok->tk_symb = ch;
+		case '=':
+			if (nch == '=')
+				return ptok->tk_symb = EQUAL;
+
+ 			/*	The following piece of code tries to recognise
+ 				old-fashioned assignment operators `=op'
+				Note however, that these are removed from the
+				ANSI C standard.
+			*/
+ 			switch (nch) {
+ 			case '+':
+ 				ptok->tk_symb = PLUSAB;
+				goto warn;
+ 			case '-':
+ 				ptok->tk_symb = MINAB;
+				goto warn;
+ 			case '*':
+ 				ptok->tk_symb = TIMESAB;
+				goto warn;
+ 			case '/':
+ 				ptok->tk_symb = DIVAB;
+				goto warn;
+ 			case '%':
+ 				ptok->tk_symb = MODAB;
+				goto warn;
+ 			case '>':
+ 			case '<':
+ 				GetChar(ch);
+ 				if (ch != nch) {
+ 					UnGetChar();
+ 					lexerror("illegal combination '=%c'",
+ 						nch);
+ 				}
+ 				ptok->tk_symb = nch == '<' ? LEFTAB : RIGHTAB;
+				goto warn;
+ 			case '&':
+ 				ptok->tk_symb = ANDAB;
+				goto warn;
+ 			case '^':
+ 				ptok->tk_symb = XORAB;
+				goto warn;
+ 			case '|':
+ 				ptok->tk_symb = ORAB;
+			warn:
+				warning("Old-fashioned assignment operator");
+				return ptok->tk_symb;
+ 			}
+			UnGetChar();
+			return ptok->tk_symb = ch;
+		case '>':
+			if (nch == '=')
+				return ptok->tk_symb = GREATEREQ;
+			if (nch == '>')
+				return ptok->tk_symb = RIGHT;
+			UnGetChar();
+			return ptok->tk_symb = ch;
+		case '|':
+			if (nch == '|')
+				return ptok->tk_symb = OR;
+			UnGetChar();
+			return ptok->tk_symb = ch;
+		}
+	case STCHAR:				/* character constant	*/
+		ptok->tk_ival = char_constant("character");
+		ptok->tk_fund = INT;
+		return ptok->tk_symb = INTEGER;
+	case STSTR:					/* string	*/
+		ptok->tk_bts = string_token("string", '"', &(ptok->tk_len));
+		ptok->tk_fund = CHAR;		/* string of characters */
+		return ptok->tk_symb = STRING;
+	case STELL:		/* wide character constant/string prefix */
+		nch = GetChar();
+		if (nch == '"') {
+			ptok->tk_bts = string_token("wide character string",
+					'"', &(ptok->tk_len));
+			ptok->tk_fund = WCHAR;	/* string of wide characters */
+			return ptok->tk_symb = STRING;
+		} else if (nch == '\'') {
+			ptok->tk_ival = char_constant("wide character");
+			ptok->tk_fund = INT;
+			return ptok->tk_symb = INTEGER;
+		}
+		UnGetChar();
+	case STIDF:
+	{
+		register char *tg = &buf[0];
+		register int pos = -1;
+		register int hash;
+		register struct idf *idef;
+		extern int idfsize;		/* ??? */
+
+		hash = STARTHASH();
+		do	{			/* read the identifier	*/
+			if (++pos < idfsize) {
+				*tg++ = ch;
+				hash = ENHASH(hash, ch, pos);
+			}
+			ch = GetChar();
+		} while (in_idf(ch));
+
+		hash = STOPHASH(hash);
+		if (ch != EOI)
+			UnGetChar();
+		*tg++ = '\0';	/* mark the end of the identifier	*/
+		idef = ptok->tk_idf = idf_hashed(buf, tg - buf, hash);
+		idef->id_file = ptok->tk_file;
+		idef->id_line = ptok->tk_line;
+#ifndef NOPP
+		if (idef->id_macro && ReplaceMacros) {
+			if (idef->id_macro->mc_count > 0)
+				idef->id_macro->mc_count--;
+			else if (replace(idef))
+				goto again;
+		}
+		if (UnknownIdIsZero && idef->id_reserved != SIZEOF) {
+			ptok->tk_ival = (arith)0;
+			ptok->tk_fund = INT;
+			return ptok->tk_symb = INTEGER;
+		}
+#endif NOPP
+		ptok->tk_symb = (
+			idef->id_reserved ? idef->id_reserved
+			: idef->id_def && idef->id_def->df_sc == TYPEDEF ?
+				TYPE_IDENTIFIER
+			: IDENTIFIER
+		);
+		return IDENTIFIER;
+	}
+	case STNUM:				/* a numeric constant	*/
+	{
+		register char *np = &buf[1];
+		register int base = 10;
+		register int vch;
+		register arith val = 0;
+
+		if (ch == '.') {
+#ifndef NOFLOAT
+			/*	A very embarrasing ambiguity. We have either a
+				floating point number or field operator or
+				ELLIPSIS.
+			*/
+			ch = GetChar();
+			if (!is_dig(ch)) {	/* . or ... */
+				if (ch == '.') {
+					if ((ch = GetChar()) == '.')
+						return ptok->tk_symb = ELLIPSIS;
+					/* This is funny: we can't push the
+					   second dot back. But then again
+					   ..<ch> is already an error in C,
+					   so why bother ?
+					*/
+					UnGetChar();
+					lexerror("illegal combination '..'");
+				}
+				UnGetChar();
+				return ptok->tk_symb = '.';
+			} else
+				*np++ = '0';
+			UnGetChar();
+#else
+			if ((ch = GetChar()) == '.') {
+				if ((ch = GetChar()) == '.')
+					return ptok->tk_symb = ELLIPSIS;
+				UnGetChar();
+				lexerror("illegal combination '..'");
+			}
+			UnGetChar();
+			return ptok->tk_symb = '.';
+#endif
+		}
+		if (ch == '0') {
+			*np++ = ch;
+			ch = GetChar();
+			if (ch == 'x' || ch == 'X') {
+				base = 16;
+				ch = GetChar();
+			}
+			else
+				base = 8;
+		}
+		while (vch = val_in_base(ch, base), vch >= 0) {
+			val = val*base + vch;
+			if (np < &buf[NUMSIZE])
+				*np++ = ch;
+			ch = GetChar();
+		}
+		if (is_suf(ch)) {
+			register int suf_long = 0;
+			register int suf_unsigned = 0;
+
+			/*	The type of the integal constant is
+				based on its suffix.
+			*/
+			do {
+				switch (ch) {
+				case 'l':
+				case 'L':
+					suf_long++;
+					break;
+				case 'u':
+				case 'U':
+					suf_unsigned++;
+					break;
+				}
+				ch = GetChar();
+			} while (is_suf(ch));
+			UnGetChar();
+
+			if (suf_long > 1)
+				lexerror("only one long suffix allowed");
+			if (suf_unsigned > 1)
+				lexerror("only one unsigned suffix allowed");
+
+			ptok->tk_fund = (suf_long && suf_unsigned) ? ULONG :
+					(suf_long) ? LONG : UNSIGNED;
+			ptok->tk_ival = val;
+			return ptok->tk_symb = INTEGER;
+		}
+#ifndef NOFLOAT
+		if (base == 16 || !(ch == '.' || ch == 'e' || ch == 'E'))
+#endif NOFLOAT
+		{
+			UnGetChar();
+			ptok->tk_ival = val;
+			/*	The semantic analyser must know if the
+				integral constant is given in octal/hexa-
+				decimal form, in which case its type is
+				UNSIGNED, or in decimal form, in which case
+				its type is signed, indicated by
+				the fund INTEGER.
+			*/
+			ptok->tk_fund = 
+				(base == 10 || (base == 8 && val == (arith)0))
+					? INTEGER : UNSIGNED;
+			return ptok->tk_symb = INTEGER;
+		}
+		/* where's the test for the length of the integral ???	*/
+#ifndef NOFLOAT
+		if (ch == '.'){
+			if (np < &buf[NUMSIZE])
+				*np++ = ch;
+			ch = GetChar();
+		}
+		while (is_dig(ch)){
+			if (np < &buf[NUMSIZE])
+				*np++ = ch;
+			ch = GetChar();
+		}
+		if (ch == 'e' || ch == 'E') {
+			if (np < &buf[NUMSIZE])
+				*np++ = ch;
+			ch = GetChar();
+			if (ch == '+' || ch == '-') {
+				if (np < &buf[NUMSIZE])
+					*np++ = ch;
+				ch = GetChar();
+			}
+			if (!is_dig(ch)) {
+				lexerror("malformed floating constant");
+				if (np < &buf[NUMSIZE])
+					*np++ = ch;
+			}
+			while (is_dig(ch)) {
+				if (np < &buf[NUMSIZE])
+					*np++ = ch;
+				ch = GetChar();
+			}
+		}
+
+		/*	The type of an integral floating point
+			constant may be given by the float (f)
+			or long double (l) suffix.
+		*/
+		if (ch == 'f' || ch == 'F')
+			ptok->tk_fund = FLOAT;
+		else if (ch == 'l' || ch == 'L')
+			ptok->tk_fund = LNGDBL;
+		else {
+			ptok->tk_fund = DOUBLE;
+			UnGetChar();
+		}
+
+		*np++ = '\0';
+		buf[0] = '-';	/* good heavens...	*/
+		if (np == &buf[NUMSIZE+1]) {
+			lexerror("floating constant too long");
+			ptok->tk_fval = Salloc("0.0",(unsigned) 5) + 1;
+		}
+		else
+			ptok->tk_fval = Salloc(buf,(unsigned) (np - buf)) + 1;
+		return ptok->tk_symb = FLOATING;
+#endif NOFLOAT
+	}
+	case STEOI:			/* end of text on source file	*/
+		return ptok->tk_symb = EOI;
+	default:				/* this cannot happen	*/
+		crash("bad class for char 0%o", ch);
+	}
+	/*NOTREACHED*/
+}
+
+skipcomment()
+{
+	/*	The last character read has been the '*' of '/_*'.  The
+		characters, except NL and EOI, between '/_*' and the first
+		occurring '*_/' are not interpreted.
+		NL only affects the LineNumber.  EOI is not legal.
+
+		Important note: it is not possible to stop skipping comment
+		beyond the end-of-file of an included file.
+		EOI is returned by LoadChar only on encountering EOF of the
+		top-level file...
+	*/
+	register int c;
+
+	NoUnstack++;
+	c = GetChar();
+#ifdef	LINT
+	lint_start_comment();
+	lint_comment_char(c);
+#endif	LINT
+	do {
+		while (c != '*') {
+			if (class(c) == STNL) {
+				++LineNumber;
+			} else
+			if (c == EOI) {
+				NoUnstack--;
+#ifdef	LINT
+				lint_end_comment();
+#endif	LINT
+				return;
+			}
+			if (c == '/' && (c = GetChar()) == '*')
+				strict("extra comment delimiter found");
+			c = GetChar();
+#ifdef	LINT
+			lint_comment_char(c);
+#endif	LINT
+		} /* last Character seen was '*' */
+		c = GetChar();
+#ifdef	LINT
+		lint_comment_char(c);
+#endif	LINT
+	} while (c != '/');
+#ifdef	LINT
+	lint_end_comment();
+#endif	LINT
+	NoUnstack--;
+}
+
+arith
+char_constant(nm)
+	char *nm;
+{
+	register arith val = 0;
+	register int ch;
+	int size = 0;
+
+	ch = GetChar();
+	if (ch == '\'')
+		lexerror("%s constant too short", nm);
+	else
+	while (ch != '\'') {
+		if (ch == '\n') {
+			lexerror("newline in %s constant", nm);
+			LineNumber++;
+			break;
+		}
+		if (ch == '\\')
+			ch = quoted(GetChar());
+		if (ch >= 128) ch -= 256;
+		val = val*256 + ch;
+		size++;
+		ch = GetChar();
+	}
+	if (size > 1)
+		strict("%s constant includes more than one character", nm);
+	if (size > (int)int_size)
+		lexerror("%s constant too long", nm);
+	return val;
+}
+
+char *
+string_token(nm, stop_char, plen)
+	char *nm;
+	int *plen;
+{
+	register int ch;
+	register int str_size;
+	register char *str = Malloc((unsigned) (str_size = ISTRSIZE));
+	register int pos = 0;
+	
+	ch = GetChar();
+	while (ch != stop_char) {
+		if (ch == '\n') {
+			lexerror("newline in %s", nm);
+			LineNumber++;
+			break;
+		}
+		if (ch == EOI) {
+			lexerror("end-of-file inside %s", nm);
+			break;
+		}
+		if (ch == '\\')
+			ch = quoted(GetChar());
+		str[pos++] = ch;
+		if (pos == str_size)
+			str = Srealloc(str, (unsigned) (str_size += RSTRSIZE));
+		ch = GetChar();
+	}
+	str[pos++] = '\0'; /* for filenames etc. */
+	*plen = pos;
+	return str;
+}
+
+int
+quoted(ch)
+	register int ch;
+{	
+	/*	quoted() replaces an escaped character sequence by the
+		character meant.
+	*/
+	/* first char after backslash already in ch */
+	if (!is_oct(ch)) {		/* a quoted char */
+		switch (ch) {
+		case 'n':
+			ch = '\n';
+			break;
+		case 't':
+			ch = '\t';
+			break;
+		case 'b':
+			ch = '\b';
+			break;
+		case 'r':
+			ch = '\r';
+			break;
+		case 'f':
+			ch = '\f';
+			break;
+		case 'a':		/* alert */
+			ch = '\007';
+			break;
+		case 'v':		/* vertical tab */
+			ch = '\013';
+			break;
+		case 'x':		/* quoted hex */
+		{
+			register int hex = 0;
+			register int vch;
+
+			for (;;) {
+				ch = GetChar();
+				if (vch = val_in_base(ch, 16), vch == -1)
+					break;
+				hex = hex * 16 + vch;
+			}
+			UnGetChar();
+			ch = hex;
+		}
+		}
+	}
+	else {				/* a quoted octal */
+		register int oct = 0, cnt = 0;
+
+		do {
+			oct = oct*8 + (ch-'0');
+			ch = GetChar();
+		} while (is_oct(ch) && ++cnt < 3);
+		UnGetChar();
+		ch = oct;
+	}
+	return ch&0377;
+}
+
+
+int
+val_in_base(ch, base)
+	register int ch;
+{
+	switch (base) {
+	case 8:
+		return (is_dig(ch) && ch < '9') ? ch - '0' : -1;
+	case 10:
+	case 16:
+		return is_dig(ch) ? ch - '0'
+			: is_hex(ch) ? (ch - 'a' + 10) & 017
+			: -1;
+	default:
+		fatal("(val_in_base) illegal base value %d", base);
+		/* NOTREACHED */
+	}
+}
+
+
+int
+GetChar()
+{
+	/*	The routines GetChar and trigraph parses the trigraph
+		sequences and removes occurences of \\\n.
+	*/
+	register int ch;
+
+again:
+	LoadChar(ch);
+
+	/* possible trigraph sequence */
+	if (ch == '?')
+		ch = trigraph();
+
+	/* \\\n are removed from the input stream */
+	if (ch == '\\') {
+		LoadChar(ch);
+		if (ch == '\n') {
+			++LineNumber;
+			goto again;
+		}
+		PushBack();
+		ch = '\\';
+	}
+	return(LexSave = ch);
+}
+
+
+int
+trigraph()
+{
+	register int ch;
+
+	LoadChar(ch);
+	if (ch == '?') {
+		LoadChar(ch);
+		switch (ch) {		/* its a trigraph */
+		case '=':
+			ch =  '#';
+			return(ch);
+		case '(':
+			ch = '[';
+			return(ch);
+		case '/':
+			ch = '\\';
+			return(ch);
+		case ')':
+			ch = ']';
+			return(ch);
+		case '\'':
+			ch = '^';
+			return(ch);
+		case '<':
+			ch = '{';
+			return(ch);
+		case '!':
+			ch = '|';
+			return(ch);
+		case '>':
+			ch = '}';
+			return(ch);
+		case '-':
+			ch = '~';
+			return(ch);
+		}
+		PushBack();
+	}
+	PushBack();
+	return('?');
+}

+ 69 - 0
lang/cem/cemcom.ansi/LLlex.h

@@ -0,0 +1,69 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* D E F I N I T I O N S   F O R   T H E   L E X I C A L   A N A L Y Z E R */
+
+/*	A token from the input stream is represented by an integer,
+	called a "symbol", but it may have other information associated
+	to it.
+*/
+
+#include "nofloat.h"
+#include "file_info.h"
+#include "nopp.h"
+
+/* the structure of a token:	*/
+struct token	{
+	int tok_symb;		/* the token itself */
+	char *tok_file;		/* the file it (probably) comes from */
+	unsigned int tok_line;	/* the line it (probably) comes from */
+	int tok_fund;
+	union	{
+		struct idf *tok_idf;	/* for IDENTIFIER & TYPE_IDENTIFIER */
+		struct	{		/* for STRING */
+			char *tok_bts;	/* row of bytes */
+			int tok_len;	/* length of row of bytes */
+		} tok_string;
+		arith tok_ival;		/* for INTEGER */
+#ifndef NOFLOAT
+		char *tok_fval;		/* for FLOATING */
+#endif NOFLOAT
+	} tok_data;
+};
+
+#define tk_symb	tok_symb
+#define tk_file	tok_file
+#define tk_line	tok_line
+#define tk_fund	tok_fund
+#define tk_idf	tok_data.tok_idf
+#define tk_bts	tok_data.tok_string.tok_bts
+#define tk_len	tok_data.tok_string.tok_len
+#define tk_ival	tok_data.tok_ival
+#ifndef NOFLOAT
+#define tk_fval	tok_data.tok_fval
+#endif NOFLOAT
+
+extern struct token dot, ahead, aside;
+
+#ifndef NOPP
+extern int ReplaceMacros;	/* "LLlex.c"	*/
+extern int AccDefined;		/* "LLlex.c"	*/
+extern int Unstacked;		/* "LLlex.c"	*/
+extern int UnknownIdIsZero;	/* "LLlex.c"	*/
+#endif NOPP
+extern int EoiForNewline;	/* "LLlex.c"	*/
+extern int AccFileSpecifier;	/* "LLlex.c"	*/
+extern int SkipEscNewline;	/* "LLlex.c"	*/
+extern int File_Inserted;	/* "LLlex.c"	*/
+
+extern int NoUnstack;		/* buffer.c	*/
+
+extern int err_occurred;	/* "error.c"	*/
+
+#define	DOT	dot.tk_symb
+#define	AHEAD	ahead.tk_symb
+#define	ASIDE	aside.tk_symb
+
+#define EOF	(-1)

+ 59 - 0
lang/cem/cemcom.ansi/LLmessage.c

@@ -0,0 +1,59 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*		PARSER ERROR ADMINISTRATION		*/
+
+#include	<alloc.h>
+#include	"nofloat.h"
+#include	"idf.h"
+#include	"arith.h"
+#include	"LLlex.h"
+#include	"Lpars.h"
+
+extern char *symbol2str();
+
+LLmessage(tk)	{
+	err_occurred = 1;
+	if (tk < 0)	{
+		error("end of file expected");
+	}
+	else if (tk)	{
+		error("%s missing", symbol2str(tk));
+		insert_token(tk);
+	}
+	else
+		error("%s deleted", symbol2str(DOT));
+}
+
+insert_token(tk)
+	int tk;
+{
+	aside = dot;
+
+	DOT = tk;
+
+	switch (tk)	{
+	/* The operands need some body */
+	case IDENTIFIER:
+		dot.tk_idf = gen_idf();
+		break;
+	case TYPE_IDENTIFIER:
+		dot.tk_idf = str2idf("int");
+		break;
+	case STRING:
+		dot.tk_bts = Salloc("", 1);
+		dot.tk_len = 1;
+		break;
+	case INTEGER:
+		dot.tk_fund = INT;
+		dot.tk_ival = 1;
+		break;
+#ifndef NOFLOAT
+	case FLOATING:
+		dot.tk_fval = Salloc("0.0", 4);
+		break;
+#endif NOFLOAT
+	}
+}

+ 145 - 0
lang/cem/cemcom.ansi/LintPars

@@ -0,0 +1,145 @@
+!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 PREPEND_SCOPES	1	/* collect exa, exp, ina and inp commands
+					and if USE_TMP is defined let them
+					precede the rest of the generated
+					compact code	*/
+#undef USE_TMP		1	/* use C_insertpart, C_endpart mechanism
+					to generate EM-code in the order needed
+					for the code-generators. If not defined,
+					the old-style peephole optimizer is
+					needed.	*/
+
+
+!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 */
+
+

+ 1091 - 0
lang/cem/cemcom.ansi/Makefile

@@ -0,0 +1,1091 @@
+# $Header$
+#	M A K E F I L E   F O R   A C K   C - C O M P I L E R
+
+# Machine and environ dependent definitions
+EMHOME = ../../..
+CC = /proj/em/Work/bin/fcc.cc
+CFLOW = cflow
+MAKE = make
+MKDEP = $(EMHOME)/bin/mkdep
+PRID = $(EMHOME)/bin/prid
+CID = $(EMHOME)/bin/cid
+
+# Libraries and EM interface definitions
+SYSLIB = $(EMHOME)/modules/lib/libsystem.a
+EMKLIB = $(EMHOME)/modules/lib/libemk.a $(EMHOME)/lib/em_data.a
+EMOLIB = $(EMHOME)/modules/lib/libemopt.a
+EMELIB = $(EMHOME)/modules/lib/libeme.a $(EMHOME)/lib/em_data.a
+STRLIB = $(EMHOME)/modules/lib/libstring.a
+PRTLIB = $(EMHOME)/modules/lib/libprint.a
+EMMESLIB = $(EMHOME)/modules/lib/libem_mes.a
+EMMESOLIB = $(EMHOME)/modules/lib/libem_mesO.a
+EMMESCELIB = $(EMHOME)/modules/lib/libem_mesCE.a
+MACH = sun3
+EMCELIB = $(EMHOME)/lib/$(MACH)/ce.a \
+		$(EMHOME)/lib/$(MACH)/back.a \
+		$(EMHOME)/modules/lib/libobject.a $(EMHOME)/lib/em_data.a
+INPLIB = $(EMHOME)/modules/lib/libinput.a
+ALLOCLIB = $(EMHOME)/modules/lib/liballoc.a
+MALLOC = $(EMHOME)/modules/lib/malloc.o
+LIBS = $(INPLIB) $(EMMESLIB) $(EMKLIB) $(PRTLIB) $(STRLIB) \
+	$(ALLOCLIB) $(MALLOC) $(SYSLIB)
+ELIBS = $(INPLIB) $(EMMESLIB) $(EMELIB) $(PRTLIB) $(STRLIB) \
+	$(ALLOCLIB) $(MALLOC) $(SYSLIB)
+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
+EMKLLIB = $(EMHOME)/modules/lib/llib-lemk.ln
+EMELLIB = $(EMHOME)/modules/lib/llib-leme.ln
+STRLLIB = $(EMHOME)/modules/lib/llib-lstring.ln
+PRTLLIB = $(EMHOME)/modules/lib/llib-lprint.ln
+EMMESLLIB = $(EMHOME)/modules/lib/llib-lem_mes.ln
+INPLLIB = $(EMHOME)/modules/lib/llib-linput.ln
+ALLOCLLIB = $(EMHOME)/modules/lib/llib-lalloc.ln
+#LINTLIBS =
+LINTLIBS = $(EMMESLLIB) $(EMKLLIB) $(PRTLLIB) $(STRLLIB) $(ALLOCLLIB) $(SYSLLIB)
+CURRDIR = 
+
+COPTIONS =
+
+# What parser generator to use and how
+GEN = $(EMHOME)/bin/LLgen
+GENOPTIONS = -v
+
+# Special #defines during compilation
+PROF = #-pg
+CDEFS =	$(EM_INCLUDES) $(LIB_INCLUDES)
+CFLAGS = $(CDEFS) $(COPTIONS) $(PROF) #-O
+LDFLAGS = -i $(PROF)
+
+# Grammar files and their objects
+LSRC =	tokenfile.g declar.g statement.g expression.g program.g ival.g
+LCSRC =	tokenfile.c declar.c statement.c expression.c program.c Lpars.c ival.c
+LOBJ =	tokenfile.o declar.o statement.o expression.o program.o Lpars.o ival.o
+
+# Objects of hand-written C files
+CSRC =	main.c idf.c declarator.c decspecs.c struct.c \
+	expr.c ch7.c ch7bin.c cstoper.c arith.c \
+	code.c dumpidf.c error.c field.c\
+	tokenname.c LLlex.c LLmessage.c \
+	input.c domacro.c replace.c init.c options.c \
+	skip.c stack.c type.c ch7mon.c label.c eval.c \
+	switch.c conversion.c util.c proto.c \
+	pragma.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 \
+	code.o dumpidf.o error.o field.o\
+	tokenname.o LLlex.o LLmessage.o \
+	input.o domacro.o replace.o init.o options.o \
+	skip.o stack.o type.o ch7mon.o label.o eval.o \
+	switch.o conversion.o util.o proto.o \
+	pragma.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
+GOBJ =	char.o symbol2str.o next.o
+
+STRSRC = code.str declar.str decspecs.str def.str expr.str field.str \
+	estack.str util.str proto.str replace.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 proto.h replace.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 argbuf.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 \
+	regcount.h
+
+HSRC = LLlex.h align.h arith.h assert.h atw.h class.h \
+	 input.h label.h level.h mes.h sizes.h specials.h \
+	 file_info.h tokenname.h l_lint.h
+
+HFILES = $(HSRC) $(GHSRC) $(GHSTRSRC)
+
+# generated files, for 'make clean' only
+GENERATED = tokenfile.g Lpars.h LLfiles LL.output lint.out \
+	print hfiles Cfiles $(GHSRC) $(GSRC) longnames $(LCSRC)
+
+# include files containing ALLOCDEF specifications
+OBJ =	$(COBJ) $(LOBJ) $(GOBJ)
+SRC =	$(CSRC) $(LCSRC) $(GCSRC)
+
+LINT = /usr/bin/lint
+LINTFLAGS =
+
+MYLINT = /usr/star/dick/bin/lint	#../lint
+MYLINTFLAGS = #-xh
+
+#EXCLEXCLEXCLEXCL
+
+.SUFFIXES: .str .h
+.str.h:
+	./make.allocd <$*.str >$*.h
+
+Main:	Cfiles
+	sh -c 'if $(CC) nmclash.c > /dev/null 2>&1 ; then make "EMHOME="$(EMHOME) $(CURRDIR)main ; else EMHOME=$(EMHOME); export EMHOME; ./Resolve main ; fi'
+	@rm -f nmclash.o a.out
+
+Emain:	Cfiles
+	sh -c 'if $(CC) nmclash.c > /dev/null 2>&1 ; then make "EMHOME="$(EMHOME) $(CURRDIR)emain ; else EMHOME=$(EMHOME); export EMHOME; ./Resolve emain ; fi'
+	@rm -f nmclash.o a.out
+
+Omain:	Cfiles
+	rm -f *.o
+	sh -c 'if $(CC) nmclash.c > /dev/null 2>&1 ; then make "EMHOME="$(EMHOME) "COPTIONS="-DPEEPHOLE $(CURRDIR)omain ; else EMHOME=$(EMHOME); export EMHOME; ./Resolve omain ; fi'
+	@rm -f nmclash.o a.out
+	mv *.o PEEPHOLE
+
+CEmain:	Cfiles
+	rm -f *.o
+	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
+	mv *.o CODE_EXPANDER
+
+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
+	cp $(CURRDIR)cemcom.1 $(EMHOME)/man/em_cemcom.6
+
+Oinstall:	Omain
+	cp $(CURRDIR)omain $(EMHOME)/lib/em_cemcomO
+
+cmp:	Main
+	-cmp $(CURRDIR)main $(EMHOME)/lib/em_cemcom
+	-cmp $(CURRDIR)cemcom.1 $(EMHOME)/man/em_cemcom.6
+
+pr:
+	@pr Makefile make.* char.tab Parameters $(HSRC) $(STRSRC) $(LSRC) $(CSRC)
+
+opr:
+	$(MAKE) pr | opr
+
+clean:
+	rm -f $(OBJ)
+	rm -f $(GENERATED) main
+	(cd .. ; rm -rf Xsrc)
+
+cflow:	Cfiles
+	$(CFLOW) $(CDEFS) $(SRC)
+
+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'
+
+# entry points not to be used directly
+
+Cfiles:	hfiles LLfiles $(GENCFILES) $(GSRC) $(GHSRC) Makefile
+	echo $(SRC) $(HFILES) > Cfiles
+
+hfiles: ./make.hfiles Parameters
+	./make.hfiles Parameters
+	@touch hfiles
+
+LLfiles: $(LSRC)
+	$(GEN) $(GENOPTIONS) $(LSRC)
+	@touch LLfiles
+
+tokenfile.g:	tokenname.c make.tokfile
+	<tokenname.c ./make.tokfile >tokenfile.g
+
+symbol2str.c:	tokenname.c make.tokcase
+	<tokenname.c ./make.tokcase >symbol2str.c
+
+char.c:	char.tab
+	$(EMHOME)/bin/tabgen -fchar.tab >char.c
+
+next.c:	make.next $(STRSRC)
+	./make.next $(STRSRC) >next.c
+
+code.h:		make.allocd
+declar.h:	make.allocd
+decspecs.h:	make.allocd
+def.h:		make.allocd
+expr.h:		make.allocd
+field.h:	make.allocd
+idf.h:		make.allocd
+macro.h:	make.allocd
+stack.h:	make.allocd
+stmt.h:		make.allocd
+struct.h:	make.allocd
+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
+	echo '#AUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTO' >>Makefile.new
+	$(MKDEP) $(SRC) | sed 's/\.c:/.o:/' >>Makefile.new
+	mv Makefile Makefile.old
+	mv Makefile.new Makefile
+
+#INCLINCLINCLINCL
+
+$(CURRDIR)main:	$(OBJ) $(CURRDIR)Makefile
+	$(CC) $(COPTIONS) $(LDFLAGS) $(OBJ) $(LIBS) -o $(CURRDIR)main 
+	size $(CURRDIR)main
+
+$(CURRDIR)emain:	$(OBJ) $(CURRDIR)Makefile
+	$(CC) $(COPTIONS) $(LDFLAGS) $(OBJ) $(ELIBS) -o $(CURRDIR)emain 
+	size $(CURRDIR)emain
+
+$(CURRDIR)omain:	$(OBJ) $(CURRDIR)Makefile
+	$(CC) $(COPTIONS) $(LDFLAGS) $(OBJ) $(OLIBS) -o $(CURRDIR)omain 
+	size $(CURRDIR)omain
+
+$(CURRDIR)cemain:	$(OBJ) $(CURRDIR)Makefile
+	$(CC) $(COPTIONS) $(LDFLAGS) $(OBJ) $(CELIBS) -o $(CURRDIR)cemain 
+	size $(CURRDIR)cemain
+
+$(CURRDIR)lnt:		$(OBJ) $(CURRDIR)Makefile
+	$(CC) $(COPTIONS) $(LDFLAGS) $(OBJ) $(LLIBS) -o $(CURRDIR)lnt 
+	size $(CURRDIR)lnt
+
+Xlint:	$(SRC)
+	$(LINT) $(CDEFS) $(LINTFLAGS) $(SRC)
+
+Xmylint:	$(SRC)
+	$(MYLINT) $(CDEFS) $(MYLINTFLAGS) $(SRC)
+
+#AUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTO
+main.o: LLlex.h
+main.o: Lpars.h
+main.o: align.h
+main.o: arith.h
+main.o: debug.h
+main.o: declar.h
+main.o: file_info.h
+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
+main.o: nofloat.h
+main.o: nopp.h
+main.o: proto.h
+main.o: sizes.h
+main.o: spec_arith.h
+main.o: specials.h
+main.o: target_sizes.h
+main.o: tokenname.h
+main.o: type.h
+main.o: use_tmp.h
+idf.o: LLlex.h
+idf.o: Lpars.h
+idf.o: align.h
+idf.o: arith.h
+idf.o: assert.h
+idf.o: botch_free.h
+idf.o: debug.h
+idf.o: declar.h
+idf.o: decspecs.h
+idf.o: def.h
+idf.o: file_info.h
+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
+idf.o: nofloat.h
+idf.o: nopp.h
+idf.o: nparams.h
+idf.o: proto.h
+idf.o: sizes.h
+idf.o: spec_arith.h
+idf.o: specials.h
+idf.o: stack.h
+idf.o: struct.h
+idf.o: target_sizes.h
+idf.o: type.h
+declarator.o: Lpars.h
+declarator.o: arith.h
+declarator.o: botch_free.h
+declarator.o: debug.h
+declarator.o: declar.h
+declarator.o: def.h
+declarator.o: expr.h
+declarator.o: idf.h
+declarator.o: label.h
+declarator.o: level.h
+declarator.o: lint.h
+declarator.o: nobitfield.h
+declarator.o: nocross.h
+declarator.o: nofloat.h
+declarator.o: nopp.h
+declarator.o: proto.h
+declarator.o: sizes.h
+declarator.o: spec_arith.h
+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
+decspecs.o: spec_arith.h
+decspecs.o: type.h
+struct.o: LLlex.h
+struct.o: Lpars.h
+struct.o: align.h
+struct.o: arith.h
+struct.o: assert.h
+struct.o: botch_free.h
+struct.o: debug.h
+struct.o: def.h
+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
+struct.o: nofloat.h
+struct.o: nopp.h
+struct.o: proto.h
+struct.o: sizes.h
+struct.o: spec_arith.h
+struct.o: stack.h
+struct.o: struct.h
+struct.o: target_sizes.h
+struct.o: type.h
+expr.o: LLlex.h
+expr.o: Lpars.h
+expr.o: arith.h
+expr.o: botch_free.h
+expr.o: declar.h
+expr.o: decspecs.h
+expr.o: def.h
+expr.o: expr.h
+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
+expr.o: nofloat.h
+expr.o: nopp.h
+expr.o: sizes.h
+expr.o: spec_arith.h
+expr.o: target_sizes.h
+expr.o: type.h
+ch7.o: Lpars.h
+ch7.o: arith.h
+ch7.o: assert.h
+ch7.o: debug.h
+ch7.o: def.h
+ch7.o: expr.h
+ch7.o: file_info.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
+ch7.o: proto.h
+ch7.o: spec_arith.h
+ch7.o: struct.h
+ch7.o: type.h
+ch7bin.o: Lpars.h
+ch7bin.o: arith.h
+ch7bin.o: botch_free.h
+ch7bin.o: expr.h
+ch7bin.o: idf.h
+ch7bin.o: label.h
+ch7bin.o: lint.h
+ch7bin.o: noRoption.h
+ch7bin.o: nobitfield.h
+ch7bin.o: nofloat.h
+ch7bin.o: nopp.h
+ch7bin.o: spec_arith.h
+ch7bin.o: struct.h
+ch7bin.o: type.h
+cstoper.o: Lpars.h
+cstoper.o: arith.h
+cstoper.o: assert.h
+cstoper.o: debug.h
+cstoper.o: expr.h
+cstoper.o: idf.h
+cstoper.o: label.h
+cstoper.o: nobitfield.h
+cstoper.o: nocross.h
+cstoper.o: nofloat.h
+cstoper.o: nopp.h
+cstoper.o: sizes.h
+cstoper.o: spec_arith.h
+cstoper.o: target_sizes.h
+cstoper.o: type.h
+arith.o: Lpars.h
+arith.o: arith.h
+arith.o: expr.h
+arith.o: field.h
+arith.o: idf.h
+arith.o: label.h
+arith.o: lint.h
+arith.o: mes.h
+arith.o: noRoption.h
+arith.o: nobitfield.h
+arith.o: nocross.h
+arith.o: nofloat.h
+arith.o: nopp.h
+arith.o: proto.h
+arith.o: sizes.h
+arith.o: spec_arith.h
+arith.o: target_sizes.h
+arith.o: type.h
+code.o: Lpars.h
+code.o: arith.h
+code.o: assert.h
+code.o: atw.h
+code.o: botch_free.h
+code.o: code.h
+code.o: dataflow.h
+code.o: debug.h
+code.o: declar.h
+code.o: decspecs.h
+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
+code.o: nofloat.h
+code.o: nopp.h
+code.o: sizes.h
+code.o: spec_arith.h
+code.o: specials.h
+code.o: stack.h
+code.o: stmt.h
+code.o: target_sizes.h
+code.o: type.h
+code.o: use_tmp.h
+dumpidf.o: Lpars.h
+dumpidf.o: arith.h
+dumpidf.o: debug.h
+dumpidf.o: declar.h
+dumpidf.o: def.h
+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
+dumpidf.o: proto.h
+dumpidf.o: spec_arith.h
+dumpidf.o: stack.h
+dumpidf.o: static.h
+dumpidf.o: struct.h
+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
+error.o: tokenname.h
+field.o: Lpars.h
+field.o: align.h
+field.o: arith.h
+field.o: assert.h
+field.o: code.h
+field.o: debug.h
+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
+field.o: nopp.h
+field.o: sizes.h
+field.o: spec_arith.h
+field.o: target_sizes.h
+field.o: type.h
+tokenname.o: LLlex.h
+tokenname.o: Lpars.h
+tokenname.o: arith.h
+tokenname.o: file_info.h
+tokenname.o: idf.h
+tokenname.o: nofloat.h
+tokenname.o: nopp.h
+tokenname.o: spec_arith.h
+tokenname.o: tokenname.h
+LLlex.o: LLlex.h
+LLlex.o: Lpars.h
+LLlex.o: arith.h
+LLlex.o: assert.h
+LLlex.o: class.h
+LLlex.o: debug.h
+LLlex.o: def.h
+LLlex.o: file_info.h
+LLlex.o: idf.h
+LLlex.o: idfsize.h
+LLlex.o: input.h
+LLlex.o: lint.h
+LLlex.o: macro.h
+LLlex.o: nocross.h
+LLlex.o: nofloat.h
+LLlex.o: nopp.h
+LLlex.o: numsize.h
+LLlex.o: sizes.h
+LLlex.o: spec_arith.h
+LLlex.o: strsize.h
+LLlex.o: target_sizes.h
+LLmessage.o: LLlex.h
+LLmessage.o: Lpars.h
+LLmessage.o: arith.h
+LLmessage.o: file_info.h
+LLmessage.o: idf.h
+LLmessage.o: nofloat.h
+LLmessage.o: nopp.h
+LLmessage.o: spec_arith.h
+input.o: file_info.h
+input.o: input.h
+input.o: inputtype.h
+input.o: nopp.h
+domacro.o: LLlex.h
+domacro.o: Lpars.h
+domacro.o: arith.h
+domacro.o: assert.h
+domacro.o: botch_free.h
+domacro.o: class.h
+domacro.o: debug.h
+domacro.o: file_info.h
+domacro.o: idf.h
+domacro.o: idfsize.h
+domacro.o: ifdepth.h
+domacro.o: input.h
+domacro.o: macro.h
+domacro.o: nofloat.h
+domacro.o: nopp.h
+domacro.o: nparams.h
+domacro.o: parbufsize.h
+domacro.o: spec_arith.h
+domacro.o: textsize.h
+replace.o: LLlex.h
+replace.o: argbuf.h
+replace.o: arith.h
+replace.o: assert.h
+replace.o: class.h
+replace.o: debug.h
+replace.o: file_info.h
+replace.o: idf.h
+replace.o: idfsize.h
+replace.o: input.h
+replace.o: lapbuf.h
+replace.o: macro.h
+replace.o: nofloat.h
+replace.o: nopp.h
+replace.o: nparams.h
+replace.o: numsize.h
+replace.o: pathlength.h
+replace.o: replace.h
+replace.o: spec_arith.h
+replace.o: static.h
+replace.o: strsize.h
+init.o: class.h
+init.o: idf.h
+init.o: macro.h
+init.o: nopp.h
+options.o: align.h
+options.o: arith.h
+options.o: botch_free.h
+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
+options.o: nocross.h
+options.o: nofloat.h
+options.o: nopp.h
+options.o: sizes.h
+options.o: spec_arith.h
+options.o: target_sizes.h
+options.o: use_tmp.h
+skip.o: LLlex.h
+skip.o: arith.h
+skip.o: class.h
+skip.o: file_info.h
+skip.o: input.h
+skip.o: nofloat.h
+skip.o: nopp.h
+skip.o: spec_arith.h
+stack.o: Lpars.h
+stack.o: arith.h
+stack.o: botch_free.h
+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
+stack.o: nofloat.h
+stack.o: nopp.h
+stack.o: spec_arith.h
+stack.o: stack.h
+stack.o: struct.h
+stack.o: type.h
+type.o: Lpars.h
+type.o: align.h
+type.o: arith.h
+type.o: botch_free.h
+type.o: decspecs.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
+type.o: nopp.h
+type.o: proto.h
+type.o: sizes.h
+type.o: spec_arith.h
+type.o: target_sizes.h
+type.o: type.h
+ch7mon.o: Lpars.h
+ch7mon.o: arith.h
+ch7mon.o: botch_free.h
+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
+ch7mon.o: spec_arith.h
+ch7mon.o: type.h
+label.o: Lpars.h
+label.o: arith.h
+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
+label.o: nopp.h
+label.o: spec_arith.h
+label.o: type.h
+eval.o: Lpars.h
+eval.o: align.h
+eval.o: arith.h
+eval.o: assert.h
+eval.o: atw.h
+eval.o: code.h
+eval.o: dataflow.h
+eval.o: debug.h
+eval.o: def.h
+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
+eval.o: nofloat.h
+eval.o: nopp.h
+eval.o: sizes.h
+eval.o: spec_arith.h
+eval.o: specials.h
+eval.o: stack.h
+eval.o: target_sizes.h
+eval.o: type.h
+switch.o: Lpars.h
+switch.o: arith.h
+switch.o: assert.h
+switch.o: botch_free.h
+switch.o: code.h
+switch.o: debug.h
+switch.o: density.h
+switch.o: expr.h
+switch.o: idf.h
+switch.o: label.h
+switch.o: noRoption.h
+switch.o: nobitfield.h
+switch.o: nofloat.h
+switch.o: nopp.h
+switch.o: spec_arith.h
+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
+conversion.o: sizes.h
+conversion.o: spec_arith.h
+conversion.o: target_sizes.h
+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
+util.o: sizes.h
+util.o: stack.h
+util.o: target_sizes.h
+util.o: use_tmp.h
+util.o: util.h
+proto.o: Lpars.h
+proto.o: align.h
+proto.o: arith.h
+proto.o: assert.h
+proto.o: botch_free.h
+proto.o: debug.h
+proto.o: declar.h
+proto.o: decspecs.h
+proto.o: def.h
+proto.o: expr.h
+proto.o: idf.h
+proto.o: idfsize.h
+proto.o: label.h
+proto.o: level.h
+proto.o: lint.h
+proto.o: nobitfield.h
+proto.o: nocross.h
+proto.o: nofloat.h
+proto.o: nopp.h
+proto.o: nparams.h
+proto.o: proto.h
+proto.o: spec_arith.h
+proto.o: stack.h
+proto.o: struct.h
+proto.o: target_sizes.h
+proto.o: type.h
+pragma.o: LLlex.h
+pragma.o: Lpars.h
+pragma.o: arith.h
+pragma.o: assert.h
+pragma.o: botch_free.h
+pragma.o: class.h
+pragma.o: debug.h
+pragma.o: file_info.h
+pragma.o: idf.h
+pragma.o: idfsize.h
+pragma.o: ifdepth.h
+pragma.o: input.h
+pragma.o: macro.h
+pragma.o: nofloat.h
+pragma.o: nopp.h
+pragma.o: nparams.h
+pragma.o: parbufsize.h
+pragma.o: spec_arith.h
+pragma.o: textsize.h
+blocks.o: Lpars.h
+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
+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: assert.h
+l_lint.o: code.h
+l_lint.o: debug.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: interface.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: interface.h
+l_states.o: l_brace.h
+l_states.o: l_comment.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: interface.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: assert.h
+l_ev_ord.o: code.h
+l_ev_ord.o: debug.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: interface.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: assert.h
+l_outdef.o: code.h
+l_outdef.o: debug.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: interface.h
+l_outdef.o: l_class.h
+l_outdef.o: l_comment.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: interface.h
+l_comment.o: l_comment.h
+l_comment.o: l_state.h
+l_comment.o: lint.h
+l_comment.o: spec_arith.h
+l_dummy.o: arith.h
+l_dummy.o: label.h
+l_dummy.o: lint.h
+l_dummy.o: spec_arith.h
+tokenfile.o: Lpars.h
+declar.o: LLlex.h
+declar.o: Lpars.h
+declar.o: arith.h
+declar.o: code.h
+declar.o: debug.h
+declar.o: declar.h
+declar.o: decspecs.h
+declar.o: def.h
+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
+declar.o: nopp.h
+declar.o: proto.h
+declar.o: sizes.h
+declar.o: spec_arith.h
+declar.o: struct.h
+declar.o: target_sizes.h
+declar.o: type.h
+statement.o: LLlex.h
+statement.o: Lpars.h
+statement.o: arith.h
+statement.o: botch_free.h
+statement.o: code.h
+statement.o: debug.h
+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
+statement.o: spec_arith.h
+statement.o: stack.h
+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
+expression.o: nopp.h
+expression.o: spec_arith.h
+expression.o: type.h
+program.o: LLlex.h
+program.o: Lpars.h
+program.o: arith.h
+program.o: code.h
+program.o: declar.h
+program.o: decspecs.h
+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
+program.o: spec_arith.h
+program.o: type.h
+Lpars.o: Lpars.h
+ival.o: LLlex.h
+ival.o: Lpars.h
+ival.o: arith.h
+ival.o: assert.h
+ival.o: debug.h
+ival.o: def.h
+ival.o: estack.h
+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
+ival.o: nofloat.h
+ival.o: nopp.h
+ival.o: proto.h
+ival.o: sizes.h
+ival.o: spec_arith.h
+ival.o: struct.h
+ival.o: target_sizes.h
+ival.o: type.h
+char.o: class.h
+symbol2str.o: Lpars.h

+ 718 - 0
lang/cem/cemcom.ansi/Makefile.erik

@@ -0,0 +1,718 @@
+# $Header$
+#	M A K E F I L E   F O R   A C K   C - C O M P I L E R
+
+# Machine and environ dependent definitions
+EMHOME =	/usr/em#			# ACK tree on this machine
+DESTINATION =	/user1/$$USER/bin#		# where to put the stuff
+MKDEP =		$(EMHOME)/bin/mkdep#		# dependency generator
+MAP =
+#MAP = -DInsertFile=ins_file -DInsertText=ins_text# bug in m68k2 back end
+SIM =		/user1/dick/bin/sim#		# Dicks sim program
+LINT =		/usr/new/lint
+
+# Libraries and EM interface definitions
+SYSLIB =	$(EMHOME)/modules/lib/libsystem.a
+EMKLIB =	$(EMHOME)/modules/lib/libemk.a
+EMELIB =	$(EMHOME)/modules/lib/libeme.a $(EMHOME)/lib/em_data.a
+STRLIB =	$(EMHOME)/modules/lib/libstring.a
+PRTLIB =	$(EMHOME)/modules/lib/libprint.a
+EMMESLIB =	$(EMHOME)/modules/lib/libem_mes.a
+INPLIB =	$(EMHOME)/modules/lib/libinput.a
+ALLOCLIB =	$(EMHOME)/modules/lib/liballoc.a
+MALLOC =	$(EMHOME)/modules/lib/malloc.o
+#CH3LIB =	$(EMHOME)/modules/lib/libch3.a
+CH3LIB =
+LIBS =		$(INPLIB) $(CH3LIB) $(EMMESLIB) $(EMKLIB) \
+		$(PRTLIB) $(STRLIB) $(ALLOCLIB) $(MALLOC) $(SYSLIB)
+ELIBS =		$(INPLIB) $(CH3LIB) $(EMMESLIB) $(EMELIB) \
+		$(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-lsys.ln
+EMKLLIB =	$(EMHOME)/modules/lib/llib-lemk.ln
+EMELLIB =	$(EMHOME)/modules/lib/llib-leme.ln
+STRLLIB =	$(EMHOME)/modules/lib/llib-lstr.ln
+PRTLLIB =	$(EMHOME)/modules/lib/llib-lprint.ln
+EMMESLLIB =	$(EMHOME)/modules/lib/llib-lmes.ln
+INPLLIB =	$(EMHOME)/modules/lib/llib-linput.ln
+CH3LLIB =	$(EMHOME)/modules/lib/llib-lch3.ln
+ALLOCLLIB =	$(EMHOME)/modules/lib/llib-alloc.ln
+LINTLIBS =
+#LINTLIBS =	$(CH3LLIB) $(INPLLIB) $(EMMESLLIB) $(EMKLLIB) \
+#		$(PRTLLIB) $(STRLLIB) $(SYSLLIB) $(ALLOCLLIB)
+
+# Where to install the compiler and its driver
+CEMCOM =	$(DESTINATION)/cemcom
+DRIVER =	$(DESTINATION)/cem
+
+# What C compiler to use and how
+# CC = $(ACK) -.c
+# CC = CC
+# CC = /bin/cc
+COPTIONS =
+
+# What parser generator to use and how
+GEN =		$(EMHOME)/bin/LLgen
+GENOPTIONS =	-vv
+
+# Special #defines during compilation
+CDEFS =		$(MAP) $(EM_INCLUDES) $(LIB_INCLUDES)
+CFLAGS =	$(CDEFS) $(COPTIONS) -O# we cannot pass the COPTIONS to lint!
+
+# Grammar files and their objects
+LSRC =	tokenfile.g declar.g statement.g expression.g program.g ival.g
+GLCSRC = tokenfile.c declar.c statement.c expression.c program.c Lpars.c ival.c
+LOBJ =	tokenfile.o declar.o statement.o expression.o program.o Lpars.o ival.o
+
+CSRC =  main.c idf.c declarator.c decspecs.c struct.c \
+        expr.c ch7.c ch7bin.c cstoper.c arith.c \
+        asm.c code.c dumpidf.c error.c field.c\
+        tokenname.c LLlex.c LLmessage.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
+# Objects of hand-written C files
+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\
+	tokenname.o LLlex.o LLmessage.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
+
+# Objects of other generated C files
+GCSRC = char.c symbol2str.c next.c
+GOBJ =	char.o symbol2str.o next.o
+
+# generated source files
+GSRC =	char.c symbol2str.c next.c \
+	code.h declar.h decspecs.h def.h expr.h field.h  estack.h \
+	idf.h macro.h stack.h stmt.h struct.h switch.h type.h util.h
+
+# .h files generated by `make hfiles'; PLEASE KEEP THIS UP-TO-DATE!
+GHSRC = botch_free.h dataflow.h debug.h density.h errout.h \
+	idfsize.h ifdepth.h inputtype.h inumlength.h lapbuf.h \
+	nobitfield.h nofloat.h nopp.h noRoption.h nocross.h \
+	nparams.h numsize.h parbufsize.h pathlength.h \
+	strsize.h target_sizes.h textsize.h use_tmp.h spec_arith.h static.h \
+	reg_count.h
+
+# Other generated files, for 'make clean' only
+GENERATED = tokenfile.g Lpars.h LLfiles LL.output lint.out \
+	print Xref lxref hfiles cfiles $(GLCSRC)
+
+# include files containing ALLOCDEF specifications
+NEXTFILES = 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
+
+.SUFFIXES: .str .h
+.str.h:
+	./make.allocd <$*.str >$*.h
+
+all:	cc
+
+cc:
+	make "EMHOME="$(EMHOME) "CC=$(CC)" hfiles
+	make "EMHOME="$(EMHOME) "CC=$(CC)" LLfiles
+	make "EMHOME="$(EMHOME) "CC=$(CC)" main
+
+cem:	cem.c
+	$(CC) -O cem.c $(SYSLIB) -o cem
+
+lint.cem: cem.c
+	$(LINT) -bx cem.c
+
+hfiles: ./make.hfiles Parameters
+	./make.hfiles Parameters
+	@touch hfiles
+
+LLfiles: $(LSRC)
+	$(GEN) $(GENOPTIONS) $(LSRC)
+	@touch LLfiles
+
+tokenfile.g:	tokenname.c make.tokfile
+	<tokenname.c ./make.tokfile >tokenfile.g
+
+symbol2str.c:	tokenname.c make.tokcase
+	<tokenname.c ./make.tokcase >symbol2str.c
+
+char.c:	char.tab
+	$(EMHOME)/bin/tabgen -fchar.tab >char.c
+
+next.c:	make.next $(NEXTFILES)
+	./make.next $(NEXTFILES) >next.c
+
+code.h:		make.allocd
+declar.h:	make.allocd
+decspecs.h:	make.allocd
+def.h:		make.allocd
+estack.h:	make.allocd
+expr.h:		make.allocd
+field.h:	make.allocd
+idf.h:		make.allocd
+macro.h:	make.allocd
+stack.h:	make.allocd
+stmt.h:		make.allocd
+struct.h:	make.allocd
+switch.h:	make.allocd
+type.h:		make.allocd
+util.h:		make.allocd
+
+# Objects needed for 'main'
+OBJ =	$(COBJ) $(LOBJ) $(GOBJ)
+SRC =	$(CSRC) $(LCSRC) $(GCSRC)
+
+main:	$(OBJ) Makefile.erik
+	$(CC) $(COPTIONS) $(LFLAGS) $(OBJ) $(LIBS) -o main 
+	size main
+
+emain:	$(OBJ) Makefile.erik
+	$(CC) $(COPTIONS) $(LFLAGS) $(OBJ) $(ELIBS) -o emain 
+	size emain
+
+cfiles: hfiles LLfiles $(GSRC)
+	@touch cfiles
+
+install: main cem
+	cp main $(CEMCOM)
+	cp cem $(DRIVER)
+
+print:	files
+	pr `cat files` > print
+
+tags:	cfiles
+	ctags $(SRC)
+
+shar:	files
+	shar `cat files`
+
+listcfiles:
+	@echo $(SRC)
+
+listobjects:
+	@echo $(OBJ)
+
+depend:	cfiles
+	sed '/^#AUTOAUTO/,$$d' Makefile.erik >Makefile.erik.new
+	echo '#AUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTO' >>Makefile.erik.new
+	$(MKDEP) $(SRC) | sed 's/\.c:/.o:/' >>Makefile.erik.new
+	mv Makefile.erik Makefile.erik.old
+	mv Makefile.erik.new Makefile.erik
+	
+xref:
+	ctags -x `grep "\.[ch]" files`|sed "s/).*/)/">Xref
+	
+lxref:
+	lxref $(OBJ) -lc >lxref
+
+lint:	lint.main lint.cem
+
+lint.main: cfiles
+	$(LINT) -bx $(CDEFS) $(SRC) $(LINTLIBS) >lint.out
+
+cchk:
+	cchk $(SRC)
+
+clean:
+	rm -f $(LCSRC) $(OBJ) $(GENERATED) $(GSRC) $(GHSRC)
+
+sim:	cfiles
+	$(SIM) $(SIMFLAGS) $(CSRC) $(GSRC) $(LSRC)
+
+#AUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTO
+main.o: LLlex.h
+main.o: Lpars.h
+main.o: align.h
+main.o: arith.h
+main.o: debug.h
+main.o: declar.h
+main.o: file_info.h
+main.o: idf.h
+main.o: input.h
+main.o: inputtype.h
+main.o: level.h
+main.o: noRoption.h
+main.o: nobitfield.h
+main.o: nocross.h
+main.o: nofloat.h
+main.o: nopp.h
+main.o: sizes.h
+main.o: spec_arith.h
+main.o: specials.h
+main.o: target_sizes.h
+main.o: tokenname.h
+main.o: type.h
+main.o: use_tmp.h
+idf.o: LLlex.h
+idf.o: Lpars.h
+idf.o: align.h
+idf.o: arith.h
+idf.o: assert.h
+idf.o: botch_free.h
+idf.o: debug.h
+idf.o: declar.h
+idf.o: decspecs.h
+idf.o: def.h
+idf.o: file_info.h
+idf.o: idf.h
+idf.o: idfsize.h
+idf.o: label.h
+idf.o: level.h
+idf.o: noRoption.h
+idf.o: nobitfield.h
+idf.o: nocross.h
+idf.o: nofloat.h
+idf.o: nopp.h
+idf.o: sizes.h
+idf.o: spec_arith.h
+idf.o: specials.h
+idf.o: stack.h
+idf.o: struct.h
+idf.o: target_sizes.h
+idf.o: type.h
+declarator.o: Lpars.h
+declarator.o: arith.h
+declarator.o: botch_free.h
+declarator.o: declar.h
+declarator.o: expr.h
+declarator.o: idf.h
+declarator.o: label.h
+declarator.o: nobitfield.h
+declarator.o: nocross.h
+declarator.o: nofloat.h
+declarator.o: nopp.h
+declarator.o: sizes.h
+declarator.o: spec_arith.h
+declarator.o: target_sizes.h
+declarator.o: type.h
+decspecs.o: Lpars.h
+decspecs.o: arith.h
+decspecs.o: decspecs.h
+decspecs.o: def.h
+decspecs.o: level.h
+decspecs.o: noRoption.h
+decspecs.o: nobitfield.h
+decspecs.o: nofloat.h
+decspecs.o: spec_arith.h
+decspecs.o: type.h
+struct.o: LLlex.h
+struct.o: Lpars.h
+struct.o: align.h
+struct.o: arith.h
+struct.o: assert.h
+struct.o: botch_free.h
+struct.o: debug.h
+struct.o: def.h
+struct.o: field.h
+struct.o: file_info.h
+struct.o: idf.h
+struct.o: level.h
+struct.o: noRoption.h
+struct.o: nobitfield.h
+struct.o: nocross.h
+struct.o: nofloat.h
+struct.o: nopp.h
+struct.o: sizes.h
+struct.o: spec_arith.h
+struct.o: stack.h
+struct.o: struct.h
+struct.o: target_sizes.h
+struct.o: type.h
+expr.o: LLlex.h
+expr.o: Lpars.h
+expr.o: arith.h
+expr.o: botch_free.h
+expr.o: declar.h
+expr.o: decspecs.h
+expr.o: def.h
+expr.o: expr.h
+expr.o: file_info.h
+expr.o: idf.h
+expr.o: label.h
+expr.o: level.h
+expr.o: noRoption.h
+expr.o: nobitfield.h
+expr.o: nocross.h
+expr.o: nofloat.h
+expr.o: nopp.h
+expr.o: sizes.h
+expr.o: spec_arith.h
+expr.o: target_sizes.h
+expr.o: type.h
+ch7.o: Lpars.h
+ch7.o: arith.h
+ch7.o: assert.h
+ch7.o: debug.h
+ch7.o: def.h
+ch7.o: expr.h
+ch7.o: idf.h
+ch7.o: label.h
+ch7.o: nobitfield.h
+ch7.o: nofloat.h
+ch7.o: nopp.h
+ch7.o: spec_arith.h
+ch7.o: struct.h
+ch7.o: type.h
+ch7bin.o: Lpars.h
+ch7bin.o: arith.h
+ch7bin.o: botch_free.h
+ch7bin.o: expr.h
+ch7bin.o: idf.h
+ch7bin.o: label.h
+ch7bin.o: noRoption.h
+ch7bin.o: nobitfield.h
+ch7bin.o: nofloat.h
+ch7bin.o: nopp.h
+ch7bin.o: spec_arith.h
+ch7bin.o: struct.h
+ch7bin.o: type.h
+cstoper.o: Lpars.h
+cstoper.o: arith.h
+cstoper.o: assert.h
+cstoper.o: debug.h
+cstoper.o: expr.h
+cstoper.o: idf.h
+cstoper.o: label.h
+cstoper.o: nobitfield.h
+cstoper.o: nocross.h
+cstoper.o: nofloat.h
+cstoper.o: nopp.h
+cstoper.o: sizes.h
+cstoper.o: spec_arith.h
+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
+arith.o: label.h
+arith.o: mes.h
+arith.o: noRoption.h
+arith.o: nobitfield.h
+arith.o: nofloat.h
+arith.o: nopp.h
+arith.o: spec_arith.h
+arith.o: type.h
+code.o: Lpars.h
+code.o: arith.h
+code.o: assert.h
+code.o: atw.h
+code.o: botch_free.h
+code.o: code.h
+code.o: dataflow.h
+code.o: debug.h
+code.o: declar.h
+code.o: decspecs.h
+code.o: def.h
+code.o: expr.h
+code.o: file_info.h
+code.o: idf.h
+code.o: label.h
+code.o: level.h
+code.o: noRoption.h
+code.o: nobitfield.h
+code.o: nocross.h
+code.o: nofloat.h
+code.o: nopp.h
+code.o: sizes.h
+code.o: spec_arith.h
+code.o: specials.h
+code.o: stack.h
+code.o: stmt.h
+code.o: target_sizes.h
+code.o: type.h
+code.o: use_tmp.h
+dumpidf.o: Lpars.h
+dumpidf.o: arith.h
+dumpidf.o: debug.h
+dumpidf.o: def.h
+dumpidf.o: expr.h
+dumpidf.o: field.h
+dumpidf.o: idf.h
+dumpidf.o: label.h
+dumpidf.o: nobitfield.h
+dumpidf.o: nofloat.h
+dumpidf.o: nopp.h
+dumpidf.o: spec_arith.h
+dumpidf.o: stack.h
+dumpidf.o: static.h
+dumpidf.o: struct.h
+dumpidf.o: type.h
+error.o: LLlex.h
+error.o: arith.h
+error.o: debug.h
+error.o: errout.h
+error.o: expr.h
+error.o: file_info.h
+error.o: label.h
+error.o: nofloat.h
+error.o: nopp.h
+error.o: spec_arith.h
+error.o: tokenname.h
+field.o: Lpars.h
+field.o: align.h
+field.o: arith.h
+field.o: assert.h
+field.o: code.h
+field.o: debug.h
+field.o: expr.h
+field.o: field.h
+field.o: idf.h
+field.o: label.h
+field.o: nobitfield.h
+field.o: nocross.h
+field.o: nofloat.h
+field.o: nopp.h
+field.o: sizes.h
+field.o: spec_arith.h
+field.o: target_sizes.h
+field.o: type.h
+tokenname.o: LLlex.h
+tokenname.o: Lpars.h
+tokenname.o: arith.h
+tokenname.o: file_info.h
+tokenname.o: idf.h
+tokenname.o: nofloat.h
+tokenname.o: nopp.h
+tokenname.o: spec_arith.h
+tokenname.o: tokenname.h
+LLlex.o: LLlex.h
+LLlex.o: Lpars.h
+LLlex.o: arith.h
+LLlex.o: assert.h
+LLlex.o: class.h
+LLlex.o: debug.h
+LLlex.o: def.h
+LLlex.o: file_info.h
+LLlex.o: idf.h
+LLlex.o: idfsize.h
+LLlex.o: input.h
+LLlex.o: nocross.h
+LLlex.o: nofloat.h
+LLlex.o: nopp.h
+LLlex.o: numsize.h
+LLlex.o: sizes.h
+LLlex.o: spec_arith.h
+LLlex.o: strsize.h
+LLlex.o: target_sizes.h
+LLmessage.o: LLlex.h
+LLmessage.o: Lpars.h
+LLmessage.o: arith.h
+LLmessage.o: file_info.h
+LLmessage.o: idf.h
+LLmessage.o: nofloat.h
+LLmessage.o: nopp.h
+LLmessage.o: spec_arith.h
+input.o: file_info.h
+input.o: input.h
+input.o: inputtype.h
+input.o: nopp.h
+domacro.o: LLlex.h
+domacro.o: Lpars.h
+domacro.o: arith.h
+domacro.o: assert.h
+domacro.o: botch_free.h
+domacro.o: class.h
+domacro.o: debug.h
+domacro.o: file_info.h
+domacro.o: idf.h
+domacro.o: idfsize.h
+domacro.o: ifdepth.h
+domacro.o: input.h
+domacro.o: interface.h
+domacro.o: macro.h
+domacro.o: nofloat.h
+domacro.o: nopp.h
+domacro.o: nparams.h
+domacro.o: parbufsize.h
+domacro.o: spec_arith.h
+domacro.o: textsize.h
+replace.o: LLlex.h
+replace.o: arith.h
+replace.o: assert.h
+replace.o: class.h
+replace.o: debug.h
+replace.o: file_info.h
+replace.o: idf.h
+replace.o: input.h
+replace.o: interface.h
+replace.o: macro.h
+replace.o: nofloat.h
+replace.o: nopp.h
+replace.o: pathlength.h
+replace.o: spec_arith.h
+replace.o: static.h
+replace.o: strsize.h
+init.o: class.h
+init.o: idf.h
+init.o: interface.h
+init.o: macro.h
+init.o: nopp.h
+options.o: align.h
+options.o: arith.h
+options.o: botch_free.h
+options.o: class.h
+options.o: dataflow.h
+options.o: idf.h
+options.o: idfsize.h
+options.o: macro.h
+options.o: noRoption.h
+options.o: nobitfield.h
+options.o: nocross.h
+options.o: nofloat.h
+options.o: nopp.h
+options.o: sizes.h
+options.o: spec_arith.h
+options.o: target_sizes.h
+options.o: use_tmp.h
+scan.o: class.h
+scan.o: idf.h
+scan.o: input.h
+scan.o: interface.h
+scan.o: lapbuf.h
+scan.o: macro.h
+scan.o: nopp.h
+scan.o: nparams.h
+skip.o: LLlex.h
+skip.o: arith.h
+skip.o: class.h
+skip.o: file_info.h
+skip.o: input.h
+skip.o: interface.h
+skip.o: nofloat.h
+skip.o: nopp.h
+skip.o: spec_arith.h
+stack.o: Lpars.h
+stack.o: arith.h
+stack.o: botch_free.h
+stack.o: debug.h
+stack.o: def.h
+stack.o: idf.h
+stack.o: level.h
+stack.o: mes.h
+stack.o: noRoption.h
+stack.o: nobitfield.h
+stack.o: nofloat.h
+stack.o: nopp.h
+stack.o: spec_arith.h
+stack.o: stack.h
+stack.o: struct.h
+stack.o: type.h
+type.o: Lpars.h
+type.o: align.h
+type.o: arith.h
+type.o: botch_free.h
+type.o: def.h
+type.o: idf.h
+type.o: nobitfield.h
+type.o: nocross.h
+type.o: nofloat.h
+type.o: nopp.h
+type.o: sizes.h
+type.o: spec_arith.h
+type.o: target_sizes.h
+type.o: type.h
+ch7mon.o: Lpars.h
+ch7mon.o: arith.h
+ch7mon.o: botch_free.h
+ch7mon.o: def.h
+ch7mon.o: expr.h
+ch7mon.o: idf.h
+ch7mon.o: label.h
+ch7mon.o: nobitfield.h
+ch7mon.o: nofloat.h
+ch7mon.o: nopp.h
+ch7mon.o: spec_arith.h
+ch7mon.o: type.h
+label.o: Lpars.h
+label.o: arith.h
+label.o: def.h
+label.o: idf.h
+label.o: label.h
+label.o: level.h
+label.o: noRoption.h
+label.o: nobitfield.h
+label.o: nofloat.h
+label.o: nopp.h
+label.o: spec_arith.h
+label.o: type.h
+eval.o: Lpars.h
+eval.o: align.h
+eval.o: arith.h
+eval.o: assert.h
+eval.o: atw.h
+eval.o: code.h
+eval.o: dataflow.h
+eval.o: debug.h
+eval.o: def.h
+eval.o: expr.h
+eval.o: idf.h
+eval.o: label.h
+eval.o: level.h
+eval.o: mes.h
+eval.o: nobitfield.h
+eval.o: nocross.h
+eval.o: nofloat.h
+eval.o: nopp.h
+eval.o: sizes.h
+eval.o: spec_arith.h
+eval.o: specials.h
+eval.o: stack.h
+eval.o: target_sizes.h
+eval.o: type.h
+switch.o: Lpars.h
+switch.o: arith.h
+switch.o: assert.h
+switch.o: botch_free.h
+switch.o: code.h
+switch.o: debug.h
+switch.o: density.h
+switch.o: expr.h
+switch.o: idf.h
+switch.o: label.h
+switch.o: noRoption.h
+switch.o: nobitfield.h
+switch.o: nofloat.h
+switch.o: nopp.h
+switch.o: spec_arith.h
+switch.o: switch.h
+switch.o: type.h
+conversion.o: Lpars.h
+conversion.o: arith.h
+conversion.o: nobitfield.h
+conversion.o: nocross.h
+conversion.o: nofloat.h
+conversion.o: sizes.h
+conversion.o: spec_arith.h
+conversion.o: target_sizes.h
+conversion.o: type.h
+util.o: Lpars.h
+util.o: align.h
+util.o: def.h
+util.o: nocross.h
+util.o: nofloat.h
+util.o: regcount.h
+util.o: sizes.h
+util.o: stack.h
+util.o: target_sizes.h
+util.o: use_tmp.h
+util.o: util.h
+blocks.o: Lpars.h
+blocks.o: align.h
+blocks.o: arith.h
+blocks.o: atw.h
+blocks.o: label.h
+blocks.o: nocross.h
+blocks.o: nofloat.h
+blocks.o: sizes.h
+blocks.o: spec_arith.h
+blocks.o: stack.h
+blocks.o: target_sizes.h
+dataflow.o: dataflow.h
+char.o: class.h
+symbol2str.o: Lpars.h

+ 67 - 0
lang/cem/cemcom.ansi/Resolve

@@ -0,0 +1,67 @@
+: create a directory Xsrc with name clashes resolved
+: and run make in that directory
+: '$Header$'
+
+case $# in
+1)	
+	;;
+*)	echo "$0: one argument expected" 1>&2
+	exit 1
+	;;
+esac
+PW=`pwd`
+options=
+case $1 in
+main|emain|lnt)
+	target=$PW/$1
+	;;
+omain)
+	target=$PW/$1
+	options=-DPEEPHOLE
+	;;
+cemain)
+	target=$PW/$1
+	options=-DCODE_EXPANDER
+	;;
+Xlint)
+	target=$1
+	;;
+*)	echo "$0: $1: Illegal argument" 1>&2
+	exit 1
+	;;
+esac
+if test -d ../Xsrc
+then
+	:
+else	mkdir ../Xsrc
+fi
+make EMHOME=$EMHOME longnames
+: remove code generating routines from the clashes list as they are defines.
+: code generating routine names start with C_
+sed '/^C_/d' < longnames > tmp$$
+cclash -c -l7 tmp$$ > ../Xsrc/Xclashes
+rm -f tmp$$
+cd ../Xsrc
+if cmp -s Xclashes clashes
+then
+	:
+else
+	mv Xclashes clashes
+fi
+rm -f Makefile
+for i in `cat $PW/Cfiles`
+do
+	cat >> Makefile <<EOF
+
+$i:	clashes $PW/$i
+	cid -Fclashes < $PW/$i > $i
+EOF
+done
+make EMHOME=$EMHOME `cat $PW/Cfiles`
+rm -f Makefile
+ed - $PW/Makefile <<'EOF'
+/^#EXCLEXCL/,/^#INCLINCL/d
+w Makefile
+q
+EOF
+make EMHOME=$EMHOME COPTIONS=$options CURRDIR=$PW/ $target

+ 145 - 0
lang/cem/cemcom.ansi/SmallPars

@@ -0,0 +1,145 @@
+!File: lint.h
+#undef	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 PREPEND_SCOPES	1	/* collect exa, exp, ina and inp commands
+					and if USE_TMP is defined let them
+					precede the rest of the generated
+					compact code	*/
+#undef USE_TMP		1	/* use C_insertpart, C_endpart mechanism
+					to generate EM-code in the order needed
+					for the code-generators. If not defined,
+					the old-style peephole optimizer is
+					needed.	*/
+
+
+!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
+#undef INP_READ_IN_ONE	1	/* read input file in one	*/
+
+
+!File: nopp.h
+#define 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
+#define 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 */
+
+

+ 8 - 0
lang/cem/cemcom.ansi/Version.c

@@ -0,0 +1,8 @@
+/* $Header$ */
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+#ifndef	lint
+static char Version[] = "ACK CEM compiler Version 3.1";
+#endif	lint

+ 35 - 0
lang/cem/cemcom.ansi/align.h

@@ -0,0 +1,35 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*	 A L I G N M E N T   D E F I N I T I O N S	*/
+
+#include "nofloat.h"
+#include "nocross.h"
+#include "target_sizes.h"
+
+#ifndef NOCROSS
+extern int
+	short_align, word_align, int_align, long_align,
+#ifndef NOFLOAT
+	float_align, double_align, lngdbl_align,
+#endif NOFLOAT
+	pointer_align,
+	struct_align, union_align;
+#else NOCROSS
+#define short_align	((int)AL_SHORT)
+#define word_align	((int)AL_WORD)
+#define int_align	((int)AL_INT)
+#define long_align	((int)AL_LONG)
+#ifndef NOFLOAT
+#define float_align	((int)AL_FLOAT)
+#define double_align	((int)AL_DOUBLE)
+#define	lngdbl_align	((int)AL_LNGDBL)
+#endif NOFLOAT
+#define pointer_align	((int)AL_POINTER)
+#define struct_align	((int)AL_STRUCT)
+#define union_align	((int)AL_UNION)
+#endif NOCROSS
+
+extern arith align();

+ 575 - 0
lang/cem/cemcom.ansi/arith.c

@@ -0,0 +1,575 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*	A R I T H M E T I C   C O N V E R S I O N S	 */
+
+/*	This file contains the routines for the various conversions that
+	may befall operands in C. It is structurally a mess, but I haven't
+	decided yet whether I can't find the right structure or the
+	semantics of C is a mess.
+*/
+
+#include	<alloc.h>
+#include	"lint.h"
+#include	"nofloat.h"
+#include	"nobitfield.h"
+#include	"idf.h"
+#include	"arith.h"
+#include	"sizes.h"
+#include	"type.h"
+#include	"proto.h"
+#include	"label.h"
+#include	"expr.h"
+#include	"Lpars.h"
+#include	"field.h"
+#include	"mes.h"
+#include	"noRoption.h"
+
+extern char *symbol2str();
+extern char options[];
+
+arithbalance(e1p, oper, e2p)	/* RM 6.6 */
+	register struct expr **e1p, **e2p;
+	int oper;
+{
+	/*	The expressions *e1p and *e2p are balanced to be operands
+		of the arithmetic operator oper.
+	*/
+	register int t1, t2, u1, u2;
+
+	t1 = any2arith(e1p, oper);
+	t2 = any2arith(e2p, oper);
+	/* Now t1 and t2 are either INT, LONG, FLOAT, DOUBLE, or LNGDBL */
+
+#ifndef NOFLOAT
+	/*	If any operand has the type long double, the other operand
+		is converted to long double.
+	*/
+	if (t1 == LNGDBL) {
+		if (t2 != LNGDBL)
+			int2float(e2p, lngdbl_type);
+		return;
+	} else if (t2 == LNGDBL) {
+		if (t1 != LNGDBL)
+			int2float(e1p, lngdbl_type);
+		return;
+	}
+
+	/*	If any operand has the type double, the other operand
+		is converted to double.
+	*/
+	if (t1 == DOUBLE) {
+		if (t2 != DOUBLE)
+			int2float(e2p, double_type);
+		return;
+	} else if (t2 == DOUBLE) {
+		if (t1 != DOUBLE)
+			int2float(e1p, double_type);
+		return;
+	}
+
+	/*	If any operand has the type float, the other operand
+		is converted to float.
+	*/
+	if (t1 == FLOAT) {
+		if (t2 != FLOAT)
+			int2float(e2p, float_type);
+		return;
+	} else if (t2 == FLOAT) {
+		if (t1 != FLOAT)
+			int2float(e1p, float_type);
+		return;
+	}
+#endif NOFLOAT
+
+	/* Now they are INT or LONG */
+	u1 = (*e1p)->ex_type->tp_unsigned;
+	u2 = (*e2p)->ex_type->tp_unsigned;
+
+	/*	If either operand has type unsigned long int, the other
+		operand is converted to unsigned long int.
+	*/
+	if (t1 == LONG && u1 && (t2 != LONG || !u2))
+		t2 = int2int(e2p, ulong_type);
+	else if (t2 == LONG && u2 && (t1 != LONG || !u1))
+		t1 = int2int(e1p, ulong_type);
+
+	/*	If one operand has type long int and the other has type unsigned
+		int, if a long int can represent all values of an unsigned int,
+		the operand of type unsigned int is converted to long int; if
+		a long int cannot represent all values of an unsigned int,
+		both operands are converted to unsigned long int.
+	*/
+	if (t1 == LONG && t2 == INT && u2)
+		t2 = int2int(e2p, (int_size<long_size)? long_type : ulong_type);
+	else if (t2 == LONG && t1 == INT && u1)
+		t1 = int2int(e1p, (int_size<long_size)? long_type : ulong_type);
+	if (int_size > long_size) /* sanity check */
+		crash("size of int exceeds size of long");
+
+	/*	If either operand has type long int, the other operand is con-
+		verted to long int.
+	*/
+	if (t1 == LONG && t2 != LONG)
+		t2 = int2int(e2p, long_type);
+	else
+	if (t2 == LONG && t1 != LONG)
+		t1 = int2int(e1p, long_type);
+
+	/*	If either operand has type unsigned int, the other operand
+		is converted to unsigned int.
+		Otherwise, both operands have type int.
+	*/
+	if (u1 && !u2)
+		t2 = int2int(e2p, (t1 == LONG) ? ulong_type : uint_type);
+	else
+	if (!u1 && u2)
+		t1 = int2int(e1p, (t2 == LONG) ? ulong_type : uint_type);
+}
+
+relbalance(e1p, oper, e2p)
+	register struct expr **e1p, **e2p;
+{
+	/*	The expressions *e1p and *e2p are balanced to be operands
+		of the relational operator oper.
+	*/
+	if ((*e1p)->ex_type->tp_fund == FUNCTION)
+		function2pointer(*e1p);
+	if ((*e2p)->ex_type->tp_fund == FUNCTION)
+		function2pointer(*e2p);
+	if ((*e1p)->ex_type->tp_fund == POINTER)
+		ch76pointer(e2p, oper, (*e1p)->ex_type);
+	else
+	if ((*e2p)->ex_type->tp_fund == POINTER)
+		ch76pointer(e1p, oper, (*e2p)->ex_type);
+	else
+	if (	(*e1p)->ex_type == (*e2p)->ex_type &&
+		(*e1p)->ex_type->tp_fund == ENUM
+	)
+		{}
+	else
+		arithbalance(e1p, oper, e2p);
+}
+
+ch76pointer(expp, oper, tp)
+	struct expr **expp;
+	register struct type *tp;
+{
+	/*	Checks whether *expp may be compared to tp using oper,
+		as described in chapter 7.6 and 7.7.
+		tp is known to be a pointer.
+	*/
+	register struct expr *exp = *expp;
+
+	if (exp->ex_type->tp_fund == POINTER)	{
+		if (exp->ex_type != tp)
+			ch7cast(expp, oper, tp);
+	}
+	else
+	if (	is_integral_type(exp->ex_type)
+#ifndef NOROPTION
+		&&
+		(	!options['R'] /* we don't care */ ||
+			(oper == EQUAL || oper == NOTEQUAL || oper == ':')
+		)
+#endif NOROPTION
+	)		/* ch 7.7 */
+		ch7cast(expp, CAST, tp);
+	else	{
+		expr_error(exp, "%s on %s and pointer",
+				symbol2str(oper),
+				symbol2str(exp->ex_type->tp_fund)
+			);
+		ch7cast(expp, oper, tp);
+	}
+}
+
+int
+any2arith(expp, oper)
+	register struct expr **expp;
+	register int oper;
+{
+	/*	Turns any expression into int_type, long_type or
+		double_type.
+	*/
+	int fund;
+
+	switch (fund = (*expp)->ex_type->tp_fund)	{
+	case CHAR:
+	case SHORT:
+	case GENERIC:
+		int2int(expp,
+			(*expp)->ex_type->tp_unsigned ? uint_type : int_type);
+		break;
+	case INT:
+	case LONG:
+		break;
+	case ENUM:
+		/* test the admissibility of the operator */
+		if (	is_test_op(oper) || oper == '=' || oper == PARCOMMA ||
+			oper == ',' || oper == ':'
+		)	{
+			/* allowed by K & R */
+		}
+		else
+#ifndef NOROPTION
+		if (!options['R'])	{
+			/* allowed by us */
+		}
+		else
+			expr_warning(*expp, "%s on enum", symbol2str(oper));
+#endif NOROPTION
+#ifndef	LINT
+		int2int(expp, int_type);
+#endif	LINT
+		break;
+#ifndef	NOFLOAT
+	case FLOAT:
+/*
+		float2float(expp, double_type);
+		break;
+*/
+	case DOUBLE:
+	case LNGDBL:
+		break;
+#endif	NOFLOAT
+#ifndef NOBITFIELD
+	case FIELD:
+		field2arith(expp);
+		break;
+#endif NOBITFIELD
+	default:
+		expr_error(*expp, "operator %s on non-numerical operand (%s)",
+			symbol2str(oper), symbol2str(fund));
+	case ERRONEOUS:
+		erroneous2int(expp);
+		break;
+	}
+
+	return (*expp)->ex_type->tp_fund;
+}
+
+erroneous2int(expp)
+	struct expr **expp;
+{
+	/*	the (erroneous) expression *expp is replaced by an
+		int expression
+	*/
+	register struct expr *exp = *expp;
+	int flags = exp->ex_flags;
+	
+	free_expression(exp);
+	exp = intexpr((arith)0, INT);
+	exp->ex_flags = (flags | EX_ERROR);
+	*expp = exp;
+}
+
+struct expr *
+arith2arith(tp, oper, expr)
+	struct type *tp;
+	int oper;
+	register struct expr *expr;
+{
+	/*	arith2arith constructs a new expression containing a
+		run-time conversion between some arithmetic types.
+	*/
+	register struct expr *new = new_expr();
+	
+	new->ex_file = expr->ex_file;
+	new->ex_line = expr->ex_line;
+	new->ex_type = tp;
+	new->ex_class = Type;
+	return new_oper(tp, new, oper, expr);
+}
+
+int
+int2int(expp, tp)
+	struct expr **expp;
+	register struct type *tp;
+{
+	/*	The expression *expp, which is of some integral type, is
+		converted to the integral type tp.
+	*/
+	register struct expr *exp = *expp;
+	
+	if (is_cp_cst(exp))	{
+		register struct type *tp1 = exp->ex_type;
+
+		exp->ex_type = tp;
+		if (! tp1->tp_unsigned && tp->tp_unsigned) {
+			/*	Avoid "unreal" overflow warnings, such as
+				caused by f.i.:
+					unsigned int x = ~0;
+					unsigned int y = -1;
+			*/
+			extern long full_mask[];
+			long remainder = exp->VL_VALUE &
+						~full_mask[(int)(tp->tp_size)];
+
+			if (remainder == 0 ||
+			    remainder == ~full_mask[(int)(tp->tp_size)]) {
+				exp->VL_VALUE &= ~remainder;
+			}
+		}
+		cut_size(exp);
+	}
+	else	{
+		exp = arith2arith(tp, INT2INT, exp);
+	}
+	*expp = exp;
+	return exp->ex_type->tp_fund;
+}
+
+#ifndef NOFLOAT
+int2float(expp, tp)
+	register struct expr **expp;
+	struct type *tp;
+{
+	/*	The expression *expp, which is of some integral type, is
+		converted to the floating type tp.
+	*/
+	register struct expr *exp = *expp;
+	char buf[32];
+	
+	fp_used = 1;
+	if (is_cp_cst(exp)) {
+		*expp = new_expr();
+		**expp = *exp;
+		sprint(buf+1, "%ld", (long)(exp->VL_VALUE));
+		buf[0] = '-';
+		exp = *expp;
+		exp->ex_type = tp;
+		exp->ex_class = Float;
+		exp->FL_VALUE = Salloc(buf, (unsigned)strlen(buf)+2) + 1;
+		exp->FL_DATLAB = 0;
+	}
+	else	*expp = arith2arith(tp, INT2FLOAT, *expp);
+}
+
+float2int(expp, tp)
+	struct expr **expp;
+	struct type *tp;
+{
+	/*	The expression *expp, which is of some floating type, is
+		converted to the integral type tp.
+	*/
+	
+	fp_used = 1;
+	*expp = arith2arith(tp, FLOAT2INT, *expp);
+}
+
+float2float(expp, tp)
+	register struct expr **expp;
+	struct type *tp;
+{
+	/*	The expression *expp, which is of some floating type, is
+		converted to the floating type tp.
+		There is no need for an explicit conversion operator
+		if the expression is a constant.
+	*/
+	
+	fp_used = 1;
+	if (is_fp_cst(*expp))
+		(*expp)->ex_type = tp;
+	else
+		*expp = arith2arith(tp, FLOAT2FLOAT, *expp);
+}
+#endif NOFLOAT
+
+array2pointer(exp)
+	register struct expr *exp;
+{
+	/*	The expression, which must be an array, is converted
+		to a pointer.
+	*/
+	exp->ex_type = construct_type(POINTER, exp->ex_type->tp_up, 0,
+				     (arith)0, NO_PROTO);
+}
+
+function2pointer(exp)
+	register struct expr *exp;
+{
+	/*	The expression, which must be a function, is converted
+		to a pointer to the function.
+	*/
+	exp->ex_type = construct_type(POINTER, exp->ex_type, 0,
+				     (arith)0, NO_PROTO);
+}
+
+string2pointer(ex)
+	register struct expr *ex;
+{
+	/*	The expression, which must be a string constant, is converted
+		to a pointer to the string-containing area.
+	*/
+	label lbl = data_label();
+
+	code_string(ex->SG_VALUE, ex->SG_LEN, lbl);
+	ex->ex_class = Value;
+	ex->VL_CLASS = Label;
+	ex->VL_LBL = lbl;
+	ex->VL_VALUE = (arith)0;
+}
+
+opnd2integral(expp, oper)
+	register struct expr **expp;
+	int oper;
+{
+	register int fund = (*expp)->ex_type->tp_fund;
+
+	if (fund != INT && fund != LONG)	{
+		expr_error(*expp, "%s operand to %s",
+				symbol2str(fund), symbol2str(oper));
+		erroneous2int(expp);
+		/* fund = INT; */
+	}
+}
+
+opnd2logical(expp, oper)
+	register struct expr **expp;
+	int oper;
+{
+	int fund = (*expp)->ex_type->tp_fund;
+
+	if (fund == FUNCTION || fund == ARRAY) {
+		expr_warning(*expp, "%s operand to %s",
+			symbol2str(fund),
+			symbol2str(oper));
+		if (fund == FUNCTION) {
+			function2pointer(*expp);
+		}
+		else	array2pointer(*expp);
+	}
+#ifndef NOBITFIELD
+	else
+	if (fund == FIELD)
+		field2arith(expp);
+#endif NOBITFIELD
+	switch (fund = (*expp)->ex_type->tp_fund) {
+	case CHAR:
+	case SHORT:
+	case INT:
+	case LONG:
+	case ENUM:
+	case POINTER:
+#ifndef NOFLOAT
+	case FLOAT:
+	case DOUBLE:
+#endif NOFLOAT
+		break;
+	default:
+		expr_error(*expp, "%s operand to %s",
+			symbol2str(fund), symbol2str(oper));
+	case ERRONEOUS:
+		erroneous2int(expp);
+		break;
+	}
+}
+
+opnd2test(expp, oper)
+	register struct expr **expp;
+{
+	opnd2logical(expp, oper);
+	if ((*expp)->ex_class == Oper && is_test_op((*expp)->OP_OPER))
+		{ /* It is already a test */ }
+	else
+		ch7bin(expp, NOTEQUAL, intexpr((arith)0, INT));
+}
+
+int
+is_test_op(oper)
+{
+	switch (oper)	{
+	case '<':
+	case '>':
+	case LESSEQ:
+	case GREATEREQ:
+	case EQUAL:
+	case NOTEQUAL:
+	case '!':
+	case AND:
+	case OR:	/* && and || also impose a test	*/
+		return 1;
+	default:
+		return 0;
+	}
+	/*NOTREACHED*/
+}
+
+any2opnd(expp, oper)
+	register struct expr **expp;
+{
+	if (!*expp)
+		return;
+	switch ((*expp)->ex_type->tp_fund)	{	/* RM 7.1 */
+	case CHAR:
+	case SHORT:
+	case ENUM:
+#ifndef NOFLOAT
+	case FLOAT:
+#endif NOFLOAT
+		any2arith(expp, oper);
+		break;
+	case ARRAY:
+		array2pointer(*expp);
+		break;
+	case POINTER:
+		if ((*expp)->ex_class == String)
+			string2pointer(*expp);
+		break;
+#ifndef NOBITFIELD
+	case FIELD:
+		field2arith(expp);
+		break;
+#endif NOBITFIELD
+	}
+}
+
+#ifndef NOBITFIELD
+field2arith(expp)
+	register struct expr **expp;
+{
+	/*	The expression to extract the bitfield value from the
+		memory word is put in the tree.
+	*/
+	register struct type *tp = (*expp)->ex_type->tp_up;
+	register struct field *fd = (*expp)->ex_type->tp_field;
+	register struct type *atype = tp->tp_unsigned ? uword_type : word_type;
+
+	(*expp)->ex_type = atype;
+
+	if (atype->tp_unsigned)	{	/* don't worry about the sign bit */
+		ch7bin(expp, RIGHT, intexpr((arith)fd->fd_shift, INT));
+		ch7bin(expp, '&', intexpr(fd->fd_mask, INT));
+	}
+	else	{	/* take care of the sign bit: sign extend if needed */
+		arith bits_in_type = atype->tp_size * 8;
+
+		ch7bin(expp, LEFT,
+			intexpr(bits_in_type - fd->fd_width - fd->fd_shift,
+						INT)
+		);
+		ch7bin(expp, RIGHT, intexpr(bits_in_type - fd->fd_width, INT));
+	}
+	ch7cast(expp, CAST, tp);	/* restore its original type */
+}
+#endif NOBITFIELD
+
+#ifndef NOFLOAT
+/*	switch_sign_fp() negates the given floating constant expression
+	The lexical analyser has reserved an extra byte of space in front
+	of the string containing the representation of the floating
+	constant.  This byte contains the '-' character and we have to
+	take care of the first byte the fl_value pointer points to.
+*/
+switch_sign_fp(expr)
+	register struct expr *expr;
+{
+	if (*(expr->FL_VALUE) == '-')
+		++(expr->FL_VALUE);
+	else
+		--(expr->FL_VALUE);
+}
+#endif NOFLOAT

+ 28 - 0
lang/cem/cemcom.ansi/arith.h

@@ -0,0 +1,28 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* COMPILER ARITHMETIC */
+
+/*	Normally the compiler does its internal arithmetics in longs
+	native to the source machine, which is always good for local
+	compilations, and generally OK too for cross compilations
+	downwards and sidewards.  For upwards cross compilation and
+	to save storage on small machines, SPECIAL_ARITHMETICS will
+	be handy.
+*/
+
+#include	"spec_arith.h"
+
+#ifndef	SPECIAL_ARITHMETICS
+
+#include <em_arith.h>		/* obtain definition of "arith"	*/
+
+#else	SPECIAL_ARITHMETICS
+
+/*	All preprocessor arithmetic should be done in longs.
+*/
+#define	arith	long				/* dummy */
+
+#endif	SPECIAL_ARITHMETICS

+ 16 - 0
lang/cem/cemcom.ansi/asm.c

@@ -0,0 +1,16 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*		A S M			*/
+
+/*ARGSUSED*/
+code_asm(s, l)
+	char *s;
+	int l;
+{
+	/*	'asm' '(' string ')' ';'
+	*/
+	error("\"asm\" instruction not implemented");
+}

+ 24 - 0
lang/cem/cemcom.ansi/assert.h

@@ -0,0 +1,24 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*	 A S S E R T I O N    M A C R O   D E F I N I T I O N		*/
+
+/*	At some points in the program, it must be sure that some condition
+	holds true, due to further, successful, processing.  As long as
+	there is no reasonable method to prove that a program is 100%
+	correct, these assertions are needed in some places.
+*/
+#include	"debug.h"	/* UF */
+
+#ifdef	DEBUG
+/*	Note: this macro uses parameter substitution inside strings */
+#define	ASSERT(exp)	(exp || crash("in %s, %u: assertion %s failed", \
+				__FILE__, __LINE__, "exp"))
+#define	NOTREACHED()	crash("in %s, %u: unreachable statement reached", \
+				__FILE__, __LINE__)
+#else
+#define	ASSERT(exp)
+#define	NOTREACHED()
+#endif	DEBUG

+ 10 - 0
lang/cem/cemcom.ansi/atw.h

@@ -0,0 +1,10 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* Align To Word boundary Definition	*/
+
+#include "sizes.h"
+
+#define	ATW(arg)	((((arg) + word_size - 1) / word_size) * word_size)

+ 168 - 0
lang/cem/cemcom.ansi/blocks.c

@@ -0,0 +1,168 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $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"
+#include "sizes.h"
+#include "atw.h"
+#include "align.h"
+#ifndef STB
+#include "label.h"
+#include "stack.h"
+#include "Lpars.h"
+extern arith NewLocal();
+#define LocalPtrVar()	NewLocal(pointer_size, pointer_align, reg_pointer, REGISTER)
+#endif STB
+
+/*	Because EM does not support the loading and storing of
+	objects having other sizes than word fragment and multiple,
+	we need to have a way of transferring these objects, whereby
+	we simulate "loi" and "sti": the address of the source resp.
+	destination is located on top of stack and a call is done
+	to load_block() resp. store_block().
+	===============================================================
+	# Loadblock() works on the stack as follows: ([ ] indicates the
+	# position of the stackpointer)
+	# lower address--->
+	# 1)	| &object
+	# 2)	| ... ATW(sz) bytes ... | sz | &stack_block | &object
+	# 3)	| ... ATW(sz) bytes ...
+	===============================================================
+	Loadblock() pushes ATW(sz) bytes directly onto the stack!
+
+	Store_block() works on the stack as follows:
+	lower address--->
+	1)	| ... ATW(sz) bytes ... | &object
+	2)	| ... ATW(sz) bytes ... | &object | &stack_block | sz
+	3)	<empty>
+
+	If sz is a legal argument for "loi" or "sti", just one EM
+	instruction is generated.
+	In the other cases, the notion of alignment is taken into account:
+	we only push an object of the size accepted by EM onto the stack,
+	while we need a loop to store the stack block into a memory object.
+*/
+store_block(sz, al)
+	arith sz;
+	int al;
+{
+	if (
+		((sz == al) && (word_align % al == 0)) ||
+		(
+			(sz % word_size == 0 || word_size % sz == 0) &&
+			(al % word_align == 0)
+		)
+	)	/* Lots of Irritating Stupid Parentheses */
+		C_sti(sz);
+	else {
+#ifndef STB
+		arith src, dst;
+
+		/* allocate two pointer temporaries */
+		src = LocalPtrVar();
+		dst = LocalPtrVar();
+
+		/* load the addresses */
+		StoreLocal(dst, pointer_size);
+		C_lor((arith)1);	/* push current sp */
+		StoreLocal(src, pointer_size);
+		copy_loop(sz, src, dst);
+		C_asp(ATW(sz));
+		FreeLocal(dst);
+		FreeLocal(src);
+#else STB
+		/*	address of destination lies on the stack	*/
+
+		/*	push address of first byte of block on stack onto
+			the stack by computing it from the current stack
+			pointer position
+		*/
+		C_lor((arith)1);	/* push current sp		*/
+		C_adp(pointer_size);	/* set & to 1st byte of block	*/
+		C_loc(sz);		/* number of bytes to transfer	*/
+		C_cal("__stb");		/* call transfer routine	*/
+		C_asp(pointer_size + pointer_size + int_size + ATW(sz));
+#endif STB
+	}
+}
+
+load_block(sz, al)
+	arith sz;
+	int al;
+{
+	arith esz = ATW(sz);	/* effective size == actual # pushed bytes */
+
+	if (
+		((sz == al) && (word_align % al == 0)) ||
+		(
+			(sz % word_size == 0 || word_size % sz == 0) &&
+			(al % word_align == 0)
+		)
+	)	/* Lots of Irritating Stupid Parentheses */
+		C_loi(sz);
+	else {
+#ifndef STB
+		arith src, dst;
+
+		/* allocate two pointer temporaries */
+		src = LocalPtrVar();
+		dst = LocalPtrVar();
+
+		StoreLocal(src, pointer_size);
+		C_asp(-esz);		/* allocate stack block */
+		C_lor((arith)1);	/* push & of stack block as dst	*/
+		StoreLocal(dst, pointer_size);
+		copy_loop(sz, src, dst);
+		FreeLocal(dst);
+		FreeLocal(src);
+#else STB
+		C_asp(-(esz - pointer_size));	/* allocate stack block */
+		C_lor((arith)1);	/* push & of stack block as dst	*/
+		C_dup(pointer_size);		/* fetch source address	*/
+		C_adp(esz - pointer_size);
+		C_loi(pointer_size);
+		C_loc(sz);			/* # bytes to copy	*/
+		C_cal("__stb");			/* library copy routine	*/
+		C_asp(int_size + pointer_size + pointer_size);
+#endif STB
+	}
+}
+
+#ifndef STB
+copy_loop(sz, src, dst)
+	arith sz, src, dst;
+{
+	/* generate inline byte-copy loop */
+	label l_cont = text_label(), l_stop = text_label();
+
+	C_loc(sz);		/* amount of bytes */
+	C_df_ilb(l_cont);
+	C_dup(word_size);
+	C_zle(l_stop);
+	C_dec();
+	LoadLocal(src, pointer_size);
+	C_dup(pointer_size);
+	C_adp((arith)1);
+	StoreLocal(src, pointer_size);
+	C_loi((arith)1);
+	LoadLocal(dst, pointer_size);
+	C_dup(pointer_size);
+	C_adp((arith)1);
+	StoreLocal(dst, pointer_size);
+	C_sti((arith)1);
+	C_bra(l_cont);
+	C_df_ilb(l_stop);
+	C_asp(word_size);
+}
+#endif STB
+
+#endif	LINT
+

+ 230 - 0
lang/cem/cemcom.ansi/cem.1

@@ -0,0 +1,230 @@
+.TH CEM 1L 86/11/12
+.SH NAME
+cem \- ACK C compiler
+.SH SYNOPSIS
+.B cem
+[ option ] ... file ...
+.SH DESCRIPTION
+.I Cem
+is a
+.I cc (1)-like
+C compiler that uses the C front-end compiler
+.I cemcom (1)
+of the Amsterdam Compiler Kit.
+.I Cem
+interprets its arguments not starting with a '\-' as
+source files, to be compiled by the various parts of the compilation process,
+which are listed below.
+File arguments whose names end with \fB.\fP\fIcharacter\fP are interpreted as
+follows:
+.IP .[ao]
+object file.
+.IP .[ci]
+C source code
+.IP .e
+EM assembler source file.
+.IP .k
+compact EM file, not yet optimized by the EM peephole optimizer.
+.IP .m
+compact EM file, already optimized by the peephole optimizer.
+.IP .s
+assembler file.
+.LP
+The actions to be taken by
+.I cem
+are directed by the type of file argument and the various options that are
+presented to it.
+.PP
+The following set of options, which is a mixture of options interpreted by
+.I cc (1)
+and 
+.I ack (?)
+are interpreted by
+.I cem .
+(The options not specified here are passed to the loader.)
+.IP \fB\-B\fP\fIname\fP
+Use 
+.I name
+as front-end compiler instead of the default 
+.I cemcom (1).
+.br
+Same as "\fB\-Rcem=\fP\fIname\fP".
+.IP \fB\-C\fP
+Run C preprocessor 
+.I /lib/cpp
+only and prevent it from eliding comments.
+.IP \fB\-D\fP\fIname\fP\fB=\fP\fIdef\fP
+Define the 
+.I name
+to the preprocessor, as if by "#define".
+.IP \fB\-D\fP\fIname\fP
+.br
+Same as "\fB\-D\fP\fIname\fP\fB=1\fP".
+.IP \fB\-E\fP
+Run only the macro preprocessor on the named files and send the
+result to standard output.
+.IP \fB\-I\fP\fIdir\fP
+\&"#include" files whose names do not begin with '/' are always
+sought first in the directory of the \fIfile\fP argument, then in directories
+in \fB\-I\fP options, then in directories on a standard list (which in fact
+consists of "/usr/include").
+.IP \fB\-L\fP\fIdir\fP
+Use \fIdir\fP as library-containing directory instead of the default.
+.IP \fB\-N\fP\fIc\fP
+Only effective if ACK pipeline is used. 
+This option causes some default actions and options to be suppressed, according
+to
+.I c :
+.RS
+.IP \fBc\fP
+do not convert from EM a.out to local a.out format (i.e., skip the 
+.B cv
+pass.)
+.IP \fBl\fP
+do not pass the default loader flags to the
+.B ld
+pass.
+.RE
+.IP \fB\-P\fP
+Same as \fB\-E\fP, but sending the result of input file \fIfile\fP\fB.[ceis]\fP
+to \fIfile\fP\fB.i\fP.
+.IP \fB\-R\fP
+Passed to \fIcemcom\fP(1) in order to parse the named C programs according
+to the C language as described in [K&R] (also called \fIRestricted\fP C).
+.IP \fB\-R\fP\fIprog\fP\fB=\fP\fIname\fP
+.br
+Use \fIname\fP as program for phase \fIprog\fP of the compilation instead of
+the default.
+\&\fIProg\fP is one of the following names:
+.RS
+.IP \fBcpp\fP
+macro preprocessor
+.IP \fBcem\fP
+front\-end compiler
+.IP \fBopt\fP
+EM peephole optimizer
+.IP \fBdecode\fP
+EM compact to EM assembler translator
+.IP \fBencode\fP
+EM assembler to EM compact translator
+.IP \fBbe\fP
+EM compact code to target\-machine assembly code compiler
+.IP \fBcg\fP
+same as \fBbe\fP
+.IP \fBas\fP
+assembler
+.IP \fBld\fP
+linker/loader
+.IP \fBcv\fP
+a.out format converting program (only if ACK pipeline is used)
+.RE
+.IP \fB\-R\fP\fIprog\fP\fB\-\fP\fIoption\fP
+.br
+Pass \fB\-\fP\fIoption\fP to the compilation phase indicated by \fIprog\fP.
+.IP \fB\-S\fP
+Same as \fB\-c.s\fP.
+.IP \fB\-U\fP\fIname\fP
+.br
+Remove any initial definition of \fIname\fP.
+.IP \fB\-V\fP\fIcm\fP.\fIn\fP,\ \fB\-V\fIcm\fP.\fIncm\fP.\fIn\fP\ ...
+.br
+Set the size and alignment requirements of the C constructs of the named
+C input files.
+The letter \fIc\fP indicates the simple type, which is one of
+\fBs\fP(short), \fBi\fP(int), \fBl\fP(long), \fBf\fP(float), \fBd\fP(double) or
+\fBp\fP(pointer).
+The \fIm\fP parameter can be used to specify the length of the type (in bytes)
+and the \fIn\fP parameter for the alignment of that type.
+Absence of \fIm\fP or \fIn\fP causes the default value to be retained.
+To specify that the bitfields should be right adjusted instead of the
+default left adjustment, specify \fBr\fP as \fIc\fP parameter
+without parameters.
+.br
+This option is passed directly to \fIcemcom\fP(1).
+.IP \fB\-c\fP
+Same as \fB\-c.o\fP.
+.IP \fB\-c.e\fP
+Produce human-readable EM assembly code on \fIfile\fP\fB.e\fP for the
+named files \fIfile\fP\fB.[cikm]\fP 
+.IP \fB\-c.k\fP
+Compile C source \fIfile\fP\fB.[ci]\fP or
+encode human-readable EM assembly code from \fIfile\fP\fB.e\fP
+into non-optimized compact EM code and write the result on \fIfile\fP\fB.k\fP
+.IP \fB\-c.m\fP
+Compile C source \fIfile\fP\fB.[ci]\fP,
+translate non-optimized EM code from \fIfile\fP\fB.k\fP or
+encode EM assembly code from \fIfile\fP\fB.e\fP
+into optimized compact EM code and write the result on \fIfile\fP\fB.m\fP
+.IP \fB\-c.o\fP
+Suppress the loading phase of the compilation, and force an object file to
+be produced even if only one program is compiled
+.IP \fB\-c.s\fP
+Compile the named \fIfile\fP\fB.[ceikm]\fP input files, and leave the 
+assembly language output on corresponding files suffixed ".s".
+.IP \fB\-k\fP
+Same as \fB\-c.k\fP.
+.IP \fB\-l\fP\fIname\fP
+.br
+Append the library \fBlib\fP\fIname\fP\fB.a\fP to the list of files that
+should be loaded and linked into the final output file.
+The library is searched for in the library directory.
+.IP \fB\-m\fP
+Same as \fB\-c.m\fP.
+.IP \fB\-o\fP\ \fIoutput\fP
+.br
+Name the final output file \fIoutput\fP.
+If this option is used, the default "a.out" will be left undisturbed.
+.IP \fB\-p\fP
+Produce EM profiling code (\fBfil\fP and \fBlin\fP instructions to
+enable an interpreter to keep track of the current location in the
+source code)
+.IP \fB\-t\fP
+Keep the intermediate files, produced during the various phases of the 
+compilation.
+The produced files are named \fIfile\fP\fB.\fP\fIcharacter\fP where 
+\&\fIcharacter\fP indicates the type of the file as listed before.
+.IP \fB\-v\fP
+Verbose.
+Print the commands before they are executed.
+.IP \fB\-vn\fP
+Do not really execute (for debugging purposes only).
+.IP \fB\-vd\fP
+Print some additional information (for debugging purposes only).
+.IP \fB\-\-\fP\fIanything\fP
+.br
+Equivalent to \fB\-Rcem\-\-\fP\fIanything\fP.
+The options 
+.B \-\-C ,
+.B \-\-E
+and
+.B \-\-P
+all have the same effect as respectively
+.B \-C ,
+.B \-E
+and
+.B \-P
+except for the fact that the macro preprocessor is taken to be the
+built\-in preprocessor of the \fBcem\fP phase.
+Most "\-\-" options are used by
+.I cemcom (1)
+to set some internal debug switches.
+.LP
+.SH SEE ALSO
+cemcom(1), cc(1), ack(?), as(1), ld(1)
+.br
+.IP [K&R]
+B.W. Kernighan and D.M. Ritchie, \fIThe C Programming Language\fP,
+Prentice-Hall, 1978.
+.SH DIAGNOSTICS
+.I Cem
+reports any failure of its components.
+.SH BUGS
+.IP \(bu
+All intermediate files are placed in the current working directory which
+causes files with the same name as the intermediate files to be overwritten.
+.IP \(bu
+.B Cem
+only accepts a limited number of arguments to be passed to the components.
+(e.g., 256).
+.IP \(bu
+Please report suggestions and other bugs to erikb@vu44.uucp

+ 764 - 0
lang/cem/cemcom.ansi/cem.c

@@ -0,0 +1,764 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/*	$Header$	*/
+/*
+	Driver for the CEMCOM compiler: works like /bin/cc and accepts
+	most of the options accepted by /bin/cc and /usr/em/bin/ack.
+	Date written: dec 4, 1985
+	Adapted for 68000 (Aug 19, 1986)
+	Merged the vax and mantra versions (Nov 10, 1986)
+	Author: Erik Baalbergen
+*/
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <signal.h>
+
+#define MAXARGC	256	/* maximum number of arguments allowed in a list */
+#define USTR_SIZE	1024	/* maximum length of string variable */
+
+struct arglist {
+	int al_argc;
+	char *al_argv[MAXARGC];
+};
+
+/* some system-dependent variables	*/
+char *PP = "/lib/cpp";
+char *CEM = "/usr/em/lib/em_cemcom";
+char *ENCODE = "/usr/em/lib/em_encode";
+char *DECODE = "/usr/em/lib/em_decode";
+char *OPT = "/usr/em/lib/em_opt";
+char *SHELL = "/bin/sh";
+
+#ifndef MANTRA
+char *CG = "/usr/em/lib/vax4/cg";
+char *AS = "/bin/as";
+char *AS_FIX = "/user1/erikb/bin/mcomm";
+char *LD = "/bin/ld";
+char *LIBDIR = "/user1/cem/lib";
+char *V_FLAG = "-Vs2.2w4.4i4.4l4.4f4.4d8.4p4.4";
+#else MANTRA
+char *CG = "/usr/em/lib/m68k2/cg";
+char *AS = "/usr/em/lib/m68k2/as";
+char *LD = "/usr/em/lib/em_led";
+char *CV = "/usr/em/lib/m68k2/cv";
+char *LIBDIR = "/usr/em/lib/m68k2";
+char *V_FLAG = "-Vs2.2w2.2i2.2l4.2f4.2d8.2p4.2";
+#endif MANTRA
+
+struct arglist LD_HEAD = {
+	2,
+	{
+#ifndef MANTRA
+		"/usr/em/lib/vax4/head_em",
+		"/usr/em/lib/vax4/head_cc"
+#else MANTRA
+		"/usr/em/lib/m68k2/head_em",
+		"/usr/em/lib/m68k2/head_cc"
+#endif MANTRA
+	}
+};
+
+struct arglist LD_TAIL = {
+#ifndef MANTRA
+	4,
+	{
+		"/user1/cem/lib/libc.a",
+		"/user1/cem/lib/stb.o",
+		"/usr/em/lib/vax4/tail_mon",
+		"/usr/em/lib/vax4/tail_em"
+	}
+#else MANTRA
+	7,
+	{
+		"/usr/em/lib/m68k2/tail_cc.1s",
+		"/usr/em/lib/m68k2/tail_cc.2g",
+		"/usr/em/lib/m68k2/tail_cem",
+		"/usr/em/lib/m68k2/tail_fp.a",
+		"/usr/em/lib/m68k2/tail_em.rt",
+		"/usr/em/lib/m68k2/tail_mon",
+		"/usr/em/lib/m68k2/end_em"
+	}
+#endif MANTRA
+};
+
+char *o_FILE = "a.out";
+#ifdef MANTRA
+char *cv_FILE = "cv.out";
+#endif MANTRA
+
+#define remove(str)	(((FLAG(t) == 0) && unlink(str)), (str)[0] = '\0')
+#define cleanup(str)		(str && remove(str))
+#define mkname(dst, s1, s2)	mkstr(dst, (s1), (s2), 0)
+#define init(al)		(al)->al_argc = 1
+#define library(nm) \
+	mkstr(alloc((unsigned int)strlen(nm) + strlen(LIBDIR) + 7), \
+		LIBDIR, "/lib", nm, ".a", 0)
+
+struct arglist SRCFILES, LDFILES, GEN_LDFILES, PP_FLAGS, CEM_FLAGS,
+	OPT_FLAGS, DECODE_FLAGS, ENCODE_FLAGS, CG_FLAGS, AS_FLAGS,
+	O_FLAGS, DEBUG_FLAGS, CALL_VEC;
+
+#ifndef MANTRA
+struct arglist LD_FLAGS;
+#else MANTRA
+struct arglist LD_FLAGS = {
+	5,
+	{
+		"-b0:0x80000",
+		"-a0:2",
+		"-a1:2",
+		"-a2:2",
+		"-a3:2"
+	}
+};
+struct arglist CV_FLAGS;
+int Nc_flag = 0;
+#endif MANTRA
+
+/* option naming */
+#define NAME(chr)	chr
+#define FLAG(chr)	NAME(chr)_flag
+int E_flag, P_flag, S_flag, c_flag, e_flag, k_flag, 
+	m_flag, o_flag, t_flag, v_flag;
+
+/* various passes */
+struct prog {
+	char *p_name;
+	char **p_task;
+	struct arglist *p_flags;
+} ProgParts[] = {
+	{ "cpp",	&PP,		&PP_FLAGS	},
+	{ "cem",	&CEM,		&CEM_FLAGS	},
+	{ "opt",	&OPT,		&OPT_FLAGS	},
+	{ "decode",	&DECODE,	&DECODE_FLAGS	},
+	{ "encode",	&ENCODE,	&ENCODE_FLAGS	},
+	{ "be",		&CG,		&CG_FLAGS	},
+	{ "cg",		&CG,		&CG_FLAGS	},
+	{ "as",		&AS,		&AS_FLAGS	},
+	{ "ld",		&LD,		&LD_FLAGS	},
+#ifdef MANTRA
+	{ "cv",		&CV,		&CV_FLAGS	},
+#endif MANTRA
+	{ 0,		0,		0		}
+};
+
+/* various forward declarations */
+int trap();
+char *mkstr();
+char *alloc();
+long sizeof_file();
+
+/* various globals */
+char *ProgCall = 0;
+int debug = 0;
+int exec = 1;
+int RET_CODE = 0;
+
+main(argc, argv)
+	char *argv[];
+{
+	char *str, **argvec, *file, *ldfile = 0;
+	int count, ext;
+	char Nfile[USTR_SIZE], kfile[USTR_SIZE], sfile[USTR_SIZE],
+		mfile[USTR_SIZE], ofile[USTR_SIZE], BASE[USTR_SIZE];
+	register struct arglist *call = &CALL_VEC;
+
+	set_traps(trap);
+	ProgCall = *argv++;
+	append(&CEM_FLAGS, "-L");
+	while (--argc > 0) {
+		if (*(str = *argv++) != '-') {
+			append(&SRCFILES, str);
+			continue;
+		}
+		switch (str[1]) {
+		case '-':
+			switch (str[2]) {
+			case 'C':
+			case 'E':
+			case 'P':
+				FLAG(E) = 1;
+				append(&PP_FLAGS, str);
+				PP = CEM;
+				FLAG(P) = (str[2] == 'P');
+				break;
+			default:
+				append(&DEBUG_FLAGS, str);
+				break;
+			}
+			break;
+		case 'B':
+			PP = CEM = &str[2];
+			break;
+		case 'C':
+		case 'E':
+		case 'P':
+			FLAG(E) = 1;
+			append(&PP_FLAGS, str);
+			FLAG(P) = (str[1] == 'P');
+			break;
+		case 'c':
+			if (str[2] == '.') {
+				switch (str[3]) {
+				case 's':
+					FLAG(S) = 1;
+					break;
+				case 'k':
+					FLAG(k) = 1;
+					break;
+				case 'o':
+					FLAG(c) = 1;
+					break;
+				case 'm':
+					FLAG(m) = 1;
+					break;
+				case 'e':
+					FLAG(e) = 1;
+					break;
+				default:
+					bad_option(str);
+				}
+			}
+			else
+			if (str[2] == '\0')
+				FLAG(c) = 1;
+			else
+				bad_option(str);
+			break;
+		case 'D':
+		case 'I':
+		case 'U':
+			append(&PP_FLAGS, str);
+			break;
+		case 'k':
+			FLAG(k) = 1;
+			break;
+		case 'l':
+			if (str[2] == '\0')	/* no standard libraries */
+				LD_HEAD.al_argc = LD_TAIL.al_argc = 0;
+			else	/* use library from library directory */
+				append(&SRCFILES, library(&str[2]));
+			break;
+		case 'L':	/* change default library directory */
+			LIBDIR = &str[2];
+			break;
+		case 'm':
+			FLAG(m) = 1;
+			break;
+#ifdef MANTRA
+		case 'N':
+			switch (str[2]) {
+			case 'c': /* no a.out conversion */
+				Nc_flag = 1;
+				break;
+			case 'l': /* no default options to led */
+				LD_FLAGS.al_argc = 0;
+				break;
+			default:
+				bad_option(str);
+			}
+			break;
+#endif MANTRA
+		case 'o':
+			FLAG(o) = 1;
+			if (argc-- < 0)
+				bad_option(str);
+			else
+				o_FILE = *argv++;
+			break;
+		case 'O':
+			append(&O_FLAGS, "-O");
+			break;
+		case 'R':
+			if (str[2] == '\0')
+				append(&CEM_FLAGS, str);
+			else
+				Roption(str);
+			break;
+		case 'S':
+			FLAG(S) = 1;
+			break;
+		case 't':
+			FLAG(t) = 1;
+			break;
+		case 'v':	/* set debug switches */
+			FLAG(v) = 1;
+			switch (str[2]) {
+			case 'd':
+				debug = 1;
+				break;
+			case 'n':	/* no execute */
+				exec = 0;
+				break;
+			case '\0':
+				break;
+			default:
+				bad_option(str);
+			}
+			break;
+		case 'V':
+			V_FLAG = str;
+			break;
+		default:
+			append(&LD_FLAGS, str);
+		}
+	}
+	if (debug) report("Note: debug output");
+	if (exec == 0)
+		report("Note: no execution");
+	count = SRCFILES.al_argc;
+	argvec = &(SRCFILES.al_argv[0]);
+	Nfile[0] = '\0';
+	while (count-- > 0) {
+		basename(file = *argvec++, BASE);
+		if (FLAG(E)) {
+			char ifile[USTR_SIZE];
+
+			init(call);
+			append(call, PP);
+			concat(call, &DEBUG_FLAGS);
+			concat(call, &PP_FLAGS);
+			append(call, file);
+			runvec(call, FLAG(P) ? mkname(ifile, BASE, ".i") : 0);
+			continue;
+		}
+		ext = extension(file);
+		/* .c to .k and .N	*/
+		if (ext == 'c' || ext == 'i') {
+			init(call);
+			append(call, CEM);
+			concat(call, &DEBUG_FLAGS);
+			append(call, V_FLAG);
+			concat(call, &CEM_FLAGS);
+			concat(call, &PP_FLAGS);
+			append(call, file);
+			append(call, mkname(kfile, BASE, ".k"));
+			append(call, mkname(Nfile, BASE, ".N"));
+			if (runvec(call, (char *)0)) {
+				file = kfile;
+				ext = 'k';
+				if (sizeof_file(Nfile) <= 0L)
+					remove(Nfile);
+			}
+			else {
+				remove(kfile);
+				remove(Nfile);
+				continue;
+			}
+		}
+		/* .e to .k */
+		if (ext == 'e') {
+			init(call);
+			append(call, ENCODE);
+			concat(call, &ENCODE_FLAGS);
+			append(call, file);
+			append(call, mkname(kfile, BASE, ".k"));
+			if (runvec(call, (char *)0) == 0)
+				continue;
+			file = kfile;
+			ext = 'k';
+		}
+		if (FLAG(k))
+			continue;
+		/* decode .k or .m */
+		if (FLAG(e) && (ext == 'k' || ext == 'm')) {
+			char efile[USTR_SIZE];
+			init(call);
+			append(call, DECODE);
+			concat(call, &DECODE_FLAGS);
+			append(call, file);
+			append(call, mkname(efile, BASE, ".e"));
+			runvec(call, (char *)0);
+			cleanup(kfile);
+			continue;
+		}
+		/* .k to .m */
+		if (ext == 'k') {
+			init(call);
+			append(call, OPT);
+			concat(call, &OPT_FLAGS);
+			append(call, file);
+			if (runvec(call, mkname(mfile, BASE, ".m")) == 0)
+				continue;
+			file = mfile;
+			ext = 'm';
+			cleanup(kfile);
+		}
+		if (FLAG(m))
+			continue;
+		/* .m to .s */
+		if (ext == 'm') {
+			init(call);
+			append(call, CG);
+			concat(call, &CG_FLAGS);
+			append(call, file);
+			append(call, mkname(sfile, BASE, ".s"));
+			if (runvec(call, (char *)0) == 0)
+				continue;
+			if (Nfile[0] != '\0') {
+#ifndef MANTRA
+				init(call);
+				append(call, AS_FIX);
+				append(call, Nfile);
+				append(call, sfile);
+				runvec(call, (char *)0);
+#endif MANTRA
+				remove(Nfile);
+			}
+			cleanup(mfile);
+			file = sfile;
+			ext = 's';
+		}
+		if (FLAG(S))
+			continue;
+		/* .s to .o */
+		if (ext == 's') {
+			ldfile = FLAG(c) ?
+				ofile :
+				alloc((unsigned)strlen(BASE) + 3);
+			init(call);
+			append(call, AS);
+			concat(call, &AS_FLAGS);
+#ifdef MANTRA
+			append(call, "-");
+#endif MANTRA
+			append(call, "-o");
+			append(call, mkname(ldfile, BASE, ".o"));
+			append(call, file);
+			if (runvec(call, (char *)0) == 0)
+				continue;
+			file = ldfile;
+			ext = 'o';
+			cleanup(sfile);
+		}
+		if (FLAG(c))
+			continue;
+		append(&LDFILES, file);
+		if (ldfile) {
+			append(&GEN_LDFILES, ldfile);
+			ldfile = 0;
+		}
+	}
+	/* *.o to a.out */
+	if (RET_CODE == 0 && LDFILES.al_argc > 0) {
+		init(call);
+		append(call, LD);
+		concat(call, &LD_FLAGS);
+		append(call, "-o");
+#ifndef MANTRA
+		append(call, o_FILE);
+#else MANTRA
+		append(call, Nc_flag ? o_FILE : cv_FILE);
+#endif MANTRA
+		concat(call, &LD_HEAD);
+		concat(call, &LDFILES);
+		concat(call, &LD_TAIL);
+		if (runvec(call, (char *)0)) {
+			register i = GEN_LDFILES.al_argc;
+
+			while (i-- > 0)
+				remove(GEN_LDFILES.al_argv[i]);
+#ifdef MANTRA
+			/* convert to local a.out format */
+			if (Nc_flag == 0) {
+				init(call);
+				append(call, CV);
+				concat(call, &CV_FLAGS);
+				append(call, cv_FILE);
+				append(call, o_FILE);
+				if (runvec(call, (char *)0))
+					remove(cv_FILE);
+			}
+#endif MANTRA
+		}
+	}
+	exit(RET_CODE);
+}
+
+#define BUFSIZE  (USTR_SIZE * MAXARGC)
+char alloc_buf[BUFSIZE];
+
+char *
+alloc(u)
+	unsigned u;
+{
+	static char *bufptr = &alloc_buf[0];
+	register char *p = bufptr;
+
+	if ((bufptr += u) >= &alloc_buf[BUFSIZE])
+		panic("no space");
+	return p;
+}
+
+append(al, arg)
+	register struct arglist *al;
+	char *arg;
+{
+	if (al->al_argc >= MAXARGC)
+		panic("argument list overflow");
+	al->al_argv[(al->al_argc)++] = arg;
+}
+
+concat(al1, al2)
+	struct arglist *al1, *al2;
+{
+	register int i = al2->al_argc;
+	register char **p = &(al1->al_argv[al1->al_argc]);
+	register char **q = &(al2->al_argv[0]);
+
+	if ((al1->al_argc += i) >= MAXARGC)
+		panic("argument list overflow");
+	while (i-- > 0)
+		*p++ = *q++;
+}
+
+/*	The next function is a dirty old one, taking a variable number of
+	arguments.
+	Take care that the last argument is a null-valued pointer!
+*/
+/*VARARGS1*/
+char *
+mkstr(dst, arg)
+	char *dst, *arg;
+{
+	char **vec = (char **) &arg;
+	register char *p;
+	register char *q = dst;
+
+	while (p = *vec++) {
+		while (*q++ = *p++);
+		q--;
+	}
+	return dst;
+}
+
+Roption(str)
+	char *str;	/* of the form "prog=/-arg"	*/
+{
+	char *eq;
+	char *prog, *arg;
+	char bc;
+	char *cindex();
+
+	prog = &str[2];
+	if (eq = cindex(prog, '='))
+		bc = '=';
+	else
+	if (eq = cindex(prog, '-'))
+		bc = '-';
+	else {
+		bad_option(str);
+		return;
+	}
+	*eq++ = '\0';
+	if (arg = eq) {
+		char *opt = 0;
+		struct prog *pp = &ProgParts[0];
+
+		if (bc == '-')
+			opt = mkstr(alloc((unsigned)strlen(arg) + 2),
+								"-", arg, 0);
+		while (pp->p_name) {
+			if (strcmp(prog, pp->p_name) == 0) {
+				if (opt)
+					append(pp->p_flags, opt);
+				else
+					*(pp->p_task) = arg;
+				return;
+			}
+			pp++;
+		}
+	}
+	bad_option(str);
+}
+
+basename(str, dst)
+	char *str;
+	register char *dst;
+{
+	register char *p1 = str;
+	register char *p2 = p1;
+
+	while (*p1)
+		if (*p1++ == '/')
+			p2 = p1;
+	p1--;
+	if (*--p1 == '.') {
+		*p1 = '\0';
+		while (*dst++ = *p2++) {}
+		*p1 = '.';
+	}
+	else
+		while (*dst++ = *p2++) {}
+}
+
+int
+extension(fn)
+	register char *fn;
+{
+	char c;
+
+	while (*fn++) {}
+	fn--;
+	c = *--fn;
+	return (*--fn == '.') ? c : 0;
+}
+
+long
+sizeof_file(nm)
+	char *nm;
+{
+	struct stat stbuf;
+
+	if (stat(nm, &stbuf) == 0)
+		return stbuf.st_size;
+	return -1;
+}
+
+char * sysmsg[]  = {
+	0,
+	"Hangup",
+	"Interrupt",
+	"Quit",
+	"Illegal instruction",
+	"Trace/BPT trap",
+	"IOT trap",
+	"EMT trap",
+	"Floating exception",
+	"Killed",
+	"Bus error",
+	"Memory fault",
+	"Bad system call",
+	"Broken pipe",
+	"Alarm call",
+	"Terminated",
+	"Signal 16"
+};
+
+runvec(vec, outp)
+	struct arglist *vec;
+	char *outp;
+{
+	int status, fd;
+	char *task = vec->al_argv[1];
+
+	vec->al_argv[vec->al_argc] = 0;
+	if (FLAG(v))
+		print_vec(vec);
+	if (exec == 0)
+		return 1;
+	if (fork() == 0) {	/* start up the process */
+		extern int errno;
+		if (outp) {	/* redirect standard output	*/
+			close(1);
+			if ((fd = creat(outp, 0666)) < 0)
+				panic("cannot create %s", outp);
+			if (fd != 1)
+				panic("illegal redirection");
+		}
+		if (debug) report("exec %s", task);
+		execv(task, &(vec->al_argv[1]));
+		/* not an a.out file, let's try it with the SHELL */
+		if (debug) report("try it with %s", SHELL);
+		if (errno == ENOEXEC) {
+			vec->al_argv[0] = SHELL;
+			execv(SHELL, &(vec->al_argv[0]));
+		}
+		/* failed, so ... */
+		panic("cannot execute %s", task);
+		exit(1);
+	}
+	else {
+		int loworder, highorder, sig;
+
+		wait(&status);
+		loworder = status & 0377;
+		highorder = (status >> 8) & 0377;
+		if (loworder == 0) {
+			if (highorder)
+				report("%s: exit status %d", task, highorder);
+			return highorder ? ((RET_CODE = 1), 0) : 1;
+		}
+		else {
+			sig = loworder & 0177;
+			if (sig == 0177)
+				report("%s: stopped by ptrace", task);
+			else
+			if (sysmsg[sig])
+				report("%s: %s%s", task, sysmsg[sig],
+					(loworder & 0200)
+						? " - core dumped"
+						: "");
+			RET_CODE = 1;
+			return 0;
+		}
+	}
+	/*NOTREACHED*/
+}
+
+bad_option(str)
+	char *str;
+{
+	report("bad option %s", str);
+}
+
+/*VARARGS1*/
+report(fmt, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)
+	char *fmt;
+{
+	fprintf(stderr, "%s: ", ProgCall);
+	fprintf(stderr, fmt, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+	fprintf(stderr, "\n");
+}
+
+/*VARARGS1*/
+panic(fmt, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)
+	char *fmt;
+{
+	fprintf(stderr, "%s: ", ProgCall);
+	fprintf(stderr, fmt, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+	fprintf(stderr, "\n");
+	exit(1);
+}
+
+set_traps(f)
+	int (*f)();
+{
+	signal(SIGHUP, f);
+	signal(SIGINT, f);
+	signal(SIGQUIT, f);
+	signal(SIGALRM, f);
+	signal(SIGTERM, f);
+}
+
+/*ARGSUSED*/
+trap(sig)
+{
+	set_traps(SIG_IGN);
+	panic("Trapped");
+}
+
+print_vec(vec)
+	struct arglist *vec;
+{
+	register i;
+
+	for (i = 1; i < vec->al_argc; i++)
+		printf("%s ", vec->al_argv[i]);
+	printf("\n");
+}
+
+char *
+cindex(s, c)
+	char *s, c;
+{
+	while (*s)
+		if (*s++ == c)
+			return s - 1;
+	return (char *) 0;
+}

+ 79 - 0
lang/cem/cemcom.ansi/cemcom.1

@@ -0,0 +1,79 @@
+.TH EM_CEMCOM 6ACK
+.ad
+.SH NAME
+em_cemcom \- C to EM compiler
+.SH SYNOPSIS
+\fB~/em/lib/em_cemcom\fP [\fIoptions\fP] \fIsource \fP[\fIdestination \fP[\fInamelist\fP]]
+.SH DESCRIPTION
+\fICemcom\fP is a compiler that translates C programs
+into EM compact code.
+The input is taken from \fIsource\fP, while the
+EM code is written on \fIdestination\fP.
+If either of these two names is "\fB-\fP", standard input or output respectively
+is taken.
+The file \fInamelist\fP, if supplied, will contain a list of the names
+of external, so-called \fBcommon\fP, variables.
+When the preprocessor is invoked to run stand-alone, \fIdestination\fP
+needs not be specified.
+.br
+\fIOptions\fP is a, possibly empty, sequence of the following combinations:
+.IP \fB\-D\fIname\fR=\fItext\fR
+.br
+define \fIname\fR as a macro with \fItext\fR as its replacement text.
+.IP \fB\-D\fIname\fR
+.br
+the same as \fB\-D\fIname\fR=1.
+.IP \fB\-I\fIdirname\fR
+.br
+insert \fIdirname\fR in the list of include directories.
+.IP \fB\-M\fP\fIn\fP
+set maximum identifier length to \fIn\fP.
+.IP \fB\-n\fR
+do not generate EM register messages.
+The user-declared variables are not stored into registers on the target
+machine.
+.IP \fB\-L\fR
+don't generate the EM \fBfil\fR and \fBlin\fR instructions 
+that usually are generated to enable
+an interpreter to keep track of the current location in the source code.
+.IP \fB\-p\fR
+generate code at each procedure entry to call the routine
+.BR procentry ,
+and at each return to call the routine
+.BE procexit .
+These routines are supplied with one parameter, a pointer to a
+string containing the name of the procedure.
+.IP \fB\-R\fR
+interpret the input as restricted C (according to the language as 
+described in \fIThe C programming language\fR by Kernighan and Ritchie.)
+.IP \fB\-U\fIname\fR
+.br
+get rid of the compiler-predefined macro \fIname\fR.
+.IP \fB\-V\fIcm\fR.\fIn\fR,\ \fB\-V\fIcm\fR.\fIncm\fR.\fIn\fR\ ...
+.br
+set the size and alignment requirements.
+The letter \fIc\fR indicates the simple type, which is one of
+\fBs\fR(short), \fBi\fR(int), \fBl\fR(long), \fBf\fR(float), \fBd\fR(double) or
+\fBp\fR(pointer).
+The \fIm\fR parameter can be used to specify the length of the type (in bytes)
+and the \fIn\fR parameter for the alignment of that type.
+Absence of \fIm\fR or \fIn\fR causes the default value to be retained.
+To specify that the bitfields should be right adjusted instead of the
+default left adjustment, specify \fBr\fR as \fIc\fR parameter.
+.IP \fB\-w\fR
+suppress warning messages
+.IP \fB\-\-\fItext\fR
+.br
+where \fItext\fR can be either of the above or
+a debug flag of the compiler (which is not useful for the common user.)
+This feature can be used in various shell scripts and surrounding programs
+to force a certain option to be handed over to \fBcemcom\fR.
+.LP
+.SH FILES
+.IR ~em/lib/em_cemcom :
+the compiler
+.SH DIAGNOSTICS
+All warning and error messages are written on standard error output.
+.SH REFERENCE
+Baalbergen, E.H., D. Grune, M. Waage ;"\fIThe CEM compiler\fR", 
+Informatica Manual IM-4

+ 540 - 0
lang/cem/cemcom.ansi/ch7.c

@@ -0,0 +1,540 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $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"
+#include	"idf.h"
+#include	"arith.h"
+#include	"proto.h"
+#include	"type.h"
+#include	"struct.h"
+#include	"label.h"
+#include	"expr.h"
+#include	"def.h"
+#include	"Lpars.h"
+#include	"assert.h"
+#include	"file_info.h"
+
+extern char options[];
+extern char *symbol2str();
+
+/*	Most expression-handling routines have a pointer to a
+	(struct type *) as first parameter. The object under the pointer
+	gets updated in the process.
+*/
+
+ch7sel(expp, oper, idf)
+	struct expr **expp;
+	struct idf *idf;
+{
+	/*	The selector idf is applied to *expp; oper may be '.' or
+		ARROW.
+	*/
+	register struct expr *exp;
+	register struct type *tp;
+	register struct sdef *sd;
+
+	any2opnd(expp, oper);
+	exp = *expp;
+	tp = exp->ex_type;
+	if (oper == ARROW)	{
+		if (tp->tp_fund == POINTER &&
+		    ( tp->tp_up->tp_fund == STRUCT ||
+		      tp->tp_up->tp_fund == UNION))	/* normal case */
+			tp = tp->tp_up;
+		else {	/* constructions like "12->selector" and
+				"char c; c->selector"
+			*/
+			switch (tp->tp_fund)	{
+			case INT:
+			case LONG:
+				/* Allowed by RM 14.1 */
+				ch7cast(expp, CAST, pa_type);
+				sd = idf2sdef(idf, tp);
+				tp = sd->sd_stype;
+				break;
+			case POINTER:
+				break;
+			default:
+				expr_error(exp, "-> applied to %s",
+					symbol2str(tp->tp_fund));
+			case ERRONEOUS:
+				exp->ex_type = error_type;
+				return;
+			}
+		}
+	} /* oper == ARROW */
+	else { /* oper == '.' */
+		/* filter out illegal expressions "non_lvalue.sel" */
+		if (!exp->ex_lvalue) {
+			expr_error(exp, "dot requires lvalue");
+			return;
+		}
+	}
+	exp = *expp;
+	switch (tp->tp_fund)	{
+	case POINTER:	/* for int *p;	p->next = ...	*/
+	case STRUCT:
+	case UNION:
+		break;
+	case INT:
+	case LONG:
+		/* warning will be given by idf2sdef() */
+		break;
+	default:
+		if (!is_anon_idf(idf))
+			expr_error(exp, "selector %s applied to %s",
+				idf->id_text, symbol2str(tp->tp_fund));
+	case ERRONEOUS:
+		exp->ex_type = error_type;
+		return;
+	}
+	sd = idf2sdef(idf, tp);
+	if (oper == '.')	{
+		/*	there are 3 cases in which the selection can be
+			performed compile-time: 
+			I:	n.sel (n either an identifier or a constant)
+			II:	(e.s1).s2 (transformed into (e.(s1+s2)))
+			III:	(e->s1).s2 (transformed into (e->(s1+s2)))
+				The code performing these conversions is
+				extremely obscure.
+		*/
+		if (exp->ex_class == Value)	{
+			/*	It is an object we know the address of; so
+				we can calculate the address of the
+				selected member 
+			*/
+			exp->VL_VALUE += sd->sd_offset;
+			exp->ex_type = sd->sd_type;
+			if (exp->ex_type == error_type)
+				exp->ex_flags |= EX_ERROR;
+		}
+		else
+		if (exp->ex_class == Oper)	{
+			struct oper *op = &(exp->ex_object.ex_oper);
+			
+			if (op->op_oper == '.' || op->op_oper == ARROW)	{
+				ASSERT(is_cp_cst(op->op_right));
+				op->op_right->VL_VALUE += sd->sd_offset;
+				exp->ex_type = sd->sd_type;
+				if (exp->ex_type == error_type)
+					exp->ex_flags |= EX_ERROR;
+			}
+			else
+				exp = new_oper(sd->sd_type, exp, '.',
+						intexpr(sd->sd_offset, INT));
+		}
+	}
+	else /* oper == ARROW */
+		exp = new_oper(sd->sd_type,
+			exp, oper, intexpr(sd->sd_offset, INT));
+	exp->ex_lvalue = (sd->sd_type->tp_fund != ARRAY);
+	if (sd->sd_type->tp_typequal & TQ_CONST)
+		exp->ex_flags |= EX_READONLY;
+	if (sd->sd_type->tp_typequal & TQ_VOLATILE)
+		exp->ex_flags |= EX_VOLATILE;
+	*expp = exp;
+}
+
+ch7incr(expp, oper)
+	struct expr **expp;
+{
+	/*	The monadic prefix/postfix incr/decr operator oper is
+		applied to *expp.
+	*/
+	ch7asgn(expp, oper, intexpr((arith)1, INT));
+}
+
+ch7cast(expp, oper, tp)
+	register struct expr **expp;
+	register struct type *tp;
+{
+	/*	The expression *expp is cast to type tp; the cast is
+		caused by the operator oper.  If the cast has
+		to be passed on to run time, its left operand will be an
+		expression of class Type.
+	*/
+	register struct type *oldtp;
+
+	if ((*expp)->ex_type->tp_fund == FUNCTION)
+		function2pointer(*expp);
+	if ((*expp)->ex_type->tp_fund == ARRAY)
+		array2pointer(*expp);
+	if ((*expp)->ex_class == String)
+		string2pointer(*expp);
+	oldtp = (*expp)->ex_type;
+
+#ifndef NOBITFIELD
+	if (oldtp->tp_fund == FIELD)	{
+		field2arith(expp);
+		ch7cast(expp, oper, tp);
+	}
+	else
+	if (tp->tp_fund == FIELD) {
+		ch7cast(expp, oper, tp->tp_up);
+	}
+	else
+#endif NOBITFIELD
+	if (equal_type(tp, oldtp)) {
+		/* life is easy */
+	}
+	else
+	if (tp->tp_fund == VOID) {
+		/* easy again */
+		(*expp)->ex_type = void_type;
+	}
+	else
+	if (is_arith_type(oldtp) && is_arith_type(tp))	{
+		int oldi = is_integral_type(oldtp);
+		int i = is_integral_type(tp);
+
+		if (oldi && i)	{
+			if (	oper != CAST
+			&&	(	tp->tp_fund == ENUM
+				||	oldtp->tp_fund == ENUM
+				)
+			) {
+				expr_warning(*expp,
+					"dubious %s on enum",
+					symbol2str(oper));
+			}
+#ifdef	LINT
+			if (oper == CAST)
+				(*expp)->ex_type = tp;
+			else
+				int2int(expp, tp);
+#else	LINT
+			int2int(expp, tp);
+#endif	LINT
+		}
+#ifndef NOFLOAT
+		else
+		if (oldi && !i)	{
+			if (oldtp->tp_fund == ENUM && oper != CAST)
+				expr_warning(*expp,
+					"conversion of enum to %s\n",
+					symbol2str(tp->tp_fund));
+#ifdef	LINT
+			if (oper == CAST)
+				(*expp)->ex_type = tp;
+			else
+				int2float(expp, tp);
+#else	LINT
+			int2float(expp, tp);
+#endif	LINT
+		}
+		else
+		if (!oldi && i) {
+#ifdef	LINT
+			if (oper == CAST)
+				(*expp)->ex_type = tp;
+			else
+				float2int(expp, tp);
+#else	LINT
+			float2int(expp, tp);
+#endif	LINT
+		}
+		else {
+			/* !oldi && !i */
+#ifdef	LINT
+			if (oper == CAST)
+				(*expp)->ex_type = tp;
+			else
+				float2float(expp, tp);
+#else	LINT
+			float2float(expp, tp);
+#endif	LINT
+		}
+#else NOFLOAT
+		else {
+			crash("(ch7cast) floats not implemented\n");
+			/*NOTREACHED*/
+		}
+#endif NOFLOAT
+	}
+	else
+	if (oldtp->tp_fund == POINTER && tp->tp_fund == POINTER)	{
+		if (oper == CASTAB)
+			expr_warning(*expp, "incompatible pointers");
+		else
+		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
+	if (oldtp->tp_fund == POINTER && is_integral_type(tp))	{
+		/* from pointer to integral */
+		if (oper != CAST)
+			expr_warning(*expp,
+				"illegal conversion of pointer to %s",
+				symbol2str(tp->tp_fund));
+		if (oldtp->tp_size > tp->tp_size)
+			expr_warning(*expp,
+				"conversion of pointer to %s loses accuracy",
+				symbol2str(tp->tp_fund));
+		if (oldtp->tp_size != tp->tp_size)
+			int2int(expp, tp);
+		else
+			(*expp)->ex_type = tp;
+	}
+	else
+	if (tp->tp_fund == POINTER && is_integral_type(oldtp))	{
+		/* from integral to pointer */
+		switch (oper)	{
+		case CAST:
+			break;
+		case CASTAB:
+		case EQUAL:
+		case NOTEQUAL:
+		case '=':
+		case RETURN:
+			if (is_cp_cst(*expp) && (*expp)->VL_VALUE == (arith)0)
+				break;
+		default:
+			expr_warning(*expp,
+				"illegal conversion of %s to pointer",
+				symbol2str(oldtp->tp_fund));
+			break;
+		}
+		if (oldtp->tp_size > tp->tp_size)
+			expr_warning(*expp,
+				"conversion of %s to pointer loses accuracy",
+				symbol2str(oldtp->tp_fund));
+		if (oldtp->tp_size != tp->tp_size)
+			int2int(expp, tp);
+		else
+			(*expp)->ex_type = tp;
+	}
+	else
+	if (oldtp->tp_fund == ERRONEOUS) {
+		/* we just won't look */
+		(*expp)->ex_type = tp;	/* brute force */
+	}
+	else
+	if (oldtp->tp_size == tp->tp_size && oper == CAST)	{
+		expr_warning(*expp, "dubious conversion based on equal size");
+		(*expp)->ex_type = tp;		/* brute force */
+	}
+	else	{
+		if (oldtp->tp_fund != ERRONEOUS && tp->tp_fund != ERRONEOUS)
+			expr_error(*expp, "cannot convert %s to %s",
+				symbol2str(oldtp->tp_fund),
+				symbol2str(tp->tp_fund)
+			);
+		(*expp)->ex_type = tp;		/* brute force */
+	}
+}
+
+/*	Determine whether two types are equal.
+*/
+equal_type(tp, otp)
+	register struct type *tp, *otp;
+{
+	if (tp == otp)
+		return 1;
+	if (!tp || !otp)
+		return 0;
+
+	if (tp->tp_fund != otp->tp_fund)
+		return 0;
+	if (tp->tp_unsigned != otp->tp_unsigned)
+		return 0;
+	if (tp->tp_align != otp->tp_align)
+		return 0;
+	if (tp->tp_fund != ARRAY)
+		if (tp->tp_size != otp->tp_size)
+			return 0;
+
+	switch (tp->tp_fund) {
+
+	case FUNCTION:
+		/*	If both types have parameter type lists, the type of
+			each parameter in the composite parameter type list
+			is the composite type of the corresponding paramaters.
+		*/
+		if (tp->tp_proto && otp->tp_proto &&
+		    !equal_proto(tp->tp_proto, otp->tp_proto))
+			return 0;
+		return equal_type(tp->tp_up, otp->tp_up);
+
+	case ARRAY:
+		/*	If one type is an array of known size, the composite
+			type is an array of that size
+		*/
+		if (tp->tp_size != otp->tp_size &&
+		     (tp->tp_size != -1 && otp->tp_size != -1))
+			return 0;
+		return equal_type(tp->tp_up, otp->tp_up);
+
+	case POINTER:
+	case FIELD:
+		return equal_type(tp->tp_up, otp->tp_up);
+
+	case STRUCT:
+	case UNION:
+	case ENUM:
+		return tp->tp_idf == otp->tp_idf && tp->tp_sdef == otp->tp_sdef;
+
+	default:
+		return 1;
+	}
+}
+
+equal_proto(pl, opl)
+	register struct proto *pl, *opl;
+{
+	if (pl == opl)
+		return 1;
+
+	/*	If only one type is a function type with a parameter type list
+		(a function prototype), the composite type is a function
+		prototype with parameter type list.
+	*/
+	if (pl == 0 || opl == 0) return 0;
+
+	if (pl->pl_flag != opl->pl_flag)
+		return 0;
+
+	if (!equal_type(pl->pl_type, opl->pl_type))
+		return 0;
+
+	return equal_proto(pl->next, opl->next);
+}
+
+ch7asgn(expp, oper, expr)
+	struct expr **expp;
+	struct expr *expr;
+{
+	/*	The assignment operators.
+		"f op= e" should be interpreted as
+		"f = (typeof f)((typeof (f op e))f op (typeof (f op e))e)"
+		and not as "f = f op (typeof f)e".
+		Consider, for example, (i == 10) i *= 0.9; (i == 9), where
+		typeof i == int.
+		The resulting expression tree becomes:
+				op=
+				/ \
+			       /   \
+			      f     (typeof (f op e))e
+		EVAL should however take care of evaluating (typeof (f op e))f
+	*/
+	register struct expr *exp = *expp;
+	int fund = exp->ex_type->tp_fund;
+	int vol = 0;
+	struct type *tp;
+
+	/* We expect an lvalue */
+	if (!exp->ex_lvalue)	{
+		expr_error(exp, "no lvalue in lhs of %s", symbol2str(oper));
+		exp->ex_depth = 99;	/* no direct store/load at EVAL() */
+			/* what is 99 ??? DG */
+	}
+	if (exp->ex_flags & EX_READONLY)
+		strict("lhs of assignment is read-only");
+
+	/*	Preserve volatile markers across the tree.
+		This is questionable, depending on the way the optimizer
+		wants this information.
+	vol = (exp->ex_flags & EX_VOLATILE) || (expr->ex_flags & EX_VOLATILE);
+	*/
+
+	if (oper == '=') {
+		ch7cast(&expr, oper, exp->ex_type);
+		tp = expr->ex_type;
+	}
+	else {	/* turn e into e' where typeof(e') = typeof (f op e) */
+		struct expr *extmp = intexpr((arith)0, INT);
+
+		/* this is really $#@&*%$# ! */
+		/* if you correct this, please correct lint_new_oper() too */
+		extmp->ex_lvalue = 1;
+		extmp->ex_type = exp->ex_type;
+		ch7bin(&extmp, oper, expr);
+		/* Note that ch7bin creates a tree of the expression
+			((typeof (f op e))f op (typeof (f op e))e),
+		   where f ~ extmp and e ~ expr.
+		   We want to use (typeof (f op e))e.
+		   Ch7bin does not create a tree if both operands
+		   were illegal or constants!
+		*/
+		tp = extmp->ex_type;	/* perform the arithmetic in type tp */
+		if (extmp->ex_class == Oper) {
+			expr = extmp->OP_RIGHT;
+			extmp->OP_RIGHT = NILEXPR;
+			free_expression(extmp);
+		}
+		else
+			expr = extmp;
+	}
+#ifndef NOBITFIELD
+	if (fund == FIELD)
+		exp = new_oper(exp->ex_type->tp_up, exp, oper, expr);
+	else
+		exp = new_oper(exp->ex_type, exp, oper, expr);
+#else NOBITFIELD
+	exp = new_oper(exp->ex_type, exp, oper, expr);
+#endif NOBITFIELD
+	exp->OP_TYPE = tp;	/* for EVAL() */
+	exp->ex_flags |= vol ? (EX_SIDEEFFECTS|EX_VOLATILE) : EX_SIDEEFFECTS;
+	*expp = exp;
+}
+
+/*	Some interesting (?) questions answered.
+*/
+int
+is_integral_type(tp)
+	register struct type *tp;
+{
+	switch (tp->tp_fund)	{
+	case GENERIC:
+	case CHAR:
+	case SHORT:
+	case INT:
+	case LONG:
+	case ENUM:
+		return 1;
+#ifndef NOBITFIELD
+	case FIELD:
+		return is_integral_type(tp->tp_up);
+#endif NOBITFIELD
+	default:
+		return 0;
+	}
+}
+
+int
+is_arith_type(tp)
+	register struct type *tp;
+{
+	switch (tp->tp_fund)	{
+	case GENERIC:
+	case CHAR:
+	case SHORT:
+	case INT:
+	case LONG:
+	case ENUM:
+#ifndef NOFLOAT
+	case FLOAT:
+	case DOUBLE:
+	case LNGDBL:
+#endif NOFLOAT
+		return 1;
+#ifndef NOBITFIELD
+	case FIELD:
+		return is_arith_type(tp->tp_up);
+#endif NOBITFIELD
+	default:
+		return 0;
+	}
+}

+ 350 - 0
lang/cem/cemcom.ansi/ch7bin.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$ */
+/* SEMANTIC ANALYSIS (CHAPTER 7RM)  --  BINARY OPERATORS */
+
+#include	"botch_free.h"
+#include	<alloc.h>
+#include	"nofloat.h"
+#include	"lint.h"
+#include	"idf.h"
+#include	"arith.h"
+#include	"type.h"
+#include	"struct.h"
+#include	"label.h"
+#include	"expr.h"
+#include	"Lpars.h"
+#include	"noRoption.h"
+
+extern char options[];
+extern char *symbol2str();
+
+/*	This chapter asks for the repeated application of code to handle
+	an operation that may be executed at compile time or at run time,
+	depending on the constancy of the operands.
+*/
+
+#define commutative_binop(expp, oper, expr)	mk_binop(expp, oper, expr, 1)
+#define non_commutative_binop(expp, oper, expr)	mk_binop(expp, oper, expr, 0)
+
+ch7bin(expp, oper, expr)
+	register struct expr **expp;
+	struct expr *expr;
+{
+	/*	apply binary operator oper between *expp and expr.
+		NB: don't swap operands if op is one of the op= operators!!!
+	*/
+
+	any2opnd(expp, oper);
+	any2opnd(&expr, oper);
+	switch (oper)	{
+	case '[':				/* RM 7.1 */
+		/* RM 14.3 states that indexing follows the commutative laws */
+		switch ((*expp)->ex_type->tp_fund)	{
+		case POINTER:
+		case ARRAY:
+			break;
+		case ERRONEOUS:
+			return;
+		default:		/* unindexable */
+			switch (expr->ex_type->tp_fund)	{
+			case POINTER:
+			case ARRAY:
+				break;
+			case ERRONEOUS:
+				return;
+			default:
+				expr_error(*expp,
+					"indexing an object of type %s",
+					symbol2str((*expp)->ex_type->tp_fund));
+				return;
+			}
+			break;
+		}
+		ch7bin(expp, '+', expr);
+		ch7mon('*', expp);
+		break;
+
+	case '(':				/* RM 7.1 */
+		if (	(*expp)->ex_type->tp_fund == POINTER &&
+			(*expp)->ex_type->tp_up->tp_fund == FUNCTION
+		)	{
+#ifndef NOROPTION
+			if (options['R'])
+				warning("function pointer called");
+#endif NOROPTION
+			ch7mon('*', expp);
+		}
+		if ((*expp)->ex_type->tp_fund != FUNCTION)	{
+			expr_error(*expp, "call of non-function (%s)",
+				symbol2str((*expp)->ex_type->tp_fund));
+			/* leave the expression; it may still serve */
+			free_expression(expr);	/* there go the parameters */
+		}
+		else
+			*expp = new_oper((*expp)->ex_type->tp_up,
+					*expp, '(', expr);
+		(*expp)->ex_flags |= EX_SIDEEFFECTS;
+		break;
+
+	case PARCOMMA:				/* RM 7.1 */
+		if ((*expp)->ex_type->tp_fund == FUNCTION)
+			function2pointer(*expp);
+		*expp = new_oper(expr->ex_type, *expp, PARCOMMA, expr);
+		break;
+
+	case '%':
+	case MODAB:
+	case ANDAB:
+	case XORAB:
+	case ORAB:
+		opnd2integral(expp, oper);
+		opnd2integral(&expr, oper);
+		/* Fall through */
+	case '/':
+	case DIVAB:
+	case TIMESAB:
+		arithbalance(expp, oper, &expr);
+		non_commutative_binop(expp, oper, expr);
+		break;
+
+	case '&':
+	case '^':
+	case '|':
+		opnd2integral(expp, oper);
+		opnd2integral(&expr, oper);
+		/* Fall through */
+	case '*':
+		arithbalance(expp, oper, &expr);
+		commutative_binop(expp, oper, expr);
+		break;
+
+	case '+':
+		if (expr->ex_type->tp_fund == POINTER)	{ /* swap operands */
+			struct expr *etmp = expr;
+			expr = *expp;
+			*expp = etmp;
+		}
+		/*FALLTHROUGH*/
+	case PLUSAB:
+	case POSTINCR:
+	case PLUSPLUS:
+		if ((*expp)->ex_type->tp_fund == POINTER)	{
+			pointer_arithmetic(expp, oper, &expr);
+			if (expr->ex_type->tp_size != (*expp)->ex_type->tp_size)
+				ch7cast(&expr, CAST, (*expp)->ex_type);
+			pointer_binary(expp, oper, expr);
+		}
+		else	{
+			arithbalance(expp, oper, &expr);
+			if (oper == '+')
+				commutative_binop(expp, oper, expr);
+			else
+				non_commutative_binop(expp, oper, expr);
+		}
+		break;
+
+	case '-':
+	case MINAB:
+	case POSTDECR:
+	case MINMIN:
+		if ((*expp)->ex_type->tp_fund == POINTER)	{
+			if (expr->ex_type->tp_fund == POINTER)
+				pntminuspnt(expp, oper, expr);
+			else {
+				pointer_arithmetic(expp, oper, &expr);
+				pointer_binary(expp, oper, expr);
+			}
+		}
+		else	{
+			arithbalance(expp, oper, &expr);
+			non_commutative_binop(expp, oper, expr);
+		}
+		break;
+
+	case LEFT:
+	case RIGHT:
+	case LEFTAB:
+	case RIGHTAB:
+		opnd2integral(expp, oper);
+		opnd2integral(&expr, oper);
+		arithbalance(expp, oper, &expr); /* ch. 7.5 */
+		ch7cast(&expr, oper, int_type); /* cvt. rightop to int */
+		non_commutative_binop(expp, oper, expr);
+		break;
+
+	case '<':
+	case '>':
+	case LESSEQ:
+	case GREATEREQ:
+	case EQUAL:
+	case NOTEQUAL:
+		relbalance(expp, oper, &expr);
+		non_commutative_binop(expp, oper, expr);
+		(*expp)->ex_type = int_type;
+		break;
+
+	case AND:
+	case OR:
+		opnd2test(expp, oper);
+		opnd2test(&expr, oper);
+		if (is_cp_cst(*expp))	{
+			register struct expr *ex = *expp;
+
+			/* the following condition is a short-hand for
+				((oper == AND) && o1) || ((oper == OR) && !o1)
+				where o1 == (*expp)->VL_VALUE;
+				and ((oper == AND) || (oper == OR))
+			*/
+			if ((oper == AND) == (ex->VL_VALUE != (arith)0))
+				*expp = expr;
+			else {
+				ex->ex_flags |= expr->ex_flags;
+				free_expression(expr);
+				*expp = intexpr((arith)((oper == AND) ? 0 : 1),
+						INT);
+			}
+			(*expp)->ex_flags |= ex->ex_flags;
+			free_expression(ex);
+		}
+		else
+		if (is_cp_cst(expr))	{
+			/* Note!!!: the following condition is a short-hand for
+				((oper == AND) && o2) || ((oper == OR) && !o2)
+				where o2 == expr->VL_VALUE
+				and ((oper == AND) || (oper == OR))
+			*/
+			if ((oper == AND) == (expr->VL_VALUE != (arith)0)) {
+				(*expp)->ex_flags |= expr->ex_flags;
+				free_expression(expr);
+			}
+			else {
+				if (oper == OR)
+					expr->VL_VALUE = (arith)1;
+				ch7bin(expp, ',', expr);
+			}
+		}
+		else
+			*expp = new_oper(int_type, *expp, oper, expr);
+		(*expp)->ex_flags |= EX_LOGICAL;
+		break;
+
+	case ':':
+		if (	is_struct_or_union((*expp)->ex_type->tp_fund)
+		||	is_struct_or_union(expr->ex_type->tp_fund)
+		)	{
+			if (!equal_type((*expp)->ex_type, expr->ex_type))
+				expr_error(*expp, "illegal balance");
+		}
+		else
+			relbalance(expp, oper, &expr);
+#ifdef	LINT
+		if (	(is_cp_cst(*expp) && is_cp_cst(expr))
+		&&	(*expp)->VL_VALUE == expr->VL_VALUE
+		) {
+			hwarning("operands of : are constant and equal");
+		}
+#endif	LINT
+		*expp = new_oper((*expp)->ex_type, *expp, oper, expr);
+		break;
+
+	case '?':
+		opnd2logical(expp, oper);
+		if (is_cp_cst(*expp)) {
+#ifdef	LINT
+			hwarning("condition in ?: expression is constant");
+#endif	LINT
+			*expp = (*expp)->VL_VALUE ?
+				expr->OP_LEFT : expr->OP_RIGHT;
+		}
+		else {
+			*expp = new_oper(expr->ex_type, *expp, oper, expr);
+		}
+		break;
+
+	case ',':
+		if (is_cp_cst(*expp))
+			*expp = expr;
+		else
+			*expp = new_oper(expr->ex_type, *expp, oper, expr);
+		(*expp)->ex_flags |= EX_COMMA;
+		break;
+	}
+}
+
+pntminuspnt(expp, oper, expr)
+	register struct expr **expp, *expr;
+{
+	/*	Subtracting two pointers is so complicated it merits a
+		routine of its own.
+	*/
+	struct type *up_type = (*expp)->ex_type->tp_up;
+
+	if (!equal_type(up_type, expr->ex_type->tp_up)) {
+		expr_error(*expp, "subtracting incompatible pointers");
+		free_expression(expr);
+		erroneous2int(expp);
+		return;
+	}
+	/*	we hope the optimizer will eliminate the load-time
+		pointer subtraction
+	*/
+	*expp = new_oper((*expp)->ex_type, *expp, oper, expr);
+	ch7cast(expp, CAST, pa_type);	/* ptr-ptr: result has pa_type	*/
+	ch7bin(expp, '/',
+		intexpr(size_of_type(up_type, "object"), pa_type->tp_fund));
+	ch7cast(expp, CAST, int_type);	/* result will be an integer expr */
+}
+
+mk_binop(expp, oper, expr, commutative)
+	struct expr **expp;
+	register struct expr *expr;
+{
+	/*	Constructs in *expp the operation indicated by the operands.
+		"commutative" indicates whether "oper" is a commutative
+		operator.
+	*/
+	register struct expr *ex = *expp;
+
+	if (is_cp_cst(expr) && is_cp_cst(ex))
+		cstbin(expp, oper, expr);
+	else	{
+		*expp = (commutative && expr->ex_depth >= ex->ex_depth) ?
+				new_oper(ex->ex_type, expr, oper, ex) :
+				new_oper(ex->ex_type, ex, oper, expr);
+	}
+}
+
+pointer_arithmetic(expp1, oper, expp2)
+	register struct expr **expp1, **expp2;
+{
+	/*	prepares the integral expression expp2 in order to
+		apply it to the pointer expression expp1
+	*/
+#ifndef NOFLOAT
+	if (any2arith(expp2, oper) == DOUBLE)	{
+		expr_error(*expp2,
+			"illegal combination of float and pointer");
+		erroneous2int(expp2);
+	}
+#endif NOFLOAT
+	ch7bin( expp2, '*',
+		intexpr(size_of_type((*expp1)->ex_type->tp_up, "object"),
+			pa_type->tp_fund)
+	);
+}
+
+pointer_binary(expp, oper, expr)
+	register struct expr **expp, *expr;
+{
+	/*	constructs the pointer arithmetic expression out of
+		a pointer expression, a binary operator and an integral
+		expression.
+	*/
+	if (is_ld_cst(expr) && is_ld_cst(*expp))
+		cstbin(expp, oper, expr);
+	else
+		*expp = new_oper((*expp)->ex_type, *expp, oper, expr);
+}

+ 166 - 0
lang/cem/cemcom.ansi/ch7mon.c

@@ -0,0 +1,166 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* SEMANTIC ANALYSIS (CHAPTER 7RM) -- MONADIC OPERATORS */
+
+#include	"botch_free.h"
+#include	<alloc.h>
+#include	"nofloat.h"
+#include	"nobitfield.h"
+#include	"Lpars.h"
+#include	"arith.h"
+#include	"type.h"
+#include	"label.h"
+#include	"expr.h"
+#include	"idf.h"
+#include	"def.h"
+
+extern char options[];
+extern long full_mask[/*MAXSIZE*/];	/* cstoper.c */
+char *symbol2str();
+
+ch7mon(oper, expp)
+	register struct expr **expp;
+{
+	/*	The monadic prefix operator oper is applied to *expp.
+	*/
+	register struct expr *expr;
+
+	switch (oper)	{
+	case '*':			/* RM 7.2 */
+		/* no FIELD type allowed	*/
+		if ((*expp)->ex_type->tp_fund == ARRAY)
+			array2pointer(*expp);
+		if ((*expp)->ex_type->tp_fund != POINTER)	{
+			expr_error(*expp,
+				"* applied to non-pointer (%s)",
+				symbol2str((*expp)->ex_type->tp_fund));
+		}
+		else {
+			expr = *expp;
+			if (expr->ex_lvalue == 0 && expr->ex_class != String)
+				/* dereference in administration only */
+				expr->ex_type = expr->ex_type->tp_up;
+			else	/* runtime code */
+				*expp = new_oper(expr->ex_type->tp_up, NILEXPR,
+							'*', expr);
+			(*expp)->ex_lvalue = (
+				(*expp)->ex_type->tp_fund != ARRAY &&
+				(*expp)->ex_type->tp_fund != FUNCTION
+				);
+			if ((*expp)->ex_type->tp_typequal & TQ_CONST)
+				(*expp)->ex_flags |= EX_READONLY;
+			if ((*expp)->ex_type->tp_typequal & TQ_VOLATILE)
+				(*expp)->ex_flags |= EX_VOLATILE;
+		}
+		break;
+	case '&':
+		if ((*expp)->ex_type->tp_fund == ARRAY) {
+			warning("& before array ignored");
+			array2pointer(*expp);
+		}
+		else
+		if ((*expp)->ex_type->tp_fund == FUNCTION) {
+			warning("& before function ignored");
+			function2pointer(*expp);
+		}
+		else
+#ifndef NOBITFIELD
+		if ((*expp)->ex_type->tp_fund == FIELD)
+			expr_error(*expp, "& applied to field variable");
+		else
+#endif NOBITFIELD
+		if (!(*expp)->ex_lvalue)
+			expr_error(*expp, "& applied to non-lvalue");
+		else {
+			/* assume that enums are already filtered out	*/
+			if (ISNAME(*expp)) {
+				register struct def *def =
+					(*expp)->VL_IDF->id_def;
+
+				/*	&<var> indicates that <var>
+					cannot be used as register
+					anymore
+				*/
+				if (def->df_sc == REGISTER) {
+					expr_error(*expp,
+					"& on register variable not allowed");
+					break;	/* break case '&' */
+				}
+			}
+			(*expp)->ex_type = pointer_to((*expp)->ex_type);
+			(*expp)->ex_lvalue = 0;
+			(*expp)->ex_flags &= ~EX_READONLY;
+		}
+		break;
+	case '~':
+#ifndef NOFLOAT
+	{
+		int fund = (*expp)->ex_type->tp_fund;
+
+		if (fund == FLOAT || fund == DOUBLE)	{
+			expr_error(
+				*expp,
+				"~ not allowed on %s operands",
+				symbol2str(fund)
+			);
+			erroneous2int(expp);
+			break;
+		}
+		/* FALLTHROUGH */
+	}
+#endif NOFLOAT
+	case '-':
+		any2arith(expp, oper);
+		if (is_cp_cst(*expp))	{
+			arith o1 = (*expp)->VL_VALUE;
+
+			(*expp)->VL_VALUE = (oper == '-') ? -o1 :
+			  ((*expp)->ex_type->tp_unsigned ?
+				(~o1) & full_mask[(*expp)->ex_type->tp_size] :
+				~o1
+			  );
+		}
+		else
+#ifndef NOFLOAT
+		if (is_fp_cst(*expp))
+			switch_sign_fp(*expp);
+		else
+#endif NOFLOAT
+			*expp = new_oper((*expp)->ex_type,
+					NILEXPR, oper, *expp);
+		break;
+	case '!':
+		if ((*expp)->ex_type->tp_fund == FUNCTION)
+			function2pointer(*expp);
+		if ((*expp)->ex_type->tp_fund != POINTER)
+			any2arith(expp, oper);
+		opnd2test(expp, '!');
+		if (is_cp_cst(*expp))	{
+			(*expp)->VL_VALUE = !((*expp)->VL_VALUE);
+			(*expp)->ex_type = int_type;	/* a cast ???(EB) */
+		}
+		else
+			*expp = new_oper(int_type, NILEXPR, oper, *expp);
+		(*expp)->ex_flags |= EX_LOGICAL;
+		break;
+	case PLUSPLUS:
+	case MINMIN:
+		ch7incr(expp, oper);
+		break;
+	case SIZEOF:
+		if (ISNAME(*expp) && (*expp)->VL_IDF->id_def->df_formal_array)
+			warning("sizeof formal array %s is sizeof pointer!",
+				(*expp)->VL_IDF->id_text);
+		expr = intexpr((*expp)->ex_class == String ?
+				   (arith)((*expp)->SG_LEN) :
+				   size_of_type((*expp)->ex_type, "object"),
+				INT);
+		expr->ex_flags |= EX_SIZEOF;
+		free_expression(*expp);
+		*expp = expr;
+		break;
+	}
+}

+ 74 - 0
lang/cem/cemcom.ansi/char.tab

@@ -0,0 +1,74 @@
+%
+%	CHARACTER CLASSES
+%
+% some general settings:
+%S129
+%F	%s,
+%
+%	START OF TOKEN
+%
+%iSTGARB
+STSKIP:\r \t\013\f
+STNL:\n
+STCOMP:-!&+<=>|
+STSIMP:%()*,/:;?[]^{}~
+STCHAR:'
+STIDF:a-zA-KM-Z_
+STELL:L
+STNUM:.0-9
+STSTR:"
+STEOI:\200
+%T/* character classes */
+%T#include "class.h"
+%Tchar tkclass[] = {
+%p
+%T};
+%
+%	INIDF
+%
+%C
+1:a-zA-Z_0-9
+%Tchar inidf[] = {
+%F	%s,
+%p
+%T};
+%
+%	ISDIG
+%
+%C
+1:0-9
+%Tchar isdig[] = {
+%p
+%T};
+%
+%	ISHEX
+%
+%C
+1:a-fA-F
+%Tchar ishex[] = {
+%p
+%T};
+%
+%	ISOCT
+%
+%C
+1:0-7
+%Tchar isoct[] = {
+%p
+%T};
+%
+%	ISSUF
+%
+%C
+1:lLuU
+%Tchar issuf[] = {
+%p
+%T};
+%
+%	ISWSP
+%
+%C
+1: \t\n
+%Tchar iswsp[] = {
+%p
+%T};

+ 44 - 0
lang/cem/cemcom.ansi/class.h

@@ -0,0 +1,44 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*		U S E   O F   C H A R A C T E R   C L A S S E S		*/
+
+/*	As a starter, chars are divided into classes, according to which
+	token they can be the start of.
+	At present such a class number is supposed to fit in 4 bits.
+*/
+
+#define	class(ch)	(tkclass[ch])
+
+/*	Being the start of a token is, fortunately, a mutual exclusive
+	property, so, although there are less than 16 classes they can be
+	packed in 4 bits.
+*/
+
+#define	STSKIP	0	/* spaces and so on: skipped characters		*/
+#define	STNL	1	/* newline character(s): update linenumber etc.	*/
+#define	STGARB	2	/* garbage ascii character: not allowed in C	*/
+#define	STSIMP	3	/* this character can occur as token in C	*/
+#define	STCOMP	4	/* this one can start a compound token in C	*/
+#define	STELL	5	/* possible start of wide char stuff or idf	*/
+#define	STIDF	6	/* being the initial character of an identifier	*/
+#define	STCHAR	7	/* the starter of a character constant		*/
+#define	STSTR	8	/* the starter of a string			*/
+#define	STNUM	9	/* the starter of a numeric constant		*/
+#define	STEOI	10	/* End-Of-Information mark			*/
+
+/*	But occurring inside a token is not, so we need 1 bit for each
+	class.  This is implemented as a collection of tables to speed up
+	the decision whether a character has a special meaning.
+*/
+#define	in_idf(ch)	(inidf[ch])
+#define	is_oct(ch)	(isoct[ch])
+#define	is_dig(ch)	(isdig[ch])
+#define	is_hex(ch)	(ishex[ch])
+#define	is_suf(ch)	(issuf[ch])
+#define	is_wsp(ch)	(iswsp[ch])
+
+extern char tkclass[];
+extern char inidf[], isoct[], isdig[], ishex[], issuf[], iswsp[];

+ 657 - 0
lang/cem/cemcom.ansi/code.c

@@ -0,0 +1,657 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*	C O D E - G E N E R A T I N G   R O U T I N E S		*/
+
+#include	"lint.h"
+#include	<em.h>
+#include	"botch_free.h"
+#include	<alloc.h>
+#include	"dataflow.h"
+#include	"use_tmp.h"
+#include	"arith.h"
+#include	"type.h"
+#include	"idf.h"
+#include	"label.h"
+#include	"code.h"
+#include	"stmt.h"
+#include	"def.h"
+#include	"expr.h"
+#include	"sizes.h"
+#include	"stack.h"
+#include	"level.h"
+#include	"decspecs.h"
+#include	"declar.h"
+#include	"Lpars.h"
+#include	"specials.h"
+#include	"atw.h"
+#include	"assert.h"
+#include	"noRoption.h"
+#include	"file_info.h"
+#ifdef	LINT
+#include	"l_lint.h"
+#endif	LINT
+
+label lab_count = 1;
+label datlab_count = 1;
+
+#ifndef NOFLOAT
+int fp_used;
+#endif NOFLOAT
+
+/* global function info */
+char *func_name;
+struct type *func_type;
+int func_notypegiven;
+
+#ifdef USE_TMP
+static int	tmp_id;
+static int	pro_id;
+#endif USE_TMP
+
+extern char options[];
+extern char *symbol2str();
+
+#ifndef	LINT
+init_code(dst_file)
+	char *dst_file;
+{
+	/*	init_code() initialises the output file on which the
+		compact EM code is written
+	*/
+	C_init(word_size, pointer_size); /* initialise EM module */
+	if (C_open(dst_file) == 0)
+		fatal("cannot write to %s\n", dst_file);
+	C_magic();
+	C_ms_emx(word_size, pointer_size);
+#ifdef USE_TMP
+#ifdef PREPEND_SCOPES
+	C_insertpart(tmp_id = C_getid());
+#endif	USE_TMP
+#endif	PREPEND_SCOPES
+}
+#endif	LINT
+
+struct string_cst *str_list = 0;
+
+code_string(val, len, dlb)
+	char *val;
+	int len;
+	label dlb;
+{
+	register struct string_cst *sc = new_string_cst();
+
+	C_ina_dlb(dlb);
+	sc->next = str_list;
+	str_list = sc;
+	sc->sc_value = val;
+	sc->sc_len = len;
+	sc->sc_dlb = dlb;
+}
+
+def_strings(sc)
+	register struct string_cst *sc;
+{
+	while (sc) {
+		struct string_cst *sc1 = sc;
+
+		C_df_dlb(sc->sc_dlb);
+		str_cst(sc->sc_value, sc->sc_len);
+		sc = sc->next;
+		free_string_cst(sc1);
+	}
+}
+
+end_code()
+{
+	/*	end_code() performs the actions to be taken when closing
+		the output stream.
+	*/
+#ifndef NOFLOAT
+	if (fp_used) {
+		/* floating point used	*/
+		C_ms_flt();
+	}
+#endif NOFLOAT
+	def_strings(str_list);
+	str_list = 0;
+	C_ms_src((int)(LineNumber - 2), FileName);
+	C_close();
+}
+
+#ifdef	PREPEND_SCOPES
+prepend_scopes()
+{
+	/*	prepend_scopes() runs down the list of global idf's
+		and generates those exa's, exp's, ina's and inp's
+		that superior hindsight has provided.
+	*/
+	register struct stack_entry *se = local_level->sl_entry;
+
+#ifdef USE_TMP
+	C_beginpart(tmp_id);
+#endif USE_TMP
+	while (se != 0)	{
+		register struct idf *id = se->se_idf;
+		register struct def *df = id->id_def;
+		
+		if (df && (df->df_initialized || df->df_used || df->df_alloc))
+			code_scope(id->id_text, df);
+		se = se->next;
+	}
+#ifdef USE_TMP
+	C_endpart(tmp_id);
+#endif USE_TMP
+}
+#endif	PREPEND_SCOPES
+
+code_scope(text, def)
+	char *text;
+	register struct def *def;
+{
+	/*	generates code for one name, text, of the storage class
+		as given by def, if meaningful.
+	*/
+	int fund = def->df_type->tp_fund;
+	
+	switch (def->df_sc)	{
+	case EXTERN:
+	case GLOBAL:
+	case IMPLICIT:
+		if (fund == FUNCTION)
+			C_exp(text);
+		else
+			C_exa_dnam(text);
+		break;
+	case STATIC:
+		if (fund == FUNCTION)
+			C_inp(text);
+		else
+			C_ina_dnam(text);
+		break;
+	}
+}
+
+static label return_label, return2_label;
+static char return_expr_occurred;
+static arith func_size;
+static label func_res_label;
+static char *last_fn_given = "";
+static label file_name_label;
+
+begin_proc(ds, idf)		/* to be called when entering a procedure */
+	struct decspecs *ds;
+	struct idf *idf;
+{
+	/*	begin_proc() is called at the entrance of a new function
+		and performs the necessary code generation:
+		-	a scope indicator (if needed) exp/inp
+		-	the procedure entry pro $name
+		-	reserves some space if the result of the function
+			does not fit in the return area
+		-	a fil pseudo instruction
+	*/
+	register char *name = idf->id_text;
+	register struct def *def = idf->id_def;
+
+#ifndef PREPEND_SCOPES
+	code_scope(name, def);
+#endif	PREPEND_SCOPES
+#ifdef	DATAFLOW
+	if (options['d'])
+		DfaStartFunction(name);
+#endif	DATAFLOW
+
+	/* set global function info */
+	func_name = name;
+	if (def->df_type->tp_fund != FUNCTION) {
+		error("making function body for non-function");
+		func_type = error_type;
+	}
+	else {
+		func_type = def->df_type->tp_up;
+	}
+	func_notypegiven = ds->ds_notypegiven;
+	func_size = ATW(func_type->tp_size);
+
+#ifndef USE_TMP
+	C_pro_narg(name);
+#else
+	C_insertpart(pro_id = C_getid());
+#endif
+	if (is_struct_or_union(func_type->tp_fund))	{
+		C_df_dlb(func_res_label = data_label());
+		C_bss_cst(func_size, (arith)0, 1);
+	}
+	else
+		func_res_label = 0;
+	/*	Special arrangements if the function result doesn't fit in
+		the function return area of the EM machine.  The size of
+		the function return area is implementation dependent.
+	*/
+	lab_count = (label) 1;
+	return_label = text_label();
+	return2_label = text_label();
+	return_expr_occurred = 0;
+	LocalInit();
+	prc_entry(name);
+	if (! options['L'])	{	/* profiling */
+		if (strcmp(last_fn_given, FileName) != 0)	{
+			/* previous function came from other file */
+			C_df_dlb(file_name_label = data_label());
+			C_con_scon(last_fn_given = FileName,
+				(arith)(strlen(FileName) + 1));
+		}
+		/* enable debug trace of EM source */
+		C_fil_dlb(file_name_label, (arith)0);
+		C_lin((arith)LineNumber);
+	}
+}
+
+end_proc(fbytes)
+	arith fbytes;
+{
+	/*	end_proc() deals with the code to be generated at the end of
+		a function, as there is:
+		-	the EM ret instruction: "ret 0"
+		-	loading of the function result in the function
+			result area if there has been a return <expr>
+			in the function body (see do_return_expr())
+		-	indication of the use of floating points
+		-	indication of the number of bytes used for
+			formal parameters
+		-	use of special identifiers such as "setjmp"
+		-	"end" + number of bytes used for local variables
+	*/
+	arith nbytes;
+	char optionsn = options['n'];
+
+#ifdef	DATAFLOW
+	if (options['d'])
+		DfaEndFunction();
+#endif	DATAFLOW
+	C_df_ilb(return2_label);
+	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);
+			store_block(func_size, func_type->tp_align);
+			C_lae_dlb(func_res_label, (arith)0);
+			C_ret(pointer_size);
+		}
+		else
+			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
+	   L_LOCAL is already unstacked. Therefore, "unstack_level" must
+	   also pass "sl_max_block" to the level above L_LOCAL.
+	*/
+	nbytes = ATW(- local_level->sl_max_block);
+#ifdef USE_TMP
+	C_beginpart(pro_id);
+	C_pro(func_name, nbytes);
+#endif
+	if (fbytes > max_int) {
+		error("%s has more than %ld parameter bytes",
+			func_name, (long) max_int);
+	}
+	C_ms_par(fbytes);		/* # bytes for formals		*/
+	if (sp_occurred[SP_SETJMP]) {	/* indicate use of "setjmp"	*/
+		options['n'] = 1;
+		C_ms_gto();
+		sp_occurred[SP_SETJMP] = 0;
+	}
+#ifdef USE_TMP
+	C_endpart(pro_id);
+#endif
+	LocalFinish();
+	C_end(nbytes);
+	if (nbytes > max_int) {
+		error("%s has more than %ld bytes of local variables",
+			func_name, (long) max_int);
+	}
+	options['n'] = optionsn;
+}
+
+do_return()
+{
+	/*	do_return handles the case of a return without expression.
+		This version branches to the return label, which is
+		probably smarter than generating a direct return.
+		Return sequences may be expensive.
+	*/
+	C_bra(return2_label);
+}
+
+do_return_expr(expr)
+	struct expr *expr;
+{
+	/*	do_return_expr() generates the expression and the jump for
+		a return statement with an expression.
+	*/
+	ch7cast(&expr, RETURN, func_type);
+	code_expr(expr, RVAL, TRUE, NO_LABEL, NO_LABEL);
+	C_bra(return_label);
+	return_expr_occurred = 1;
+}
+
+code_declaration(idf, expr, lvl, sc)
+	register struct idf *idf;	/* idf to be declared	*/
+	struct expr *expr;	/* initialisation; NULL if absent	*/
+	int lvl;		/* declaration level	*/
+	int sc;			/* storage class, as in the declaration */
+{
+	/*	code_declaration() does the actual declaration of the
+		variable indicated by "idf" on declaration level "lvl".
+		If the variable is initialised, the expression is given
+		in "expr", but for global and static initialisations it
+		is just non-zero, as the expression is not parsed yet.
+		There are some cases to be considered:
+		-	filter out typedefs, they don't correspond to code;
+		-	global variables, coded only if initialized;
+		-	local static variables;
+		-	local automatic variables;
+		Since the expression may be modified in the process,
+		code_declaration() frees it after use, as the caller can
+		no longer do so.
+		
+		If there is a storage class indication (EXTERN/STATIC),
+		code_declaration() will generate an exa or ina.
+		The sc is the actual storage class, as given in the
+		declaration.  This is to allow:
+			extern int a;
+			int a = 5;
+		while at the same time forbidding
+			extern int a = 5;
+	*/
+	register struct def *def = idf->id_def;
+	register arith size = def->df_type->tp_size;
+	int def_sc = def->df_sc;
+	
+	if (def_sc == TYPEDEF)	/* no code for typedefs		*/
+		return;
+	if (sc == EXTERN && expr && !is_anon_idf(idf))
+		error("%s is extern; cannot initialize", idf->id_text);
+#ifndef PREPEND_SCOPES
+	if (def->df_type->tp_fund == FUNCTION) {
+		code_scope(idf->id_text, def);
+	}
+#endif PREPEND_SCOPES
+	if (lvl == L_GLOBAL)	{	/* global variable	*/
+		/* is this an allocating declaration? */
+		if (	(sc == 0 || sc == STATIC)
+			&& def->df_type->tp_fund != FUNCTION
+			&& size >= 0
+		)
+			def->df_alloc = ALLOC_SEEN;
+		if (expr) {	/* code only if initialized */
+#ifndef PREPEND_SCOPES
+			code_scope(idf->id_text, def);
+#endif PREPEND_SCOPES
+			def->df_alloc = ALLOC_DONE;
+			C_df_dnam(idf->id_text);
+		}
+	}
+	else
+	if (lvl >= L_LOCAL)	{	/* local variable	*/
+		/* STATIC, EXTERN, GLOBAL, IMPLICIT, AUTO or REGISTER */
+		switch (def_sc)	{
+		case STATIC:
+			if (def->df_type->tp_fund == FUNCTION) {
+				/* should produce "inp $function" ??? */
+				break;
+			}
+			/*	they are handled on the spot and get an
+				integer label in EM.
+			*/
+			C_df_dlb((label)def->df_address);
+			if (expr) { /* there is an initialisation */
+			}
+			else {	/* produce blank space */
+				if (size <= 0) {
+					error("size of %s unknown", idf->id_text);
+					size = (arith)0;
+				}
+				C_bss_cst(ATW(size), (arith)0, 1);
+			}
+			break;
+		case EXTERN:
+		case GLOBAL:
+		case IMPLICIT:
+			/* we are sure there is no expression */
+#ifndef	PREPEND_SCOPES
+			code_scope(idf->id_text, def);
+#endif	PREPEND_SCOPES
+			break;
+		case AUTO:
+		case REGISTER:
+			if (expr)
+				loc_init(expr, idf);
+			break;
+		default:
+			crash("bad local storage class");
+			/*NOTREACHED*/
+		}
+	}
+}
+
+loc_init(expr, id)
+	struct expr *expr;
+	register struct idf *id;
+{
+	/*	loc_init() generates code for the assignment of
+		expression expr to the local variable described by id.
+		It frees the expression afterwards.
+	*/
+	register struct expr *e = expr;
+	register struct type *tp = id->id_def->df_type;
+	
+	ASSERT(id->id_def->df_sc != STATIC);
+	switch (tp->tp_fund)	{
+	case ARRAY:
+	case STRUCT:
+	case UNION:
+		error("automatic %s cannot be initialized in declaration",
+			symbol2str(tp->tp_fund));
+		free_expression(e);
+		return;
+	}
+	if (ISCOMMA(e))	{	/* embraced: int i = {12};	*/
+#ifndef NOROPTION
+		if (options['R'])	{
+			if (ISCOMMA(e->OP_LEFT)) /* int i = {{1}} */
+				expr_error(e, "extra braces not allowed");
+			else
+			if (e->OP_RIGHT != 0) /* int i = {1 , 2} */
+				expr_error(e, "too many initializers");
+		}
+#endif NOROPTION
+		while (e)	{
+			loc_init(e->OP_LEFT, id);
+			e = e->OP_RIGHT;
+		}
+	}
+	else	{	/* not embraced	*/
+		ch7cast(&expr, '=', tp);	/* may modify expr */
+#ifndef	LINT
+		{
+			struct value vl;
+
+			EVAL(expr, RVAL, TRUE, NO_LABEL, NO_LABEL);
+			vl.vl_class = Name;
+			vl.vl_data.vl_idf = id;
+			vl.vl_value = (arith)0;
+			store_val(&vl, tp);
+		}
+#else	LINT
+		id->id_def->df_set = 1;
+#endif	LINT
+		free_expression(expr);
+	}
+}
+
+bss(idf)
+	register struct idf *idf;
+{
+	/*	bss() allocates bss space for the global idf.
+	*/
+	arith size = idf->id_def->df_type->tp_size;
+	
+#ifndef	PREPEND_SCOPES
+	code_scope(idf->id_text, idf->id_def);
+#endif	PREPEND_SCOPES
+	/*	Since bss() is only called if df_alloc is non-zero, and
+		since df_alloc is only non-zero if size >= 0, we have:
+	*/
+	/*	but we already gave a warning at the declaration of the
+		array. Besides, the message given here does not apply to
+		voids
+	
+	if (options['R'] && size == 0)
+		warning("actual array of size 0");
+	*/
+	C_df_dnam(idf->id_text);
+	C_bss_cst(ATW(size), (arith)0, 1);
+}
+
+formal_cvt(df)
+	register struct def *df;
+{
+	/*	formal_cvt() converts a formal parameter of type char or
+		short from int to that type.
+	*/
+	register struct type *tp = df->df_type;
+
+	if (tp->tp_size != int_size &&
+		(tp->tp_fund == CHAR || tp->tp_fund == SHORT)
+	) {
+		LoadLocal(df->df_address, int_size);
+		/* conversion(int_type, df->df_type); ???
+		   No, you can't do this on the stack! (CJ)
+		*/
+		StoreLocal(df->df_address, tp->tp_size);
+	}
+}
+
+#ifdef	LINT
+/*ARGSUSED*/
+#endif	LINT
+code_expr(expr, val, code, tlbl, flbl)
+	struct expr *expr;
+	label tlbl, flbl;
+{
+	/*	code_expr() is the parser's interface to the expression code
+		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));
+
+	/*	HERE WE SHOULD GENERATE A MESSAGE:
+		if (expr->ex_flags & EX_VOLATILE)
+			HANDS_OFF
+	*/
+	EVAL(expr, val, code, tlbl, flbl);
+#else	LINT
+	lint_expr(expr, code ? USED : IGNORED);
+#endif	LINT
+}
+
+/*	The FOR/WHILE/DO/SWITCH stacking mechanism:
+	stack_stmt() has to be called at the entrance of a
+	for, while, do or switch statement to indicate the
+	EM labels where a subsequent break or continue causes
+	the program to jump to.
+*/
+static struct stmt_block *stmt_stack;	/* top of statement stack */
+
+/*	code_break() generates EM code needed at the occurrence of "break":
+	it generates a branch instruction to the break label of the
+	innermost statement in which break has a meaning.
+	As "break" is legal in any of 'while', 'do', 'for' or 'switch',
+	which are the only ones that are stacked, only the top of
+	the stack is interesting.
+*/
+code_break()
+{
+	register struct stmt_block *stmt_block = stmt_stack;
+
+	if (stmt_block)
+		C_bra(stmt_block->st_break);
+	else
+		error("break not inside for, while, do or switch");
+}
+
+/*	code_continue() generates EM code needed at the occurrence of
+	"continue":
+	it generates a branch instruction to the continue label of the
+	innermost statement in which continue has a meaning.
+*/
+code_continue()
+{
+	register struct stmt_block *stmt_block = stmt_stack;
+
+	while (stmt_block)	{
+		if (stmt_block->st_continue)	{
+			C_bra(stmt_block->st_continue);
+			return;
+		}
+		stmt_block = stmt_block->next;
+	}
+	error("continue not inside for, while or do");
+}
+
+stack_stmt(break_label, cont_label)
+	label break_label, cont_label;
+{
+	register struct stmt_block *stmt_block = new_stmt_block();
+
+	stmt_block->next = stmt_stack;
+	stmt_block->st_break = break_label;
+	stmt_block->st_continue = cont_label;
+	stmt_stack = stmt_block;
+}
+
+unstack_stmt()
+{
+	/*	unstack_stmt() unstacks the data of a statement
+		which may contain break or continue
+	*/
+	register struct stmt_block *sbp = stmt_stack;
+	stmt_stack = sbp->next;
+	free_stmt_block(sbp);
+}
+
+static label prc_name;
+
+prc_entry(name)
+	char *name;
+{
+	if (options['p']) {
+		C_df_dlb(prc_name = data_label());
+		C_rom_scon(name, (arith) (strlen(name) + 1));
+		C_lae_dlb(prc_name, (arith) 0);
+		C_cal("procentry");
+		C_asp(pointer_size);
+	}
+}
+
+prc_exit()
+{
+	if (options['p']) {
+		C_lae_dlb(prc_name, (arith) 0);
+		C_cal("procexit");
+		C_asp(pointer_size);
+	}
+}

+ 22 - 0
lang/cem/cemcom.ansi/code.str

@@ -0,0 +1,22 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*	C O D E - G E N E R A T O R   D E F I N I T I O N S	*/
+
+struct string_cst	{	/* storing string constants */
+	struct string_cst *next;
+	char *sc_value;
+	int sc_len;
+	label sc_dlb;
+};
+
+extern struct string_cst *str_list;
+
+/* ALLOCDEF "string_cst" 10 */
+
+#define	LVAL	0
+#define	RVAL	1
+#define	FALSE	0
+#define	TRUE	1

+ 158 - 0
lang/cem/cemcom.ansi/conversion.c

@@ -0,0 +1,158 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $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"
+#include	"type.h"
+#include	"sizes.h"
+#include	"Lpars.h"
+
+#define	T_SIGNED		1
+#define	T_UNSIGNED		2
+#ifndef NOFLOAT
+#define	T_FLOATING		3
+#endif NOFLOAT
+
+/*	conversion() generates the EM code for a conversion between
+	the types char, short, int, long, float, double and pointer.
+	There are three conversion types: signed, unsigned and floating.
+	The EM code to obtain this conversion looks like:
+		LOC sizeof(from_type)
+		LOC sizeof(to_type)
+		C??
+*/
+
+static int convtype();
+
+conversion(from_type, to_type)
+	register struct type *from_type, *to_type;
+{
+	register arith from_size = from_type->tp_size;
+	register arith to_size = to_type->tp_size;
+	int from_cnvtype = convtype(from_type);
+	int to_cnvtype = convtype(to_type);
+
+	if ((int)to_size < (int)word_size) to_size = word_size;
+	if ((int)from_size == (int)to_size && from_cnvtype == to_cnvtype)
+		return;
+	switch (from_cnvtype)	{
+	case T_SIGNED:
+		switch (to_cnvtype)	{
+		case T_SIGNED:
+			C_loc(from_size);
+			C_loc(to_size);
+			C_cii();
+			break;
+		case T_UNSIGNED:
+#ifndef NOFLOAT
+		case T_FLOATING:
+#endif NOOFLOAT
+			if ((int)from_size < (int)word_size) {
+				C_loc(from_size);
+				C_loc(word_size);
+				C_cii();
+				from_size = word_size;
+			}
+			C_loc(from_size);
+			C_loc(to_size);
+			if (to_cnvtype == T_UNSIGNED) C_ciu();
+			else C_cif();
+			break;
+		}
+		break;
+	case T_UNSIGNED:
+		if ((int)from_size < (int)word_size) from_size = word_size;
+		C_loc(from_size);
+		C_loc(to_size);
+		switch (to_cnvtype)	{
+		case T_SIGNED:
+			C_cui();
+			break;
+		case T_UNSIGNED:
+			C_cuu();
+			break;
+#ifndef NOFLOAT
+		case T_FLOATING:
+			C_cuf();
+			break;
+#endif NOFLOAT
+		}
+		break;
+#ifndef NOFLOAT
+	case T_FLOATING:
+		C_loc(from_size);
+		C_loc(to_size);
+		switch (to_cnvtype)	{
+		case T_SIGNED:
+			C_cfi();
+			break;
+		case T_UNSIGNED:
+			C_cfu();
+			break;
+		case T_FLOATING:
+			C_cff();
+			break;
+		}
+		break;
+#endif NOFLOAT
+	default:
+		crash("(conversion) illegal type conversion");
+		/*NOTREACHED*/
+	}
+	if ((int)(to_type->tp_size) < (int)word_size
+#ifndef NOFLOAT
+	    && to_cnvtype != T_FLOATING
+#endif NOFLOAT
+	    ) {
+		extern long full_mask[];
+
+		if (to_cnvtype == T_SIGNED) {
+			C_loc(to_type->tp_size);
+			C_loc(word_size);
+			C_cii();
+		}
+		else {
+			C_loc((arith) full_mask[(int)(to_type->tp_size)]);
+			C_and(word_size);
+		}
+	}
+}
+
+/*	convtype() returns in which category a given type falls:
+	signed, unsigned or floating
+*/
+static int
+convtype(tp)
+	register struct type *tp;
+{
+	switch (tp->tp_fund)	{
+	case GENERIC:
+	case CHAR:
+	case SHORT:
+	case INT:
+	case ERRONEOUS:
+	case LONG:
+	case ENUM:
+		return tp->tp_unsigned ? T_UNSIGNED : T_SIGNED;
+#ifndef NOFLOAT
+	case FLOAT:
+	case DOUBLE:
+	case LNGDBL:
+		return T_FLOATING;
+#endif NOFLOAT
+	case POINTER:
+		return T_UNSIGNED;
+	}
+	return 0;
+}
+
+#endif	LINT
+

+ 237 - 0
lang/cem/cemcom.ansi/cstoper.c

@@ -0,0 +1,237 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*	C O N S T A N T   E X P R E S S I O N   H A N D L I N G		*/
+
+#include	"target_sizes.h"
+#include	"idf.h"
+#include	"arith.h"
+#include	"type.h"
+#include	"label.h"
+#include	"expr.h"
+#include	"sizes.h"
+#include	"Lpars.h"
+#include	"assert.h"
+
+long mach_long_sign;	/* sign bit of the machine long */
+int mach_long_size;	/* size of long on this machine == sizeof(long) */
+long full_mask[MAXSIZE];/* full_mask[1] == 0XFF, full_mask[2] == 0XFFFF, .. */
+arith max_int;		/* maximum integer on target machine	*/
+arith max_unsigned;	/* maximum unsigned on target machine	*/
+
+cstbin(expp, oper, expr)
+	register struct expr **expp, *expr;
+{
+	/*	The operation oper is performed on the constant
+		expressions *expp(ld) and expr(ct), and the result restored in
+		*expp.
+	*/
+	register arith o1 = (*expp)->VL_VALUE;
+	register arith o2 = expr->VL_VALUE;
+	int uns = (*expp)->ex_type->tp_unsigned;
+
+	ASSERT(is_ld_cst(*expp) && is_cp_cst(expr));
+	switch (oper)	{
+	case '*':
+		o1 *= o2;
+		break;
+	case '/':
+		if (o2 == 0)	{
+			expr_error(expr, "division by 0");
+			break;
+		}
+		if (uns)	{
+			/*	this is more of a problem than you might
+				think on C compilers which do not have
+				unsigned long.
+			*/
+			if (o2 & mach_long_sign)	{/* o2 > max_long */
+				o1 = ! (o1 >= 0 || o1 < o2);
+				/*	this is the unsigned test
+					o1 < o2 for o2 > max_long
+				*/
+			}
+			else	{		/* o2 <= max_long */
+				long half, bit, hdiv, hrem, rem;
+
+				half = (o1 >> 1) & ~mach_long_sign;
+				bit = o1 & 01;
+				/*	now o1 == 2 * half + bit
+					and half <= max_long
+					and bit <= max_long
+				*/
+				hdiv = half / o2;
+				hrem = half % o2;
+				rem = 2 * hrem + bit;
+				o1 = 2 * hdiv + (rem < 0 || rem >= o2);
+				/*	that is the unsigned compare
+					rem >= o2 for o2 <= max_long
+				*/
+			}
+		}
+		else
+			o1 /= o2;
+		break;
+	case '%':
+		if (o2 == 0)	{
+			expr_error(expr, "modulo by 0");
+			break;
+		}
+		if (uns)	{
+			if (o2 & mach_long_sign)	{/* o2 > max_long */
+				o1 = (o1 >= 0 || o1 < o2) ? o1 : o1 - o2;
+				/*	this is the unsigned test
+					o1 < o2 for o2 > max_long
+				*/
+			}
+			else	{		/* o2 <= max_long */
+				long half, bit, hrem, rem;
+
+				half = (o1 >> 1) & ~mach_long_sign;
+				bit = o1 & 01;
+				/*	now o1 == 2 * half + bit
+					and half <= max_long
+					and bit <= max_long
+				*/
+				hrem = half % o2;
+				rem = 2 * hrem + bit;
+				o1 = (rem < 0 || rem >= o2) ? rem - o2 : rem;
+			}
+		}
+		else
+			o1 %= o2;
+		break;
+	case '+':
+		o1 += o2;
+		break;
+	case '-':
+		o1 -= o2;
+		break;
+	case LEFT:
+		o1 <<= o2;
+		break;
+	case RIGHT:
+		if (o2 == 0)
+			break;
+		if (uns)	{
+			o1 >>= 1;
+			o1 &= ~mach_long_sign;
+			o1 >>= (o2-1);
+		}
+		else
+			o1 >>= o2;
+		break;
+	case '<':
+		{
+			arith tmp = o1;
+
+			o1 = o2;
+			o2 = tmp;
+		}
+		/* Fall through */
+	case '>':
+		if (uns)	{
+			o1 = (o1 & mach_long_sign ?
+				(o2 & mach_long_sign ? o1 > o2 : 1) :
+				(o2 & mach_long_sign ? 0 : o1 > o2)
+			);
+		}
+		else
+			o1 = o1 > o2;
+		break;
+	case LESSEQ:
+		{
+			arith tmp = o1;
+
+			o1 = o2;
+			o2 = tmp;
+		}
+		/* Fall through */
+	case GREATEREQ:
+		if (uns)	{
+			o1 = (o1 & mach_long_sign ?
+				(o2 & mach_long_sign ? o1 >= o2 : 1) :
+				(o2 & mach_long_sign ? 0 : o1 >= o2)
+			);
+		}
+		else
+			o1 = o1 >= o2;
+		break;
+	case EQUAL:
+		o1 = o1 == o2;
+		break;
+	case NOTEQUAL:
+		o1 = o1 != o2;
+		break;
+	case '&':
+		o1 &= o2;
+		break;
+	case '|':
+		o1 |= o2;
+		break;
+	case '^':
+		o1 ^= o2;
+		break;
+	}
+	(*expp)->VL_VALUE = o1;
+	cut_size(*expp);
+	(*expp)->ex_flags |= expr->ex_flags;
+	(*expp)->ex_flags &= ~EX_PARENS;
+	free_expression(expr);
+}
+
+cut_size(expr)
+	register struct expr *expr;
+{
+	/*	The constant value of the expression expr is made to
+		conform to the size of the type of the expression.
+	*/
+	register arith o1 = expr->VL_VALUE;
+	int uns = expr->ex_type->tp_unsigned;
+	int size = (int) expr->ex_type->tp_size;
+
+	ASSERT(expr->ex_class == Value);
+	if (expr->ex_type->tp_fund == POINTER) {
+		/* why warn on "ptr-3" ?
+		   This quick hack fixes it
+		*/
+		uns = 0;
+	}
+	if (uns) {
+		if (o1 & ~full_mask[size])
+			expr_warning(expr,
+				"overflow in unsigned constant expression");
+		o1 &= full_mask[size];
+	}
+	else {
+		int nbits = (int) (mach_long_size - size) * 8;
+		long remainder = o1 & ~full_mask[size];
+
+		if (remainder != 0 && remainder != ~full_mask[size])
+			expr_warning(expr, "overflow in constant expression");
+		o1 <<= nbits;		/* ??? */
+		o1 >>= nbits;
+	}
+	expr->VL_VALUE = o1;
+}
+
+init_cst()
+{
+	register int i = 0;
+	register arith bt = (arith)0;
+
+	while (!(bt < 0))	{
+		bt = (bt << 8) + 0377, i++;
+		if (i == MAXSIZE)
+			fatal("array full_mask too small for this machine");
+		full_mask[i] = bt;
+	}
+	mach_long_size = i;
+	mach_long_sign = 1L << (mach_long_size * 8 - 1);
+	if ((int)long_size < mach_long_size)
+		fatal("sizeof (long) insufficient on this machine");
+	max_int = full_mask[(int)int_size] & ~(1L << ((int)int_size * 8 - 1));
+	max_unsigned = full_mask[(int)int_size];
+}

+ 37 - 0
lang/cem/cemcom.ansi/dataflow.c

@@ -0,0 +1,37 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*	DATAFLOW ANALYSIS ON C PROGRAMS	*/
+
+/*	Compile the C compiler with flag DATAFLOW.
+	Use the compiler option --d.
+*/
+
+#include	"dataflow.h"	/* UF */
+
+#ifdef	DATAFLOW
+char *CurrentFunction = 0;
+int NumberOfCalls;
+
+DfaStartFunction(nm)
+	char *nm;
+{
+	CurrentFunction = nm;
+	NumberOfCalls = 0;
+}
+
+DfaEndFunction()
+{
+	if (NumberOfCalls == 0)
+		print("DFA: %s: --none--\n", CurrentFunction);
+}
+
+DfaCallFunction(s)
+	char *s;
+{
+	print("DFA: %s: %s\n", CurrentFunction, s);
+	++NumberOfCalls;
+}
+#endif	DATAFLOW

+ 696 - 0
lang/cem/cemcom.ansi/declar.g

@@ -0,0 +1,696 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*	DECLARATION SYNTAX PARSER	*/
+
+{
+#include	"lint.h"
+#include	<alloc.h>
+#include	"nobitfield.h"
+#include	"debug.h"
+#include	"arith.h"
+#include	"LLlex.h"
+#include	"label.h"
+#include	"code.h"
+#include	"idf.h"
+#include	"type.h"
+#include	"proto.h"
+#include	"struct.h"
+#include	"field.h"
+#include	"decspecs.h"
+#include	"def.h"
+#include	"declar.h"
+#include	"label.h"
+#include	"expr.h"
+#include	"sizes.h"
+#include	"level.h"
+#ifdef	LINT
+#include	"l_lint.h"
+#include	"l_state.h"
+#endif	LINT
+}
+
+/* 8 */
+declaration
+	{struct decspecs Ds;}
+:
+	{Ds = null_decspecs;}
+	decl_specifiers(&Ds)
+	init_declarator_list(&Ds)?
+	';'
+;
+
+/*	A `decl_specifiers' describes a sequence of a storage_class_specifier,
+	an unsigned_specifier, a size_specifier and a simple type_specifier,
+	which may occur in arbitrary order and each of which may be absent;
+	at least one of them must be present, however, since the totally
+	empty case has already be dealt with in `external_definition'.
+	This means that something like:
+		unsigned extern int short xx;
+	is perfectly good C.
+	
+	On top of that, multiple occurrences of storage_class_specifiers,
+	unsigned_specifiers and size_specifiers are errors, but a second
+	type_specifier should end the decl_specifiers and be treated as
+	the name to be declared (see the thin ice in RM11.1).
+	Such a language is not easily expressed in a grammar; enumeration
+	of the permutations is unattractive. We solve the problem by
+	having a regular grammar for the "soft" items, handling the single
+	occurrence of the type_specifier in the grammar (we have no choice),
+	collecting all data in a `struct decspecs' and turning that data
+	structure into what we want.
+	
+	The existence of declarations like
+		short typedef yepp;
+	makes all hope of writing a specific grammar for typedefs illusory.
+*/
+
+decl_specifiers	/* non-empty */ (register struct decspecs *ds;)
+	/*	Reads a non-empty decl_specifiers and fills the struct
+		decspecs *ds.
+	*/
+:
+[
+	other_specifier(ds)+
+	[%if (DOT != IDENTIFIER || AHEAD == IDENTIFIER)
+		/* the thin ice in R.M. 11.1 */
+		single_type_specifier(ds) other_specifier(ds)*
+	|
+		empty
+	]
+|
+	single_type_specifier(ds) other_specifier(ds)*
+]
+	{do_decspecs(ds);}
+;
+
+/* 8.1 */
+other_specifier(register struct decspecs *ds;)
+:
+	[ AUTO | STATIC | EXTERN | TYPEDEF | REGISTER ]
+	{	if (ds->ds_sc_given)
+			error("repeated storage class specifier");
+		ds->ds_sc_given = 1;
+		ds->ds_sc = DOT;
+	}
+|
+	[ SHORT | LONG ]
+	{	if (ds->ds_size)
+			error("repeated size specifier");
+		ds->ds_size = DOT;
+	}
+|
+	[ SIGNED | UNSIGNED ]
+	{	if (ds->ds_unsigned != 0)
+			error("repeated sign specifier");
+		ds->ds_unsigned = DOT;
+	}
+|
+	/*	This qualifier applies to the top type.
+		E.g. const float * is a pointer to const float.
+	*/
+	[ VOLATILE | CONST ]
+	{	if (DOT == VOLATILE) {
+			if (ds->ds_typequal & TQ_VOLATILE)
+				error("repeated type qualifier");
+			ds->ds_typequal |= TQ_VOLATILE;
+		}
+		if (DOT == CONST) {
+			if (ds->ds_typequal & TQ_CONST)
+				error("repeated type qualifier");
+			ds->ds_typequal |= TQ_CONST;
+		}
+	}
+;
+
+/* 8.2 */
+type_specifier(struct type **tpp;)
+	/*	Used in struct/union declarations and in casts; only the
+		type is relevant.
+	*/
+	{struct decspecs Ds; Ds = null_decspecs;}
+:
+	decl_specifiers(&Ds)
+	{
+		if (Ds.ds_sc_given)
+			error("storage class ignored");
+		if (Ds.ds_sc == REGISTER)
+			error("register ignored");
+	}
+	{*tpp = Ds.ds_type;}
+;
+
+single_type_specifier(register struct decspecs *ds;):
+	%default TYPE_IDENTIFIER	/* this includes INT, CHAR, etc. */
+	{idf2type(dot.tk_idf, &ds->ds_type);}
+|
+	IDENTIFIER
+	{
+		error("%s is not a type identifier", dot.tk_idf->id_text);
+		ds->ds_type = error_type;
+		if (dot.tk_idf->id_def) {
+			dot.tk_idf->id_def->df_type = error_type;
+			dot.tk_idf->id_def->df_sc = TYPEDEF;
+		}
+	}
+|
+	struct_or_union_specifier(&ds->ds_type)
+|
+	enum_specifier(&ds->ds_type)
+;
+
+/* 8.3 */
+init_declarator_list(struct decspecs *ds;):
+	init_declarator(ds)
+	[ ',' init_declarator(ds) ]*
+;
+
+init_declarator(register struct decspecs *ds;)
+	{
+		struct declarator Dc;
+	}
+:
+	{
+		Dc = null_declarator;
+	}
+[
+	declarator(&Dc)
+	{
+		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)
+	|
+		{ code_declaration(Dc.dc_idf, (struct expr *) 0, level, ds->ds_sc); }
+	]
+]
+	{
+#ifdef	LINT
+		add_auto(Dc.dc_idf);
+#endif	LINT
+		remove_declarator(&Dc);
+	}
+;
+
+/* 8.6: initializer */
+initializer(struct idf *idf; int sc;)
+	{
+		struct expr *expr = (struct expr *) 0;
+		int globalflag = level == L_GLOBAL ||
+				 (level >= L_LOCAL && sc == STATIC);
+	}
+:
+	{	if (idf->id_def->df_type->tp_fund == FUNCTION)	{
+			error("illegal initialization of function");
+			idf->id_def->df_type->tp_fund = ERRONEOUS;
+		}
+	}
+	'='
+	{
+#ifdef	LINT
+		lint_statement();
+#endif	LINT
+		if (globalflag) {
+			struct expr ex;
+			code_declaration(idf, &ex, level, sc);
+		}
+	}
+	initial_value(globalflag ? &(idf->id_def->df_type) : (struct type **)0,
+			&expr)
+	{	if (! globalflag) {
+			if (idf->id_def->df_type->tp_fund == FUNCTION)	{
+				free_expression(expr);
+				expr = 0;
+			}
+#ifdef	DEBUG
+			print_expr("initializer-expression", expr);
+#endif	DEBUG
+#ifdef	LINT
+			change_state(idf, SET);
+#endif	LINT
+			code_declaration(idf, expr, level, sc);
+		}
+		init_idf(idf);
+	}
+;
+
+/*
+	Functions yielding pointers to functions must be declared as, e.g.,
+		int (*hehe(par1, par2))() char *par1, *par2;	{}
+	Since the function heading is read as a normal declarator,
+	we just include the (formal) parameter list in the declarator
+	description list dc.
+*/
+declarator(register struct declarator *dc;)
+	{	struct formal *fm = NO_PARAMS;
+		struct proto *pl = NO_PROTO;
+		arith count;
+		int qual;
+	}
+:
+	primary_declarator(dc)
+	[/*%while(1)*/
+		'('
+		[ %if (DOT != IDENTIFIER && DOT != ')')
+			parameter_type_list(&pl)
+		|
+			formal_list(&fm)
+		|
+			empty
+		]
+		')'
+		{	add_decl_unary(dc, FUNCTION, 0, (arith)0, fm, pl);
+			fm = NO_PARAMS;
+		}
+	|
+		arrayer(&count)
+		{add_decl_unary(dc, ARRAY, 0, count, NO_PARAMS, NO_PROTO);}
+	]*
+|
+	pointer(&qual) declarator(dc)
+	{add_decl_unary(dc, POINTER, qual, (arith)0, NO_PARAMS, NO_PROTO);}
+;
+
+primary_declarator(register struct declarator *dc;) :
+	identifier(&dc->dc_idf)
+|
+	'(' declarator(dc) ')'
+;
+
+arrayer(arith *sizep;)
+	{ struct expr *expr; }
+:
+	'['
+		[
+			constant_expression(&expr)
+			{
+				check_array_subscript(expr);
+				*sizep = expr->VL_VALUE;
+				free_expression(expr);
+			}
+		|
+			empty
+			{ *sizep = (arith)-1; }
+		]
+	']'
+;
+
+formal_list (struct formal **fmp;)
+:
+	formal(fmp) [ ',' formal(fmp) ]*
+;
+
+formal(struct formal **fmp;)
+	{struct idf *idf;	}
+:
+	identifier(&idf)
+	{
+		register struct formal *new = new_formal();
+		
+		new->fm_idf = idf;
+		new->next = *fmp;
+		*fmp = new;
+	}
+;
+
+/* Change 2 */
+enum_specifier(register struct type **tpp;)
+	{
+		struct idf *idf;
+		arith l = (arith)0;
+	}
+:
+	ENUM
+	[
+		{declare_struct(ENUM, (struct idf *) 0, tpp);}
+		enumerator_pack(*tpp, &l)
+	|
+		identifier(&idf)
+		[
+			{declare_struct(ENUM, idf, tpp);}
+			enumerator_pack(*tpp, &l)
+		|
+			{apply_struct(ENUM, idf, tpp);}
+			empty
+		]
+	]
+;
+
+enumerator_pack(register struct type *tp; arith *lp;) :
+	'{'
+	enumerator(tp, lp)
+	[%while (AHEAD != '}')
+		','
+		enumerator(tp, lp)
+	]*
+	[
+		','	{warning("unexpected trailing comma in enumerator pack");}
+	]?
+	'}'
+	{tp->tp_size = int_size;}
+	/*	fancy implementations that put small enums in 1 byte
+		or so should start here.
+	*/
+;
+
+enumerator(struct type *tp; arith *lp;)
+	{
+		struct idf *idf;
+		struct expr *expr;
+	}
+:
+	identifier(&idf)
+	[
+		'='
+		constant_expression(&expr)
+		{
+			*lp = expr->VL_VALUE;
+			free_expression(expr);
+		}
+	]?
+	{declare_enum(tp, idf, (*lp)++);}
+;
+
+/* 8.5 */
+struct_or_union_specifier(register struct type **tpp;)
+	{
+		int fund;
+		struct idf *idfX;
+		register struct idf *idf;
+	}
+:
+	[ STRUCT | UNION ]
+	{fund = DOT;}
+	[
+		{
+			declare_struct(fund, (struct idf *)0, tpp);
+		}
+		struct_declaration_pack(*tpp)
+	|
+		identifier(&idfX)	{ idf = idfX; }
+		[
+			{
+				declare_struct(fund, idf, tpp);
+				(idf->id_struct->tg_busy)++;
+			}
+			struct_declaration_pack(*tpp)
+			{
+				(idf->id_struct->tg_busy)--;
+			}
+		|
+			{apply_struct(fund, idf, tpp);}
+			empty
+		]
+	]
+;
+
+struct_declaration_pack(register struct type *stp;)
+	{
+		struct sdef **sdefp = &stp->tp_sdef;
+		arith size = (arith)0;
+	}
+:
+	/*	The size is only filled in after the whole struct has
+		been read, to prevent recursive definitions.
+	*/
+	'{'
+	struct_declaration(stp, &sdefp, &size)+
+	'}'
+	{stp->tp_size = align(size, stp->tp_align);}
+;
+
+struct_declaration(struct type *stp; struct sdef ***sdefpp; arith *szp;)
+	{struct type *tp;}
+:
+	type_specifier(&tp) struct_declarator_list(tp, stp, sdefpp, szp) ';'
+;
+
+struct_declarator_list(struct type *tp, *stp;
+			struct sdef ***sdefpp; arith *szp;)
+:
+	struct_declarator(tp, stp, sdefpp, szp)
+	[ ',' struct_declarator(tp, stp, sdefpp, szp) ]*
+;
+
+struct_declarator(struct type *tp; struct type *stp;
+			struct sdef ***sdefpp; arith *szp;)
+	{
+		struct declarator Dc;
+		struct field *fd = 0;
+	}
+:
+	{
+		Dc = null_declarator;
+	}
+[
+	declarator(&Dc)
+	{reject_params(&Dc);}
+	bit_expression(&fd)?
+|
+	{Dc.dc_idf = gen_idf();}
+	bit_expression(&fd)
+]
+	{add_sel(stp, declare_type(tp, &Dc), Dc.dc_idf, sdefpp, szp, fd);}
+	{remove_declarator(&Dc);}
+;
+
+bit_expression(struct field **fd;)
+	{ struct expr *expr; }
+:
+	{
+		*fd = new_field();
+	}
+	':'
+	constant_expression(&expr)
+	{
+		(*fd)->fd_width = expr->VL_VALUE;
+		free_expression(expr);
+#ifdef NOBITFIELD
+		error("bitfields are not implemented");
+#endif NOBITFIELD
+	}
+;
+
+/* 8.7 */
+cast(struct type **tpp;)
+	{struct declarator Dc;}
+:
+	{Dc = null_declarator;}
+	'('
+	type_specifier(tpp)
+	abstract_declarator(&Dc)
+	')'
+	{*tpp = declare_type(*tpp, &Dc);}
+	{remove_declarator(&Dc);}
+;
+
+/*	This code is an abject copy of that of 'declarator', for lack of
+	a two-level grammar.
+*/
+abstract_declarator(register struct declarator *dc;)
+	{	struct proto *pl = NO_PROTO;
+		arith count;
+		int qual;
+	}
+:
+	primary_abstract_declarator(dc)
+	[
+		'('
+		[
+			parameter_type_list(&pl)
+		|
+			empty
+		]
+		')'
+		{add_decl_unary(dc, FUNCTION, 0, (arith)0, NO_PARAMS, pl);}
+	|
+		arrayer(&count)
+		{add_decl_unary(dc, ARRAY, 0, count, NO_PARAMS, NO_PROTO);}
+	]*
+|
+	pointer(&qual) abstract_declarator(dc)
+	{add_decl_unary(dc, POINTER, qual, (arith)0, NO_PARAMS, NO_PROTO);}
+;
+
+primary_abstract_declarator(struct declarator *dc;)
+:
+[%if (AHEAD == ')')
+	empty
+|
+	'(' abstract_declarator(dc) ')'
+]
+;
+
+parameter_type_list(struct proto **plp;)
+	{	int save_level; }
+:
+	{	if (level > L_PROTO) {
+			save_level = level;
+			level = L_PROTO;
+		} else level--;
+	}
+	parameter_decl_list(plp)
+	[
+		',' ELLIPSIS
+		{	register struct proto *new = new_proto();
+
+			new->next = *plp;
+			new->pl_flag = ELLIPSIS;
+			*plp = new;
+		}
+
+	]?
+	{	if (level == L_PROTO)
+			level = save_level;
+		else level++;
+	}
+;
+
+parameter_decl_list(struct proto **plp;)
+:
+	parameter_decl(plp)
+	[ %while (AHEAD != ELLIPSIS)
+		',' parameter_decl(plp)
+	]*
+;
+
+parameter_decl(struct proto **plp;)
+	{	register struct proto *new = new_proto();
+		struct declarator Dc;
+		struct decspecs Ds;
+	}
+:
+	{	Dc = null_declarator;
+		Ds = null_decspecs;
+	}
+	decl_specifiers(&Ds)
+	parameter_declarator(&Dc)
+	{	add_proto(new, &Ds, &Dc, level);
+		new->next = *plp;
+		*plp = new;
+	}
+;
+
+/*	This is weird. Due to the LR structure of the ANSI C grammar
+	we have to duplicate the actions of 'declarator' and
+	'abstract_declarator'. Calling these separate, as in
+
+	parameter_decl:
+		decl_specifiers
+		[
+			declarator
+		|
+			abstract_declarator
+		]
+
+
+	gives us a conflict on the terminals '(' and '*'. E.i. on
+	some input, it is impossible to decide which rule we take.
+	Combining the two declarators into one common declarator
+	is out of the question, since this results in an empty
+	string for the non-terminal 'declarator'.
+	So we combine the two only for the use of parameter_decl,
+	since this is the only place where they don't give
+	conflicts. However, this makes the grammar messy.
+*/
+parameter_declarator(register struct declarator *dc;)
+	{	struct formal *fm = NO_PARAMS;
+		struct proto *pl = NO_PROTO;
+		arith count;
+		int qual;
+	}
+:
+	primary_parameter_declarator(dc)
+	[
+		'('
+		[ %if(DOT != IDENTIFIER && DOT != ')')
+			parameter_type_list(&pl)
+		|
+			formal_list(&fm)
+		|
+			empty
+		]
+		')'
+		{add_decl_unary(dc, FUNCTION, 0, (arith)0, fm, pl);}
+	|
+		arrayer(&count)
+		{add_decl_unary(dc, ARRAY, 0, count, NO_PARAMS, NO_PROTO);}
+	]*
+|
+	pointer(&qual) parameter_declarator(dc)
+	{add_decl_unary(dc, POINTER, qual, (arith)0, NO_PARAMS, NO_PROTO);}
+;
+
+primary_parameter_declarator(register struct declarator *dc;)
+:
+[ %if(AHEAD == ')')
+	empty
+|
+	identifier(&dc->dc_idf)
+|
+	'(' parameter_declarator(dc) ')'
+]
+;
+
+pointer(int *qual;)
+:
+	'*' type_qualifier_list(qual)
+;
+
+
+/*	Type qualifiers may come in three flavours:
+	volatile, const, const volatile.
+	These all have different semantic properties:
+
+	volatile:
+		means that the object can be modified
+		without prior knowledge of the implementation.
+
+	const:
+		means that the object can not be modified; thus
+		it's illegal to use this as a l-value.
+
+	const volatile:
+		means  that the object can be modified without
+		prior knowledge of the implementation, but may
+		not be used as a l-value.
+*/
+type_qualifier_list(int *qual;)
+:
+[
+	[ VOLATILE | CONST ]
+	{ *qual = (DOT == VOLATILE) ? TQ_VOLATILE : TQ_CONST; }
+
+	[
+		[ VOLATILE | CONST ]
+		{	if (DOT == VOLATILE) {
+				if (*qual & TQ_VOLATILE)
+					error("repeated type qualifier");
+				*qual |= TQ_VOLATILE;
+			}
+			if (DOT == CONST) {
+				if (*qual & TQ_CONST)
+					error("repeated type qualifier");
+				*qual |= TQ_CONST;
+			}
+		}
+					
+	]*
+|
+	empty
+	{ *qual = 0; }
+]
+;
+
+
+empty:
+;
+
+/* 8.8 */
+/* included in the IDENTIFIER/TYPE_IDENTIFIER mechanism */

+ 44 - 0
lang/cem/cemcom.ansi/declar.str

@@ -0,0 +1,44 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* DEFINITION OF DECLARATOR DESCRIPTORS */
+
+/*	A 'declarator' consists of an idf and a linked list of
+	language-defined unary operations: *, [] and (), called
+	decl_unary's.
+*/
+
+struct declarator	{
+	struct declarator *next;
+	struct idf *dc_idf;
+	struct decl_unary *dc_decl_unary;
+	struct formal *dc_formal;	/* params for function	*/
+};
+
+/* ALLOCDEF "declarator" 50 */
+
+
+struct formal	{			/* list of formals */
+	struct formal *next;
+	struct idf *fm_idf;
+};
+
+/* ALLOCDEF "formal" 5 */
+
+
+#define	NO_PARAMS ((struct formal *) 0)
+
+struct decl_unary	{
+	struct decl_unary *next;
+	int du_fund;			/* POINTER, ARRAY or FUNCTION	*/
+	int du_typequal;		/* CONST, VOLATILE, or 0 */
+	arith du_count;			/* for ARRAYs only	*/
+	struct proto *du_proto;		/* params for function or prototype */
+};
+
+/* ALLOCDEF "decl_unary" 10 */
+
+extern struct type *declare_type();
+extern struct declarator null_declarator;

+ 126 - 0
lang/cem/cemcom.ansi/declarator.c

@@ -0,0 +1,126 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*	D E C L A R A T O R   M A N I P U L A T I O N		*/
+
+#include	"botch_free.h"
+#include	<alloc.h>
+#include	"arith.h"
+#include	"type.h"
+#include	"proto.h"
+#include	"Lpars.h"
+#include	"declar.h"
+#include	"def.h"
+#include	"idf.h"
+#include	"label.h"
+#include	"expr.h"
+#include	"sizes.h"
+#include	"debug.h"
+#include	"level.h"
+
+extern char options[];
+struct declarator null_declarator;
+
+struct type *
+declare_type(tp, dc)
+	struct type *tp;
+	struct declarator *dc;
+{
+	/*	Applies the decl_unary list starting at dc->dc_decl_unary
+		to the type tp and returns the result.
+		Functions that are declared within a parameter type list
+		are purely prototypes. Simply add the type list to the
+		function node.
+	*/
+	register struct decl_unary *du = dc->dc_decl_unary;
+
+	while (du)	{
+		tp = construct_type(du->du_fund, tp, du->du_typequal,
+				    du->du_count, du->du_proto);
+		du = du->next;
+	}
+	return tp;
+}
+
+add_decl_unary(dc, fund, qual,  count, fm, pl)
+	register struct declarator *dc;
+	int qual;
+	arith count;
+	struct formal *fm;
+	struct proto *pl;
+{
+	/*	A decl_unary describing a constructor with fundamental
+		type fund and with size count is inserted in front of the
+		declarator dc.
+	*/
+	register struct decl_unary *new = new_decl_unary();
+
+	new->next = dc->dc_decl_unary;
+	new->du_fund = fund;
+	new->du_count = count;
+	new->du_typequal = qual;
+	new->du_proto = pl;
+	if (fm)	{
+		if (dc->dc_decl_unary)	{
+			/* parameters only allowed at first decl_unary	*/
+			error("formal parameters list discarded");
+		}
+		else	{
+			/* register the proto	*/
+			dc->dc_formal = fm;
+		}
+	}
+
+	dc->dc_decl_unary = new;
+}
+
+remove_declarator(dc)
+	struct declarator *dc;
+{
+	/*	The decl_unary list starting at dc->dc_decl_unary is
+		removed.
+	*/
+	register struct decl_unary *du = dc->dc_decl_unary;
+
+	while (du)	{
+		struct decl_unary *old_du = du;
+
+		du = du->next;
+		free_decl_unary(old_du);
+	}
+}
+
+reject_params(dc)
+	register struct declarator *dc;
+{
+	/*	The declarator is checked to have no parameters, if it
+		is a function.
+	*/
+	if (dc->dc_formal)	{
+		error("non_empty formal parameter pack");
+		free_formals(dc->dc_formal);
+		dc->dc_formal = 0;
+	}
+}
+
+check_array_subscript(expr)
+	register struct expr *expr;
+{
+	arith size = expr->VL_VALUE;
+
+	if (size < 0)	{
+		error("array size is negative");
+		expr->VL_VALUE = (arith)1;
+	}
+	else
+	if (size == 0) {
+		warning("array size is 0");
+	}
+	else
+	if (size & ~max_unsigned) {	/* absolutely ridiculous */
+		expr_error(expr, "overflow in array size");
+		expr->VL_VALUE = (arith)1;
+	}
+}

+ 197 - 0
lang/cem/cemcom.ansi/decspecs.c

@@ -0,0 +1,197 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*	D E C L A R A T I O N   S P E C I F I E R   C H E C K I N G	*/
+
+#include	"nofloat.h"
+#include	"assert.h"
+#include	"Lpars.h"
+#include	"decspecs.h"
+#include	"arith.h"
+#include	"type.h"
+#include	"level.h"
+#include	"def.h"
+#include	"noRoption.h"
+
+extern char options[];
+extern int level;
+extern char *symbol2str();
+extern char *type2str();
+extern char *qual2str();
+extern struct type *qualifier_type();
+
+struct decspecs null_decspecs;
+
+do_decspecs(ds)
+	register struct decspecs *ds;
+{
+	/*	The provisional decspecs ds as obtained from the program
+		is turned into a legal consistent decspecs.
+	*/
+	register struct type *tp = ds->ds_type;
+	
+	ASSERT(level != L_FORMAL1);
+	
+	/*
+	if (ds->ds_notypegiven && !ds->ds_sc_given)
+		strict("data definition lacking type or storage class");
+	*/
+
+	if (	level == L_GLOBAL &&
+		(ds->ds_sc == AUTO || ds->ds_sc == REGISTER)
+	)	{
+		warning("no global %s variable allowed",
+			symbol2str(ds->ds_sc));
+		ds->ds_sc = GLOBAL;
+	}
+
+	if (level == L_FORMAL2)	{
+		if (ds->ds_sc_given &&
+		    ds->ds_sc != REGISTER){
+			error("%s formal illegal", symbol2str(ds->ds_sc));
+			ds->ds_sc = FORMAL;
+		}
+	}
+
+	/*	Since type qualifiers may be associated with types by means
+		of typedefs, we have to perform same basic tests down here.
+	*/
+	if (tp != (struct type *)0) {
+		if ((ds->ds_typequal & TQ_VOLATILE) && (tp->tp_typequal & TQ_VOLATILE))
+			error("indirect repeated type qualifier");
+		if ((ds->ds_typequal & TQ_CONST) && (tp->tp_typequal & TQ_CONST))
+			error("indirect repeated type qualifier");
+		ds->ds_typequal |= tp->tp_typequal;
+	}
+
+	/*	The tests concerning types require a full knowledge of the
+		type and will have to be postponed to declare_idf.
+	*/
+
+	/* some adjustments as described in RM 8.2 */
+	if (tp == 0) {
+		ds->ds_notypegiven = 1;
+		tp = int_type;
+	}
+	switch (ds->ds_size)	{
+	case SHORT:
+		if (tp == int_type)
+			tp = short_type;
+		else
+			error("short with illegal type");
+		break;
+	case LONG:
+		if (tp == int_type)
+			tp = long_type;
+		else
+#ifndef NOFLOAT
+		if (tp == double_type)
+			tp = lngdbl_type;
+		else
+#endif NOFLOAT
+			error("long with illegal type");
+		break;
+	}
+	if (ds->ds_unsigned == UNSIGNED) {
+		switch (tp->tp_fund)	{
+		case CHAR:
+#ifndef NOROPTION
+			if (options['R'])
+				warning("unsigned char not allowed");
+#endif
+			tp = uchar_type;
+			break;
+		case SHORT:
+#ifndef NOROPTION
+			if (options['R'])
+				warning("unsigned short not allowed");
+#endif
+			tp = ushort_type;
+			break;
+		case INT:
+			tp = uint_type;
+			break;
+		case LONG:
+#ifndef NOROPTION
+			if (options['R'])
+				warning("unsigned long not allowed");
+#endif
+			tp = ulong_type;
+			break;
+		default:
+			error("unsigned with illegal type");
+			break;
+		}
+	}
+	if (ds->ds_unsigned == SIGNED) {
+		switch (tp->tp_fund) {
+		case CHAR:
+			tp = char_type;
+			break;
+		case SHORT:
+			tp = short_type;
+			break;
+		case INT:
+			tp = int_type;
+			break;
+		case LONG:
+			tp = long_type;
+			break;
+		default:
+			error("signed with illegal type");
+			break;
+		}
+	}
+
+	ds->ds_type = qualifier_type(tp, ds->ds_typequal);
+}
+
+/*	Make tp into a qualified type. This is not as trivial as it
+	may seem. If tp is a fundamental type the qualified type is
+	either existent or will be generated.
+	In case of a complex type the top of the type list will be
+	replaced by a qualified version.
+*/
+struct type *
+qualifier_type(tp, typequal)
+	register struct type *tp;
+	int typequal;
+{
+	register struct type *dtp = tp;
+	register int fund = tp->tp_fund;
+
+	while (dtp && dtp->tp_typequal != typequal)
+		dtp = dtp->next;
+
+	if (!dtp) {
+		dtp = create_type(fund);
+		dtp->tp_unsigned = tp->tp_unsigned;
+		dtp->tp_align = tp->tp_align;
+		dtp->tp_typequal = typequal;
+		dtp->tp_size = tp->tp_size;
+		switch (fund) {
+		case POINTER:
+		case ARRAY:
+		case FUNCTION:
+		case STRUCT:
+		case UNION:
+		case ENUM:
+			dtp->tp_idf = tp->tp_idf;
+			dtp->tp_sdef = tp->tp_sdef;
+			dtp->tp_up = tp->tp_up;
+			dtp->tp_field = tp->tp_field;
+			dtp->tp_pointer = tp->tp_pointer;
+			dtp->tp_array = tp->tp_array;
+			dtp->tp_function = tp->tp_function;
+			break;
+		default:
+			break;
+		}
+		dtp->next = tp->next; /* don't know head or tail */
+		tp->next = dtp;
+	}
+	return(dtp);
+}
+

+ 20 - 0
lang/cem/cemcom.ansi/decspecs.str

@@ -0,0 +1,20 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* DECLARATION SPECIFIER DEFINITION */
+
+struct decspecs	{
+	struct decspecs *next;
+	struct type *ds_type;	/* single type */
+	int ds_notypegiven;	/* set if type not given explicitly */
+	int ds_sc_given;	/* 1 if the st. class is explicitly given */
+	int ds_sc;		/* storage class, given or implied */
+	int ds_size;		/* LONG, SHORT or 0 */
+	int ds_unsigned;	/* SIGNED, UNSIGNED or 0 */
+	int ds_typequal;	/* type qualifiers - see type.str */
+};
+
+extern struct type *qualifier_type();
+extern struct decspecs null_decspecs;

+ 40 - 0
lang/cem/cemcom.ansi/def.str

@@ -0,0 +1,40 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* IDENTIFIER DEFINITION DESCRIPTOR */
+
+#include	"lint.h"
+
+struct def	{		/* for ordinary tags */
+	struct def *next;
+	int df_level;
+	struct type *df_type;
+	int df_sc;		/*	may be:
+					GLOBAL, STATIC, EXTERN, IMPLICIT,
+					TYPEDEF,
+					FORMAL, AUTO,
+					ENUM, LABEL
+				*/
+	char df_initialized;	/* an initialization has been generated */
+	char df_alloc;		/* 0, ALLOC_SEEN or ALLOC_DONE */
+	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;
+};
+
+#define	ALLOC_SEEN	1	/* an allocating declaration has been seen */
+#define	ALLOC_DONE	2	/* the allocating declaration has been done */
+
+#define REG_DEFAULT	0	/* register candidate, not declared as such */
+#define REG_BONUS	10	/* register candidate, declared as such */
+
+/* ALLOCDEF "def" 50 */

+ 688 - 0
lang/cem/cemcom.ansi/domacro.c

@@ -0,0 +1,688 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* PREPROCESSOR: CONTROLLINE INTERPRETER */
+
+#include	"arith.h"
+#include	"LLlex.h"
+#include	"Lpars.h"
+#include	"debug.h"
+#include	"idf.h"
+#include	"input.h"
+#include	"nopp.h"
+
+#ifndef NOPP
+#include	"ifdepth.h"	
+#include	"botch_free.h"	
+#include	"nparams.h"	
+#include	"parbufsize.h"	
+#include	"textsize.h"	
+#include	"idfsize.h"	
+#include	"assert.h"
+#include	<alloc.h>
+#include	"class.h"
+#include	"macro.h"
+
+extern	char **inctable;	/* list of include directories		*/
+extern	char *getwdir();
+char ifstack[IFDEPTH];	/* if-stack: the content of an entry is	*/
+				/* 1 if a corresponding ELSE has been	*/
+				/* encountered.				*/
+
+int	nestlevel = -1;
+
+struct idf *
+GetIdentifier()
+{
+	/*	returns a pointer to the descriptor of the identifier that is
+		read from the input stream. A null-pointer is returned if
+		the input does not contain an identifier.
+		The substitution of macros is disabled.
+	*/
+	int tok;
+	struct token tk;
+
+	ReplaceMacros = 0;
+	tok = GetToken(&tk);
+	ReplaceMacros = 1;
+	return tok == IDENTIFIER ? tk.tk_idf : (struct idf *)0;
+}
+
+/*	domacro() is the control line interpreter. The '#' has already
+	been read by the lexical analyzer by which domacro() is called.
+	The token appearing directly after the '#' is obtained by calling
+	the basic lexical analyzing function GetToken() and is interpreted
+	to perform the action belonging to that token.
+	An error message is produced when the token is not recognized,
+	i.e. it is not one of "define" .. "undef" , integer or newline.
+*/
+domacro()
+{
+	struct token tk;	/* the token itself			*/
+
+	EoiForNewline = 1;
+	switch(GetToken(&tk)) {		/* select control line action	*/
+	case IDENTIFIER:		/* is it a macro keyword?	*/
+		switch (tk.tk_idf->id_resmac) {
+		case K_DEFINE:				/* "define"	*/
+			do_define();
+			break;
+		case K_ELIF:				/* "elif"	*/
+			do_elif();
+			break;
+		case K_ELSE:				/* "else"	*/
+			do_else();
+			break;
+		case K_ENDIF:				/* "endif"	*/
+			do_endif();
+			break;
+		case K_IF:				/* "if"		*/
+			do_if();
+			break;
+		case K_IFDEF:				/* "ifdef"	*/
+			do_ifdef(1);
+			break;
+		case K_IFNDEF:				/* "ifndef"	*/
+			do_ifdef(0);
+			break;
+		case K_INCLUDE:				/* "include"	*/
+			do_include();
+			break;
+		case K_LINE:				/* "line"	*/
+			/*	set LineNumber and FileName according to
+				the arguments.
+			*/
+			if (GetToken(&tk) != INTEGER) {
+				lexerror("#line without linenumber");
+				SkipToNewLine(0);
+			}
+			else
+				do_line((unsigned int)tk.tk_ival);
+			break;
+		case K_ERROR:				/* "error"	*/
+			do_error();
+			break;
+		case K_PRAGMA:				/* "pragma"	*/
+			do_pragma();
+			break;
+		case K_UNDEF:				/* "undef"	*/
+			do_undef();
+			break;
+		default:
+			/* invalid word seen after the '#'	*/
+			lexerror("%s: unknown control", tk.tk_idf->id_text);
+			SkipToNewLine(0);
+		}
+		break;
+	case INTEGER:		/* # <integer> [<filespecifier>]?	*/
+		do_line((unsigned int)tk.tk_ival);
+		break;
+	case EOI:	/* only `#' on this line: do nothing, ignore	*/
+		break;
+	default:	/* invalid token following '#'		*/
+		lexerror("illegal # line");
+		SkipToNewLine(0);
+	}
+	EoiForNewline = 0;
+}
+
+
+skip_block()
+{
+	/*	skip_block() skips the input from
+		1)	a false #if, #ifdef, #ifndef or #elif until the
+			corresponding #elif (resulting in true), #else or
+			#endif is read.
+		2)	a #else corresponding to a true #if, #ifdef,
+			#ifndef or #elif until the corresponding #endif is
+			seen.
+	*/
+	register int ch;
+	register int skiplevel = nestlevel; /* current nesting level	*/
+	struct token tk;
+
+	NoUnstack++;
+	for (;;) {
+		ch = GetChar();	/* read first character after newline	*/
+		while (class(ch) == STSKIP)
+			ch = GetChar();
+		if (ch != '#') {
+			if (ch == EOI) {
+				NoUnstack--;
+				return;
+			}
+			SkipToNewLine(0);
+			continue;
+		}
+		if (GetToken(&tk) != IDENTIFIER) {
+			SkipToNewLine(0);
+			continue;
+		}
+		/*	an IDENTIFIER: look for #if, #ifdef and #ifndef
+			without interpreting them.
+			Interpret #else, #elif and #endif if they occur
+			on the same level.
+		*/
+		switch(tk.tk_idf->id_resmac) {
+		case K_IF:
+		case K_IFDEF:
+		case K_IFNDEF:
+			push_if();
+			break;
+		case K_ELIF:
+			if (nestlevel == skiplevel) {
+				nestlevel--;
+				push_if();
+				if (ifexpr()) {
+					NoUnstack--;
+					return;
+				}
+			}
+			break;
+		case K_ELSE:
+			++(ifstack[nestlevel]);
+			if (nestlevel == skiplevel) {
+				if (SkipToNewLine(1))
+					strict("garbage following #endif");
+				NoUnstack--;
+				return;
+			}
+			break;
+		case K_ENDIF:
+			ASSERT(nestlevel > nestlow);
+			if (nestlevel == skiplevel) {
+				if (SkipToNewLine(1))
+					strict("garbage following #endif");
+				nestlevel--;
+				NoUnstack--;
+				return;
+			}
+			nestlevel--;
+			break;
+		}
+	}
+}
+
+
+ifexpr()
+{
+	/*	ifexpr() returns whether the restricted constant
+		expression following #if or #elif evaluates to true.  This
+		is done by calling the LLgen generated subparser for
+		constant expressions.  The result of this expression will
+		be given in the extern long variable "ifval".
+	*/
+	extern arith ifval;
+	int errors = err_occurred;
+
+	ifval = (arith)0;
+	AccDefined = 1;
+	UnknownIdIsZero = 1;
+	PushLex();	/* NEW parser */
+	If_expr();	/* invoke constant expression parser	*/
+	PopLex();	/* OLD parser */
+	AccDefined = 0;
+	UnknownIdIsZero = 0;
+	return (errors == err_occurred) && (ifval != (arith)0);
+}
+
+do_include()
+{
+	/*	do_include() performs the inclusion of a file.
+	*/
+	char *filenm;
+	char *result;
+	int tok;
+	struct token tk;
+
+	AccFileSpecifier = 1;
+	if (((tok = GetToken(&tk)) == FILESPECIFIER) || tok == STRING)
+		filenm = tk.tk_bts;
+	else {
+		lexerror("bad include syntax");
+		filenm = (char *)0;
+	}
+	AccFileSpecifier = 0;
+	SkipToNewLine(0);
+	inctable[0] = WorkingDir;
+	if (filenm) {
+		if (!InsertFile(filenm, &inctable[tok==FILESPECIFIER],&result)){
+			fatal("cannot open include file \"%s\"", filenm);
+		}
+		else {
+			WorkingDir = getwdir(result);
+			File_Inserted = 1;
+			FileName = result;
+			LineNumber = 0;
+			nestlow = nestlevel;
+		}
+	}
+}
+
+do_define()
+{
+	/*	do_define() interprets a #define control line.
+	*/
+	struct idf *id;		/* the #defined identifier's descriptor	*/
+	int nformals = -1;	/* keep track of the number of formals	*/
+	char *formals[NPARAMS];	/* pointers to the names of the formals	*/
+	char parbuf[PARBUFSIZE];		/* names of formals	*/
+	char *repl_text;	/* start of the replacement text	*/
+	int length;		/* length of the replacement text	*/
+	register ch;
+	char *get_text();
+
+	/* read the #defined macro's name	*/
+	if (!(id = GetIdentifier())) {
+		lexerror("#define: illegal macro name");
+		SkipToNewLine(0);
+		return;
+	}
+	/*	there is a formal parameter list if the identifier is
+		followed immediately by a '('. 
+	*/
+	ch = GetChar();
+	if (ch == '(') {
+		if ((nformals = getparams(formals, parbuf)) == -1) {
+			SkipToNewLine(0);
+			return;	/* an error occurred	*/
+		}
+		ch = GetChar();
+	}
+	/* read the replacement text if there is any			*/
+	ch = skipspaces(ch,0);	/* find first character of the text	*/
+	ASSERT(ch != EOI);
+	if (class(ch) == STNL) {
+		/*	Treat `#define something' as `#define something ""'
+		*/
+		repl_text = "";
+		length = 0;
+	}
+	else {
+		UnGetChar();
+		repl_text = get_text((nformals > 0) ? formals : 0, &length);
+	}
+	macro_def(id, repl_text, nformals, length, NOFLAG);
+	LineNumber++;
+}
+
+push_if()
+{
+	if (nestlevel >= IFDEPTH)
+		fatal("too many nested #if/#ifdef/#ifndef");
+	else
+		ifstack[++nestlevel] = 0;
+}
+
+do_elif()
+{
+	if (nestlevel <= nestlow || (ifstack[nestlevel])) {
+		lexerror("#elif without corresponding #if");
+		SkipToNewLine(0);
+	}
+	else { /* restart at this level as if a #if is detected.  */
+		nestlevel--;
+		push_if();
+		skip_block();
+	}
+}
+
+do_else()
+{
+	struct token tok;
+
+	if (SkipToNewLine(1))
+		strict("garbage following #else");
+	if (nestlevel <= nestlow || (ifstack[nestlevel]))
+		lexerror("#else without corresponding #if");
+	else {	/* mark this level as else-d */
+		++(ifstack[nestlevel]);
+		skip_block();
+	}
+}
+
+do_endif()
+{
+	struct token tok;
+
+	if (SkipToNewLine(1))
+		strict("garbage following #endif");
+	if (nestlevel <= nestlow)	{
+		lexerror("#endif without corresponding #if");
+	}
+	else	nestlevel--;
+}
+
+do_if()
+{
+	push_if();
+	if (!ifexpr())	/* a false #if/#elif expression */
+		skip_block();
+}
+
+do_ifdef(how)
+{
+	register struct idf *id;
+
+	/*	how == 1 : ifdef; how == 0 : ifndef
+	*/
+	push_if();
+	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
+		SkipToNewLine(0);
+}
+
+do_undef()
+{
+	register struct idf *id;
+
+	/* Forget a macro definition.	*/
+	if (id = GetIdentifier()) {
+		if (id->id_macro) { /* forget the macro */
+			free_macro(id->id_macro);
+			id->id_macro = (struct macro *) 0;
+		} /* else: don't complain */
+	}
+	else
+		lexerror("illegal #undef construction");
+	SkipToNewLine(0);
+}
+
+do_error()
+{
+	static char errbuf[512];
+	register char *bp = errbuf;
+	register int ch;
+
+	while ((ch = GetChar()) != '\n')
+		*bp++ = ch;
+	*bp = '\0';
+	UnGetChar();
+	lexerror("user error: %s", errbuf);
+}
+
+int
+getparams(buf, parbuf)
+	char *buf[];
+	char parbuf[];
+{
+	/*	getparams() reads the formal parameter list of a macro
+		definition.
+		The number of parameters is returned.
+		As a formal parameter list is expected when calling this
+		routine, -1 is returned if an error is detected, for
+		example:
+			#define one(1), where 1 is not an identifier.
+		Note that the '(' has already been eaten.
+		The names of the formal parameters are stored into parbuf.
+	*/
+	register char **pbuf = &buf[0];
+	register int c;
+	register char *ptr = &parbuf[0];
+	register char **pbuf2;
+
+	c = GetChar();
+	c = skipspaces(c,0);
+	if (c == ')') {		/* no parameters: #define name()	*/
+		*pbuf = (char *) 0;
+		return 0;
+	}
+	for (;;) {		/* eat the formal parameter list	*/
+		if (class(c) != STIDF && class(c) != STELL) {
+			lexerror("#define: bad formal parameter");
+			return -1;
+		}
+		*pbuf = ptr;	/* name of the formal	*/
+		*ptr++ = c;
+		if (ptr >= &parbuf[PARBUFSIZE])
+			fatal("formal parameter buffer overflow");
+		do {			/* eat the identifier name	*/
+			c = GetChar();
+			*ptr++ = c;
+			if (ptr >= &parbuf[PARBUFSIZE])
+				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,0);
+		if (c == ')') {	/* end of the formal parameter list	*/
+			*pbuf = (char *) 0;
+			return pbuf - buf;
+		}
+		if (c != ',') {
+			lexerror("#define: bad formal parameter list");
+			return -1;
+		}
+		c = GetChar();
+		c = skipspaces(c,0);
+	}
+	/*NOTREACHED*/
+}
+
+macro_def(id, text, nformals, length, flags)
+	register struct idf *id;
+	char *text;
+{
+	register struct macro *newdef = id->id_macro;
+
+	/*	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.
+	*/
+	if (newdef) {		/* is there a redefinition?	*/
+		if (macroeq(newdef->mc_text, text))
+			return;
+		lexwarning("redefine \"%s\"", id->id_text);
+	}
+	else
+		id->id_macro = newdef = new_macro();
+	newdef->mc_text = text;		/* replacement text	*/
+	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;
+}
+
+int
+find_name(nm, index)
+	char *nm, *index[];
+{
+	/*	find_name() returns the index of "nm" in the namelist
+		"index" if it can be found there.  0 is returned if it is
+		not there.
+	*/
+	register char **ip = &index[0];
+
+	while (*ip)
+		if (strcmp(nm, *ip++) == 0)
+			return ip - &index[0];
+	/* arrived here, nm is not in the name list.	*/
+	return 0;
+}
+
+char *
+get_text(formals, length)
+	char *formals[];
+	int *length;
+{
+	/*	get_text() copies the replacement text of a macro
+		definition with zero, one or more parameters, thereby
+		substituting each formal parameter by a special character
+		(non-ascii: 0200 & (order-number in the formal parameter
+		list)) in order to substitute this character later by the
+		actual parameter.  The replacement text is copied into
+		itself because the copied text will contain fewer or the
+		same amount of characters.  The length of the replacement
+		text is returned.
+
+		Implementation:
+		finite automaton : we are only interested in
+		identifiers, because they might be replaced by some actual
+		parameter.  Other tokens will not be seen as such.
+	*/
+	register int c;
+	register int text_size;
+	char *text = Malloc(text_size = ITEXTSIZE);
+	register int pos = 0;
+
+	c = GetChar();
+
+	while ((c != EOI) && (class(c) != STNL)) {
+		if (c == '\'' || c == '"') {
+			register int delim = c;
+
+			do {
+				/* being careful, as ever */
+				if (pos+3 >= text_size)
+					text = Srealloc(text,
+							text_size += RTEXTSIZE);
+				text[pos++] = c;
+				if (c == '\\')
+					text[pos++] = GetChar();
+				c = GetChar();
+			} while (c != delim && c != EOI && class(c) != STNL);
+			text[pos++] = c;
+			c = GetChar();
+		}
+		else
+		if (c == '/') {
+			c = GetChar();
+			if (pos+1 >= text_size)
+				text = Srealloc(text, text_size += RTEXTSIZE);
+			if (c == '*') {
+				skipcomment();
+				text[pos++] = ' ';
+				c = GetChar();
+			}
+			else
+				text[pos++] = '/';
+		}
+		else
+		if (formals && (class(c) == STIDF || class(c) == STELL)) {
+			char id_buf[IDFSIZE + 1];
+			register id_size = 0;
+			register n;
+
+			/* read identifier: it may be a formal parameter */
+			id_buf[id_size++] = c;
+			do {
+				c = GetChar();
+				if (id_size <= IDFSIZE)
+					id_buf[id_size++] = c;
+			} while (in_idf(c));
+			id_buf[--id_size] = '\0';
+			if (n = find_name(id_buf, formals)) {
+				/* construct the formal parameter mark	*/
+				if (pos+1 >= text_size)
+					text = Srealloc(text,
+						text_size += RTEXTSIZE);
+				text[pos++] = FORMALP | (char) n;
+			}
+			else {
+				register char *ptr = &id_buf[0];
+
+				while (pos + id_size >= text_size)
+					text = Srealloc(text,
+						text_size += RTEXTSIZE);
+				while (text[pos++] = *ptr++) ;
+				pos--;
+			}
+		}
+		else {
+			if (pos+1 >= text_size)
+				text = Srealloc(text, text_size += RTEXTSIZE);
+			text[pos++] = c;
+			c = GetChar();
+		}
+	}
+	text[pos++] = '\0';
+	*length = pos - 1;
+	return text;
+}
+
+#define	BLANK(ch)	((ch == ' ') || (ch == '\t'))
+
+/*	macroeq() decides whether two macro replacement texts are
+	identical.  This version compares the texts, which occur
+	as strings, without taking care of the leading and trailing
+	blanks (spaces and tabs).
+*/
+macroeq(s, t)
+	register char *s, *t;
+{
+	
+	/* skip leading spaces	*/
+	while (BLANK(*s)) s++;
+	while (BLANK(*t)) t++;
+	/* first non-blank encountered in both strings	*/
+	/* The actual comparison loop:			*/
+	while (*s && *s == *t)
+		s++, t++;
+	/* two cases are possible when arrived here:	*/
+	if (*s == '\0')	{	/* *s == '\0'		*/
+		while (BLANK(*t)) t++;
+		return *t == '\0';
+	}
+	else	{		/* *s != *t		*/
+		while (BLANK(*s)) s++;
+		while (BLANK(*t)) t++;
+		return (*s == '\0') && (*t == '\0');
+	}
+}
+#else NOPP
+domacro()
+{
+	int tok;
+	struct token tk;
+
+	EoiForNewline = 1;
+	if ((tok = GetToken(&tk)) == IDENTIFIER) {
+		if (strcmp(tk.tk_idf->id_text, "line") != 0) {
+			error("illegal # line");
+			SkipToNewLine(0);
+			return;
+		}
+		tok = GetToken(&tk);
+	}
+	if (tok != INTEGER) {
+		error("illegal # line");
+		SkipToNewLine(0);
+		return;
+	}
+	do_line((unsigned int) tk.tk_ival);
+	EoiForNewline = 0;
+}
+#endif NOPP
+
+
+do_line(l)
+	unsigned int l;
+{
+	struct token tk;
+
+	LineNumber = l - 1;	/* the number of the next input line */
+	if (GetToken(&tk) == STRING)	/* is there a filespecifier? */
+		FileName = tk.tk_bts;
+	SkipToNewLine(0);
+}

+ 512 - 0
lang/cem/cemcom.ansi/dumpidf.c

@@ -0,0 +1,512 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*	DUMP ROUTINES	*/
+
+#include	"debug.h"
+
+#ifdef	DEBUG
+#include	"nofloat.h"
+#include	"nopp.h"
+#include	"nobitfield.h"
+#include	"arith.h"
+#include	"stack.h"
+#include	"idf.h"
+#include	"def.h"
+#include	"type.h"
+#include	"proto.h"
+#include	"struct.h"
+#include	"field.h"
+#include	"Lpars.h"
+#include	"label.h"
+#include	"expr.h"
+#include	"static.h"
+#include	"declar.h"
+
+/*	Some routines (symbol2str, token2str, type2str) which should have
+ *	yielded strings are written to yield a pointer to a transient piece
+ *	of memory, containing the string, since this is the only reasonable
+ *	thing to do in C. `Transient' means that the result may soon
+ *	disappear, which is generally not a problem, since normally it is
+ *	consumed immediately. Sometimes we need more than one of them, and
+ *	MAXTRANS is the maximum number we will need simultaneously.
+ */
+#define	MAXTRANS	6
+
+extern char options[];
+
+extern char *sprint();
+
+extern struct idf *idf_hashtable[];
+extern char *symbol2str(), *type2str(), *qual2str(), *next_transient();
+
+enum sdef_kind {selector, field};		/* parameter for dumpsdefs */
+
+static int dumplevel;
+
+newline()	{
+	register int dl = dumplevel;
+	
+	print("\n");
+	while (dl >= 2)	{
+		print("\t");
+		dl -= 2;
+	}
+	if (dl)
+		print("    ");
+}
+
+dumpidftab(msg, opt)
+	char msg[];
+{
+	/*	Dumps the identifier table in readable form (but in
+		arbitrary order).
+		Unless opt & 1, macros are not dumped.
+		Unless opt & 2, reserved identifiers are not dumped.
+		Unless opt & 4, universal identifiers are not dumped.
+	*/
+	int i;
+
+	print(">>> DUMPIDF, %s (start)", msg);
+	dumpstack();
+	for (i = 0; i < HASHSIZE; i++)	{
+		register struct idf *notch = idf_hashtable[i];
+
+		while (notch)	{
+			dumpidf(notch, opt);
+			notch = notch->next;
+		}
+	}
+	newline();
+	print(">>> DUMPIDF, %s (end)\n", msg);
+}
+
+dumpstack()
+{
+	/*	Dumps the identifier stack, starting at the top.
+	*/
+	register struct stack_level *stl = local_level;
+	
+	while (stl)	{
+		register struct stack_entry *se = stl->sl_entry;
+		
+		newline();
+		print("%3d: ", stl->sl_level);
+		while (se)	{
+			print("%s ", se->se_idf->id_text);
+			se = se->next;
+		}
+		stl = stl->sl_previous;
+	}
+	print("\n");
+}
+
+dumpidf(idf, opt)
+	register struct idf *idf;
+{
+	/*	All information about the identifier idf is divulged in a
+		hopefully readable format.
+	*/
+	int started = 0;
+	
+	if (!idf)
+		return;
+#ifndef NOPP
+	if ((opt&1) && idf->id_macro)	{
+		if (!started++)	{
+			newline();
+			print("%s:", idf->id_text);
+		}
+		print(" macro");
+	}
+#endif NOPP
+	if ((opt&2) && idf->id_reserved)	{
+		if (!started++)	{
+			newline();
+			print("%s:", idf->id_text);
+		}
+		print(" reserved: %d;", idf->id_reserved);
+	}
+	if (idf->id_def && ((opt&4) || idf->id_def->df_level))	{
+		if (!started++)	{
+			newline();
+			print("%s:", idf->id_text);
+		}
+		dumpdefs(idf->id_def, opt);
+	}
+	if (idf->id_sdef)	{
+		if (!started++)	{
+			newline();
+			print("%s:", idf->id_text);
+		}
+		dumpsdefs(idf->id_sdef, selector);
+	}
+	if (idf->id_struct)	{
+		if (!started++)	{
+			newline();
+			print("%s:", idf->id_text);
+		}
+		dumptags(idf->id_struct);
+	}
+	if (idf->id_enum)	{
+		if (!started++)	{
+			newline();
+			print("%s:", idf->id_text);
+		}
+		dumptags(idf->id_enum);
+	}
+}
+
+dumpdefs(def, opt)
+	register struct def *def;
+{
+	dumplevel++;
+	while (def && ((opt&4) || def->df_level))	{
+		newline();
+		print("L%d: %s %s%stype%s %lo; ",
+			def->df_level,
+			symbol2str(def->df_sc),
+			def->df_initialized ? "init'd " : "",
+			def->df_used ? "used " : "",
+			def->df_sc == ENUM ? ", =" : " at",
+			def->df_address
+		);
+		print("%s, line %u",
+			def->df_file ? def->df_file : "NO_FILE", def->df_line);
+		dump_type(def->df_type);
+		def = def->next;
+	}
+	dumplevel--;
+}
+
+dumptags(tag)
+	register struct tag *tag;
+{
+	dumplevel++;
+	while (tag)	{
+		register struct type *tp = tag->tg_type;
+		register int fund = tp->tp_fund;
+
+		newline();
+		print("L%d: %s %s",
+			tag->tg_level,
+			fund == STRUCT ? "struct" :
+			fund == UNION ? "union" :
+			fund == ENUM ? "enum" : "<UNKNOWN>",
+			tp->tp_idf->id_text
+		);
+		if (is_struct_or_union(fund))	{
+			print(" {");
+			dumpsdefs(tp->tp_sdef, field);
+			newline();
+			print("}");
+		}
+		print(";");
+		tag = tag->next;
+	}
+	dumplevel--;
+}
+
+dumpsdefs(sdef, sdk)
+	register struct sdef *sdef;
+	enum sdef_kind sdk;
+{
+	/*	Since sdef's are members of two chains, there are actually
+		two dumpsdefs's, one following the chain of all selectors
+		belonging to the same idf, starting at idf->id_sdef;
+		and the other following the chain of all selectors belonging
+		to the same struct, starting at stp->tp_sdef.
+	*/
+
+	dumplevel++;
+	while (sdef)	{
+		newline();
+		print("L%d: ", sdef->sd_level);
+#ifndef NOBITFIELD
+		if (sdk == selector)
+#endif NOBITFIELD
+			print("selector %s at offset %lu in %s;",
+				type2str(sdef->sd_type),
+				sdef->sd_offset, type2str(sdef->sd_stype)
+			);
+#ifndef NOBITFIELD
+		else	print("field %s at offset %lu;",
+				type2str(sdef->sd_type), sdef->sd_offset
+			);
+#endif NOBITFIELD
+		sdef = (sdk == selector ? sdef->next : sdef->sd_sdef);
+	}
+	dumplevel--;
+}
+
+dump_proto(pl)
+	register struct proto *pl;
+{
+	register struct type *type;
+	register int argcnt = 0;
+
+	newline();
+	print("dump proto type list (start)");
+	newline();
+	while (pl) {
+		print("%d: %s", argcnt++,
+			pl->pl_flag == FORMAL ?
+			(pl->pl_flag == VOID ? "void" : "formal")
+			: "ellipsis");
+		newline();
+		if (type = pl->pl_type){
+			dump_type(type);
+			newline();
+		}
+		if (pl->pl_idf) {
+			dumplevel++;
+			print("idf:");
+			dumpidf(pl->pl_idf, 7);
+			dumplevel--;
+		}
+		newline();
+		pl = pl->next;
+	}
+	print("dump proto type list (end)\n");
+}
+
+dump_type(tp)
+	register struct type *tp;
+{
+	int ops = 1;
+
+	dumplevel++;
+	newline();
+	if (!tp) {
+		print("<NILTYPE>");
+		newline();
+		return;
+	}
+
+	print("(@%lx, #%ld, &%d) ", tp, (long)tp->tp_size, tp->tp_align);
+
+	while (ops)	{
+		print("%s", qual2str(tp->tp_typequal));
+		switch (tp->tp_fund)	{
+		case POINTER:
+			print("pointer to ");
+			break;
+		case ARRAY:
+			print("array [%ld] of ", tp->tp_size);
+			break;
+		case FUNCTION:
+			print("function ");
+			if (tp->tp_proto) {
+				print("with prototype");
+				dumplevel++;
+				dump_proto(tp->tp_proto);
+				dumplevel--;
+				newline();
+			}
+			print("yielding ");
+			break;
+		default:
+			print("%s%s ", tp->tp_unsigned ? "unsigned " : "",
+				       symbol2str(tp->tp_fund));
+			if (tp->tp_idf)
+				print("%s ", tp->tp_idf->id_text);
+#ifndef NOBITFIELD
+			if (tp->tp_field)	{
+				struct field *fd = tp->tp_field;
+				
+				print("[s=%ld,w=%ld] of ",
+					fd->fd_shift, fd->fd_width);
+			}
+			else
+#endif NOBITFIELD
+			ops = 0;
+			break;
+		}
+		tp = tp->tp_up;
+	}
+	dumplevel--;
+}
+
+char *
+type2str(tp)
+	register struct type *tp;
+{
+	/*	Yields a pointer to a one-line description of the type tp.
+	*/
+	char *buf = next_transient();
+	int ops = 1;
+
+	buf[0] = '\0';
+	if (!tp)	{
+		sprint(buf, "<NILTYPE>");
+		return buf;
+	}
+	sprint(buf, "%s(@%lx, #%ld, &%d) ",
+			buf, tp, (long)tp->tp_size, tp->tp_align);
+
+	while (ops)	{
+		sprint(buf, "%s%s", buf, qual2str(tp->tp_typequal));
+		switch (tp->tp_fund)	{
+		case POINTER:
+			sprint(buf, "%spointer to ", buf);
+			break;
+		case ARRAY:
+			sprint(buf, "%sarray [%ld] of ", buf, tp->tp_size);
+			break;
+		case FUNCTION:
+			sprint(buf, "%sfunction yielding ", buf);
+			break;
+		default:
+			sprint(buf, "%s%s%s ", buf,
+					tp->tp_unsigned ? "unsigned " : "",
+					symbol2str(tp->tp_fund)
+			);
+			if (tp->tp_idf)
+				sprint(buf, "%s %s ", buf,
+					tp->tp_idf->id_text);
+#ifndef NOBITFIELD
+			if (tp->tp_field)	{
+				struct field *fd = tp->tp_field;
+				
+				sprint(buf, "%s [s=%ld,w=%ld] of ", buf,
+					fd->fd_shift, fd->fd_width);
+			}
+			else
+#endif NOBITFIELD
+			ops = 0;
+			break;
+		}
+		tp = tp->tp_up;
+	}
+	return buf;
+}
+
+char *
+qual2str(qual)
+	int qual;
+{
+	char *buf = next_transient();
+
+	*buf = '\0';
+	if (qual == 0)
+		sprint(buf, "(none)");
+	if (qual & TQ_CONST)
+		sprint(buf, "%sconst ", buf);
+	if (qual & TQ_VOLATILE)
+		sprint(buf, "%svolatile ", buf);
+
+	return qual == 0 ? "" : buf;
+}
+
+GSTATIC char trans_buf[MAXTRANS][300];
+
+char *		/* the ultimate transient buffer supplier */
+next_transient()
+{
+	static int bnum;
+
+	if (++bnum == MAXTRANS)
+		bnum = 0;
+	return trans_buf[bnum];
+}
+
+print_expr(msg, expr)
+	char msg[];
+	struct expr *expr;
+{
+	/*	Provisional routine to print an expression preceded by a
+		message msg.
+	*/
+	if (options['x'])	{
+		print("\n%s: ", msg);
+		print("(L=line, T=type, r/lV=r/lvalue, F=flags, D=depth)\n");
+		p1_expr(0, expr);
+	}
+}
+
+p1_expr(lvl, expr)
+	register struct expr *expr;
+{
+	p1_indent(lvl);
+	if (!expr)	{
+		print("NILEXPR\n");
+		return;
+	}
+	print("expr: L=%u, T=%s, %cV, F=%03o, D=%d, %s: ",
+		expr->ex_line,
+		type2str(expr->ex_type),
+		expr->ex_lvalue ? 'l' : 'r',
+		expr->ex_flags & 0xFF,
+		expr->ex_depth,
+		expr->ex_class == Value ? "Value" :
+		expr->ex_class == String ? "String" :
+#ifndef NOFLOAT
+		expr->ex_class == Float ? "Float" :
+#endif NOFLOAT
+		expr->ex_class == Oper ? "Oper" :
+		expr->ex_class == Type ? "Type" : "UNKNOWN CLASS"
+	);
+	switch (expr->ex_class)	{
+		struct oper *o;
+	case Value:
+		switch (expr->VL_CLASS) {
+		case Const:
+			print("(Const) ");
+			break;
+		case Name:
+			print("(Name) %s + ", expr->VL_IDF->id_text);
+			break;
+		case Label:
+			print("(Label) .%lu + ", expr->VL_LBL);
+			break;
+		default:
+			print("(Unknown) ");
+			break;
+		}
+		print(expr->ex_type->tp_unsigned ? "%lu\n" : "%ld\n",
+			expr->VL_VALUE);
+		break;
+	case String:
+	{
+		char *bts2str();
+
+		print(
+			"\"%s\"\n",
+			bts2str(expr->SG_VALUE, expr->SG_LEN-1,
+							next_transient())
+		);
+		break;
+	}
+#ifndef NOFLOAT
+	case Float:
+		print("%s\n", expr->FL_VALUE);
+		break;
+#endif NOFLOAT
+	case Oper:
+		o = &expr->ex_object.ex_oper;
+		print("\n");
+		p1_expr(lvl+1, o->op_left);
+		p1_indent(lvl);
+		print("%s <%s>\n", symbol2str(o->op_oper),
+			type2str(o->op_type)
+		);
+		p1_expr(lvl+1, o->op_right);
+		break;
+	case Type:
+		print("\n");
+		break;
+	default:
+		print("UNKNOWN CLASS\n");
+		break;
+	}
+}
+
+p1_indent(lvl)
+	register int lvl;
+{
+	while (lvl--)
+		print("  ");
+}
+#endif	DEBUG

+ 355 - 0
lang/cem/cemcom.ansi/error.c

@@ -0,0 +1,355 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*	E R R O R   A N D  D I A G N O S T I C   R O U T I N E S	*/
+
+#include	<varargs.h>
+#include	<system.h>
+#include	<em.h>
+
+#include	"lint.h"
+#include	"nopp.h"
+#include	"errout.h"
+#include	"debug.h"
+
+#include	"tokenname.h"
+#include	"arith.h"
+#include	"label.h"
+#include	"expr.h"
+#include	"def.h"
+#include	"LLlex.h"
+
+/*	This file contains the error-message and diagnostic
+	functions.  Beware, they are called with a variable number of
+	arguments!
+*/
+
+/* error classes */
+#define	STRICT		1
+#define	WARNING		2
+#define	ERROR		3
+#define	CRASH		4
+#define	FATAL		5
+
+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
+		expr_error()	errors in expressions
+	The difference lies in the place where the file name and line
+	number come from.
+	Lexical errors report from the global variables LineNumber and
+	FileName, expression errors get their information from the
+	expression, whereas other errors use the information in the token.
+*/
+
+static _error();
+
+/*VARARGS*/
+error(va_alist)				/* fmt, args */
+	va_dcl
+{
+	va_list ap;
+
+	va_start(ap);
+	{
+		_error(ERROR, dot.tk_file, dot.tk_line, ap);
+	}
+	va_end(ap);
+}
+
+/*VARARGS*/
+expr_error(va_alist)			/* expr, fmt, args */
+	va_dcl
+{
+	va_list ap;
+
+	va_start(ap);
+	{
+		register struct expr *expr = va_arg(ap, struct expr *);
+
+		if (!(expr->ex_flags & EX_ERROR)) {
+			/* to prevent proliferation */
+			_error(ERROR, expr->ex_file, expr->ex_line, ap);
+			expr->ex_flags |= EX_ERROR;
+		}
+	}
+	va_end(ap);
+}
+
+/*VARARGS*/
+strict(va_alist)
+	va_dcl
+{
+	va_list ap;
+
+	va_start(ap);
+	{
+		_error(STRICT, FileName, LineNumber, ap);
+	}
+	va_end(ap);
+}
+
+/*VARARGS*/
+warning(va_alist)
+	va_dcl
+{
+	va_list ap;
+
+	va_start(ap);
+	{
+		_error(WARNING, NILEXPR, ap);
+	}
+	va_end(ap);
+}
+
+/*VARARGS*/
+expr_warning(va_alist)			/* expr, fmt, args */
+	va_dcl
+{
+	va_list ap;
+
+	va_start(ap);
+	{
+		struct expr *expr = va_arg(ap, struct expr *);
+
+		if (!(expr->ex_flags & EX_ERROR)) {
+			/* to prevent proliferation */
+			_error(WARNING, expr->ex_file, expr->ex_line, ap);
+		}
+	}
+	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
+{
+	va_list ap;
+
+	va_start(ap);
+	{
+		_error(ERROR, FileName, LineNumber, ap);
+	}
+	va_end(ap);
+}
+
+#ifndef	NOPP
+/*VARARGS*/
+lexwarning(va_alist)			/* fmt, args */
+	va_dcl
+{
+	va_list ap;
+
+	va_start(ap);
+	{
+		_error(WARNING, FileName, LineNumber, ap);
+	}
+	va_end(ap);
+}
+#endif	NOPP
+
+/*VARARGS*/
+crash(va_alist)				/* fmt, args */
+	va_dcl
+{
+	va_list ap;
+
+	va_start(ap);
+	{
+		_error(CRASH, FileName, LineNumber, ap);
+	}
+	va_end(ap);
+
+	C_close();
+#ifdef	DEBUG
+	sys_stop(S_ABORT);
+#else	DEBUG
+	sys_stop(S_EXIT);
+#endif	DEBUG
+	/* NOTREACHED */
+}
+
+/*VARARGS*/
+fatal(va_alist)				/* fmt, args */
+	va_dcl
+{
+	va_list ap;
+
+	va_start(ap);
+	{
+		_error(FATAL, FileName, LineNumber, ap);
+	}
+	va_end(ap);
+
+	if (C_busy()) C_close();
+	sys_stop(S_EXIT);
+	/*NOTREACHED*/
+}
+
+static
+_error(class, fn, ln, ap)
+	int class;
+	char *fn;
+	unsigned int ln;
+	va_list 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 *);
+	
+	/*	Since name and number are gathered from different places
+		depending on the class, we first collect the relevant
+		values and then decide what to print.
+	*/
+	/* preliminaries */
+	switch (class)	{
+	case WARNING:
+		if (options['w'])
+			return;
+		break;
+
+	case STRICT:
+		if (options['s'])
+			return;
+		break;
+
+	case ERROR:
+	case CRASH:
+	case FATAL:
+		if (C_busy())
+			C_ms_err();
+		err_occurred = 1;
+		break;
+	}
+
+	/* the remark */
+	switch (class)	{	
+	case STRICT:
+		remark = "(strict)";
+		break;
+	case WARNING:
+#ifndef	LINT
+		remark = "(warning)";
+#else	LINT
+		remark = 0;
+#endif	LINT
+		break;
+
+	case ERROR:
+		remark = 0;
+		break;
+
+	case CRASH:
+		remark = "CRASH\007";
+		break;
+
+	case FATAL:
+		remark = "fatal error --";
+		break;
+	default:
+		/*NOTREACHED*/;
+	}
+	
+#ifndef	LINT
+	if (ln == last_ln && fn && last_fn && strcmp(fn, last_fn) == 0)	{
+		/* we've seen this place before */
+		e_seen++;
+		if (e_seen == MAXERR_LINE)
+			fmt = "etc ...";
+		else
+		if (e_seen > MAXERR_LINE)
+			/* and too often, I'd say ! */
+			return;
+	}
+	else	{
+		/* brand new place */
+		last_fn = fn;
+		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);
+	if (remark)
+		fprint(ERROUT, "%s ", remark);
+	doprnt(ERROUT, fmt, ap);		/* contents of error */
+	fprint(ERROUT, "\n");
+}

+ 21 - 0
lang/cem/cemcom.ansi/estack.str

@@ -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$ */
+/* EXPRESSION STACK */
+/* Used for global initializations */
+struct e_stack {
+	struct e_stack	*next;
+	arith		s_cnt1, s_cnt2;
+	struct sdef 	*s_def;
+	struct type 	**s_tpp;
+	char 		s_nested;
+};
+
+/* ALLOCDEF "e_stack" 5 */
+
+#define bytes_upto_here	s_cnt1
+#define last_offset	s_cnt2
+#define elem_count	s_cnt1
+#define nelem		s_cnt2

+ 994 - 0
lang/cem/cemcom.ansi/eval.c

@@ -0,0 +1,994 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* EXPRESSION-CODE GENERATOR */
+
+#include	"lint.h"
+#ifndef	LINT
+
+#include	"nofloat.h"
+#include	<em.h>
+#include	<em_reg.h>
+#include	"debug.h"
+#include	"nobitfield.h"
+#include	"dataflow.h"
+#include	"arith.h"
+#include	"type.h"
+#include	"idf.h"
+#include	"label.h"
+#include	"code.h"
+#include	"assert.h"
+#include	"def.h"
+#include	"expr.h"
+#include	"sizes.h"
+#include	"Lpars.h"
+#include	"level.h"
+#include	"stack.h"
+#include	"align.h"
+#include	"mes.h"
+#include	"atw.h"
+#include	"specials.h"
+
+#define	CRASH()		crash("EVAL: CRASH at line %u", __LINE__)
+
+char *symbol2str();
+char *long2str();
+arith NewLocal();	/* util.c */
+#define LocalPtrVar()	NewLocal(pointer_size, pointer_align, reg_pointer, REGISTER)
+
+/*	EVAL() is the main expression-tree evaluator, which turns
+	any legal expression tree into EM code. Parameters:
+
+	struct expr *expr
+		pointer to root of the expression tree to be evaluated
+
+	int val
+		indicates whether the resulting expression is to be
+		dereferenced (if val == RVAL and expr->ex_lvalue == 1)
+		or not (val == LVAL).  The latter case indicates that
+		the resulting expression is an lvalue expression which
+		should not be dereferenced by EVAL
+	
+	int code
+		indicates whether the expression tree must be turned
+		into EM code or not. E.g. the expression statement "12;"
+		delivers the expression "12" to EVAL while this should
+		not result in any EM code
+	
+	label false_label, label true_label
+		if the expression is a logical or relational expression
+		and if the loop of the program depends on the resulting
+		value then EVAL generates jumps to the specified program
+		labels, in case they are specified (i.e. are non-zero)
+*/
+
+EVAL(expr, val, code, true_label, false_label)
+	register struct expr *expr;
+	int val, code;
+	label true_label, false_label;
+{
+	register int gencode = (code == TRUE);
+
+	switch (expr->ex_class) {
+	case Value:	/* just a simple value	*/
+		if (gencode)
+			load_val(expr, val);
+		break;
+	case String:	/* a string constant	*/
+		if (gencode) {
+			string2pointer(expr);
+			C_lae_dlb(expr->VL_LBL, expr->VL_VALUE);
+		}
+		break;
+#ifndef NOFLOAT
+	case Float:	/* a floating constant	*/
+		if (gencode) {
+			label datlab = data_label();
+			
+			C_df_dlb(datlab);
+			C_rom_fcon(expr->FL_VALUE, expr->ex_type->tp_size);
+			C_lae_dlb(datlab, (arith)0);
+			C_loi(expr->ex_type->tp_size);
+		}
+		break;
+#endif NOFLOAT
+	case Oper:	/* compound expression	*/
+	{
+		int oper = expr->OP_OPER;
+		register struct expr *left = expr->OP_LEFT;
+		register struct expr *right = expr->OP_RIGHT;
+		register struct type *tp = expr->OP_TYPE;
+
+		if (tp->tp_fund == ERRONEOUS || (expr->ex_flags & EX_ERROR)) {
+			/* stop immediately */
+			break;
+		}
+		if (tp->tp_fund == VOID)
+			gencode = 0;
+		switch (oper) {
+		case '+':
+			/*	We have the following possibilities :
+				int + int, pointer + int, pointer + long,
+				long + long, double + double
+			*/
+			EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
+			EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+			if (gencode) {
+				switch (tp->tp_fund) {
+				case INT:
+				case LONG:
+					if (tp->tp_unsigned)
+						C_adu(tp->tp_size);
+					else
+						C_adi(tp->tp_size);
+					break;
+				case POINTER:
+					C_loc(right->ex_type->tp_size);
+					C_loc(pointer_size);
+					C_cuu();
+					C_ads(pointer_size);
+					break;
+#ifndef NOFLOAT
+				case FLOAT:
+				case DOUBLE:
+				case LNGDBL:
+					C_adf(tp->tp_size);
+					break;
+#endif NOFLOAT
+				default:
+					crash("bad type +");
+				}
+			}
+			break;
+		case '-':
+			if (left == 0) {	/* unary	*/
+				EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+				if (gencode) {
+					switch (tp->tp_fund) {
+					case INT:
+					case LONG:
+					case POINTER:
+						C_ngi(tp->tp_size);
+						break;
+#ifndef NOFLOAT
+					case FLOAT:
+					case DOUBLE:
+					case LNGDBL:
+						C_ngf(tp->tp_size);
+						break;
+#endif NOFLOAT
+					default:
+						CRASH();
+					}
+				}
+				break;
+			}
+			/*	else binary; we have the following flavours:
+				int - int, pointer - int, pointer - long,
+				pointer - pointer, long - long, double - double
+			*/
+			EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
+			EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+			if (!gencode)
+				break;
+			switch (tp->tp_fund) {
+			case INT:
+			case LONG:
+				if (tp->tp_unsigned)
+					C_sbu(tp->tp_size);
+				else
+					C_sbi(tp->tp_size);
+				break;
+			case POINTER:
+				if (right->ex_type->tp_fund == POINTER)
+					C_sbs(pointer_size);
+				else {
+					C_ngi(right->ex_type->tp_size);
+					C_loc(right->ex_type->tp_size);
+					C_loc(pointer_size);
+					C_cuu();
+					C_ads(pointer_size);
+				}
+				break;
+#ifndef NOFLOAT
+			case FLOAT:
+			case DOUBLE:
+			case LNGDBL:
+				C_sbf(tp->tp_size);
+				break;
+#endif NOFLOAT
+			default:
+				crash("bad type -");
+			}
+			break;
+		case '*':
+			if (left == 0) { /* unary */
+				EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+				if (gencode && right->ex_class == String) {
+					C_loi((arith)1);
+				}
+			}
+			else { /* binary */
+				EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
+				EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+				if (gencode)
+					switch (tp->tp_fund) {
+					case INT:
+					case LONG:
+					case POINTER:
+						if (tp->tp_unsigned)
+							C_mlu(tp->tp_size);
+						else
+							C_mli(tp->tp_size);
+						break;
+#ifndef NOFLOAT
+					case FLOAT:
+					case DOUBLE:
+					case LNGDBL:
+						/*C_mlf(double_size);*/
+						C_mlf(tp->tp_size);
+						break;
+#endif NOFLOAT
+					default:
+						crash("bad type *");
+					}
+			}
+			break;
+		case '/':
+			EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
+			EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+			if (gencode)
+				switch (tp->tp_fund) {
+				case INT:
+				case LONG:
+				case POINTER:
+					if (tp->tp_unsigned)
+						C_dvu(tp->tp_size);
+					else
+						C_dvi(tp->tp_size);
+					break;
+#ifndef NOFLOAT
+				case FLOAT:
+				case DOUBLE:
+				case LNGDBL:
+					/*C_dvf(double_size);*/
+					C_dvf(tp->tp_size);
+					break;
+#endif NOFLOAT
+				default:
+					crash("bad type /");
+				}
+			break;
+		case '%':
+			EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
+			EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+			ASSERT(tp->tp_fund==INT || tp->tp_fund==LONG);
+			if (gencode)
+				if (tp->tp_unsigned)
+					C_rmu(tp->tp_size);
+				else
+					C_rmi(tp->tp_size);
+			break;
+		case LEFT:
+			EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
+			EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+			if (gencode)
+				if (tp->tp_unsigned)
+					C_slu(tp->tp_size);
+				else
+					C_sli(tp->tp_size);
+			break;
+		case RIGHT:
+			EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
+			EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+			if (gencode)
+				if (tp->tp_unsigned)
+					C_sru(tp->tp_size);
+				else
+					C_sri(tp->tp_size);
+			break;
+		case '<':
+		case LESSEQ:
+		case '>':
+		case GREATEREQ:
+		case EQUAL:
+		case NOTEQUAL:
+			EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
+			EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+			if (gencode) {
+				/* The operands have the same type */
+				arith size = left->ex_type->tp_size;
+				
+				switch (tp->tp_fund) {
+				case INT:
+				case LONG:
+					if (left->ex_type->tp_unsigned)
+						C_cmu(size);
+					else
+						C_cmi(size);
+					break;
+#ifndef NOFLOAT
+				case FLOAT:
+				case DOUBLE:
+				case LNGDBL:
+					C_cmf(size);
+					break;
+#endif NOFLOAT
+				case POINTER:
+					C_cmp();
+					break;
+				case ENUM:
+					C_cmi(size);
+					break;
+				default:
+					CRASH();
+				}
+				if (true_label != 0) {
+					compare(oper, true_label);
+					C_bra(false_label);
+				}
+				else {
+					truthvalue(oper);
+				}
+			}
+			break;
+		case '&':
+		case '|':
+		case '^':
+			/* both operands should have type int	*/
+			EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
+			EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+			if (gencode) {
+				arith size = tp->tp_size;
+
+				if ((int)size < (int)word_size)
+					size = word_size;
+				switch (oper) {
+				case '&':
+					C_and(size);
+					break;
+				case '|':
+					C_ior(size);
+					break;
+				case '^':
+					C_xor(size);
+					break;
+				}
+			}
+			break;
+		case '=': {
+			int newcode = tp->tp_size > 0;	/* CJ */
+#ifndef NOBITFIELD
+			if (left->ex_type->tp_fund == FIELD) {
+				eval_field(expr, gencode);
+				break;
+			}
+#endif NOBITFIELD
+			EVAL(right, RVAL, newcode, NO_LABEL, NO_LABEL);
+			if (gencode)
+				C_dup(ATW(tp->tp_size));
+			if (left->ex_class != Value) {
+				EVAL(left, LVAL, newcode, NO_LABEL, NO_LABEL);
+				if (newcode)
+					store_block(tp->tp_size, tp->tp_align);
+			}
+			else if (newcode)
+				store_val(&(left->EX_VALUE), left->ex_type);
+			}
+			break;
+		case PLUSAB:
+		case MINAB:
+		case TIMESAB:
+		case DIVAB:
+		case MODAB:
+		case LEFTAB:
+		case RIGHTAB:
+		case ANDAB:
+		case XORAB:
+		case ORAB:
+		case POSTINCR:
+		case POSTDECR:
+		case PLUSPLUS:
+		case MINMIN:
+		{
+			arith tmp;
+			int compl;	/* Complexity of left operand */
+			int newcode = left->ex_type->tp_size > 0; /* CJ */
+#ifndef NOBITFIELD
+			if (left->ex_type->tp_fund == FIELD) {
+				eval_field(expr, gencode);
+				break;
+			}
+#endif NOBITFIELD
+			if (newcode && left->ex_class == Value) {
+				compl = 0; /* Value */
+				load_val(left, RVAL);
+			}
+			else
+			if (left->ex_depth == 1 &&
+			    !(left->ex_flags & EX_SIDEEFFECTS))	{
+				compl = 1;
+				EVAL(left, RVAL, newcode, NO_LABEL, NO_LABEL);
+			}
+			else {
+				compl = 2; /* otherwise */
+				EVAL(left, LVAL, newcode, NO_LABEL, NO_LABEL);
+				if (newcode) {
+					tmp = LocalPtrVar();
+					C_dup(pointer_size);
+					StoreLocal(tmp, pointer_size);
+					C_loi(left->ex_type->tp_size);
+				}
+			}
+			if (newcode) {
+				if (gencode && (oper == POSTINCR ||
+						oper == POSTDECR))
+					C_dup(ATW(left->ex_type->tp_size));
+				conversion(left->ex_type, tp);
+			}
+			EVAL(right, RVAL, newcode, NO_LABEL, NO_LABEL);
+			if (newcode) {
+				int dupval = gencode && oper != POSTINCR &&
+						oper != POSTDECR;
+				assop(tp, oper);
+				conversion(tp, left->ex_type);
+				if (compl == 0) {
+					store_val(&(left->EX_VALUE),
+						left->ex_type);
+					if (dupval) load_val(left, RVAL);
+				}
+				else if (compl == 1) {
+					EVAL(left, LVAL,1, NO_LABEL, NO_LABEL);
+					C_sti(left->ex_type->tp_size);
+					if (dupval) {
+						EVAL(left, LVAL, 1, NO_LABEL,
+							NO_LABEL);
+						C_loi(left->ex_type->tp_size);
+					}
+				}
+				else {
+					LoadLocal(tmp, pointer_size);
+					C_sti(left->ex_type->tp_size);
+					if (dupval) {
+						LoadLocal(tmp, pointer_size);
+						C_loi(left->ex_type->tp_size);
+					}
+					FreeLocal(tmp);
+				}
+			}
+			break;
+		}
+		case '(':
+		{
+			register struct expr *ex;
+			arith ParSize = (arith)0;
+			label setjmp_label = 0;
+
+			if (ISNAME(left)) {
+				if (left->VL_IDF->id_special == SP_SETJMP) {
+					label addr_label = data_label();
+
+					setjmp_label = text_label();
+					C_df_dlb(addr_label);
+					C_rom_ilb(setjmp_label);
+					C_lae_dlb(addr_label, (arith) 0);
+					C_loi(pointer_size);
+					ParSize += pointer_size;
+				}
+			}
+			if ((ex = right) != NILEXPR) {
+				/* function call with parameters*/
+				while (	ex->ex_class == Oper &&
+					ex->OP_OPER == PARCOMMA
+				) {
+					EVAL(ex->OP_RIGHT, RVAL,
+					     ex->ex_type->tp_size > 0,
+							NO_LABEL, NO_LABEL);
+					ParSize += ATW(ex->ex_type->tp_size);
+					ex = ex->OP_LEFT;
+				}
+				EVAL(ex, RVAL, ex->ex_type->tp_size > 0,
+						NO_LABEL, NO_LABEL);
+				ParSize += ATW(ex->ex_type->tp_size);
+			}
+			if (ISNAME(left)) {
+				/* e.g., main() { (*((int (*)())0))(); } */
+				C_cal(left->VL_IDF->id_text);
+				if (setjmp_label) {
+					C_df_ilb(setjmp_label);
+				}
+#ifdef	DATAFLOW
+				{	extern char options[];
+					if (options['d'])
+						DfaCallFunction(
+							left->VL_IDF->id_text);
+				}
+#endif	DATAFLOW
+			}
+			else {
+				EVAL(left, LVAL, TRUE, NO_LABEL, NO_LABEL);
+				C_cai();
+			}
+			/* remove parameters from stack	*/
+			if (ParSize > (arith)0)
+				C_asp(ParSize);
+			if (gencode) {
+				if (is_struct_or_union(tp->tp_fund)) {
+					C_lfr(pointer_size);
+					load_block(tp->tp_size, (int) word_size);
+				}
+				else
+					C_lfr(ATW(tp->tp_size));
+			}
+			break;
+		}
+		case '.':
+			EVAL(left, LVAL, gencode, NO_LABEL, NO_LABEL);
+			ASSERT(is_cp_cst(right));
+			if (gencode)
+				C_adp(right->VL_VALUE);
+			break;
+		case ARROW:
+			EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
+			ASSERT(is_cp_cst(right));
+			if (gencode)
+				C_adp(right->VL_VALUE);
+			break;
+		case ',':
+			EVAL(left, RVAL, FALSE, NO_LABEL, NO_LABEL);
+			EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+			break;
+		case '~':
+			EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+			if (gencode)
+				C_com(tp->tp_size);
+			break;
+		case '?':	/* must be followed by ':'	*/
+		{
+			label l_true = text_label();
+			label l_false = text_label();
+			label l_end = text_label();
+
+			EVAL(left, RVAL, TRUE, l_true, l_false);
+			C_df_ilb(l_true);
+			EVAL(right->OP_LEFT, RVAL, gencode, NO_LABEL, NO_LABEL);
+			C_bra(l_end);
+			C_df_ilb(l_false);
+			EVAL(right->OP_RIGHT, RVAL, gencode, NO_LABEL, NO_LABEL);
+			C_df_ilb(l_end);
+			break;
+		}
+		case OR:
+		case AND: {
+			label l_false, l_true, l_maybe;
+
+			l_maybe = text_label();
+			if (true_label) {
+				l_false = false_label;
+				l_true = true_label;
+			}
+			else {
+				l_false = text_label();
+				l_true = gencode ? text_label(): l_false;
+			}
+
+			EVAL(left, RVAL, TRUE, oper == AND ? l_maybe : l_true,
+					       oper == AND ? l_false : l_maybe);
+			C_df_ilb(l_maybe);
+			EVAL(right, RVAL, gencode, l_true, l_false);
+			if (gencode && !true_label) {
+				label l_end = text_label();
+
+				C_df_ilb(l_true);
+				C_loc((arith)1);
+				C_bra(l_end);
+				C_df_ilb(l_false);
+				C_loc((arith)0);
+				C_df_ilb(l_end);
+			}
+			else {
+				if (! true_label) C_df_ilb(l_false);
+			}
+			}
+			break;
+		case '!':
+			if (true_label == 0) {
+				EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+				if (gencode) {
+					C_teq();
+				}
+			}
+			else
+				EVAL(right, RVAL, gencode, false_label,
+								true_label);
+			break;
+		case INT2INT:
+#ifndef NOFLOAT
+		case INT2FLOAT:
+		case FLOAT2INT:
+		case FLOAT2FLOAT:
+#endif NOFLOAT
+			EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+			if (gencode)
+				conversion(right->ex_type, left->ex_type);
+			break;
+		default:
+			crash("(EVAL) bad operator %s\n", symbol2str(oper));
+		}
+		/*	If the rvalue of the expression is required but
+			only its lvalue is evaluated, its rvalue is
+			loaded by the following statements:
+		*/
+		if (gencode && val == RVAL && expr->ex_lvalue == 1)
+			load_block(expr->ex_type->tp_size,
+				expr->ex_type->tp_align);
+		break;
+	}
+	default:
+		crash("(EVAL) bad expression class");
+	}
+}
+
+/*	compare() serves as an auxiliary function of EVAL	*/
+compare(relop, lbl)
+	int relop;
+	label lbl;
+{
+	switch (relop) {
+	case '<':
+		C_zlt(lbl);
+		break;
+	case LESSEQ:
+		C_zle(lbl);
+		break;
+	case '>':
+		C_zgt(lbl);
+		break;
+	case GREATEREQ:
+		C_zge(lbl);
+		break;
+	case EQUAL:
+		C_zeq(lbl);
+		break;
+	case NOTEQUAL:
+		C_zne(lbl);
+		break;
+	default:
+		CRASH();
+	}
+}
+
+/*	truthvalue() serves as an auxiliary function of EVAL	*/
+truthvalue(relop)
+	int relop;
+{
+	switch (relop)	{
+	case '<':
+		C_tlt();
+		break;
+	case LESSEQ:
+		C_tle();
+		break;
+	case '>':
+		C_tgt();
+		break;
+	case GREATEREQ:
+		C_tge();
+		break;
+	case EQUAL:
+		C_teq();
+		break;
+	case NOTEQUAL:
+		C_tne();
+		break;
+	default:
+		CRASH();
+	}
+}
+
+
+/*	assop() generates the opcode of an assignment operators op=	*/
+assop(type, oper)
+	register struct type *type;
+	int oper;
+{
+	register arith size;
+	register uns = type->tp_unsigned;
+
+	if ((int)(size = type->tp_size) < (int)word_size)
+		size = word_size;
+	switch (type->tp_fund) {
+	case CHAR:
+	case SHORT:
+	case INT:
+	case LONG:
+	case ENUM:
+		switch (oper) {
+		case PLUSAB:
+		case PLUSPLUS:
+		case POSTINCR:
+			if (uns)
+				C_adu(size);
+			else
+				C_adi(size);
+			break;
+		case MINAB:
+		case MINMIN:
+		case POSTDECR:
+			if (uns)
+				C_sbu(size);
+			else
+				C_sbi(size);
+			break;
+		case TIMESAB:
+			if (uns)
+				C_mlu(size);
+			else
+				C_mli(size);
+			break;
+		case DIVAB:
+			if (uns)
+				C_dvu(size);
+			else
+				C_dvi(size);
+			break;
+		case MODAB:
+			if (uns)
+				C_rmu(size);
+			else
+				C_rmi(size);
+			break;
+		case LEFTAB:
+			if (uns)
+				C_slu(size);
+			else
+				C_sli(size);
+			break;
+		case RIGHTAB:
+			if (uns)
+				C_sru(size);
+			else
+				C_sri(size);
+			break;
+		case ANDAB:
+			C_and(size);
+			break;
+		case XORAB:
+			C_xor(size);
+			break;
+		case ORAB:
+			C_ior(size);
+			break;
+		}
+		break;
+#ifndef NOFLOAT
+	case FLOAT:
+	case DOUBLE:
+	case LNGDBL:
+		switch (oper) {
+		case PLUSAB:
+		case PLUSPLUS:
+		case POSTINCR:
+			C_adf(size);
+			break;
+		case MINAB:
+		case MINMIN:
+		case POSTDECR:
+			C_sbf(size);
+			break;
+		case TIMESAB:
+			C_mlf(size);
+			break;
+		case DIVAB:
+			C_dvf(size);
+			break;
+		}
+		break;
+#endif NOFLOAT
+	case POINTER:
+		if (oper == MINAB || oper == MINMIN || oper == POSTDECR)
+			C_ngi(size);
+		C_loc(size);
+		C_loc(pointer_size);
+		C_cuu();
+		C_ads(pointer_size);
+		break;
+	case ERRONEOUS:
+		break;
+	default:
+		crash("(assop) bad type %s\n", symbol2str(type->tp_fund));
+	}
+}
+
+/*	store_val() generates code for a store operation.
+	There are four ways of storing data:
+	- into a global variable
+	- into an automatic local variable
+	- into a local static variable
+	- absolute addressing
+*/
+store_val(vl, tp)
+	register struct value *vl;
+	struct type *tp;
+{
+	arith size = tp->tp_size;
+	int tpalign = tp->tp_align;
+	int al_on_word;
+	register int inword;
+	register int indword;
+	arith val = vl->vl_value;
+
+	if (vl->vl_class == Const) {	/* absolute addressing */
+		load_cst(val, pointer_size);
+		store_block(size, tpalign);
+		return;
+	}
+	al_on_word = (tpalign % word_align == 0);
+	if (!(inword = (size == word_size && al_on_word)))
+		indword = (size == dword_size && al_on_word);
+	if (vl->vl_class == Name) {
+		register struct idf *id = vl->vl_data.vl_idf;
+		register struct def *df = id->id_def;
+
+		if (df->df_level == L_GLOBAL) {
+			if (inword)
+				C_ste_dnam(id->id_text, val);
+			else
+			if (indword)
+				C_sde_dnam(id->id_text, val);
+			else {
+				C_lae_dnam(id->id_text, val);
+				store_block(size, tpalign);
+			}
+		}
+		else {
+			ASSERT(df->df_sc != STATIC);
+			if (inword || indword)
+				StoreLocal(df->df_address + val, size);
+			else {
+				AddrLocal(df->df_address + val);
+				store_block(size, tpalign);
+			}
+		}
+	}
+	else {	
+		label dlb = vl->vl_data.vl_lbl;
+
+		ASSERT(vl->vl_class == Label);
+		if (inword)
+			C_ste_dlb(dlb, val);
+		else
+		if (indword)
+			C_sde_dlb(dlb, val);
+		else {
+			C_lae_dlb(dlb, val);
+			store_block(size, tpalign);
+		}
+	}
+}
+
+
+/*	load_val() generates code for stacking a certain value (from ex),
+	which can be obtained in one of the following ways:
+	- value from absolute addressed memory
+	- constant value
+	- function result
+	- global variable
+	- static variable
+	- local variable
+*/
+load_val(expr, rlval)
+	register struct expr *expr; /* expression containing the value	*/
+	int rlval;		/* generate either LVAL or RVAL		*/
+{
+	register struct type *tp = expr->ex_type;
+	int rvalue = (rlval == RVAL && expr->ex_lvalue != 0);
+	arith size = tp->tp_size;
+	int tpalign = tp->tp_align;
+	int al_on_word;
+	register int inword, indword;
+	register arith val = expr->VL_VALUE;
+
+	if (expr->VL_CLASS == Const) {
+		if (rvalue) { /* absolute addressing */
+			load_cst(val, pointer_size);
+			load_block(size, tpalign);
+		}
+		else	/* integer, unsigned, long, enum etc	*/
+			load_cst(val, size);
+		return;
+	}
+	if (rvalue) {
+		al_on_word = (tpalign % word_align == 0);
+		if (!(inword = (size == word_size && al_on_word)))
+			indword = (size == dword_size && al_on_word);
+	}
+	if (expr->VL_CLASS == Label) {
+		if (rvalue) {
+			if (inword)
+				C_loe_dlb(expr->VL_LBL, val);
+			else
+			if (indword)
+				C_lde_dlb(expr->VL_LBL, val);
+			else {
+				C_lae_dlb(expr->VL_LBL, val);
+				load_block(size, tpalign);
+			}
+
+		}
+		else {
+			C_lae_dlb(expr->VL_LBL, (arith)0);
+			C_adp(val);
+		}
+	}
+	else {
+		register struct idf *id = expr->VL_IDF;
+		register struct def *df = id->id_def;
+
+		ASSERT(ISNAME(expr));
+		if (df->df_type->tp_fund == FUNCTION) {
+			/*	the previous statement tried to catch a function
+				identifier, which may be cast to a pointer to a
+				function.
+				ASSERT(!(rvalue)); ???
+			*/
+			C_lpi(id->id_text);
+		}
+		else
+		if (df->df_level == L_GLOBAL) {
+			if (rvalue) {
+				if (inword)
+					C_loe_dnam(id->id_text, val);
+				else
+				if (indword)
+					C_lde_dnam(id->id_text, val);
+				else {
+					C_lae_dnam(id->id_text, val);
+					load_block(size, tpalign);
+				}
+			}
+			else {
+				C_lae_dnam(id->id_text, (arith)0);
+				C_adp(val);
+			}
+		}
+		else {
+			ASSERT(df->df_sc != STATIC);
+			if (rvalue) {
+				if (inword || indword)
+					LoadLocal(df->df_address + val, size);
+				else {
+					AddrLocal(df->df_address + val);
+					load_block(size, tpalign);
+				}
+			}
+			else {
+				AddrLocal(df->df_address);
+				C_adp(val);
+			}
+		}
+	}
+}
+
+load_cst(val, siz)
+	arith val, siz;
+{
+	if (siz <= word_size)
+		C_loc(val);
+	else
+	if (siz == dword_size)
+		C_ldc(val);
+	else {
+		label datlab;
+
+		C_df_dlb(datlab = data_label());
+		C_rom_icon(long2str((long)val, 10), siz);
+		C_lae_dlb(datlab, (arith)0);
+		C_loi(siz);
+	}
+}
+
+#endif	LINT
+

+ 536 - 0
lang/cem/cemcom.ansi/expr.c

@@ -0,0 +1,536 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* EXPRESSION TREE HANDLING */
+
+#include	"lint.h"
+#include	"nofloat.h"
+#include	"botch_free.h"
+#include	<alloc.h>
+#include	"idf.h"
+#include	"arith.h"
+#include	"def.h"
+#include	"type.h"
+#include	"label.h"
+#include	"expr.h"
+#include	"LLlex.h"
+#include	"Lpars.h"
+#include	"decspecs.h"
+#include	"declar.h"
+#include	"sizes.h"
+#include	"level.h"
+#include	"noRoption.h"
+
+extern char *symbol2str();
+extern char options[];
+
+int
+rank_of(oper)
+	int oper;
+{
+	/*	The rank of the operator oper is returned.
+	*/
+	switch (oper)	{
+	default:
+		return 0;			/* INT2INT etc. */
+	case '[':
+	case '(':
+	case '.':
+	case ARROW:
+	case PARCOMMA:
+		return 1;
+	case '!':
+	case PLUSPLUS:
+	case MINMIN:
+	case CAST:
+	case SIZEOF:
+		return 2;			/* monadic */
+	case '*':
+	case '/':
+	case '%':
+		return 3;
+	case '+':
+	case '-':
+		return 4;
+	case LEFT:
+	case RIGHT:
+		return 5;
+	case '<':
+	case '>':
+	case LESSEQ:
+	case GREATEREQ:
+		return 6;
+	case EQUAL:
+	case NOTEQUAL:
+		return 7;
+	case '&':
+		return 8;
+	case '^':
+		return 9;
+	case '|':
+		return 10;
+	case AND:
+		return 11;
+	case OR:
+		return 12;
+	case '?':
+	case ':':
+		return 13;
+	case '=':
+	case PLUSAB:
+	case MINAB:
+	case TIMESAB:
+	case DIVAB:
+	case MODAB:
+	case RIGHTAB:
+	case LEFTAB:
+	case ANDAB:
+	case XORAB:
+	case ORAB:
+		return 14;
+	case ',':
+		return 15;
+	}
+	/*NOTREACHED*/
+}
+
+#ifndef NOROPTION
+int
+rank_of_expression(ex)
+	register struct expr *ex;
+{
+	/*	Returns the rank of the top node in the expression.
+	*/
+	if (!ex || (ex->ex_flags & EX_PARENS) || ex->ex_class != Oper)
+		return 0;
+	return rank_of(ex->OP_OPER);
+}
+
+check_conditional(expr, oper, pos_descr)
+	register struct expr *expr;
+	char *pos_descr;
+{
+	/*	Warn if restricted C is in effect and the expression expr,
+		which occurs at the position pos_descr, is not lighter than
+		the operator oper.
+	*/
+	if (options['R'] && rank_of_expression(expr) >= rank_of(oper))
+		expr_warning(expr, "%s %s is ungrammatical",
+			symbol2str(expr->OP_OPER), pos_descr);
+}
+#endif
+
+dot2expr(expp)
+	struct expr **expp;
+{
+	/*	The token in dot is converted into an expression, a
+		pointer to which is stored in *expp.
+	*/
+	register struct expr *ex = new_expr();
+
+	*expp = ex;
+	ex->ex_file = dot.tk_file;
+	ex->ex_line = dot.tk_line;
+	switch (DOT)	{
+	case IDENTIFIER:
+		idf2expr(ex);
+		break;
+	case INTEGER:
+		int2expr(ex);
+		break;
+#ifndef NOFLOAT
+	case FLOATING:
+		float2expr(ex);
+		break;
+#endif NOFLOAT
+	default:
+		crash("bad conversion to expression");
+		/*NOTREACHED*/
+	}
+}
+
+idf2expr(expr)
+	register struct expr *expr;
+{
+	/*	Dot contains an identifier which is turned into an
+		expression.
+		Note that this constitutes an applied occurrence of
+		the identifier.
+	*/
+	register struct idf *idf = dot.tk_idf;	/* != 0*/
+	register struct def *def = idf->id_def;
+	
+	if (def == 0)	{
+		if (AHEAD == '(') /* function call, declare name IMPLICITly */
+			add_def(idf, IMPLICIT, funint_type, level); /* RM 13 */
+		else	{
+			if (!is_anon_idf(idf))
+				error("%s undefined", idf->id_text);
+			/* declare idf anyway */
+			add_def(idf, 0, error_type, level);
+		}
+		def = idf->id_def;
+	}
+	/* now def != 0 */
+	if (def->df_type->tp_fund == LABEL) {
+		expr_error(expr, "illegal use of label %s", idf->id_text);
+		expr->ex_type = error_type;
+	}
+	else {
+#ifndef	LINT
+		def->df_used = 1;
+#endif	LINT
+		expr->ex_type = def->df_type;
+		if (expr->ex_type == error_type)
+			expr->ex_flags |= EX_ERROR;
+	}
+	expr->ex_lvalue =
+		(	def->df_type->tp_fund == FUNCTION ||
+			def->df_type->tp_fund == ARRAY ||
+			def->df_sc == ENUM
+		) ? 0 : 1;
+	if (def->df_type->tp_typequal & TQ_CONST)
+		expr->ex_flags |= EX_READONLY;
+	if (def->df_type->tp_typequal & TQ_VOLATILE)
+		expr->ex_flags |= EX_VOLATILE;
+	expr->ex_class = Value;
+	if (def->df_sc == ENUM)	{
+		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;
+		expr->VL_VALUE = (arith)0;
+	}
+}
+
+string2expr(expp, typ, str, len)
+	register struct expr **expp;
+	int typ, len;
+	char *str;
+{
+	/*	The string in the argument is converted into an expression,
+		a pointer to which is stored in *expp.
+	*/
+	register struct expr *ex = new_expr();
+
+	*expp = ex;
+	ex->ex_file = dot.tk_file;
+	ex->ex_line = dot.tk_line;
+	ex->ex_type = string_type;
+/*
+	ex->ex_type = qualifier_type(ex->ex_type, TQ_CONST);
+*/
+	ex->ex_flags |= EX_READONLY;
+	ex->ex_lvalue = 0;
+	ex->ex_class = String;
+	ex->SG_VALUE = str;
+	ex->SG_LEN = len;
+	ex->SG_DATLAB = 0;
+}
+
+int2expr(expr)
+	struct expr *expr;
+{
+	/*	Dot contains an integer constant which is turned
+		into an expression.
+	*/
+	fill_int_expr(expr, dot.tk_ival, dot.tk_fund);
+}
+
+#ifndef NOFLOAT
+float2expr(expr)
+	register struct expr *expr;
+{
+	/*	Dot contains a floating point constant which is turned
+		into an expression.
+	*/
+	register int fund;
+
+	fund = dot.tk_fund;
+	switch (fund) {
+	case FLOAT:
+		expr->ex_type = float_type;
+		break;
+	case DOUBLE:
+		expr->ex_type = double_type;
+		break;
+	case LNGDBL:
+		expr->ex_type = lngdbl_type;
+		break;
+	default:
+		crash("(float2expr) bad fund %s\n", symbol2str(fund));
+	}
+	expr->ex_class = Float;
+	expr->FL_VALUE = dot.tk_fval;
+	expr->FL_DATLAB = 0;
+}
+#endif NOFLOAT
+
+struct expr*
+intexpr(ivalue, fund)
+	arith ivalue;
+	int fund;
+{
+	/*	The value ivalue is turned into an integer expression of
+		the size indicated by fund.
+	*/
+	register struct expr *expr = new_expr();
+	
+	expr->ex_file = dot.tk_file;
+	expr->ex_line = dot.tk_line;
+	fill_int_expr(expr, ivalue, fund);
+	return expr;
+}
+
+fill_int_expr(ex, ivalue, fund)
+	register struct expr *ex;
+	arith ivalue;
+	int fund;
+{
+	/*	Details derived from ivalue and fund are put into the
+		constant integer expression ex.
+	*/
+	switch (fund) {
+	case INT:
+		ex->ex_type = int_type;
+		break;
+	case INTEGER:
+		if (ivalue >= 0 && ivalue <= max_int) {
+			ex->ex_type = int_type;
+			break;
+		}
+		/*FALL THROUGH*/
+	case LONG:
+		ex->ex_type = 
+			(ivalue & (1L << (8*long_size - 1))) ? ulong_type
+				: long_type;
+		break;
+	case ULONG:
+		ex->ex_type = ulong_type;
+		break;
+	case UNSIGNED:
+		/*	We cannot make a test like
+				ivalue <= max_unsigned
+			because, if
+				sizeof(long) == int_size
+			holds, max_unsigned may be a negative long in
+			which case the comparison results in an unexpected
+			answer.
+		*/
+		ex->ex_type = 
+			(ivalue & ~max_int) ?
+			  ( (ivalue & ~max_unsigned) ? 
+			      ( ivalue & (1L<<(8*long_size-1)) ?
+					ulong_type : long_type
+			      ) : uint_type
+			  ) : int_type;
+		break;
+	default:
+		crash("(intexpr) bad fund %s\n", symbol2str(fund));
+		/*NOTREACHED*/
+	}
+	ex->ex_class = Value;
+	ex->VL_CLASS = Const;
+	ex->VL_VALUE = ivalue;
+	cut_size(ex);
+}
+
+struct expr *
+new_oper(tp, e1, oper, e2)
+	struct type *tp;
+	register struct expr *e1, *e2;
+{
+	/*	A new expression is constructed which consists of the
+		operator oper which has e1 and e2 as operands; for a
+		monadic operator e1 == NILEXPR.
+		During the construction of the right recursive initialisation
+		tree it is possible for e2 to be NILEXPR.
+	*/
+	register struct expr *expr = new_expr();
+	register struct oper *op;
+
+	if (e2)	{
+		register struct expr *e = e2;
+		
+		while (e->ex_class == Oper && e->OP_LEFT)
+			e = e->OP_LEFT;
+		expr->ex_file = e->ex_file;
+		expr->ex_line = e->ex_line;
+	}
+	else
+	if (e1)	{
+		register struct expr *e = e1;
+		
+		while (e->ex_class == Oper && e->OP_RIGHT)
+			e = e->OP_RIGHT;
+		expr->ex_file = e->ex_file;
+		expr->ex_line = e->ex_line;
+	}
+	else	{
+		expr->ex_file = dot.tk_file;
+		expr->ex_line = dot.tk_line;
+	}
+
+	expr->ex_type = tp;
+	expr->ex_class = Oper;
+	/* combine depths and flags of both expressions */
+	if (e2)	{
+		int e1_depth = e1 ? e1->ex_depth : 0;
+		int e1_flags = e1 ? e1->ex_flags : 0;
+		
+		expr->ex_depth =
+			(e1_depth > e2->ex_depth ? e1_depth : e2->ex_depth) + 1;
+		expr->ex_flags = (e1_flags | e2->ex_flags) & ~EX_PARENS;
+	}
+	op = &expr->ex_object.ex_oper;
+	op->op_type = tp;
+	op->op_oper = oper;
+	op->op_left = e1;
+	op->op_right = e2;
+#ifdef	LINT
+	lint_new_oper(expr);
+#endif	LINT
+	return expr;
+}
+
+chk_cst_expr(expp)
+	register struct expr **expp;
+{
+	/*	The expression expr is checked for constancy.
+	
+		There are 6 places where constant expressions occur in C:
+		1.	after #if
+		2.	in a global initialization
+		3.	as size in an array declaration
+		4.	as value in an enum declaration
+		5.	as width in a bit field
+		6.	as case value in a switch
+		
+		The constant expression in a global initialization is
+		handled separately (by IVAL()).
+		
+		There are various disparate restrictions on each of
+		the others in the various C compilers.  I have tried some
+		hypotheses to unify them, but all have failed.
+		
+		This routine will give a warning for those operators
+		not allowed by K&R, under the R-option only.  The anomalies
+		are cast, logical operators and the expression comma.
+		Special problems (of which there is only one, sizeof in
+		Preprocessor #if) have to be dealt with locally
+		
+		Note that according to K&R the negation ! is illegal in
+		constant expressions and is indeed rejected by the
+		Ritchie compiler.
+	*/
+	register struct expr *expr = *expp;
+	register int fund = expr->ex_type->tp_fund;
+	register int flags = expr->ex_flags;
+	int err = 0;
+	
+#ifdef	DEBUG
+	print_expr("constant_expression", expr);
+#endif	DEBUG
+	if (	fund != CHAR && fund != SHORT && fund != INT &&
+		fund != ENUM && fund != LONG
+	)
+		expr_error(expr, "non-numerical constant expression"), err++;
+	else
+	if (!is_ld_cst(expr))
+		expr_error(expr, "expression is not constant"), err++;
+#ifndef NOROPTION
+	if (options['R'])	{
+		if (flags & EX_CAST)
+			expr_warning(expr, "cast in constant expression");
+		if (flags & EX_LOGICAL)
+			expr_warning(expr,
+				"logical operator in constant expression");
+		if (flags & EX_COMMA)
+			expr_warning(expr,
+				"expression comma in constant expression");
+	}
+#endif NOROPTION
+	if (err)
+		erroneous2int(expp);
+}
+
+init_expression(eppp, expr)
+	register struct expr ***eppp, *expr;
+{
+	/*	The expression expr is added to the tree designated
+		indirectly by **eppp.
+		The natural form of a tree representing an
+		initial_value_list is right-recursive, ie. with the
+		left-most comma as main operator. The iterative grammar in
+		expression.g, however, tends to produce a left-recursive
+		tree, ie. one with the right-most comma as its main
+		operator.
+		To produce a right-recursive tree from the iterative
+		grammar, we keep track of the address of the pointer where
+		the next expression must be hooked in.
+	*/
+	**eppp = new_oper(void_type, expr, INITCOMMA, NILEXPR);
+	*eppp = &(**eppp)->OP_RIGHT;
+}
+
+int
+is_ld_cst(expr)
+	register struct expr *expr;
+{
+	/*	An expression is a `load-time constant' if it is of the form
+		<idf> +/- <integral> or <integral>.
+	*/
+#ifdef	LINT
+	if (expr->ex_class == String)
+		return 1;
+#endif	LINT
+	return expr->ex_lvalue == 0 && expr->ex_class == Value;
+}
+
+int
+is_cp_cst(expr)
+	register struct expr *expr;
+{
+	/*	An expression is a `compile-time constant' if it is a
+		load-time constant, and the idf is not there.
+	*/
+	return is_ld_cst(expr) && expr->VL_CLASS == Const;
+}
+
+#ifndef NOFLOAT
+int
+is_fp_cst(expr)
+	register struct expr *expr;
+{
+	/*	An expression is a `floating-point constant' if it consists
+		of the float only.
+	*/
+	return expr->ex_class == Float;
+}
+#endif NOFLOAT
+
+free_expression(expr)
+	register struct expr *expr;
+{
+	/*	The expression expr is freed recursively.
+	*/
+	if (expr) {
+		if (expr->ex_class == Oper)	{
+			free_expression(expr->OP_LEFT);
+			free_expression(expr->OP_RIGHT);
+		}
+		free_expr(expr);
+	}
+}

+ 116 - 0
lang/cem/cemcom.ansi/expr.str

@@ -0,0 +1,116 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* EXPRESSION DESCRIPTOR */
+
+/*	What we want to define is the struct expr, but since it contains
+	a union of various goodies, we define them first; so be patient.
+*/
+
+#include	"nofloat.h"
+
+/* classes of value */
+#define Const	1
+#define Name	2
+#define Label	3
+
+struct value	{
+	int vl_class;		/* Const, Name or Label	*/
+	arith vl_value;		/* constant value or offset */
+	union {
+		struct idf *vl_idf;	/* external name */
+		label vl_lbl;		/* compiler-generated label */
+	} vl_data;
+};
+
+struct string	{
+	char *sg_value;		/* row of bytes repr. the constant */
+	int sg_len;		/* length of the row */
+	label sg_datlab;	/* global data-label			*/
+};
+
+#ifndef NOFLOAT
+struct floating	{
+	char *fl_value;		/* pointer to string repr. the fp const. */
+	label fl_datlab;	/* global data_label	*/
+};
+#endif NOFLOAT
+
+struct oper	{
+	struct type *op_type;	/* resulting type of the operation	*/
+	struct expr *op_left;
+	int op_oper;			/* the symbol of the operator	*/
+	struct expr *op_right;
+};
+
+/* The following constants indicate the class of the expression: */
+#define	Value	0		/* it is a value known at load time */
+#define	String	1		/* it is a string constant  */
+#ifndef NOFLOAT
+#define	Float	2		/* it is a floating point constant	*/
+#endif NOFLOAT
+#define	Oper	3		/* it is a run-time expression */
+#define	Type	4		/* only its type is relevant */
+
+struct expr	{
+	struct expr *next;
+	char *ex_file;		/* the file it (probably) comes from */
+	unsigned int ex_line;	/* the line it (probably) comes from */
+	struct type *ex_type;
+	char ex_lvalue;
+	short ex_flags;
+	int ex_class;
+	int ex_depth;
+	union	{
+		struct value ex_value;
+		struct string ex_string;
+#ifndef NOFLOAT
+		struct floating ex_float;
+#endif NOFLOAT
+		struct oper ex_oper;
+	} ex_object;
+};
+
+/* some abbreviated selections	*/
+#define EX_VALUE	ex_object.ex_value
+#define VL_CLASS	EX_VALUE.vl_class
+#define	VL_VALUE	EX_VALUE.vl_value
+#define	VL_IDF		EX_VALUE.vl_data.vl_idf
+#define	VL_LBL		EX_VALUE.vl_data.vl_lbl
+#define	SG_VALUE	ex_object.ex_string.sg_value
+#define SG_LEN		ex_object.ex_string.sg_len
+#define	SG_DATLAB	ex_object.ex_string.sg_datlab
+#ifndef NOFLOAT
+#define	FL_VALUE	ex_object.ex_float.fl_value
+#define	FL_DATLAB	ex_object.ex_float.fl_datlab
+#endif NOFLOAT
+#define	OP_TYPE		ex_object.ex_oper.op_type
+#define	OP_LEFT		ex_object.ex_oper.op_left
+#define	OP_OPER		ex_object.ex_oper.op_oper
+#define	OP_RIGHT	ex_object.ex_oper.op_right
+
+/*	some bits for the ex_flag field, to keep track of various
+	interesting properties of an expression.
+*/
+#define	EX_SIZEOF	0001		/* contains sizeof operator */
+#define	EX_CAST		0002		/* contains cast */
+#define	EX_LOGICAL	0004		/* contains logical operator */
+#define	EX_COMMA	0010		/* contains expression comma */
+#define	EX_PARENS	0020		/* the top level is parenthesized */
+#define EX_SIDEEFFECTS	0040		/* expression has side effects */
+#define	EX_READONLY	0100		/* read only variabele */
+#define	EX_VOLATILE	0200		/* volatile variabele */
+#define	EX_ERROR	0400		/* the expression is wrong */
+
+#define	NILEXPR		((struct expr *)0)
+
+/* some useful tests */
+#define	ISNAME(e)	((e)->ex_class == Value && (e)->VL_CLASS == Name)
+#define	ISCOMMA(e)	((e)->ex_class == Oper && (e)->OP_OPER == INITCOMMA)
+
+extern struct expr *intexpr(), *new_oper();
+
+/* ALLOCDEF "expr" 20 */
+

+ 375 - 0
lang/cem/cemcom.ansi/expression.g

@@ -0,0 +1,375 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*	EXPRESSION SYNTAX PARSER	*/
+
+{
+#include	<alloc.h>
+#include	"lint.h"
+#include	"arith.h"
+#include	"LLlex.h"
+#include	"type.h"
+#include	"idf.h"
+#include	"label.h"
+#include	"expr.h"
+#include	"code.h"
+#include	"noRoption.h"
+
+extern struct expr *intexpr();
+}
+
+/* 7.1 */
+primary(register struct expr **expp;) :
+	IDENTIFIER
+	{dot2expr(expp);}
+|
+	constant(expp)
+|
+	string(expp)
+|
+	'(' expression(expp) ')'
+	{(*expp)->ex_flags |= EX_PARENS;}
+;
+
+
+/*	Character string literals that are adjacent tokens
+	are concatenated into a single character string
+	literal.
+*/
+string(register struct expr **expp;)
+	{	register int i, len;
+		register char *str;
+		register int fund;
+	}
+:
+	STRING
+	{	str = dot.tk_bts;
+		len = dot.tk_len;
+		fund = dot.tk_fund;
+	}
+	[
+		STRING
+		{	/*	A pasted string keeps the type of the first
+				string literal.
+				The pasting of normal strings and wide
+				character strings are stated as having an
+				undefined behaviour.
+			*/
+			if (dot.tk_fund != fund)
+				warning("illegal pasting of string literals");
+			str = Srealloc(str, (unsigned) (--len + dot.tk_len));
+			for (i = 0; i < dot.tk_len; i++)
+				str[len++] = dot.tk_bts[i];
+		}
+	]*
+	{string2expr(expp, STRING, str, len);}
+;
+
+secundary(register struct expr **expp;) :
+	primary(expp)
+	[
+		index_pack(expp)
+	|
+		parameter_pack(expp)
+	|
+		selection(expp)
+	]*
+;
+
+index_pack(struct expr **expp;)
+	{struct expr *e1;}
+:
+	'[' expression(&e1) ']'
+	{ch7bin(expp, '[', e1);}
+;
+
+parameter_pack(struct expr **expp;)
+	{struct expr *e1 = 0;}
+:
+	'(' parameter_list(&e1)? ')'
+	{	ch7bin(expp, '(', e1);
+		call_proto(expp);
+	}
+;
+
+selection(struct expr **expp;)
+	{int oper; struct idf *idf;}
+:
+	[ '.' | ARROW ]
+	{oper = DOT;}
+	identifier(&idf)
+	{ch7sel(expp, oper, idf);}
+;
+
+parameter_list(struct expr **expp;)
+	{struct expr *e1 = 0;}
+:
+	assignment_expression(expp)
+	{any2opnd(expp, PARCOMMA);}
+	[	','
+		assignment_expression(&e1)
+		{any2opnd(&e1, PARCOMMA);}
+		{ch7bin(expp, PARCOMMA, e1);}
+	]*
+;
+
+/* 7.2 */
+postfixed(struct expr **expp;)
+	{int oper;}
+:
+	secundary(expp)
+	[
+		postop(&oper)
+		{ch7incr(expp, oper);}
+	|
+		empty
+	]
+;
+
+%first	first_of_type_specifier, type_specifier;
+
+unary(register struct expr **expp;)
+	{struct type *tp; int oper;}
+:
+%if (first_of_type_specifier(AHEAD) && AHEAD != IDENTIFIER)
+	cast(&tp) unary(expp)
+	{	ch7cast(expp, CAST, tp);
+		(*expp)->ex_flags |= EX_CAST;
+	}
+|
+	postfixed(expp)
+|
+	unop(&oper) unary(expp)
+	{ch7mon(oper, expp);}
+|
+	size_of(expp)
+;
+
+size_of(register struct expr **expp;)
+	{struct type *tp;}
+:
+	SIZEOF
+	[%if (first_of_type_specifier(AHEAD) && AHEAD != IDENTIFIER)
+		cast(&tp)
+		{
+			*expp = intexpr(size_of_type(tp, "type"), INT);
+			(*expp)->ex_flags |= EX_SIZEOF;
+		}
+	|
+		unary(expp)
+		{ch7mon(SIZEOF, expp);}
+	]
+;
+
+/* 7.3-7.12 */
+/*	The set of operators in C is stratified in 15 levels, with level
+	N being treated in RM 7.N.  In principle each operator is
+	assigned a rank, ranging from 1 to 15.  Such an expression can
+	be parsed by a construct like:
+		binary_expression(int maxrank;)
+			{int oper;}
+		:
+			binary_expression(maxrank - 1)
+			[%if (rank_of(DOT) <= maxrank)
+				binop(&oper)
+				binary_expression(rank_of(oper)-1)
+			]?
+		;
+	except that some call of 'unary' is necessary, depending on the
+	grammar.
+	
+	This simple view is marred by three complications:
+	1.	Level 15 (comma operator) is not allowed in many
+		contexts and is different.
+	2.	Level 13 (conditional operator) is a ternary operator,
+		which does not fit this scheme at all.
+	3.	Level 14 (assignment operators) group right-to-left, as
+		opposed to 2-12, which group left-to-right (or are
+		immaterial).
+	4.	The operators in level 14 start with operators in levels
+		2-13 (RM 7.14: The two parts of a compound assignment
+		operator are separate tokens.)  This causes LL1 problems.
+	This forces us to have four rules:
+		binary_expression	for level 2-12
+		conditional_expression	for level 13
+		assignment_expression	for level 14 and
+		expression		for the most general expression
+*/
+
+binary_expression(int maxrank; struct expr **expp;)
+	{int oper; struct expr *e1;}
+:
+	unary(expp)
+	[%while (rank_of(DOT) <= maxrank && AHEAD != '=')
+		/*	'?', '=', and ',' are no binops, and the test
+			for AHEAD != '=' keeps the other assignment
+			operators out
+		*/
+		binop(&oper)
+		binary_expression(rank_of(oper)-1, &e1)
+		{
+			ch7bin(expp, oper, e1);
+		}
+	]*
+;
+
+/* 7.13 */
+conditional_expression(struct expr **expp;)
+/*	There is some unfortunate disagreement about what is allowed
+	between the '?' and the ':' of a conditional_expression.
+	Although the Ritchie compiler does not even allow
+	conditional_expressions there, some other compilers (e.g., VAX)
+	accept a full assignment_expression there, and programs
+	(like, e.g., emacs) rely on it. So we have little choice.
+*/
+	{struct expr *e1 = 0, *e2 = 0;}
+:
+	/* allow all binary operators */
+	binary_expression(rank_of('?') - 1, expp)
+	[	'?'
+		expression(&e1)
+		{
+#ifndef NOROPTION
+			check_conditional(e1, '?', "between ? and :");
+#endif
+		}
+		':'
+		assignment_expression(&e2)
+		{	
+#ifndef NOROPTION
+			check_conditional(e2, '=', "after :");
+#endif
+			ch7bin(&e1, ':', e2);
+			opnd2test(expp, '?');
+			ch7bin(expp, '?', e1);
+		}
+	]?
+;
+
+/* 7.14 */
+assignment_expression(struct expr **expp;)
+	{
+		int oper;
+		struct expr *e1 = 0;
+	}
+:
+	conditional_expression(expp)
+	[%prefer	/* (rank_of(DOT) <= maxrank) for any asgnop */
+		asgnop(&oper)
+		assignment_expression(&e1)
+		{ch7asgn(expp, oper, e1);}
+	|
+		empty		/* LLgen artefact ??? */
+	]
+;
+
+/* 7.15 */
+expression(struct expr **expp;)
+	{struct expr *e1;}
+:
+	assignment_expression(expp)
+	[	','
+		assignment_expression(&e1)
+		{
+			ch7bin(expp, ',', e1);
+		}
+	]*
+;
+
+unop(int *oper;) :
+	['*' | '&' | '-' | '+' | '!' | '~' | PLUSPLUS | MINMIN]
+	{*oper = DOT;}
+;
+
+postop(int *oper;):
+	PLUSPLUS {*oper = POSTINCR;}
+|
+	MINMIN {*oper = POSTDECR;}
+;
+
+multop:
+	'*' | '/' | '%'
+;
+
+addop:
+	'+' | '-'
+;
+
+shiftop:
+	LEFT | RIGHT
+;
+
+relop:
+	'<' | '>' | LESSEQ | GREATEREQ
+;
+
+eqop:
+	EQUAL | NOTEQUAL
+;
+
+arithop:
+	multop | addop | shiftop
+|
+	'&' | '^' | '|'
+;
+
+binop(int *oper;) :
+	[ arithop | relop | eqop | AND | OR ]
+	{*oper = DOT;}
+;
+
+asgnop(register int *oper;):
+	'=' {*oper = DOT;}
+|
+	'+' '=' {*oper = PLUSAB;}
+|
+	'-' '=' {*oper = MINAB;}
+|
+	'*' '=' {*oper = TIMESAB;}
+|
+	'/' '=' {*oper = DIVAB;}
+|
+	'%' '=' {*oper = MODAB;}
+|
+	LEFT '=' {*oper = LEFTAB;}
+|
+	RIGHT '=' {*oper = RIGHTAB;}
+|
+	'&' '=' {*oper = ANDAB;}
+|
+	'^' '=' {*oper = XORAB;}
+|
+	'|' '=' {*oper = ORAB;}
+|
+	[ PLUSAB | MINAB | TIMESAB | DIVAB | MODAB | LEFTAB | RIGHTAB
+	| ANDAB | XORAB | ORAB ]
+	{ *oper = DOT; }
+
+;
+
+constant(struct expr **expp;) :
+[
+	INTEGER
+|
+	FLOATING
+]	{dot2expr(expp);}
+;
+
+/* 15 */
+constant_expression (struct expr **expp;) :
+	assignment_expression(expp)
+	{chk_cst_expr(expp);}
+;
+
+identifier(struct idf **idfp;) :
+[
+	IDENTIFIER
+|
+	TYPE_IDENTIFIER
+]
+	{
+		*idfp = dot.tk_idf;
+	}
+;

+ 181 - 0
lang/cem/cemcom.ansi/field.c

@@ -0,0 +1,181 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*	BITFIELD EXPRESSION EVALUATOR	*/
+
+#include	"lint.h"
+#ifndef	LINT
+
+#include	"nobitfield.h"
+
+#ifndef NOBITFIELD
+#include	<em.h>
+#include	<em_reg.h>
+#include	"debug.h"
+#include	"arith.h"
+#include	"type.h"
+#include	"idf.h"
+#include	"label.h"
+#include	"code.h"
+#include	"assert.h"
+#include	"expr.h"
+#include	"sizes.h"
+#include	"align.h"
+#include	"Lpars.h"
+#include	"field.h"
+
+arith NewLocal();		/* util.c	*/
+char *symbol2str();		/* symbol2str.c	*/
+
+/*	Eval_field() evaluates expressions involving bit fields.
+	The various instructions are not yet optimised in the expression
+	tree and are therefore dealt with in this function.
+	The actions taken at any operation are described clearly by the
+	code for this actions.
+	Notes
+	[1]	the bitfields are packed in target machine integers!
+	[2]	op is either an assignment operator or an increment/
+		decrement operator
+	[3]	atype: the type in which the bitfield arithmetic is done;
+		and in which bitfields are stored!
+*/
+eval_field(expr, code)
+	struct expr *expr;
+	int code;
+{
+	int op = expr->OP_OPER;
+	register struct expr *leftop = expr->OP_LEFT;
+	register struct expr *rightop = expr->OP_RIGHT;
+	register struct field *fd = leftop->ex_type->tp_field;
+	struct type *tp = leftop->ex_type->tp_up;
+	arith tmpvar;
+	struct type *atype = tp->tp_unsigned ? uword_type : word_type;
+	arith asize = atype->tp_size;
+
+	/* First some assertions to be sure that the rest is legal */
+	ASSERT(asize == word_size);	/* make sure that C_loc() is legal */
+	ASSERT(leftop->ex_type->tp_fund == FIELD);
+	leftop->ex_type = atype;	/* this is cheating but it works... */
+	if (op == '=') {
+		/* F = E: f = ((E & mask)<<shift) | (~(mask<<shift) & f) */
+		ASSERT(tp == rightop->ex_type);
+		EVAL(rightop, RVAL, TRUE, NO_LABEL, NO_LABEL);
+		conversion(tp, atype);
+		C_loc(fd->fd_mask);
+		C_and(asize);
+		if (code == TRUE)
+			C_dup(asize);
+		C_loc((arith)fd->fd_shift);
+		if (atype->tp_unsigned)
+			C_slu(asize);
+		else
+			C_sli(asize);
+		C_loc(~((fd->fd_mask << fd->fd_shift) | (~0 << (8 * asize))));
+		if (leftop->ex_depth == 0)	{	/* simple case	*/
+			load_val(leftop, RVAL);
+			C_and(asize);
+			C_ior(asize);
+			store_val(&(leftop->EX_VALUE), atype);
+		}
+		else	{			/* complex case	*/
+			tmpvar = NewLocal(pointer_size, pointer_align, 
+					  reg_pointer, 0);
+			EVAL(leftop, LVAL, TRUE, NO_LABEL, NO_LABEL);
+			C_dup(pointer_size);
+			StoreLocal(tmpvar, pointer_size);
+			C_loi(asize);
+			C_and(asize);
+			C_ior(asize);
+			LoadLocal(tmpvar, pointer_size);
+			C_sti(asize);
+			FreeLocal(tmpvar);
+		}
+	}
+	else {		/* treat ++F as F += 1 and --F as F -= 1	*/
+		/*	F op= e: f = (((((f>>shift)&mask) op e)&mask)<<shift)|
+					(f&~(mask<<shift))
+		*/
+		if (leftop->ex_depth == 0)	/* simple case	*/
+			load_val(leftop, RVAL);
+		else	{			/* complex case	*/
+			tmpvar = NewLocal(pointer_size, pointer_align, 
+					  reg_pointer, 0);
+			EVAL(leftop, LVAL, TRUE, NO_LABEL, NO_LABEL);
+			C_dup(pointer_size);
+			StoreLocal(tmpvar, pointer_size);
+			C_loi(asize);
+		}
+		if (atype->tp_unsigned) {
+			C_loc((arith)fd->fd_shift);
+			C_sru(asize);
+			C_loc(fd->fd_mask);
+			C_and(asize);
+		}
+		else {
+			arith bits_in_type = asize * 8;
+			C_loc(bits_in_type - (fd->fd_width + fd->fd_shift));
+			C_sli(asize);
+			C_loc(bits_in_type - fd->fd_width);
+			C_sri(asize);
+		}
+		if (code == TRUE && (op == POSTINCR || op == POSTDECR))
+			C_dup(asize);
+		conversion(atype, rightop->ex_type);
+		EVAL(rightop, RVAL, TRUE, NO_LABEL, NO_LABEL);
+		/* the 'op' operation: */
+		if (op == PLUSPLUS || op == POSTINCR)
+			assop(rightop->ex_type, PLUSAB);
+		else
+		if (op == MINMIN || op == POSTDECR)
+			assop(rightop->ex_type, MINAB);
+		else
+			assop(rightop->ex_type, op);
+		conversion(rightop->ex_type, atype);
+		C_loc(fd->fd_mask);
+		C_and(asize);
+		if (code == TRUE && op != POSTINCR && op != POSTDECR)
+			C_dup(asize);
+		C_loc((arith)fd->fd_shift);
+		if (atype->tp_unsigned)
+			C_slu(asize);
+		else
+			C_sli(asize);
+		C_loc(~((fd->fd_mask << fd->fd_shift) | (~0 << (8 * asize))));
+		if (leftop->ex_depth == 0)	{
+			load_val(leftop, RVAL);
+			C_and(asize);
+			C_ior(asize);
+			store_val(&(leftop->EX_VALUE), atype);
+		}
+		else	{
+			LoadLocal(tmpvar, pointer_size);
+			C_loi(asize);
+			C_and(asize);
+			C_ior(asize);
+			LoadLocal(tmpvar, pointer_size);
+			C_sti(asize);
+			FreeLocal(tmpvar);
+		}
+	}
+	if (code == TRUE) {
+		/*	Take care that the effective value stored in
+			the bit field (i.e. the value that is got on
+			retrieval) is on top of stack.
+		*/
+		if (atype->tp_unsigned == 0) {	/* sign extension */
+			register arith shift = asize * 8 - fd->fd_width;
+
+			C_loc(shift);
+			C_sli(asize);
+			C_loc(shift);
+			C_sri(asize);
+		}
+		conversion(atype, expr->ex_type);
+	}
+}
+#endif NOBITFIELD
+
+#endif	LINT
+

+ 16 - 0
lang/cem/cemcom.ansi/field.str

@@ -0,0 +1,16 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* FIELD DESCRIPTOR */
+
+struct field	{	/* for field specifiers	*/
+	struct field *next;
+	arith fd_mask;
+	int fd_shift;
+	int fd_width;
+	struct sdef *fd_sdef;	/* upward pointer	*/
+};
+
+/* ALLOCDEF "field" 50 */

+ 20 - 0
lang/cem/cemcom.ansi/file_info.h

@@ -0,0 +1,20 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $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;
+	int		fil_nestlow;
+	char		*fil_name;
+	char		*fil_wdir;
+};
+
+#define nestlow		finfo.fil_nestlow
+#define LineNumber	finfo.fil_lino
+#define FileName	finfo.fil_name
+#define WorkingDir	finfo.fil_wdir
+
+extern struct file_info finfo;	/* input.c */

+ 736 - 0
lang/cem/cemcom.ansi/idf.c

@@ -0,0 +1,736 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*	IDENTIFIER  FIDDLING & SYMBOL TABLE HANDLING	*/
+
+#include	"lint.h"
+#include	<em_reg.h>
+#include	"nofloat.h"
+#include	"debug.h"
+#include	"idfsize.h"
+#include	"botch_free.h"
+#include	"nopp.h"
+#include	"nparams.h"
+#include	<alloc.h>
+#include	"arith.h"
+#include	"align.h"
+#include	"LLlex.h"
+#include	"level.h"
+#include	"stack.h"
+#include	"idf.h"
+#include	"label.h"
+#include	"def.h"
+#include	"type.h"
+#include	"proto.h"
+#include	"struct.h"
+#include	"declar.h"
+#include	"decspecs.h"
+#include	"sizes.h"
+#include	"Lpars.h"
+#include	"assert.h"
+#include	"specials.h"	/* registration of special identifiers	*/
+#include	"noRoption.h"
+
+int idfsize = IDFSIZE;
+extern char options[];
+extern arith NewLocal();
+
+char sp_occurred[SP_TOTAL+1];	/* indicate occurrence of special id	*/
+
+struct idf *idf_hashtable[HASHSIZE];
+	/*	All identifiers can in principle be reached through
+		idf_hashtable; idf_hashtable[hc] is the start of a chain of
+		idf's whose tags all hash to hc. Each idf is the start of
+		a chain of def's for that idf, sorted according to level,
+		with the most recent one on top.
+		Any identifier occurring on a level is entered into this
+		list, regardless of the nature of its declaration
+		(variable, selector, structure tag, etc.).
+	*/
+
+struct idf *
+idf_hashed(tg, size, hc)
+	char *tg;
+	int size;		/* includes the '\0' character */
+	int hc;
+{
+	/*	The tag tg with length size and known hash value hc is
+		looked up in the identifier table; if not found, it is
+		entered. A pointer to it is returned.
+		The identifier has already been truncated to idfsize
+		characters.
+	*/
+	register struct idf **hook = &idf_hashtable[hc], *notch;
+
+	while ((notch = *hook))	{
+		register char *s1 = tg;
+		register char *cp = notch->id_text;
+		register int cmp;
+
+		while (!(cmp = (*s1 - *cp++))) {
+			if (*s1++ == '\0') {
+				break;
+			}
+		}
+
+		if (cmp < 0)
+			break;
+		if (cmp == 0)	{
+			/*	suppose that special identifiers, as
+				"setjmp", are already inserted
+			*/
+			sp_occurred[notch->id_special] = 1;
+			return notch;
+		}
+		hook = &notch->next;
+	}
+	/* a new struct idf must be inserted at the hook */
+	notch = new_idf();
+	notch->next = *hook;
+	*hook = notch;		/* hooked in */
+	notch->id_text = Salloc(tg, (unsigned) size);
+#ifndef NOPP
+	notch->id_resmac = 0;
+#endif NOPP
+	return notch;
+}
+
+#ifdef	DEBUG
+hash_stat()
+{
+	if (options['h'])	{
+		register int i;
+		
+		print("Hash table tally:\n");
+		for (i = 0; i < HASHSIZE; i++)	{
+			register struct idf *notch = idf_hashtable[i];
+			int cnt = 0;
+	
+			while (notch)	{
+				cnt++;
+				notch = notch->next;
+			}
+			print("%d %d\n", i, cnt);
+		}
+		print("End hash table tally\n");
+	}		
+}
+#endif	DEBUG
+
+struct idf *
+str2idf(tg)
+	char tg[];
+{
+	/*	str2idf() returns an entry in the symbol table for the
+		identifier tg.  If necessary, an entry is created.
+		It is used where the text of the identifier is available
+		but its hash value is not; otherwise idf_hashed() is to
+		be used.
+	*/
+	register char *cp = tg;
+	register int hash;
+	register int pos = -1;
+	register int ch;
+	char ntg[IDFSIZE + 1];
+	register char *ncp = ntg;
+
+	hash = STARTHASH();
+	while (++pos < idfsize && (ch = *cp++))	{
+		*ncp++ = ch;
+		hash = ENHASH(hash, ch, pos);
+	}
+	hash = STOPHASH(hash);
+	*ncp++ = '\0';
+	return idf_hashed(ntg, ncp - ntg, hash);
+}
+
+struct idf *
+gen_idf()
+{
+	/*	A new idf is created out of nowhere, to serve as an
+		anonymous name.
+	*/
+	static int name_cnt;
+	char buff[100];
+
+	sprint(buff, "#%d in %s, line %u",
+			++name_cnt, dot.tk_file, dot.tk_line);
+	return str2idf(buff);
+}
+
+int
+is_anon_idf(idf)
+	struct idf *idf;
+{
+	return idf->id_text[0] == '#';
+}
+
+declare_idf(ds, dc, lvl)
+	struct decspecs *ds;
+	struct declarator *dc;
+{
+	/*	The identifier inside dc is declared on the level lvl, with
+		properties deduced from the decspecs ds and the declarator
+		dc.
+		The level is given explicitly to be able to insert, e.g.,
+		labels on the outermost level inside the function.
+		This routine implements the rich semantics of C
+		declarations.
+	*/
+	register struct idf *idf = dc->dc_idf;
+	register int sc = ds->ds_sc;
+		/*	This local copy is essential:
+				char b(), c;
+			makes b GLOBAL and c AUTO.
+		*/
+	register struct def *def = idf->id_def;		/* may be NULL */
+	register struct type *type;
+	struct stack_level *stl = stack_level_of(lvl);
+	char formal_array = 0;
+	
+	/* determine the present type */
+	if (ds->ds_type == 0)	{
+		/*	at the L_FORMAL1 level there is no type specified yet
+		*/
+		ASSERT(lvl == L_FORMAL1);
+		type = int_type;	/* may change at L_FORMAL2 */
+	}
+	else	{
+		/* combine the decspecs and the declarator into one type */
+		type = declare_type(ds->ds_type, dc);
+		if (type->tp_size <= (arith)0 &&
+		    actual_declaration(sc, type))	{
+			if (type->tp_size == (arith) -1) {
+				/* the type is not yet known,
+				   but it has to be:
+				*/
+				extern char *symbol2str();
+				error("unknown %s-type",
+					symbol2str(type->tp_fund));
+			}
+			else if (type->tp_fund != LABEL) {
+				/* CJ */
+				warning("%s has size 0", idf->id_text);
+			}
+		}
+	}
+
+	/* some additional work for formal definitions */
+	if (lvl == L_FORMAL2)	{
+		switch (type->tp_fund)	{
+		case FUNCTION:
+			warning("%s is a function; cannot be formal",
+				idf->id_text);
+			type = construct_type(POINTER, type, 0, (arith)0,
+					      NO_PROTO);
+			break;
+		case ARRAY:	/* RM 10.1	*/
+			type = construct_type(POINTER, type->tp_up, 0, (arith)0,
+					      NO_PROTO);
+			formal_array = 1;
+			break;
+#ifndef NOFLOAT
+		case FLOAT:	/* RM 10.1	*/
+			type = double_type;
+			break;
+#endif NOFLOAT
+		case CHAR:
+		case SHORT:
+			/*	The RM is not clear about this: we must
+				convert the parameter from int (they have
+				been pushed as ints) to the specified type.
+				The conversion to type int or uint is not
+				allowed.
+			*/
+			break;
+		}
+	}
+	/*	The tests on types, postponed from do_decspecs(), can now
+		be performed.
+	*/
+	/* update the storage class */
+	if (type && type->tp_fund == FUNCTION)	{
+		if (sc == 0 || (ds->ds_sc_given && sc == AUTO))	/* RM 8.1 */
+			sc = GLOBAL;
+		else
+		if (sc == REGISTER) {
+			error("function storage class cannot be register");
+			ds->ds_sc = sc = GLOBAL;
+		}
+	}
+	else	/* non-FUNCTION */
+		if (sc == 0)
+			sc =	lvl == L_GLOBAL ? GLOBAL
+				: lvl == L_FORMAL1 || lvl == L_FORMAL2 ? FORMAL
+				: AUTO;
+#ifndef NOROPTION
+	if (options['R']) { /* some special K & R tests */
+		/* is it also an enum? */
+		if (idf->id_enum && idf->id_enum->tg_level == level)
+			warning("%s is also an enum tag", idf->id_text);
+		/* is it a universal typedef? */
+		if (def && def->df_level == L_UNIVERSAL)
+			warning("redeclaring reserved word %s", idf->id_text);
+	}
+#endif
+
+#ifdef	LINT
+	if (	def && def->df_level < lvl
+	&&	!(	lvl == L_FORMAL2
+		||	def->df_level == L_UNIVERSAL
+		||	sc == GLOBAL
+		||	sc == EXTERN
+		)
+	) {
+		/*	there is already a definition for this non-extern 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 )
+	    )
+	   )	{
+		/*	There is already a declaration for idf on this
+			level, or even more inside.
+			The rules differ for different levels.
+		*/
+		switch (lvl)	{
+		case L_GLOBAL:
+			global_redecl(idf, sc, type);
+			def->df_file = idf->id_file;
+			def->df_line = idf->id_line;
+			break;
+		case L_FORMAL1:	/* formal declaration */
+			error("formal %s redeclared", idf->id_text);
+			break;
+		case L_FORMAL2:	/* formal definition */
+		default:	/* local */
+			error("%s redeclared", idf->id_text);
+			break;
+		}
+	}
+	else	/* the idf is unknown on this level */
+	if (lvl == L_FORMAL2 && sc != ENUM && good_formal(def, idf))	{
+		/* formal declaration, update only */
+		def->df_type = type;
+		def->df_formal_array = formal_array;
+		def->df_sc = sc;
+		def->df_level = L_FORMAL2;	/* CJ */
+		def->df_file = idf->id_file;
+		def->df_line = idf->id_line;
+	}
+	else
+	if (	lvl >= L_LOCAL &&
+		(type->tp_fund == FUNCTION || sc == EXTERN)
+	)	{
+		/*	extern declaration inside function is treated the
+			same way as global extern declaration
+		*/
+#ifndef NOROPTION
+		if (	options['R'] &&
+			(sc == STATIC && type->tp_fund == FUNCTION)
+		)
+			if (!is_anon_idf(idf))
+				warning("non-global static function %s",
+					idf->id_text);
+#endif
+		declare_idf(ds, dc, L_GLOBAL);
+	}
+	else	{ /* fill in the def block */
+		register struct def *newdef = new_def();
+
+		newdef->next = def;
+		newdef->df_level = lvl;
+		newdef->df_type = type;
+		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);
+		stack_idf(idf, stl);
+		/*	We now calculate the address.
+			Globals have names and don't get addresses, they
+			get numbers instead (through data_label()).
+			Formals are handled by declare_formals().
+			So here we hand out local addresses only.
+		*/
+		if (lvl >= L_LOCAL)	{
+			ASSERT(sc);
+			switch (sc)	{
+			case REGISTER:
+			case AUTO:
+				if (type->tp_size == (arith)-1) {
+					error("size of local %s unknown",
+						idf->id_text);
+				/** type = idf->id_def->df_type = int_type; **/
+				}
+				newdef->df_address =
+					NewLocal(type->tp_size,
+						 type->tp_align,
+						 regtype(type),
+						 sc);
+				break;
+			case STATIC:
+				newdef->df_address = (arith) data_label();
+				break;
+			}
+		}
+	}
+}
+
+actual_declaration(sc, tp)
+	int sc;
+	struct type *tp;
+{
+	/*	An actual_declaration needs space, right here and now.
+	*/
+	register int fund = tp->tp_fund;
+	
+	if (sc == ENUM || sc == TYPEDEF) /* virtual declarations */
+		return 0;
+	if (fund == FUNCTION || fund == ARRAY)
+		/* allocation solved in other ways */
+		return 0;
+	/* to be allocated */
+	return 1;
+}
+
+global_redecl(idf, new_sc, tp)
+	register struct idf *idf;
+	struct type *tp;
+{
+	/*	A global identifier may be declared several times,
+		provided the declarations do not conflict; they might
+		conflict in type (or supplement each other in the case of
+		an array) or they might conflict or supplement each other
+		in storage class.
+	*/
+	register struct def *def = idf->id_def;
+
+	if (!equal_type(tp, def->df_type))
+		error("redeclaration of %s with different type", idf->id_text);
+	update_proto(tp, def->df_type);
+	if (tp->tp_fund == ARRAY) {
+		/* Multiple array declaration; this may be interesting */
+		if (tp->tp_size < 0)	{		/* new decl has [] */
+			/* nothing new */
+		} else
+		if (def->df_type->tp_size < 0)	{	/* old decl has [] */
+			def->df_type = tp;
+		}
+	}
+
+	/*	Now we may be able to update the storage class.
+		Clean out this mess as soon as we know all the possibilities
+		for new_sc.
+		For now we have:
+			EXTERN:		we have seen the word "extern"
+			GLOBAL:		the item was declared on the outer
+					level, without either "extern" or
+					"static".
+			STATIC:		we have seen the word "static"
+			IMPLICIT:	function declaration inferred from
+					call
+	*/
+	if (new_sc == IMPLICIT)
+		return;			/* no new information */
+	switch (def->df_sc)	{	/* the old storage class */
+	case EXTERN:
+		switch (new_sc)	{	/* the new storage class */
+		case EXTERN:
+		case GLOBAL:
+			break;
+		case STATIC:
+			if (def->df_initialized)	{
+				error("cannot redeclare %s to static",
+					idf->id_text);
+			}
+			else	{
+				warning("%s redeclared to static",
+						idf->id_text);
+			}
+			def->df_sc = new_sc;
+			break;
+		default:
+			crash("bad storage class");
+			/*NOTREACHED*/
+		}
+		break;
+	case GLOBAL:
+		switch (new_sc)	{	/* the new storage class */
+		case EXTERN:
+			def->df_sc = EXTERN;
+			break;
+		case GLOBAL:
+			break;
+		case STATIC:
+			if (def->df_initialized)
+				error("cannot redeclare %s to static",
+					idf->id_text);
+			else	{
+#ifndef NOROPTION
+				if (options['R'])
+					warning("%s redeclared to static",
+						idf->id_text);
+#endif
+				def->df_sc = STATIC;
+			}
+			break;
+		default:
+			crash("bad storage class");
+			/*NOTREACHED*/
+		}
+		break;
+	case STATIC:
+		switch (new_sc)	{	/* the new storage class */
+		case EXTERN:
+			if (def->df_initialized)
+				error("cannot redeclare %s to extern",
+					idf->id_text);
+			else	{
+				warning("%s redeclared to extern",
+					idf->id_text);
+				def->df_sc = EXTERN;
+			}
+			break;
+		case GLOBAL:
+		case STATIC:
+			if (def->df_type->tp_fund != FUNCTION)
+				warning("%s was already static",
+					idf->id_text);
+			break;
+		default:
+			crash("bad storage class");
+			/*NOTREACHED*/
+		}
+		break;
+	case IMPLICIT:
+		switch (new_sc)	{	/* the new storage class */
+		case EXTERN:
+		case GLOBAL:
+			def->df_sc = new_sc;
+			break;
+		case STATIC:
+#ifndef NOROPTION
+			if (options['R'])
+				warning("%s was implicitly declared as extern",
+					idf->id_text);
+#endif
+			def->df_sc = new_sc;
+			break;
+		default:
+			crash("bad storage class");
+			/*NOTREACHED*/
+		}
+		break;
+	case ENUM:
+	case TYPEDEF:
+		error("illegal redeclaration of %s", idf->id_text);
+		break;
+	default:
+		crash("bad storage class");
+		/*NOTREACHED*/
+	}
+}
+
+int
+good_formal(def, idf)
+	register struct def *def;
+	register struct idf *idf;
+{
+	/*	Succeeds if def is a proper L_FORMAL1 definition and
+		gives an error message otherwise.
+	*/
+	if (!def || def->df_level != L_FORMAL1)	{ /* not in parameter list */
+		if (!is_anon_idf(idf))
+			error("%s not in parameter list", idf->id_text);
+		return 0;
+	}
+	ASSERT(def->df_sc == FORMAL);	/* CJ */
+	return 1;
+}
+
+declare_params(dc)
+	register struct declarator *dc;
+{
+	/*	Declares the formal parameters if they exist.
+	*/
+	register struct formal *fm = dc->dc_formal;
+	
+	while (fm)	{
+		declare_parameter(fm->fm_idf);
+		fm = fm->next;
+	}
+	free_formals(dc->dc_formal);
+	dc->dc_formal = 0;
+}
+
+init_idf(idf)
+	register struct idf *idf;
+{
+	/*	The topmost definition of idf is set to initialized.
+	*/
+	register struct def *def = idf->id_def;	/* the topmost */
+	
+	if (def->df_initialized)
+		error("multiple initialization of %s", idf->id_text);
+	if (def->df_sc == TYPEDEF)	{
+		warning("typedef cannot be initialized");
+		def->df_sc = EXTERN;		/* ??? *//* What else ? */
+	}
+	def->df_initialized = 1;
+}
+
+declare_parameter(idf)
+	struct idf *idf;
+{
+	/*	idf is declared as a formal.
+	*/
+	add_def(idf, FORMAL, int_type, level);
+}
+
+declare_enum(tp, idf, l)
+	struct type *tp;
+	struct idf *idf;
+	arith l;
+{
+	/*	idf is declared as an enum constant with value l.
+	*/
+	add_def(idf, ENUM, tp, level);
+	idf->id_def->df_address = l;
+}
+
+declare_formals(fp)
+	arith *fp;
+{
+	/*	Declares those formals as int that haven't been declared
+		by the user.
+		An address is assigned to each formal parameter.
+		The total size of the formals is returned in *fp;
+	*/
+	register struct stack_entry *se = stack_level_of(L_FORMAL1)->sl_entry;
+	arith f_offset = (arith)0;
+	register int nparams = 0;
+
+#ifdef	DEBUG
+	if (options['t'])
+		dumpidftab("start declare_formals", 0);
+#endif	DEBUG
+	while (se)	{
+		register struct def *def = se->se_idf->id_def;
+		
+		def->df_address = f_offset;
+		/*	the alignment convention for parameters is: align on
+			word boundaries, i.e. take care that the following
+			parameter starts on a new word boundary.
+		*/
+		f_offset = align(f_offset + def->df_type->tp_size, (int) word_size);
+		formal_cvt(def); /* cvt int to char or short, if necessary */
+		se = se->next;
+		def->df_level = L_FORMAL2;	/* CJ */
+		RegisterAccount(def->df_address, def->df_type->tp_size,
+				regtype(def->df_type),
+				def->df_sc);
+		if (nparams++ >= STDC_NPARAMS)
+			strict("number of formal parameters exceeds ANSI limit");
+	}
+	*fp = f_offset;
+}
+
+int
+regtype(tp)
+	struct type *tp;
+{
+	switch(tp->tp_fund) {
+	case INT:
+	case LONG:
+		return reg_any;
+#ifndef NOFLOAT
+	case FLOAT:
+	case DOUBLE:
+		return reg_float;
+#endif NOFLOAT
+	case POINTER:
+		return reg_pointer;
+	}
+	return -1;
+}
+
+add_def(idf, sc, tp, lvl)
+	struct idf *idf;
+	struct type *tp;
+	int lvl;
+	int sc;
+{
+	/*	The identifier idf is declared on level lvl with storage
+		class sc and type tp, through a faked C declaration.
+		This is probably the wrong way to structure the problem,
+		but it will have to do for the time being.
+	*/
+	struct decspecs Ds; struct declarator Dc;
+
+	Ds = null_decspecs;
+	Ds.ds_type = tp;
+	Ds.ds_sc = sc;
+	Dc = null_declarator;
+	Dc.dc_idf = idf;
+	declare_idf(&Ds, &Dc, lvl);
+}
+
+update_ahead(idf)
+	register struct idf *idf;
+{
+	/*	The tk_symb of the token ahead is updated in the light of new
+		information about the identifier idf.
+	*/
+	register int tk_symb = AHEAD;
+
+	if (	(tk_symb == IDENTIFIER || tk_symb == TYPE_IDENTIFIER) &&
+		ahead.tk_idf == idf
+	)
+		AHEAD = idf->id_def && idf->id_def->df_sc == TYPEDEF ?
+				TYPE_IDENTIFIER : IDENTIFIER;
+}
+
+free_formals(fm)
+	register struct formal *fm;
+{
+	while (fm)	{
+		struct formal *tmp = fm->next;
+
+		free_formal(fm);
+		fm = tmp;
+	}
+}
+
+char hmask[IDFSIZE];
+
+init_hmask()
+{
+	/*	A simple congruence random number generator, as
+		described in Knuth, vol 2.
+	*/
+	register int h, rnd = HASH_X;
+	
+	for (h = 0; h < IDFSIZE; h++)	{
+		hmask[h] = rnd;
+		rnd = (HASH_A * rnd + HASH_C) & HASHMASK;
+	}
+}

+ 52 - 0
lang/cem/cemcom.ansi/idf.str

@@ -0,0 +1,52 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* IDENTIFIER DESCRIPTOR */
+
+#include	"nopp.h"
+
+/*	Since the % operation in the calculation of the hash function
+	turns out to be expensive, it is replaced by the cheaper XOR (^).
+	Each character of the identifier is xored with an 8-bit mask which
+	depends on the position of the character; the sum of these results
+	is the hash value.  The random masks are obtained from a
+	congruence generator in idf.c.
+*/
+
+#define	HASHSIZE	256	/* must be a power of 2 */
+#define	HASH_X		0253	/* Knuth's X */
+#define	HASH_A		77	/* Knuth's a */
+#define	HASH_C		153	/* Knuth's c */
+
+extern char hmask[];		/* the random masks */
+#define	HASHMASK		(HASHSIZE-1)	/* since it is a power of 2 */
+#define	STARTHASH()		(0)
+#define	ENHASH(hs,ch,ps)	(hs + (ch ^ hmask[ps]))
+#define	STOPHASH(hs)		(hs & HASHMASK)
+
+struct idf	{
+	struct idf *next;
+	char *id_text;
+#ifndef NOPP
+	struct macro *id_macro;
+	int id_resmac;		/* if nonzero: keyword of macroproc. 	*/
+#endif NOPP
+	int id_reserved;	/* non-zero for reserved words		*/
+	char *id_file;		/* file containing the occurrence	*/
+	unsigned int id_line;	/* line number of the occurrence	*/
+	struct def *id_def;	/* variables, typedefs, enum-constants	*/
+	struct sdef *id_sdef;	/* selector tags			*/
+	struct tag *id_struct;	/* struct and union tags		*/
+	struct tag *id_enum;	/* enum tags				*/
+	int id_proto;		/* non-zero don't complain about proto	*/
+	int id_special;		/* special action needed at occurrence	*/
+};
+
+/* ALLOCDEF "idf" 50 */
+
+extern struct idf *str2idf(), *idf_hashed();
+
+extern int level;
+extern struct idf *gen_idf();

+ 95 - 0
lang/cem/cemcom.ansi/init.c

@@ -0,0 +1,95 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* PREPROCESSOR: INITIALIZATION ROUTINES */
+
+#include	"nopp.h"
+
+#ifndef NOPP
+#include	<system.h>
+#include	<alloc.h>
+#include	<time.h>
+#include	"class.h"
+#include	"macro.h"
+#include	"idf.h"
+
+struct mkey	{
+	char *mk_reserved;
+	int mk_key;
+} mkey[] =	{
+	{"define",	K_DEFINE},
+	{"elif",	K_ELIF},
+	{"else",	K_ELSE},
+	{"endif",	K_ENDIF},
+	{"error",	K_ERROR},
+	{"if",		K_IF},
+	{"ifdef",	K_IFDEF},
+	{"ifndef",	K_IFNDEF},
+	{"include",	K_INCLUDE},
+	{"line",	K_LINE},
+	{"pragma",	K_PRAGMA},
+	{"undef",	K_UNDEF},
+	{0,		K_UNKNOWN}
+};
+
+char *strcpy();
+
+init_pp()
+{
+	static char *months[12] = {
+		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+	};
+	long clock, sys_time();
+	static char dbuf[30];
+	static char tbuf[30];
+	struct tm  *tp;
+
+	/*	Initialise the control line keywords (if, include, define, etc)
+		Although the lexical analyzer treats them as identifiers, the
+		control line handler can recognize them as keywords by the
+		id_resmac field of the identifier.
+	*/
+	{
+		register struct mkey *mk = &mkey[0];
+
+		while (mk->mk_reserved)	{
+			register struct idf *idf = str2idf(mk->mk_reserved);
+			
+			if (idf->id_resmac)
+				fatal("maximum identifier length insufficient");
+			idf->id_resmac = mk->mk_key;
+			mk++;
+		}
+	}
+
+	/*	Initialize __LINE__, __FILE__, __DATE__, __TIME__,
+		and __STDC__ macro definitions.
+	*/
+	clock = sys_time();
+	tp = localtime(&clock);
+
+	/* __DATE__ */
+	sprintf(dbuf, "\"%.3s %.2d %d\"", months[tp->tm_mon],
+			tp->tm_mday, tp->tm_year+1900);
+	macro_def(str2idf("__DATE__"), dbuf, -1, 12, NOFLAG);
+
+	/* __TIME__ */
+	sprintf(tbuf, "\"%.2d:%.2d:%.2d\"", tp->tm_hour, tp->tm_min, tp->tm_sec);
+	macro_def(str2idf("__TIME__"), tbuf, -1, 10, NOFLAG);
+
+	/* __LINE__	*/
+	macro_def(str2idf("__LINE__"), "0", -1, 1, FUNC);
+
+	/* __FILE__	*/
+	macro_def(str2idf("__FILE__"), "", -1, 1, FUNC);
+
+	/* __STDC__ */
+	macro_def(str2idf("__STDC__"), "1", -1, 1, NOFLAG);
+
+	/* defined(??) */
+	macro_def(str2idf("defined"), "", 1, 1, FUNC);
+}
+#endif NOPP

+ 64 - 0
lang/cem/cemcom.ansi/input.c

@@ -0,0 +1,64 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+
+#include "inputtype.h"
+#include "file_info.h"
+#include "input.h"
+
+#define INP_PUSHBACK	3
+#define INP_TYPE	struct file_info
+#define INP_VAR		finfo
+struct file_info	finfo;
+extern int		nestlevel;
+#include "nopp.h"
+#include <inp_pkg.body>
+
+#ifndef NOPP
+char *
+getwdir(fn)
+	register char *fn;
+{
+	register char *p;
+	char *strrindex();
+
+	p = strrindex(fn, '/');
+	while (p && *(p + 1) == '\0') {	/* remove trailing /'s */
+		*p = '\0';
+		p = strrindex(fn, '/');
+	}
+
+	if (fn[0] == '\0' || (fn[0] == '/' && p == &fn[0])) /* absolute path */
+		return "";
+	if (p) {
+		*p = '\0';
+		fn = Salloc(fn, p - &fn[0] + 1);
+		*p = '/';
+		return fn;
+	}
+	return ".";
+}
+#endif NOPP
+
+int	NoUnstack;
+
+AtEoIT()
+{
+	unstackrepl();
+	return 0;
+}
+
+AtEoIF()
+{
+#ifndef NOPP
+	if (nestlevel != nestlow) lexwarning("missing #endif");
+	else
+#endif NOPP
+	if (NoUnstack) lexerror("unexpected EOF");
+#ifndef NOPP
+	nestlevel = nestlow;
+#endif
+	return 0;
+}

+ 15 - 0
lang/cem/cemcom.ansi/input.h

@@ -0,0 +1,15 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+#define INP_PUSHBACK 3
+
+#include <inp_pkg.spec>
+
+/*	Note: The following macro only garuantees one PushBack.
+*/
+#define UnGetChar()	ChPushBack(LexSave)
+
+extern	int LexSave;	/* last character read by GetChar		*/
+extern 	int GetChar();	/* character input, with trigraph parsing	*/

+ 8 - 0
lang/cem/cemcom.ansi/interface.h

@@ -0,0 +1,8 @@
+/* $Header$ */
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+#define PRIVATE	/*static		/* or not */
+#define IMPORT	extern
+#define EXPORT

+ 700 - 0
lang/cem/cemcom.ansi/ival.g

@@ -0,0 +1,700 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* CODE FOR THE INITIALISATION OF GLOBAL VARIABLES */
+
+{
+#include	"lint.h"
+#include	"nofloat.h"
+#include	<em.h>
+#include	"debug.h"
+#include	<alloc.h>
+#include	<assert.h>
+#include	"nobitfield.h"
+#include	"arith.h"
+#include	"label.h"
+#include	"expr.h"
+#include	"type.h"
+#include	"proto.h"
+#include	"struct.h"
+#include	"field.h"
+#include	"assert.h"
+#include	"Lpars.h"
+#include	"sizes.h"
+#include	"idf.h"
+#include	"level.h"
+#include	"def.h"
+#include	"LLlex.h"
+#include	"noRoption.h"
+#include	"estack.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)
+
+char *long2str();
+char *strncpy();
+extern char options[];
+static int gen_error;
+struct type **gen_tphead(), **gen_tpmiddle();
+struct sdef *gen_align_to_next();
+struct e_stack *p_stack;
+}
+
+/*	initial_value recursively guides the initialisation expression.
+	Upto now, the initialisation of a union is not allowed!
+*/
+/* 7 */
+initial_value(register struct type **tpp; register struct expr **expp;) :
+	{ if (tpp) gen_tpcheck(tpp, 0); }
+[
+	assignment_expression(expp)
+		{
+#ifdef	LINT
+			lint_expr(*expp, USED);
+#endif	LINT
+			if ((*expp)->ex_type->tp_fund == ARRAY)
+				array2pointer(*expp);
+			if (tpp) {
+			  	gen_simple_exp(tpp, expp);
+			  	free_expression(*expp);
+				*expp = 0;
+			}
+		}
+|
+	initial_value_pack(tpp, expp)
+]
+;
+
+initial_value_pack(struct type **tpp; struct expr **expp;)
+	{ static int pack_level; }
+:
+	'{'
+			{ if (pack_level == 0) gen_error = 0; pack_level++; }
+	initial_value_list(tpp, expp)
+			{ pack_level--;
+			  if (!pack_level) {
+				while (p_stack) {
+					struct e_stack *p = p_stack->next;
+
+					free_e_stack(p_stack);
+					p_stack = p;
+				}
+			  }
+			}
+	'}'
+;
+
+initial_value_list(register struct type **tpp; struct expr **expp;)
+	{ struct expr *e1;
+	  register struct type **tpp2 = 0;
+	}
+:
+			{ if (tpp) tpp2 = gen_tphead(tpp, 0); }
+	initial_value(tpp2, &e1)
+			{ if (!tpp) init_expression(&expp, e1); }
+	[%while (AHEAD != '}')		/* >>> conflict on ',' */
+		','
+			{ if (tpp) tpp2 = gen_tpmiddle(); }
+		initial_value(tpp2, &e1)
+			{ if (!tpp) init_expression(&expp, e1); }
+	]*
+			{ if (tpp) gen_tpend(); }
+	','?				/* optional trailing comma */
+;
+
+{
+gen_tpcheck(tpp, union_allowed)
+	struct type **tpp;
+{
+	register struct type *tp;
+
+	if (gen_error) return;
+	switch((tp = *tpp)->tp_fund) {
+	case ARRAY:
+		if (! valid_type(tp->tp_up, "array element"))
+			gen_error = 1;
+		break;
+	case STRUCT:
+		if (! valid_type(tp, "struct"))
+			gen_error = 1;
+		break;
+	case UNION:
+		if (! valid_type(tp, "union"))
+			gen_error = 1;
+		break;
+	}
+}
+
+gen_simple_exp(tpp, expp)
+	struct type **tpp;
+	struct expr **expp;
+{
+	register struct type *tp;
+
+	if (gen_error) return;
+	tp = *tpp;
+	switch(tp->tp_fund) {
+	case ARRAY:
+		if ((*expp)->ex_class == String && tp->tp_up->tp_fund == CHAR) {
+			ch_array(tpp,*expp);
+			break;
+		}
+		/* Fall through */
+	case UNION:
+	case STRUCT:
+		check_and_pad(expp, tpp);
+		break;
+	case ERRONEOUS:
+		gen_error = 1;
+		break;
+	default:
+		check_ival(expp, tp);
+		break;
+	}
+}
+
+struct type **
+arr_elem(tpp, p)
+	struct type **tpp;
+	struct e_stack *p;
+{
+	register struct type *tp = *tpp;
+
+	if (tp->tp_up->tp_fund == CHAR && AHEAD == STRING && p->elem_count == 1) {
+		p->nelem = 1;
+		return tpp;
+	}
+	if (AHEAD == '{' || ! aggregate_type(tp->tp_up))
+		return &(tp->tp_up);
+	return gen_tphead(&(tp->tp_up), 1);
+}
+
+struct sdef *
+next_field(sd, p)
+	register struct sdef *sd;
+	register struct e_stack *p;
+{
+	if (sd->sd_sdef)
+		p->bytes_upto_here += zero_bytes(sd);
+	if (p->last_offset != sd->sd_offset) {
+		p->bytes_upto_here +=
+			size_of_type(sd->sd_type, "selector");
+		p->last_offset = sd->sd_offset;
+	}
+	return sd->sd_sdef;
+}
+
+struct type **
+gen_tphead(tpp, nest)
+	struct type **tpp;
+{
+	register struct type *tp = *tpp;
+	register struct e_stack *p;
+	register struct sdef *sd;
+
+	if (tpp && *tpp == error_type) {
+		gen_error = 1;
+		return 0;
+	}
+	if (gen_error) return tpp;
+	p = new_e_stack();
+	p->next = p_stack;
+	p_stack = p;
+	p->s_nested = nest;
+	p->s_tpp = tpp;
+	switch(tp->tp_fund) {
+	case ARRAY:
+		p->nelem = -1;
+		p->elem_count = 1;
+		if (tp->tp_size != (arith) -1) {
+			p->nelem = (tp->tp_size / tp->tp_up->tp_size);
+		}
+		return arr_elem(tpp, p);
+	case STRUCT:
+		p->s_def = sd = tp->tp_sdef;
+		p->bytes_upto_here = 0;
+		p->last_offset = -1;
+#ifndef NOBITFIELD
+		while (sd && is_anon_idf(sd->sd_idf)) {
+			put_bf(sd->sd_type, (arith) 0);
+			sd = next_field(sd, p);
+		}
+#endif
+		if (! sd) {
+			/* something wrong with this struct */
+			gen_error = 1;
+			p_stack = p->next;
+			free_e_stack(p);
+			return 0;
+		}
+		p->s_def = sd;
+		if (AHEAD != '{' && aggregate_type(sd->sd_type)) {
+			return gen_tphead(&(sd->sd_type), 1);
+		}
+		return &(sd->sd_type);
+	default:
+		p->nelem = 1;
+		p->elem_count = 1;
+		return tpp;
+	}
+}
+
+struct type **
+gen_tpmiddle()
+{
+	register struct type *tp;
+	register struct sdef *sd;
+	register struct e_stack *p = p_stack;
+
+	if (gen_error) {
+		if (p) return p->s_tpp;
+		return 0;
+	}
+again:
+	tp = *(p->s_tpp);
+	switch(tp->tp_fund) {
+	default:
+		if (p->elem_count == p->nelem && p->s_nested) {
+			p = p->next;
+			free_e_stack(p_stack);
+			p_stack = p;
+			goto again;
+		}
+		p->elem_count++;
+		if (p->nelem >= 0 && p->elem_count > p->nelem) {
+			too_many_initialisers();
+			return p->s_tpp;
+		}
+		if (tp->tp_fund == ARRAY) {
+			return arr_elem(p->s_tpp, p);
+		}
+		return p->s_tpp;
+	case STRUCT:
+		sd = gen_align_to_next(p);
+		if (! sd) {
+			while (p->bytes_upto_here++ < tp->tp_size)
+				con_nullbyte();
+			if (p->s_nested) {
+				p = p->next;
+				free_e_stack(p_stack);
+				p_stack = p;
+				goto again;
+			}
+			too_many_initialisers();
+			return p->s_tpp;
+		}
+		if (AHEAD != '{' && aggregate_type(sd->sd_type)) {
+			return gen_tphead(&(sd->sd_type), 1);
+		}
+		return &(sd->sd_type);
+	}
+}
+
+struct sdef *
+gen_align_to_next(p)
+	register struct e_stack *p;
+{
+	register struct sdef *sd = p->s_def;
+
+	if (! sd) return sd;
+#ifndef NOBITFIELD
+	do {
+		if (is_anon_idf(sd->sd_idf)) put_bf(sd->sd_type, (arith) 0);
+#endif
+		sd = next_field(sd, p);
+#ifndef NOBITFIELD
+	} while (sd && is_anon_idf(sd->sd_idf));
+#endif
+	p->s_def = sd;
+	return sd;
+}
+
+gen_tpend()
+{
+	register struct e_stack *p = p_stack;
+	register struct type *tp;
+	register struct sdef *sd;
+	int getout = 0;
+
+	while (!getout && p) {
+	    if (!gen_error) {
+		tp = *(p->s_tpp);
+		switch(tp->tp_fund) {
+		case ARRAY:
+			if (tp->tp_size == -1) {
+				*(p->s_tpp) = construct_type(ARRAY, tp->tp_up,
+					0, p->elem_count, NO_PROTO);
+			}
+			else {
+				while (p->nelem-- > p->elem_count) {
+					pad(tp->tp_up);
+				}
+			}
+			break;
+		case STRUCT:
+			sd = gen_align_to_next(p);
+			while (sd) {
+				pad(sd->sd_type);
+				if (sd->sd_sdef)
+					p->bytes_upto_here += zero_bytes(sd);
+				p->bytes_upto_here +=
+					size_of_type(sd->sd_type, "selector");
+				sd = sd->sd_sdef;
+			}
+			while (p->bytes_upto_here++ < tp->tp_size)
+				con_nullbyte();
+			break;
+		}
+	    }
+	    if (! p->s_nested) getout = 1;
+	    p = p->next;
+	    free_e_stack(p_stack);
+	    p_stack = p;
+	}
+	gen_error = 0;
+}
+
+/*	check_and_pad() is given a simple initialisation expression
+	where the type can be either a simple or an aggregate type.
+	In the latter case, only the first member is initialised and
+	the rest is zeroed.
+*/
+check_and_pad(expp, tpp)
+	struct type **tpp;
+	struct expr **expp;
+{
+	register struct type *tp = *tpp;
+
+	if (tp->tp_fund == ARRAY) {
+		check_and_pad(expp, &(tp->tp_up));	/* first member	*/
+		if (tp->tp_size == (arith)-1)
+			/*	no size specified upto here: just
+				set it to the size of one member.
+			*/
+			tp = *tpp = construct_type(ARRAY, tp->tp_up,
+					0, (arith)1, NO_PROTO);
+		else {
+			register int dim = tp->tp_size / tp->tp_up->tp_size;
+			/* pad remaining members with zeroes */
+			while (--dim > 0)
+				pad(tp->tp_up);
+		}
+	}
+	else
+	if (tp->tp_fund == STRUCT) {
+		register struct sdef *sd = tp->tp_sdef;
+
+		check_and_pad(expp, &(sd->sd_type));
+		/* next selector is aligned by adding extra zeroes */
+		if (sd->sd_sdef)
+			zero_bytes(sd);
+		while (sd = sd->sd_sdef) { /* pad remaining selectors	*/
+			pad(sd->sd_type);
+			if (sd->sd_sdef)
+				zero_bytes(sd);
+		}
+	}
+	else if (tp->tp_fund == UNION) {
+		/* only the first selector can be initialized */
+		register struct sdef *sd = tp->tp_sdef;
+
+		check_and_pad(expp, &(sd->sd_type));
+	}
+	else	/* simple type	*/
+		check_ival(expp, tp);
+}
+
+/*	pad() fills an element of type tp with zeroes.
+	If the element is an aggregate, pad() is called recursively.
+*/
+pad(tpx)
+	struct type *tpx;
+{
+	register struct type *tp = tpx;
+	register arith sz = tp->tp_size;
+
+	gen_tpcheck(&tpx, 1);
+	if (gen_error) return;
+	switch (tp->tp_fund) {
+	case UNION:
+#ifndef NOROPTION
+		if (options['R']) {
+			warning("initialisation of unions not allowed");
+		}
+#endif
+		break;
+#ifndef NOBITFIELD
+	case FIELD:
+		put_bf(tp, (arith)0);
+		return;
+#endif NOBITFIELD
+		default:
+			break;
+	}
+
+	while (sz >= word_size) {
+		C_con_cst((arith) 0);
+		sz -= word_size;
+	}
+	while (sz) {
+		C_con_icon("0", (arith) 1);
+		sz--;
+	}
+}
+
+/*	check_ival() checks whether the initialisation of an element
+	of a fundamental type is legal and, if so, performs the initialisation
+	by directly generating the necessary code.
+	No further comment is needed to explain the internal structure
+	of this straightforward function.
+*/
+check_ival(expp, tp)
+	register struct type *tp;
+	struct expr **expp;
+{
+	/*	The philosophy here is that ch7cast puts an explicit
+		conversion node in front of the expression if the types
+		are not compatible.  In this case, the initialisation
+		expression is no longer a constant.
+	*/
+	register struct expr *expr = *expp;
+	
+	switch (tp->tp_fund) {
+	case CHAR:
+	case SHORT:
+	case INT:
+	case LONG:
+	case ENUM:
+	case POINTER:
+		ch7cast(expp, '=', tp);
+		expr = *expp;
+#ifdef DEBUG
+		print_expr("init-expr after cast", expr);
+#endif DEBUG
+		if (!is_ld_cst(expr))
+			illegal_init_cst(expr);
+		else
+		if (expr->VL_CLASS == Const)
+			con_int(expr);
+		else
+		if (expr->VL_CLASS == Name) {
+			register struct idf *idf = expr->VL_IDF;
+
+			if (idf->id_def->df_level >= L_LOCAL)
+				illegal_init_cst(expr);
+			else	/* e.g., int f(); int p = f; */
+			if (idf->id_def->df_type->tp_fund == FUNCTION)
+				C_con_pnam(idf->id_text);
+			else	/* e.g., int a; int *p = &a; */
+				C_con_dnam(idf->id_text, expr->VL_VALUE);
+		}
+		else {
+			ASSERT(expr->VL_CLASS == Label);
+			C_con_dlb(expr->VL_LBL, expr->VL_VALUE);
+		}
+		break;
+#ifndef NOFLOAT
+	case FLOAT:
+	case DOUBLE:
+		ch7cast(expp, '=', tp);
+		expr = *expp;
+#ifdef DEBUG
+		print_expr("init-expr after cast", expr);
+#endif DEBUG
+		if (expr->ex_class == Float)
+			C_con_fcon(expr->FL_VALUE, expr->ex_type->tp_size);
+#ifdef NOTDEF
+
+Coercion from int to float is now always done compile time.
+This, to accept declarations like
+double	x = -(double)1;
+and also to prevent runtime coercions for compile-time constants.
+
+		else
+		if (expr->ex_class == Oper && expr->OP_OPER == INT2FLOAT) {
+			/* float f = 1; */
+			expr = expr->OP_RIGHT;
+			if (is_cp_cst(expr))
+				C_con_fcon(long2str((long)expr->VL_VALUE, 10),
+					tp->tp_size);
+			else 
+				illegal_init_cst(expr);
+		}
+#endif NOTDEF
+		else
+			illegal_init_cst(expr);
+		break;
+#endif NOFLOAT
+
+#ifndef NOBITFIELD
+	case FIELD:
+		ch7cast(expp, '=', tp->tp_up);
+		expr = *expp;
+#ifdef DEBUG
+		print_expr("init-expr after cast", expr);
+#endif DEBUG
+		if (is_cp_cst(expr))
+			put_bf(tp, expr->VL_VALUE);
+		else
+			illegal_init_cst(expr);
+		break;
+#endif NOBITFIELD
+
+	case ERRONEOUS:
+		break;
+	default:
+		crash("check_ival");
+		/*NOTREACHED*/
+	}
+}
+
+/*	ch_array() initialises an array of characters when given
+	a string constant.
+	Alignment is taken care of.
+*/
+ch_array(tpp, ex)
+	struct type **tpp;	/* type tp = array of characters	*/
+	struct expr *ex;
+{
+	register struct type *tp = *tpp;
+	register arith length = ex->SG_LEN;
+	char *s;
+
+	ASSERT(ex->ex_class == String);
+	if (tp->tp_size == (arith)-1) {
+		/* set the dimension	*/
+		tp = *tpp = construct_type(ARRAY, tp->tp_up, 0, length, NO_PROTO);
+	}
+	else {
+		arith dim = tp->tp_size / tp->tp_up->tp_size;
+
+		if (length > dim) {
+			expr_warning(ex, "too many initialisers");
+		}
+		length = dim;
+	}
+	/* throw out the characters of the already prepared string	*/
+	s = Malloc((unsigned) (length));
+	clear(s, (int) (length));
+	strncpy(s, ex->SG_VALUE, (int) length);
+	free(ex->SG_VALUE);
+	str_cst(s, (int) (length));
+	free(s);
+}
+
+/*	As long as some parts of the pipeline cannot handle very long string
+	constants, string constants are written out in chunks
+*/
+str_cst(str, len)
+	register char *str;
+	register int len;
+{
+	int chunksize = ((127 + (int) word_size) / (int) word_size) * (int) word_size;
+
+	while (len > chunksize) {
+		C_con_scon(str, (arith) chunksize);
+		len -= chunksize;
+		str += chunksize;
+	}
+	C_con_scon(str, (arith) len);
+}
+
+#ifndef NOBITFIELD
+/*	put_bf() takes care of the initialisation of (bit-)field
+	selectors of a struct: each time such an initialisation takes place,
+	put_bf() is called instead of the normal code generating routines.
+	Put_bf() stores the given integral value into "field" and
+	"throws" the result of "field" out if the current selector
+	is the last of this number of fields stored at the same address.
+*/
+put_bf(tp, val)
+	struct type *tp;
+	arith val;
+{
+	static long field = (arith)0;
+	static arith offset = (arith)-1;
+	register struct field *fd = tp->tp_field;
+	register struct sdef *sd =  fd->fd_sdef;
+	static struct expr exp;
+
+	ASSERT(sd);
+	if (offset == (arith)-1) {
+		/* first bitfield in this field	*/
+		offset = sd->sd_offset;
+		exp.ex_type = tp->tp_up;
+		exp.ex_class = Value;
+		exp.VL_CLASS = Const;
+	}
+	if (val != 0)	/* insert the value into "field"	*/
+		field |= (val & fd->fd_mask) << fd->fd_shift;
+	if (sd->sd_sdef == 0 || sd->sd_sdef->sd_offset != offset) {
+		/* the selector was the last stored at this address	*/
+		exp.VL_VALUE = field;
+		con_int(&exp);
+		field = (arith)0;
+		offset = (arith)-1;
+	}
+}
+#endif NOBITFIELD
+
+int
+zero_bytes(sd)
+	register struct sdef *sd;
+{
+	/*	fills the space between a selector of a struct
+		and the next selector of that struct with zero-bytes.
+	*/
+	register int n = sd->sd_sdef->sd_offset - sd->sd_offset -
+		size_of_type(sd->sd_type, "struct member");
+	register int count = n;
+
+	while (n-- > 0)
+		con_nullbyte();
+	return count;
+}
+
+int
+valid_type(tp, str)
+	struct type *tp;
+	char *str;
+{
+	ASSERT(tp!=(struct type *)0);
+	if (tp->tp_size < 0) {
+		error("size of %s unknown", str);
+		return 0;
+	}
+	return 1;
+}
+
+con_int(ex)
+	register struct expr *ex;
+{
+	register struct type *tp = ex->ex_type;
+
+	ASSERT(is_cp_cst(ex));
+	if (tp->tp_unsigned)
+		C_con_ucon(long2str((long)ex->VL_VALUE, -10), tp->tp_size);
+	else if (tp->tp_size == word_size)
+		C_con_cst(ex->VL_VALUE);
+	else
+		C_con_icon(long2str((long)ex->VL_VALUE, 10), tp->tp_size);
+}
+
+illegal_init_cst(ex)
+	struct expr *ex;
+{
+	expr_error(ex, "illegal initialisation constant");
+	gen_error = 1;
+}
+
+too_many_initialisers()
+{
+	error("too many initialisers");
+	gen_error = 1;
+}
+}

+ 28 - 0
lang/cem/cemcom.ansi/l_brace.str

@@ -0,0 +1,28 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+
+/*	To determine the minimum scope of a local variable, all (braced)
+	scopes are numbered consecutively.  Next we maintain an array which
+	maps the nesting depth (level) onto the scope number; we record
+	the scope number of the first application of a local variable
+	in its definition.  Each further application requires that the
+	level of the variable be at least large enough to comprise both
+	the present scope and that of its first application.  That level
+	number is determined by searching the array and is then recorded in
+	the definition (beacuse it is always equal to or smaller than the
+	level already there).
+
+	The array is implemented as a linked list of struct brace.
+*/
+
+struct brace	{
+	struct brace *next;
+	int br_count;
+	int br_level;
+};
+
+/* ALLOCDEF "brace" 10 */
+

+ 21 - 0
lang/cem/cemcom.ansi/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 */
+

+ 211 - 0
lang/cem/cemcom.ansi/l_comment.c

@@ -0,0 +1,211 @@
+/*
+ * (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	<ctype.h>
+
+#include	"lint.h"
+
+#ifdef	LINT
+
+#include	<alloc.h>
+#include	"interface.h"
+#include	"arith.h"
+#include	"l_state.h"
+#include	"l_comment.h"
+
+extern char loptions[];
+
+/*	Since the lexical analyser does a one-token look-ahead, pseudo-
+	comments are read too soon.  This is remedied by first storing them
+	in static variables and then moving them to the real variables
+	one token later.
+*/
+
+PRIVATE int notreached;
+PRIVATE int varargsN = -1;
+PRIVATE int argsused;
+PRIVATE int formatN;
+PRIVATE int formatVAR;
+PRIVATE char *format;
+PRIVATE char *prev_format;
+
+PRIVATE make_format();
+
+int LINTLIB;				/* file is lint library */
+int s_NOTREACHED;			/* statement not reached */
+int f_VARARGSn;				/* function with variable # of args */
+int f_ARGSUSED;				/* function does not use all args */
+int f_FORMATn;				/* argument f_FORMATn is f_FORMAT */
+char *f_FORMAT;
+int f_FORMATvar;			/* but the formal argument may be
+					   absent because of varargs.h */
+
+lint_init_comment()
+{
+	LINTLIB = loptions['L'];
+}
+
+lint_comment_ahead()
+{
+	s_NOTREACHED = notreached;
+	notreached = 0;
+}
+
+lint_comment_function()
+{
+	f_ARGSUSED = argsused | loptions['v'];
+	argsused = 0;
+
+	f_VARARGSn = varargsN;
+	varargsN = -1;
+
+	f_FORMATn = formatN;
+	formatN = 0;
+	f_FORMAT = format;
+	if (format)
+		prev_format = format;
+	format = 0;
+
+	f_FORMATvar = formatVAR;
+	formatVAR = 0;
+}
+
+PRIVATE char buf[1000];
+PRIVATE char *bufpos;			/* next free position in buf */
+
+lint_start_comment()
+{
+	bufpos = &buf[0];
+}
+
+lint_comment_char(c)
+	int c;
+{
+/* This function is called with every character between /_* and *_/ */
+	if (bufpos - &buf[0] < sizeof(buf)-1)
+		*bufpos++ = (char)c;
+}
+
+lint_end_comment()
+{
+	*bufpos++ = '\0';
+	bufpos = &buf[0];
+
+	/* skip initial blanks */
+	while (*bufpos && isspace(*bufpos)) {
+		bufpos++;
+	}
+
+	/* now test for one of the pseudo-comments */
+	if (strncmp(bufpos, "NOTREACHED", 10) == 0) {
+		notreached = 1;
+	}
+	else
+	if (strncmp(bufpos, "ARGSUSED", 8) == 0) {
+		argsused = 1;
+	}
+	else
+	if (strncmp(bufpos, "LINTLIBRARY", 11) == 0) {
+		LINTLIB = 1;
+	}
+	else
+	if (strncmp(bufpos, "VARARGS", 7) == 0) {
+		bufpos += 7;
+		varargsN = isdigit(*bufpos) ? atoi(bufpos) : 0;
+	}
+	else
+	if (strncmp(bufpos, "FORMAT", 6) == 0 && isdigit(bufpos[6])) {
+		register int argn;
+
+		bufpos += 6;
+		argn = *bufpos++ - '0';
+		varargsN = argn + 1;
+		if (*bufpos == 'v') {
+			/* something like FORMAT3v */
+			formatVAR = 1;
+			bufpos++;
+		}
+		make_format(argn, bufpos);
+		
+	}
+}
+
+/*	We use a small FSA to skip layout inside formats, but to preserve
+	a space between letters and digits.
+*/
+
+#define	NONE		0
+#define	LETGIT		1
+#define	LETGITSPACE	2
+
+PRIVATE
+make_format(argn, oldf)
+	int argn;
+	char *oldf;
+{
+	register char *newf;
+	register int last_stat;
+
+	while (*oldf && *oldf != '$') {
+		oldf++;
+	}
+	if (!*oldf) {
+		/* no format given, repeat previous format */
+		if (!prev_format) {
+			warning("format missing and no previous format");
+		}
+		formatN = argn;
+		format = prev_format;
+		return;
+	}
+	if (*oldf++ != '$') {
+		warning("no format in FORMAT pseudo-comment");
+		format = 0;
+		return;
+	}
+
+	/* there is a new format to be composed */
+	newf = Malloc(strlen(oldf));
+		/* certainly enough and probably not overly too much */
+	formatN = argn;
+	format = newf;
+
+	last_stat = NONE;
+	while (*oldf && *oldf != '$') {
+		register char ch = *oldf++;
+
+		if (isspace(ch)) {
+			if (last_stat == LETGIT)
+				last_stat = LETGITSPACE;
+		}
+		else
+		if (isalnum(ch)) {
+			switch (last_stat) {
+			case NONE:
+				last_stat = LETGIT;
+				break;
+			case LETGITSPACE:
+				*newf++ = ' ';
+				last_stat = LETGIT;
+				break;
+			}
+			*newf++ = ch;
+		}
+		else {
+			last_stat = NONE;
+			*newf++ = ch;
+		}
+	}
+	if (*oldf != '$') {
+		warning("no end of format in FORMAT pseudo-comment");
+		format = 0;
+		return;
+	}
+	*newf++ = '\0';
+}
+
+#endif	LINT

+ 15 - 0
lang/cem/cemcom.ansi/l_comment.h

@@ -0,0 +1,15 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+
+extern int LINTLIB;			/* file is lint library */
+extern int s_NOTREACHED;		/* statement not reached */
+extern int f_VARARGSn;			/* function with variable # of args */
+extern int f_ARGSUSED;			/* function does not use all args */
+extern int f_FORMATn;			/* argument f_FORMATn is f_FORMAT */
+extern char *f_FORMAT;
+extern int f_FORMATvar;			/* but the formal argument may be
+					   absent because of varargs.h */
+

+ 74 - 0
lang/cem/cemcom.ansi/l_dummy.c

@@ -0,0 +1,74 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+
+/*
+ *The following functions are hacked to null-functions (i.e. they
+ * do nothing). This needs another solution in the future.
+ */
+#include	"lint.h"
+
+#ifdef	LINT
+
+#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; {}
+#endif	LINT

+ 107 - 0
lang/cem/cemcom.ansi/l_ev_ord.c

@@ -0,0 +1,107 @@
+/*
+ * (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	"interface.h"
+#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_state.h"
+
+extern char *symbol2str();
+
+PRIVATE check_ev_order();
+
+check_and_merge(expr, espp, esp)
+	struct expr *expr;
+	struct expr_state **espp, *esp;
+{
+/* Checks for undefined evaluation orders in case of a non-sequencing 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;
+	int oper = expr->OP_OPER;
+	int is_sequencer =
+		(oper == '?' || oper == OR || oper == AND || oper ==',');
+
+	for (p1 = *espp; p1; p1 = p1->next) {
+		/* scan the list esp for the same variable */
+		p2 = esp;
+		pp = &esp;
+		while (p2) {
+			if (	/* p1 and p2 refer to the same location */
+				p1->es_idf == p2->es_idf
+			&&	p1->es_offset == p2->es_offset
+			) {
+				/* check */
+				if (!is_sequencer)
+					check_ev_order(p1, p2, expr);
+
+				/* merge the info */
+				p1->es_used |= p2->es_used;
+				p1->es_referred |= p2->es_referred;
+				p1->es_set |= p2->es_set;
+
+				/* and remove the entry from esp */
+				*pp = p2->next;
+				free_expr_state(p2);
+				p2 = *pp;
+			}
+			else {
+				/* skip over the entry in esp */
+				pp = &p2->next;
+				p2 = p2->next;
+			}
+		}
+	}
+	/*	If there is anything left in the list esp, this is put in
+		front of the list *espp is now pointing to, and *espp will be
+		left pointing to this new list.
+	*/
+	if (!esp)
+		return;
+	p1 = *espp;
+	*espp = esp;
+	while (esp->next)
+		esp = esp->next;
+	esp->next = p1;
+}
+
+PRIVATE
+check_ev_order(esp1, esp2, expr)
+	struct expr_state *esp1, *esp2;
+	struct expr *expr;
+{
+	if (	(esp1->es_used && esp2->es_set)
+	||	(esp1->es_set && esp2->es_used)
+	||	(esp1->es_set && esp2->es_set)
+	) {
+		expr_warning(expr,
+			"result of %s depends on evaluation order on %s",
+			symbol2str(expr->OP_OPER),
+			esp1->es_idf->id_text);
+	}
+}
+
+#endif	LINT

+ 442 - 0
lang/cem/cemcom.ansi/l_lint.c

@@ -0,0 +1,442 @@
+/*
+ * (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	"debug.h"
+#include	"interface.h"
+#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_state.h"
+#include	"l_outdef.h"
+
+extern char options[128];
+extern char *symbol2str();
+
+PRIVATE struct expr_state *expr2state();
+PRIVATE struct expr_state *value2state();
+PRIVATE struct expr_state *oper2state();
+PRIVATE expr_ignored();
+PRIVATE add_expr_state();
+PRIVATE referred_esp();
+PRIVATE free_expr_states();
+
+lint_init()
+{
+	lint_init_comment();
+	lint_init_stack();
+}
+
+lint_expr(expr, used)
+	struct expr *expr;
+	int used;			/* USED or IGNORED */
+{
+	register struct expr_state *esp;
+
+	esp = expr2state(expr, RVAL, used);
+	referred_esp(esp);
+	free_expr_states(esp);
+}
+
+PRIVATE struct expr_state *
+expr2state(expr, val, used)
+	register struct expr *expr;
+	int val;			/* RVAL or LVAL */
+	int used;			/* USED or IGNORED */
+{
+/* 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.
+ */
+	if (used == IGNORED) {
+		expr_ignored(expr);
+	}
+
+	switch (expr->ex_class) {
+	case Value:
+		return value2state(expr, val);
+
+	case Oper:
+		return oper2state(expr, val, used);
+
+	default:			/* String, Float, Type */
+		return 0;
+	}
+}
+
+PRIVATE struct expr_state *
+value2state(expr, val)
+	struct expr *expr;
+	int val;			/* RVAL or LVAL */
+{
+	switch (expr->VL_CLASS) {
+	case Const:
+	case Label:
+		return 0;
+
+	case Name:
+	{
+		register struct idf *idf = expr->VL_IDF;
+		struct expr_state *esp = 0;
+
+		if (!idf || !idf->id_def)
+			return 0;
+
+		if (val == RVAL && expr->ex_lvalue == 1) {
+			/* value of identifier used */
+			change_state(idf, USED);
+			add_expr_state(expr->EX_VALUE, USED, &esp);
+		}
+		if (val == RVAL && expr->ex_lvalue == 0) {
+			/* address of identifier used */
+			add_expr_state(expr->EX_VALUE, REFERRED, &esp);
+		}
+		return esp;
+	}
+
+	default:
+		NOTREACHED();
+		/* NOTREACHED */
+	}
+}
+
+/*	Let's get this straight.
+	An assignment is performed by elaborating the LHS and the RHS
+	collaterally, to use the A68 terminology, and then serially do the
+	actual assignment. This means:
+	1.	evaluate the LHS as an LVAL,
+	2.	evaluate the RHS as an RVAL,
+	3.	merge them checking for interference,
+	4.	set the result of the LHS to SET, if it is a named variable
+*/
+
+PRIVATE struct expr_state *
+oper2state(expr, val, used)
+	struct expr *expr;
+	int val;			/* RVAL or LVAL */
+	int used;			/* USED or IGNORED */
+{
+	register int oper = expr->OP_OPER;
+	register struct expr *left = expr->OP_LEFT;
+	register struct expr *right = expr->OP_RIGHT;
+	struct expr_state *esp_l = 0;
+	struct expr_state *esp_r = 0;
+
+	switch (oper) {
+
+	/* assignments */
+	case '=':
+	case PLUSAB:
+	case MINAB:
+	case TIMESAB:
+	case DIVAB:
+	case MODAB:
+	case LEFTAB:
+	case RIGHTAB:
+	case ANDAB:
+	case XORAB:
+	case ORAB:
+		/* evaluate the LHS, only once; see RM 7.14 */
+		esp_l = expr2state(left, (oper == '=' ? LVAL : RVAL), USED);
+
+		/* evaluate the RHS as an RVAL and merge */
+		esp_r = expr2state(right, RVAL, USED);
+		check_and_merge(expr, &esp_l, esp_r);
+
+		/* set resulting variable, if any */
+		if (ISNAME(left)) {
+			change_state(left->VL_IDF, SET);
+			add_expr_state(left->EX_VALUE, SET, &esp_l);
+		}
+
+		return esp_l;
+
+	case POSTINCR:
+	case POSTDECR:
+	case PLUSPLUS:
+	case MINMIN:
+		esp_l = expr2state(left, RVAL, USED);
+
+		/* set resulting variable, if any */
+		if (ISNAME(left)) {
+			change_state(left->VL_IDF, SET);
+			add_expr_state(left->EX_VALUE, SET, &esp_l);
+		}
+
+		return esp_l;
+
+	case '?':
+		esp_l = expr2state(left, RVAL, USED);
+		esp_r = expr2state(right->OP_LEFT, RVAL, USED);
+		check_and_merge(expr, &esp_l, esp_r);
+		esp_r = expr2state(right->OP_RIGHT, RVAL, USED);
+		check_and_merge(expr, &esp_l, esp_r);
+		return esp_l;
+
+	case '(':
+		if (right != 0) {
+			/* function call with parameters */
+			register struct expr *ex = right;
+
+			while (	ex->ex_class == Oper
+			&&	ex->OP_OPER == PARCOMMA
+			) {
+				esp_r = expr2state(ex->OP_RIGHT, RVAL, USED);
+				check_and_merge(expr, &esp_l, esp_r);
+				ex = ex->OP_LEFT;
+			}
+			esp_r = expr2state(ex, RVAL, USED);
+			check_and_merge(expr, &esp_l, esp_r);
+		}
+
+		if (ISNAME(left)) {
+			fill_outcall(expr,
+				expr->ex_type->tp_fund == VOID ?
+				VOIDED : used
+			);
+			outcall();
+			left->VL_IDF->id_def->df_used = 1;
+		}
+		else {
+			esp_r = expr2state(left, RVAL, USED);
+			check_and_merge(expr, &esp_l, esp_r);
+		}
+		referred_esp(esp_l);
+		return esp_l;
+
+	case '.':
+		return expr2state(left, val, USED);
+
+	case ARROW:
+		return expr2state(left, RVAL, USED);
+
+	case INT2INT:
+	case INT2FLOAT:
+	case FLOAT2INT:
+	case FLOAT2FLOAT:
+		return expr2state(right, RVAL, USED);
+
+	/* monadic operators */
+	case '-':
+	case '*':
+		if (left)
+			goto dyadic;
+	case '~':
+	case '!':
+		return expr2state(right, RVAL, USED);
+
+	/* relational operators */
+	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
+		);
+		goto dyadic;
+
+	/* dyadic operators */
+	dyadic:
+	case '+':
+	case '/':
+	case '%':
+	case ',':
+	case LEFT:
+	case RIGHT:
+	case '&':
+	case '|':
+	case '^':
+	case OR:
+	case AND:
+		esp_l = expr2state(left, RVAL,
+					oper == ',' ? IGNORED : USED);
+		esp_r = expr2state(right, RVAL,
+					oper == ',' ? used : USED);
+		check_and_merge(expr, &esp_l, esp_r);
+
+		return esp_l;
+
+	default:
+		return 0;	/* for initcomma */
+	}
+}
+
+PRIVATE
+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("value as statement");
+		break;
+
+	default:			/* String Float */
+		hwarning("constant as statement");
+		break;
+	}
+}
+
+PRIVATE
+add_expr_state(value, to_state, espp)
+	struct value value;
+	struct expr_state **espp;
+{
+	register struct expr_state *esp = *espp;
+
+	ASSERT(value.vl_class == Name);
+
+	/* try to find the esp */
+	while (	esp
+	&&	!(	esp->es_idf == value.vl_data.vl_idf
+		&&	esp->es_offset == value.vl_value
+		)
+	) {
+		esp = esp->next;
+	}
+
+	/* if not found, add it */
+	if (!esp) {
+		esp = new_expr_state();
+		esp->es_idf = value.vl_data.vl_idf;
+		esp->es_offset = value.vl_value;
+		esp->next = *espp;
+		*espp = esp;
+	}
+
+	/* set state */
+	switch (to_state) {
+	case USED:
+		esp->es_used = 1;
+		break;
+	case REFERRED:
+		esp->es_referred = 1;
+		break;
+	case SET:
+		esp->es_set = 1;
+		break;
+	default:
+		NOTREACHED();
+		/* NOTREACHED */
+	}
+}
+
+PRIVATE
+referred_esp(esp)
+	struct expr_state *esp;
+{
+	/* raises all REFERRED items to SET and USED status */
+	while (esp) {
+		if (esp->es_referred) {
+			esp->es_set = 1;
+			change_state(esp->es_idf, SET);
+			esp->es_used = 1;
+			change_state(esp->es_idf, USED);
+			esp->es_referred = 0;
+		}
+		esp = esp->next;
+	}
+}
+
+PRIVATE
+free_expr_states(esp)
+	register struct expr_state *esp;
+{
+	while (esp) {
+		register struct expr_state *esp2 = esp;
+
+		esp = esp->next;
+		free_expr_state(esp2);
+	}
+}
+
+#ifdef	DEBUG
+print_esp(msg, esp)
+	char *msg;
+	struct expr_state *esp;
+{
+	print("%s: <", msg);
+	while (esp) {
+		print(" %s[%d]%c%c%c ",
+			esp->es_idf->id_text, esp->es_offset,
+			(esp->es_used ? 'U' : ' '),
+			(esp->es_referred ? 'R' : ' '),
+			(esp->es_set ? 'S' : ' ')
+		);
+		esp = esp->next;
+	}
+	print(">\n");
+}
+#endif	DEBUG
+
+#endif	LINT

+ 18 - 0
lang/cem/cemcom.ansi/l_lint.h

@@ -0,0 +1,18 @@
+/*
+ * (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
+#define	REFERRED	4
+
+/* for od_valreturned */
+#define	NOVALRETURNED	0
+#define	VALRETURNED	1
+#define	NORETURN	2		/* end of function NOTREACHED */
+

+ 395 - 0
lang/cem/cemcom.ansi/l_misc.c

@@ -0,0 +1,395 @@
+/*
+ * (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	"interface.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_state.h"
+
+extern char *symbol2str();
+extern struct type *func_type;
+
+PRIVATE lint_enum_arith();
+PRIVATE lint_conversion();
+PRIVATE int numsize();
+
+lint_new_oper(expr)
+	struct expr *expr;
+{
+	/*	Does additional checking on a newly constructed expr node
+		of class Oper.
+
+		Some code in this routine could be contracted, but since
+		I am not sure we have covered the entire ground, we'll
+		leave the contracting for some rainy day.
+	*/
+	register struct expr *left = expr->OP_LEFT;
+	register struct expr *right = expr->OP_RIGHT;
+	register int oper = expr->OP_OPER;
+	register int l_fund =
+		left == 0 ? 0 :			/* for monadics */
+		left->ex_type->tp_fund;
+	register int r_fund =
+		right == 0 ? 0 :		/* for ( without parameters */
+		right->ex_type->tp_fund;
+
+	/*	In ch7.c, in ch7asgn(), a combined operator/assignment
+		is hammered into correctness by repeated application of
+		ch7bin(), which calls new_oper(), which calls lint_new_oper().
+		These spurious calls understandably cause spurious error
+		messages, which we don't like.  So we try to suppress these
+		wierd calls here.  This refers to the code marked
+			this is really $#@&*%$# !
+		in ch7asgn().
+	*/
+	switch (oper) {
+	case PLUSAB:
+	case MINAB:
+	case TIMESAB:
+	case DIVAB:
+	case MODAB:
+	case LEFTAB:
+	case RIGHTAB:
+	case ANDAB:
+	case XORAB:
+	case ORAB:
+		/* is the left operand wierd? */
+		if (	left->ex_class == Value
+		&&	left->VL_CLASS == Const
+		&&	left->VL_VALUE == 0
+		) {
+			return;
+		}
+	}
+
+	switch (oper) {
+	case '=':
+		lint_conversion(right, l_fund);
+		break;
+
+	case PLUSAB:
+		lint_conversion(right, l_fund);
+	case '+':
+		lint_enum_arith(l_fund, oper, r_fund);
+		break;
+
+	case MINAB:
+		lint_conversion(right, l_fund);
+	case '-':
+		if (left == 0) {
+			/* unary */
+			if (r_fund == ENUM)
+				warning("negating an enum");
+		}
+		else {
+			/* binary */
+			if (l_fund == ENUM && r_fund == ENUM) {
+				if (!equal_type(left->ex_type, right->ex_type))
+					warning("subtracting enums of different type");
+				/* update the type, cem does not do it */
+				expr->ex_type = int_type;
+			}
+			lint_enum_arith(l_fund, oper, r_fund);
+		}
+		break;
+
+	case TIMESAB:
+		lint_conversion(right, l_fund);
+	case '*':
+		if (left == 0) {
+			/* unary */
+		}
+		else {
+			/* binary */
+			if (l_fund == ENUM || r_fund == ENUM)
+				warning("multiplying enum");
+		}
+		break;
+
+	case DIVAB:
+		lint_conversion(right, l_fund);
+	case '/':
+		if (l_fund == ENUM || r_fund == ENUM)
+			warning("division on enum");
+		break;
+
+	case MODAB:
+		lint_conversion(right, l_fund);
+	case '%':
+		if (l_fund == ENUM || r_fund == ENUM)
+			warning("modulo on enum");
+		break;
+
+	case '~':
+		if (r_fund == ENUM || r_fund == FLOAT || r_fund == DOUBLE)
+			warning("~ on %s", symbol2str(r_fund));
+		break;
+
+	case '!':
+		if (r_fund == ENUM)
+			warning("! on enum");
+		break;
+
+	case INT2INT:
+	case INT2FLOAT:
+	case FLOAT2INT:
+	case FLOAT2FLOAT:
+		lint_conversion(right, l_fund);
+		break;
+
+	case '<':
+	case '>':
+	case LESSEQ:
+	case GREATEREQ:
+	case EQUAL:
+	case NOTEQUAL:
+		if (	(l_fund == ENUM || r_fund == ENUM)
+		&&	!equal_type(left->ex_type, right->ex_type)
+		) {
+			warning("comparing enum with non-enum");
+		}
+		lint_relop(left, right, oper);
+		lint_relop(right, left, 
+			oper == '<' ? '>' :
+			oper == '>' ? '<' :
+			oper == LESSEQ ? GREATEREQ :
+			oper == GREATEREQ ? LESSEQ :
+			oper
+		);
+		break;
+
+	case LEFTAB:
+	case RIGHTAB:
+		lint_conversion(right, l_fund);
+	case LEFT:
+	case RIGHT:
+		if (l_fund == ENUM || r_fund == ENUM)
+			warning("shift on enum");
+		break;
+
+	case ANDAB:
+	case ORAB:
+	case XORAB:
+		lint_conversion(right, l_fund);
+	case '&':
+	case '|':
+	case '^':
+		if (l_fund == ENUM || r_fund == ENUM)
+			warning("bit operations on enum");
+		break;
+
+	case ',':
+	case '?':
+	case ':':
+	case AND:
+	case OR:
+	case POSTINCR:
+	case POSTDECR:
+	case PLUSPLUS:
+	case MINMIN:
+	case '(':
+	case '.':
+	case ARROW:
+	default:
+		/* OK with lint */
+		break;
+	}
+}
+
+PRIVATE
+lint_enum_arith(l_fund, oper, r_fund)
+	int l_fund, oper, r_fund;
+{
+	if (	l_fund == ENUM
+	&&	r_fund != CHAR
+	&&	r_fund != SHORT
+	&&	r_fund != INT
+	) {
+		warning("%s on enum and %s",
+			symbol2str(oper), symbol2str(r_fund));
+	}
+	else
+	if (	r_fund == ENUM
+	&&	l_fund != CHAR
+	&&	l_fund != SHORT
+	&&	l_fund != INT
+	) {
+		warning("%s on %s and enum",
+			symbol2str(oper), symbol2str(l_fund));
+	}
+}
+
+PRIVATE
+lint_conversion(from_expr, to_fund)
+	struct expr *from_expr;
+	int to_fund;
+{
+	register int from_fund = from_expr->ex_type->tp_fund;
+
+	/*	was there an attempt to reduce the type of the from_expr
+		of the form
+			expr & 0377
+		or something like this?
+	*/
+	if (from_expr->ex_class == Oper && from_expr->OP_OPER == INT2INT) {
+		from_expr = from_expr->OP_LEFT;
+	}
+	if (from_expr->ex_class == Oper && from_expr->OP_OPER == '&') {
+		struct expr *bits =
+			is_cp_cst(from_expr->OP_LEFT) ? from_expr->OP_LEFT :
+			is_cp_cst(from_expr->OP_RIGHT) ? from_expr->OP_RIGHT :
+			0;
+
+		if (bits) {
+			arith val = bits->VL_VALUE;
+
+			if (val < 256)
+				from_fund = CHAR;
+			else if (val < 256)
+				from_fund = SHORT;
+		}
+	}
+	if (numsize(from_fund) > numsize(to_fund)) {
+		awarning("conversion from %s to %s may lose accuracy",
+			symbol2str(from_fund), symbol2str(to_fund));
+	}
+}
+
+PRIVATE int
+numsize(fund)
+{
+	switch (fund) {
+	case CHAR:	return 1;
+	case SHORT:	return 2;
+	case INT:	return 3;
+	case ENUM:	return 3;
+	case LONG:	return 4;
+	case FLOAT:	return 5;
+	case DOUBLE:	return 6;
+	default:	return 0;
+	}
+}
+
+lint_ret_conv(from_expr)
+	struct expr *from_expr;
+{
+	lint_conversion(from_expr, func_type->tp_fund);
+}
+
+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 */
+{
+	/* left operand may be converted */
+	if (	left->ex_class == Oper
+	&&	left->OP_OPER == INT2INT
+	) {
+		left = left->OP_RIGHT;
+	}
+
+	/* <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

+ 546 - 0
lang/cem/cemcom.ansi/l_outdef.c

@@ -0,0 +1,546 @@
+/*
+ * (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	"interface.h"
+#include	"arith.h"
+#include	"assert.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	"code.h"
+#include	"expr.h"
+#include	"l_lint.h"
+#include	"l_comment.h"
+#include	"l_outdef.h"
+#include	"l_class.h"
+
+extern char *bts2str();
+extern char *symbol2str();
+
+int stat_number = 9999;			/* static scope number */
+struct outdef OutDef;
+
+PRIVATE struct outdef OutCall;
+
+PRIVATE local_EFDC();
+PRIVATE output_def();
+PRIVATE outargs();
+PRIVATE outarg();
+PRIVATE outargstring();
+PRIVATE outargtype();
+PRIVATE implicit_func_decl();
+PRIVATE fill_arg();
+
+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;
+}
+
+PRIVATE
+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 just parsed.
+ */
+	register struct stack_entry *se = stack_level_of(L_FORMAL1)->sl_entry;
+	register struct argument **hook = &OutDef.od_arg;
+	register int nrargs = 0;
+
+	while (se) {
+		register struct type *type = se->se_idf->id_def->df_type;
+		register struct argument *arg = new_argument();
+
+		/*	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.
+		*/
+		switch (type->tp_fund) {
+		case CHAR:
+		case SHORT:
+			type = int_type;
+			break;
+		case FLOAT:
+			type = double_type;
+			break;
+		}
+
+		if (f_FORMAT && nrargs == f_FORMATn) {
+			if (	!f_FORMATvar
+			&&	(	type->tp_fund != POINTER
+				||	type->tp_up->tp_fund != CHAR
+				)
+			) {
+				warning("format parameter %d is not pointer to char",
+					nrargs);
+			}
+			arg->ar_type = string_type;
+			arg->ar_class = ArgString;
+			arg->CAS_VALUE = f_FORMAT;
+			arg->CAS_LEN = strlen(f_FORMAT);
+			f_FORMAT = 0;
+		}
+		else {
+			arg->ar_type = type;
+			arg->ar_class = ArgFormal;
+		}
+		*hook = arg;
+		hook = &arg->next;
+
+		nrargs++;
+		se = se->next;
+	}
+
+	if (f_FORMAT) {
+		/*	f_FORMAT has not been consumed, perhaps due to
+			a varargs-like construction; add erroneous ArgFormals
+			until f_FORMATn, then an ArgString, if necessary.
+		*/
+		if (!f_FORMATvar) {
+			warning("FORMAT%d function has only %d argument%s",
+				f_FORMATn, nrargs, nrargs == 1 ? "" : "s"
+			);
+		}
+
+		while (nrargs < f_FORMATn) {
+			register struct argument *arg = new_argument();
+			
+			arg->ar_type = error_type;
+			arg->ar_class = ArgFormal;
+			*hook = arg;
+			hook = &arg->next;
+			nrargs++;
+		}
+		if (nrargs == f_FORMATn) {
+			register struct argument *arg = new_argument();
+			
+			arg->ar_type = string_type;
+			arg->ar_class = ArgString;
+			arg->CAS_VALUE = f_FORMAT;
+			arg->CAS_LEN = strlen(f_FORMAT);
+			f_FORMAT = 0;
+			*hook = arg;
+			hook = &arg->next;
+			nrargs++;
+		}
+		/* life is full of duplicated code; this is no good */
+	}
+
+	if (f_VARARGSn > nrargs) {
+		warning("VARARGS%d function has only %d argument%s",
+			f_VARARGSn, nrargs, nrargs == 1 ? "" : "s"
+		);
+		f_VARARGSn = nrargs;
+	}
+	OutDef.od_nrargs = 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);
+}
+
+PRIVATE
+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_arg) {
+				register struct argument *tmp = od->od_arg;
+				od->od_arg = od->od_arg->next;
+				free_argument(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);
+			outargs(od->od_arg, f_VARARGSn);
+		}
+		else {
+			printf(":%d", od->od_nrargs);
+			outargs(od->od_arg, od->od_nrargs);
+		}
+		od->od_arg = 0;
+		printf(":%d", od->od_valreturned);
+		break;
+	case FC:
+		printf(":%d", od->od_nrargs);
+		outargs(od->od_arg, od->od_nrargs);
+		od->od_arg = 0;
+		printf(":%d", od->od_valused);
+		break;
+	case EVDF:
+	case SVDF:
+	case LVDF:
+	case EFDC:
+	case EVDC:
+	case IFDC:
+	case VU:
+		break;
+	default:
+		NOTREACHED();
+		/*NOTREACHED*/
+	}
+	printf(":");
+	outargtype(od->od_type);
+	printf(":%u:%s\n", od->od_line, od->od_file);
+}
+
+PRIVATE
+outargs(arg, n)
+	struct argument *arg;
+{
+/* Output the n arguments in the argument list and remove them */
+
+	register struct argument *tmp;
+
+	while (n--) {
+		ASSERT(arg);
+		outarg(arg);
+		tmp = arg;
+		arg = arg->next;
+		free_argument(tmp);
+	}
+	/* remove the remaining entries */
+	while (arg) {
+		tmp = arg;
+		arg = arg->next;
+		free_argument(tmp);
+	}
+}
+
+PRIVATE
+outarg(arg)
+	struct argument *arg;
+{
+	printf(":");
+	switch (arg->ar_class) {
+	case ArgConst:
+		if (arg->CAA_VALUE >= 0) {
+			/* constant non-negative actual parameter */
+			printf("+");
+		}
+		outargtype(arg->ar_type);
+		break;
+
+	case ArgString:
+		outargstring(arg);
+		break;
+
+	case ArgFormal:
+	case ArgExpr:
+		outargtype(arg->ar_type);
+		if (arg->ar_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("*");
+		}
+		break;
+
+	default:
+		NOTREACHED();
+		/*NOTREACHED*/
+	}
+}
+
+PRIVATE
+outargstring(arg)
+	struct argument *arg;
+{
+	char buff[1000];
+	register char *p;
+
+	bts2str(arg->CAS_VALUE, arg->CAS_LEN, buff);
+	for (p = &buff[0]; *p; p++) {
+		if (*p == '"' || *p == ':')
+			*p = ' ';
+	}
+	printf("\"%s\"", buff);
+}
+
+PRIVATE
+outargtype(tp)
+	struct type *tp;
+{
+	switch (tp->tp_fund) {
+	case POINTER:
+		outargtype(tp->tp_up);
+		printf("*");
+		break;
+
+	case ARRAY:
+		outargtype(tp->tp_up);
+		printf("*");	/* compatible with [] */
+		break;
+
+	case FUNCTION:
+		outargtype(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:
+		NOTREACHED();
+		/*NOTREACHED*/
+	}
+}
+
+PRIVATE
+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 && !idf->id_def->df_used) {
+		/* IFDC, first time */
+		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_arg = (struct argument *)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 */
+}
+
+PRIVATE
+fill_arg(e)
+	struct expr *e;
+{
+	register struct argument *arg;
+
+	arg = new_argument();
+	arg->ar_type = e->ex_type;
+	if (is_cp_cst(e)) {
+		arg->ar_class = ArgConst;
+		arg->CAA_VALUE = e->VL_VALUE;
+	}
+	else if (e->ex_class == Value && e->VL_CLASS == Label) {
+		/* it may be a string; let's look it up */
+		register struct string_cst *sc = str_list;
+
+		while (sc) {
+			if (sc->sc_dlb == e->VL_LBL)
+				break;
+			sc = sc->next;
+		}
+		if (sc) {
+			/* it was a string */
+			arg->ar_class = ArgString;
+			arg->CAS_VALUE = sc->sc_value;
+			arg->CAS_LEN = sc->sc_len - 1;	/* included the \0 */
+		}
+		else {
+			arg->ar_class = ArgExpr;
+		}
+	}
+	else {
+		arg->ar_class = ArgExpr;
+	}
+	arg->next = OutCall.od_arg;
+	OutCall.od_arg = arg;
+	OutCall.od_nrargs++;
+}
+
+#endif	LINT

+ 47 - 0
lang/cem/cemcom.ansi/l_outdef.str

@@ -0,0 +1,47 @@
+/*
+ * (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	*/
+
+/* Values for ar_class */
+#define	ArgFormal	0
+#define	ArgExpr		1		/* actual */
+#define	ArgConst	2		/* integer constant */
+#define	ArgString	3		/* string */
+
+struct argument {
+	struct argument *next;
+	struct type *ar_type;
+	int ar_class;			/* for constant parameters */
+	union const_arg {
+		arith ca_value;
+		struct {
+			char *cas_value;
+			int cas_len;
+		} ca_string;
+	} ar_object;
+};
+
+#define	CAA_VALUE	ar_object.ca_value
+#define	CAS_VALUE	ar_object.ca_string.cas_value
+#define	CAS_LEN		ar_object.ca_string.cas_len
+
+/* ALLOCDEF "argument" 10 */
+
+struct outdef {
+	char od_class;
+	int od_statnr;
+	char *od_name;
+	char *od_file;
+	unsigned int od_line;
+	int od_nrargs;
+	struct argument *od_arg;	/* 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;
+};

+ 74 - 0
lang/cem/cemcom.ansi/l_state.str

@@ -0,0 +1,74 @@
+/*
+ * (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_referred;
+	int es_set;
+};
+
+/* ALLOCDEF "expr_state" 20 */
+

+ 1131 - 0
lang/cem/cemcom.ansi/l_states.c

@@ -0,0 +1,1131 @@
+/*
+ * (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	"interface.h"
+#include	"assert.h"
+#include	"debug.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_comment.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[];
+
+/* global variables for the lint_stack */
+PRIVATE struct lint_stack_entry stack_bottom;
+PRIVATE struct lint_stack_entry *top_ls = &stack_bottom;
+
+/* global variables for the brace stack */
+PRIVATE int brace_count;
+PRIVATE struct brace brace_bottom;
+PRIVATE struct brace *top_br = &brace_bottom;
+
+PRIVATE end_brace();
+PRIVATE lint_1_local();
+PRIVATE lint_1_global();
+PRIVATE check_autos();
+PRIVATE struct auto_def *copy_st_auto_list();
+PRIVATE free_st_auto_list();
+PRIVATE struct state *copy_state();
+PRIVATE Free_state();
+PRIVATE remove_settings();
+PRIVATE struct auto_def *merge_autos();
+PRIVATE merge_states();
+PRIVATE struct lint_stack_entry *find_wdf(), *find_wdfc(), *find_cs();
+PRIVATE cont_break_merge();
+PRIVATE lint_push();
+PRIVATE lint_pop();
+
+lint_init_stack()
+{
+/* Allocate some memory for the global stack_bottom
+ */
+	stack_bottom.ls_current = new_state();
+}
+
+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);
+}
+
+PRIVATE
+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);
+}
+
+PRIVATE
+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;
+	}
+}
+
+PRIVATE
+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;
+	int to_state;			/* SET or USED */
+{
+/* 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) {
+		switch (to_state) {
+		case SET:
+			def->df_set = 1;
+			break;
+		case USED:
+			def->df_used = 1;
+			break;
+		}
+
+		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;
+
+	switch (to_state) {
+	case SET:
+		a->ad_maybe_set = 0;
+		a->ad_set = 1;
+		break;
+	case 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;
+		break;
+	}
+}
+
+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;
+	}
+}
+
+PRIVATE
+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;
+
+	ASSERT(!(a1 && a1->ad_def->df_level > level));
+	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;
+
+	ASSERT(level == L_FORMAL1);
+	while (se) {
+		register struct def *def = se->se_idf->id_def;
+
+		if (	(def && !def->df_used)
+		&&	!(f_ARGSUSED || LINTLIB)
+		) {
+			def_warning(def, "argument %s not used in function %s",
+					se->se_idf->id_text, func_name);
+		}
+		se = se->next;
+	}
+}
+
+PRIVATE 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;
+}
+
+PRIVATE
+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);
+	}
+}
+
+PRIVATE 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;
+}
+
+PRIVATE
+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;
+}
+
+PRIVATE
+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
+
+PRIVATE 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) {
+		ASSERT(a2);
+		ASSERT(a1->ad_idf == a2->ad_idf);
+		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;
+	}
+	ASSERT(!a2);
+	return a;
+}
+
+PRIVATE
+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.
+ */
+
+PRIVATE 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;
+}
+
+PRIVATE 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;
+}
+
+PRIVATE 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(const)
+{
+/* 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();
+
+	if (const)
+		hwarning("condition in if statement is constant");
+
+	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("condition in do-while statement is constant");
+	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;
+	}
+}
+
+PRIVATE
+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(expr)
+	struct expr *expr;
+{
+/* 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();
+
+	if (is_cp_cst(expr))
+		hwarning("value in switch statement is constant");
+
+	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:
+		NOTREACHED();
+		/*NOTREACHED*/
+	}
+	top_ls->ls_current->st_notreached = 1;
+}
+
+lint_start_function()
+{
+	lint_return_stmt(-1);	/* initialization */
+	lint_comment_function();
+}
+
+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.
+	 */
+	ASSERT(top_ls == &stack_bottom);
+	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;
+
+	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;
+		}
+	}
+}
+
+PRIVATE
+lint_push(lse)
+	struct lint_stack_entry *lse;
+{
+	lse->ls_previous = top_ls;
+	top_ls->next = lse;
+	top_ls = lse;
+}
+
+PRIVATE
+lint_pop()
+{
+	top_ls = top_ls->ls_previous;
+	free_lint_stack_entry(top_ls->next);
+}
+
+#ifdef	DEBUG
+/* 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");
+}
+
+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	DEBUG
+
+#endif	LINT

+ 74 - 0
lang/cem/cemcom.ansi/label.c

@@ -0,0 +1,74 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*		L A B E L   H A N D L I N G		*/
+
+#include	"Lpars.h"
+#include	"level.h"
+#include	"idf.h"
+#include	"label.h"
+#include	"arith.h"
+#include	"def.h"
+#include	"type.h"
+#include	"noRoption.h"
+
+extern char options[];
+
+enter_label(idf, defining)
+	register struct idf *idf;
+{
+	/*	The identifier idf is entered as a label. If it is new,
+		it is entered into the idf list with the largest possible
+		scope, i.e., on the lowest possible level.
+		If defining, the label comes from a label statement.
+	*/
+	if (idf->id_def)	{
+		register struct def *def = idf->id_def;
+		
+		if (def->df_sc == LABEL)	{
+			if (defining && def->df_initialized)
+				error("redeclaration of label %s",
+								idf->id_text);
+		}
+		else	{		/* there may still be room for it */
+#ifndef NOROPTION
+			if (options['R'] && def->df_sc == TYPEDEF)
+				warning("label %s is also a typedef",
+					idf->id_text);
+#endif
+			
+			if (def->df_level == level)	/* but alas, no */
+				error("%s is not a label", idf->id_text);
+			else	{
+				register int lvl = def->df_level + 1;
+				
+#ifndef NOROPTION
+				if (options['R'] && def->df_level > L_LOCAL)
+					warning("label %s is not function-wide",
+								idf->id_text);
+#endif
+				if (lvl < L_LOCAL)
+					lvl = L_LOCAL;
+				add_def(idf, LABEL, label_type, lvl);
+			}
+		}
+	}
+	else	{
+		add_def(idf, LABEL, label_type, L_LOCAL);
+	}
+	if (idf->id_def->df_address == 0)
+		idf->id_def->df_address = (arith) text_label();
+	if (defining)
+		idf->id_def->df_initialized = 1;
+}
+
+unstack_label(idf)
+	register struct idf *idf;
+{
+	/*	The scope in which the label idf occurred is left.
+	*/
+	if (!idf->id_def->df_initialized && !is_anon_idf(idf))
+		error("label %s not defined", idf->id_text);
+}

+ 28 - 0
lang/cem/cemcom.ansi/label.h

@@ -0,0 +1,28 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*		L A B E L   D E F I N I T I O N				*/
+
+#include <em_label.h>		/* obtain definition of "label" */
+
+#define	NO_LABEL	(label) 0
+
+extern label lab_count;
+#define	text_label()	(lab_count++)		/* returns a new text label */
+
+extern label datlab_count;
+#define	data_label()	(datlab_count++)	/* returns a new data label */
+
+#define define_label(idf) enter_label(idf, 1);
+	/*	The identifier idf is defined as a label. If it is new,
+		it is entered into the idf list with the largest possible
+		scope, i.e., on the lowest possible level.
+	*/
+
+#define apply_label(idf) enter_label(idf, 0);
+	/*	The identifier idf is applied as a label. It may or may
+		not be there, and if it is there, it may be from a
+		declaration or another application.
+	*/

+ 23 - 0
lang/cem/cemcom.ansi/level.h

@@ -0,0 +1,23 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*  LEVEL DEFINITIONS */
+
+/*	The level of the top-most stack_level is kept in a global variable
+	with the obvious name 'level'. Although this variable is consulted
+	by a variety of routines, it turns out that its actual value is of
+	importance in only a very few files. Therefore the names of the
+	values are put in a separate include-file.
+	The L_PROTO level is a dummy level, which only occurs within
+	prototype declarations. When the declaration is really declared
+	the level is turned into L_FORMAL2.
+*/
+
+#define	L_PROTO		(-1)		/* prototype declaration */
+#define	L_UNIVERSAL	0
+#define	L_GLOBAL	1
+#define	L_FORMAL1	2		/* formal declaration */
+#define	L_FORMAL2	3		/* formal definition */
+#define	L_LOCAL		4		/* and up */

+ 60 - 0
lang/cem/cemcom.ansi/macro.str

@@ -0,0 +1,60 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* PREPROCESSOR: DEFINITION OF MACRO DESCRIPTOR */
+
+#include	"nopp.h"
+
+#ifndef NOPP
+/*	The flags of the mc_flag field of the macro structure. Note that
+	these flags can be set simultaneously.
+*/
+#define NOFLAG		0		/* no special flags	*/
+#define	FUNC		01		/* function attached    */
+#define NOREPLACE	02		/* don't replace	*/
+
+#define	FORMALP 0200	/* mask for creating macro formal parameter	*/
+
+/*	The macro descriptor is very simple, except the fact that the
+	mc_text, which points to the replacement text, contains the
+	non-ascii characters \201, \202, etc, indicating the position of a
+	formal parameter in this text.
+*/
+struct macro	{
+	struct macro *next;
+	char *	mc_text;	/* the replacement text		*/
+	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		*/
+};
+
+/* ALLOCDEF "macro" 20 */
+
+struct mlist {
+	struct mlist *next;
+	struct macro *m_mac;
+	char *m_repl;
+	char m_unstack;
+};
+
+/* ALLOCDEF "mlist" 20 */
+
+/* `token' numbers of keywords of command-line processor
+*/
+#define	K_UNKNOWN	0
+#define	K_DEFINE	1
+#define	K_ELIF		2
+#define	K_ELSE		3
+#define	K_ENDIF		4
+#define	K_ERROR		5
+#define	K_IF		6
+#define	K_IFDEF		7
+#define	K_IFNDEF	8
+#define	K_INCLUDE	9
+#define	K_LINE		10
+#define	K_PRAGMA	11
+#define	K_UNDEF		12
+#endif NOPP

+ 406 - 0
lang/cem/cemcom.ansi/main.c

@@ -0,0 +1,406 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* MAIN PROGRAM */
+
+#include	"lint.h"
+#include	"nofloat.h"
+#include	<system.h>
+#include	"nopp.h"
+#include	"target_sizes.h"
+#include	"debug.h"
+#include	"use_tmp.h"
+#include	"inputtype.h"
+#include	"input.h"
+#include	"level.h"
+#include	"idf.h"
+#include	"arith.h"
+#include	"type.h"
+#include	"proto.h"
+#include	"declar.h"
+#include	"tokenname.h"
+#include	"Lpars.h"
+#include	"LLlex.h"
+#include	<alloc.h>
+#include	"specials.h"
+#include	"noRoption.h"
+#include	"nocross.h"
+#include	"sizes.h"
+#include	"align.h"
+
+extern struct tokenname tkidf[];
+extern char *symbol2str();
+extern char options[128];
+
+#ifndef NOPP
+int inc_pos = 1;			/* place where next -I goes */
+int inc_total = 0;
+int inc_max;
+char **inctable;
+
+extern char *getwdir();
+#endif NOPP
+
+struct sp_id special_ids[] =	{
+	{"setjmp", SP_SETJMP},	/* non-local goto's are registered	*/
+	{0, 0}
+};
+
+#ifndef NOCROSS
+arith
+	short_size = SZ_SHORT,
+	word_size = SZ_WORD,
+	dword_size = (2 * SZ_WORD),
+	int_size = SZ_INT,
+	long_size = SZ_LONG,
+#ifndef NOFLOAT
+	float_size = SZ_FLOAT,
+	double_size = SZ_DOUBLE,
+	lngdbl_size = SZ_LNGDBL,
+#endif NOFLOAT
+	pointer_size = SZ_POINTER;
+
+int
+	short_align = AL_SHORT,
+	word_align = AL_WORD,
+	int_align = AL_INT,
+	long_align = AL_LONG,
+#ifndef NOFLOAT
+	float_align = AL_FLOAT,
+	double_align = AL_DOUBLE,
+	lngdbl_align = AL_LNGDBL,
+#endif NOFLOAT
+	pointer_align = AL_POINTER,
+	struct_align = AL_STRUCT,
+	union_align = AL_UNION;
+#endif NOCROSS
+
+#ifndef NOPP
+arith ifval;	/* ifval will contain the result of the #if expression	*/
+#endif NOPP
+
+char *prog_name;
+
+main(argc, argv)
+	char *argv[];
+{
+	/* parse and interpret the command line options	*/
+	prog_name = argv[0];
+
+	init_hmask();
+#ifndef NOPP
+	inctable = (char **) Malloc(10 * sizeof(char *));
+	inctable[0] = ".";
+	inctable[1] = "/usr/include";
+	inctable[2] = 0;
+	inc_total = 2;
+	inc_max = 10;
+
+	init_pp();	/* initialise the preprocessor macros	*/
+#endif NOPP
+
+	/*	Note: source file "-" indicates that the source is supplied
+		as standard input.  This is only allowed if INP_READ_IN_ONE is
+		not defined!
+	*/
+#ifdef INP_READ_IN_ONE
+	while (argc > 1 && *argv[1] == '-')
+#else INP_READ_IN_ONE
+	while (argc > 1 && *argv[1] == '-' && argv[1][1] != '\0')
+#endif INP_READ_IN_ONE
+	{
+		char *par = &argv[1][1];
+
+		do_option(par, 1);
+		argc--, argv++;
+	}
+#ifdef	LINT
+	lint_init();
+#endif	LINT
+	compile(argc - 1, &argv[1]);
+
+#ifdef	DEBUG
+	hash_stat();
+#endif	DEBUG
+
+	sys_stop(err_occurred ? S_EXIT : S_END);
+	/*NOTREACHED*/
+}
+
+char *source = 0;
+
+char *nmlist = 0;
+
+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'];
+#endif NOPP
+#endif
+
+	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;
+	case 3:
+		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;
+	}
+
+	if (strcmp(argv[0], "-"))
+		FileName = source = argv[0];
+	else {
+		source = 0;
+		FileName = "standard input";
+	}
+
+	if (!InsertFile(source, (char **) 0, &result)) /* read the source file	*/
+		fatal("%s: no source file %s\n", prog_name, FileName);
+	File_Inserted = 1;
+	init();
+	LineNumber = 0;
+	nestlow = -1;
+#ifndef NOPP
+	WorkingDir = getwdir(source);
+#endif NOPP
+	PushLex();			/* initialize lex machine */
+
+#ifdef DEBUG
+#ifndef NOPP
+	if (pp_only) /* run the preprocessor as if it is stand-alone	*/
+		preprocess();
+	else
+#endif NOPP
+#endif DEBUG
+	{
+#ifndef	LINT
+		init_code(destination && strcmp(destination, "-") != 0 ?
+					destination : 0);
+#endif	LINT
+
+		/* compile the source text			*/
+		C_program();
+
+#ifdef PREPEND_SCOPES
+		prepend_scopes();
+#endif PREPEND_SCOPES
+		end_code();
+
+#ifdef	DEBUG
+		if (options['u'])	{
+			unstack_level();	/* unstack L_GLOBAL */
+		}
+		if (options['f'] || options['t'])
+			dumpidftab("end of main", options['f'] ? 7 : 0);
+#endif	DEBUG
+	}
+	PopLex();
+}
+
+init()
+{
+	init_cst();	/* initialize variables of "cstoper.c"		*/
+	reserve(tkidf);		/* mark the C reserved words as such	*/
+	init_specials(special_ids);	/* mark special ids as such	*/
+
+	/*	Treat the type generic as int, having the same size and
+		alignment requirements.
+		This type is used as top type for void pointers, and is
+		transparent to the user.
+	*/
+	gen_type = standard_type(GENERIC, 0, 1, (arith)1);
+	char_type = standard_type(CHAR, 0, 1, (arith)1);
+	uchar_type = standard_type(CHAR, UNSIGNED, 1, (arith)1);
+
+	short_type = standard_type(SHORT, 0, short_align, short_size);
+	ushort_type = standard_type(SHORT, UNSIGNED, short_align, short_size);
+
+	/*	Treat type `word' as `int', having its own size and
+		alignment requirements.
+		This type is transparent to the user.
+	*/
+	word_type = standard_type(INT, 0, word_align, word_size);
+	uword_type = standard_type(INT, UNSIGNED, word_align, word_size);
+
+	int_type = standard_type(INT, 0, int_align, int_size);
+	uint_type = standard_type(INT, UNSIGNED, int_align, int_size);
+
+	long_type = standard_type(LONG, 0, long_align, long_size);
+	ulong_type = standard_type(LONG, UNSIGNED, long_align, long_size);
+
+#ifndef NOFLOAT
+	float_type = standard_type(FLOAT, 0, float_align, float_size);
+	double_type = standard_type(DOUBLE, 0, double_align, double_size);
+	lngdbl_type = standard_type(LNGDBL, 0, lngdbl_align, lngdbl_size);
+#endif NOFLOAT
+	void_type = standard_type(VOID, 0, 1, (arith)0);
+	label_type = standard_type(LABEL, 0, 0, (arith)0);
+	error_type = standard_type(ERRONEOUS, 0, 1, (arith)1);
+
+	/*	Pointer Arithmetic type: all arithmetics concerning
+		pointers is supposed to be performed in the
+		pointer arithmetic type which is equal to either
+		int_type or long_type, depending on the pointer_size
+	*/
+	if ((int)pointer_size == (int)word_size)
+		pa_type = word_type;
+	else
+	if ((int)pointer_size == (int)short_size)
+		pa_type = short_type;
+	else
+	if ((int)pointer_size == (int)int_size)
+		pa_type = int_type;
+	else
+	if ((int)pointer_size == (int)long_size)
+		pa_type = long_type;
+	else
+		fatal("pointer size incompatible with any integral size");
+
+	if ((int)int_size != (int)word_size)
+		fatal("int_size and word_size are not equal");
+	if ((int)short_size > (int)int_size || (int)int_size > (int)long_size)
+		fatal("sizes of short/int/long decreasing");
+
+	/* Build a type for function returning int, RM 13 */
+	funint_type = construct_type(FUNCTION, int_type, 0, (arith)0, NO_PROTO);
+	string_type = construct_type(POINTER, char_type, 0, (arith)0, NO_PROTO);
+
+	/* Define the standard type identifiers. */
+	add_def(str2idf("char"), TYPEDEF, char_type, L_UNIVERSAL);
+	add_def(str2idf("int"), TYPEDEF, int_type, L_UNIVERSAL);
+#ifndef NOFLOAT
+	add_def(str2idf("float"), TYPEDEF, float_type, L_UNIVERSAL);
+	add_def(str2idf("double"), TYPEDEF, double_type, L_UNIVERSAL);
+#endif NOFLOAT
+	add_def(str2idf("void"), TYPEDEF, void_type, L_UNIVERSAL);
+	stack_level();
+}
+
+init_specials(si)
+	register struct sp_id *si;
+{
+	while (si->si_identifier)	{
+		struct idf *idf = str2idf(si->si_identifier);
+		
+		if (idf->id_special)
+			fatal("maximum identifier length insufficient");
+		idf->id_special = si->si_flag;
+		si++;
+	}
+}
+
+#ifdef DEBUG
+#ifndef NOPP
+preprocess()
+{
+	/*	preprocess() is the "stand-alone" preprocessor which
+		consecutively calls the lexical analyzer LLlex() to get
+		the tokens and prints them in a suitable way.
+	*/
+	static unsigned int lastlineno = 0;
+	static char *lastfilenm = "";
+
+	while (LLlex() !=  EOI)	{
+		if (lastlineno != dot.tk_line)	{
+			if (strcmp(lastfilenm, dot.tk_file) == 0)	{
+				if (dot.tk_line - lastlineno <= 1)	{
+					lastlineno++;
+					print("\n");
+				}
+				else	{
+					lastlineno = dot.tk_line;
+					if (!options['P'])
+						print("\n#line %ld \"%s\"\n",
+							lastlineno,
+							lastfilenm
+						);
+				}
+			}
+			else	{
+				lastfilenm = dot.tk_file;
+				lastlineno = dot.tk_line;
+				if (!options['P'])
+					print("\n#line %ld \"%s\"\n",
+						lastlineno, lastfilenm);
+			}
+		}
+		else
+		if (strcmp(lastfilenm, dot.tk_file) != 0)	{
+			lastfilenm = dot.tk_file;
+			if (!options['P'])
+				print("\n#line %ld \"%s\"\n",
+					lastlineno, lastfilenm);
+		}
+		switch (DOT)	{
+		case IDENTIFIER:
+		case TYPE_IDENTIFIER:
+			print("%s ", dot.tk_idf->id_text);
+			break;
+		case STRING:
+		{
+			char sbuf[1024];	/* a transient buffer */
+			char *bts2str();
+
+			print("\"%s\" ", bts2str(dot.tk_bts, dot.tk_len, sbuf));
+			break;
+		}
+		case INTEGER:
+			print("%ld ", dot.tk_ival);
+			break;
+#ifndef NOFLOAT
+		case FLOATING:
+			print("%s ", dot.tk_fval);
+			break;
+#endif NOFLOAT
+		case EOI:
+		case EOF:
+			return;
+		default:	/* very expensive...	*/
+			print("%s ", symbol2str(DOT));
+		}
+	}
+}
+#endif NOPP
+#endif DEBUG
+
+No_Mem()				/* called by alloc package */
+{
+	fatal("out of memory");
+}
+
+C_failed()				/* called by EM_code module */
+{
+	fatal("write failed");
+}
+

+ 8 - 0
lang/cem/cemcom.ansi/make.allocd

@@ -0,0 +1,8 @@
+sed -e '
+s:^.*[ 	]ALLOCDEF[ 	].*"\(.*\)"[ 	]*\([0-9][0-9]*\).*$:\
+/* allocation definitions of struct \1 */\
+extern char *st_alloc();\
+extern struct \1 *h_\1;\
+#define	new_\1() ((struct \1 *) st_alloc((char **)\&h_\1, sizeof(struct \1), \2))\
+#define	free_\1(p) st_free(p, \&h_\1, sizeof(struct \1))\
+:'

+ 35 - 0
lang/cem/cemcom.ansi/make.hfiles

@@ -0,0 +1,35 @@
+: Update Files from database
+
+PATH=/bin:/usr/bin
+
+case $# in
+1) ;;
+*)	echo use: $0 file >&2
+	exit 1
+esac
+
+(
+IFCOMMAND="if (<\$FN) 2>/dev/null;\
+	then	if cmp -s \$FN \$TMP;\
+		then	rm \$TMP;\
+		else	mv \$TMP \$FN;\
+			echo update \$FN;\
+		fi;\
+	else	mv \$TMP \$FN;\
+		echo create \$FN;\
+	fi"
+echo 'TMP=.uf$$'
+echo 'FN=$TMP'
+echo 'cat >$TMP <<\!EOF!'
+sed -n '/^!File:/,${
+/^$/d
+/^!File:[	 ]*\(.*\)$/s@@!EOF!\
+'"$IFCOMMAND"'\
+FN=\1\
+cat >$TMP <<\\!EOF!@
+p
+}' $1
+echo '!EOF!'
+echo $IFCOMMAND
+) |
+sh

+ 3 - 0
lang/cem/cemcom.ansi/make.next

@@ -0,0 +1,3 @@
+sed -n '
+s:^.*ALLOCDEF.*"\(.*\)".*$:struct \1 *h_\1 = 0;:p
+' $*

+ 38 - 0
lang/cem/cemcom.ansi/make.tokcase

@@ -0,0 +1,38 @@
+cat <<'--EOT--'
+/* Generated by make.tokcase */
+/* $Header: */
+#include "Lpars.h"
+
+char *
+symbol2str(tok)
+	int tok;
+{
+	static char buf[2] = { '\0', '\0' };
+
+	if (040 <= tok && tok < 0177) {
+		buf[0] = tok;
+		buf[1] = '\0';
+		return buf;
+	}
+	switch (tok) {
+--EOT--
+
+sed '
+/{[A-Z]/!d
+s/.*{\(.*\),.*\(".*"\).*$/	case \1 :\
+		return \2;/
+'
+
+cat <<'--EOT--'
+	case '\n':
+	case '\f':
+	case '\v':
+	case '\r':
+	case '\t':
+		buf[0] = tok;
+		return buf;
+	default:
+		return "bad token";
+	}
+}
+--EOT--

+ 11 - 0
lang/cem/cemcom.ansi/make.tokfile

@@ -0,0 +1,11 @@
+cat <<'--EOT--'
+/* Generated by make.tokfile */
+/* $Header: */
+--EOT--
+
+sed '
+/{[A-Z]/!d
+s/.*{//
+s/,.*//
+s/.*/%token	&;/
+'

+ 246 - 0
lang/cem/cemcom.ansi/mcomm.c

@@ -0,0 +1,246 @@
+/* $Header$ */
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/*	mcomm.c -- change ".lcomm name" into ".comm name" where "name"
+	is specified in a list.
+*/
+#include <stdio.h>
+
+#define IDFSIZE 4096
+
+char *readfile();
+
+struct node {
+	char *name;
+	struct node *left, *right;
+};
+
+char *
+Malloc(n)
+	unsigned n;
+{
+	char *space;
+	char *malloc();
+
+	if ((space = malloc(n)) == 0) {
+		fprintf(stderr, "out of memory\n");
+		exit(1);
+	}
+	return space;
+}
+
+struct node *make_tree();
+
+#define new_node() ((struct node *) Malloc(sizeof (struct node)))
+
+main(argc, argv)
+	char *argv[];
+{
+	char *nl_file, *as_file;
+	char *nl_text, *as_text;
+	struct node *nl_tree = 0;
+	int nl_siz, as_siz;
+
+	if (argc != 3) {
+		fprintf(stderr, "use: %s namelist assembler_file\n", argv[0]);
+		exit(1);
+	}
+	nl_file = argv[1];
+	as_file = argv[2];
+
+	if ((nl_text = readfile(nl_file, &nl_siz)) == 0) {
+		fprintf(stderr, "%s: cannot read namelist %s\n",
+			argv[0], nl_file);
+		exit(1);
+	}
+
+	if ((as_text = readfile(as_file, &as_siz)) == 0) {
+		fprintf(stderr, "%s: cannot read assembler file %s\n",
+			argv[0], as_file);
+		exit(1);
+	}
+
+	nl_tree = make_tree(nl_text);
+	edit(as_text, nl_tree);
+
+	if (writefile(as_file, as_text, as_siz) == 0) {
+		fprintf(stderr, "%s: cannot write to %s\n", argv[0], as_file);
+		exit(1);
+	}
+	return 0;
+}
+
+#include <sys/types.h>
+#include <stat.h>
+
+char *
+readfile(filename, psiz)
+	char *filename;
+	int *psiz;
+{
+	struct stat stbuf;	/* for `stat' to get filesize		*/
+	register int fd;	/* filedescriptor for `filename'	*/
+	register char *cbuf;	/* pointer to buffer to be returned	*/
+
+	if (((fd = open(filename, 0)) < 0) || (fstat(fd, &stbuf) != 0))
+		return 0;
+	cbuf = Malloc(stbuf.st_size + 1);
+	if (read(fd, cbuf, stbuf.st_size) != stbuf.st_size)
+		return 0;
+	cbuf[stbuf.st_size] = '\0';
+	close(fd);		/* filedes no longer needed	*/
+	*psiz = stbuf.st_size;
+	return cbuf;
+}
+
+int
+writefile(filename, text, size)
+	char *filename, *text;
+{
+	register fd;
+
+	if ((fd = open(filename, 1)) < 0)
+		return 0;
+	if (write(fd, text, size) != size)
+		return 0;
+	close(fd);
+	return 1;
+}
+
+struct node *
+make_tree(nl)
+	char *nl;
+{
+	char *id = nl;
+	struct node *tree = 0;
+
+	while (*nl) {
+		if (*nl == '\n') {
+			*nl = '\0';
+			insert(&tree, id);
+			id = ++nl;
+		}
+		else {
+			++nl;
+		}
+	}
+	return tree;
+}
+
+insert(ptree, id)
+	struct node **ptree;
+	char *id;
+{
+	register cmp;
+
+	if (*ptree == 0) {
+		register struct node *nnode = new_node();
+
+		nnode->name = id;
+		nnode->left = nnode->right = 0;
+		*ptree = nnode;
+	}
+	else
+	if ((cmp = strcmp((*ptree)->name, id)) < 0)
+		insert(&((*ptree)->right), id);
+	else
+	if (cmp > 0)
+		insert(&((*ptree)->left), id);
+}
+
+struct node *
+find(tree, id)
+	struct node *tree;
+	char *id;
+{
+	register cmp;
+
+	if (tree == 0)
+		return 0;
+	if ((cmp = strcmp(tree->name, id)) < 0)
+		return find(tree->right, id);
+	if (cmp > 0)
+		return find(tree->left, id);
+	return tree;
+}
+
+edit(text, tree)
+	char *text;
+	struct node *tree;
+{
+	register char *ptr = text;
+	char idbuf[IDFSIZE];
+	register char *id;
+	register char *save_ptr;
+
+	while (*ptr) {
+		if (
+			*ptr   == '.' &&
+			*++ptr == 'l' &&
+			*++ptr == 'c' &&
+			*++ptr == 'o' &&
+			*++ptr == 'm' &&
+			*++ptr == 'm' &&
+			(*++ptr == ' ' || *ptr == '\t')
+		)
+		{
+			save_ptr = ptr - 6;
+			while (*++ptr == ' ' || *ptr == '\t')
+				;
+			if (*ptr == '_')
+				++ptr;
+			if (InId(*ptr)) {
+				id = &idbuf[0];
+				*id++ = *ptr++;
+				while (InId(*ptr))
+					*id++ = *ptr++;
+				*id = '\0';
+				if (find(tree, idbuf) != 0) {
+					*save_ptr++ = ' ';
+					*save_ptr++ = '.';
+				}
+			}
+		}
+		while (*ptr && *ptr++ != '\n')
+			;
+	}
+}
+
+InId(c)
+{
+	switch (c) {
+
+	case 'a': case 'b': case 'c': case 'd': case 'e':
+	case 'f': case 'g': case 'h': case 'i': case 'j':
+	case 'k': case 'l': case 'm': case 'n': case 'o':
+	case 'p': case 'q': case 'r': case 's': case 't':
+	case 'u': case 'v': case 'w': case 'x': case 'y':
+	case 'z':
+	case 'A': case 'B': case 'C': case 'D': case 'E':
+	case 'F': case 'G': case 'H': case 'I': case 'J':
+	case 'K': case 'L': case 'M': case 'N': case 'O':
+	case 'P': case 'Q': case 'R': case 'S': case 'T':
+	case 'U': case 'V': case 'W': case 'X': case 'Y':
+	case 'Z':
+	case '_':
+	case '.':
+	case '0': case '1': case '2': case '3': case '4':
+	case '5': case '6': case '7': case '8': case '9':
+		return 1;
+	
+	default:
+		return 0;
+	}
+}
+
+puttree(nd)
+	struct node *nd;
+{
+	if (nd) {
+		puttree(nd->left);
+		printf("%s\n", nd->name);
+		puttree(nd->right);
+	}
+}

+ 8 - 0
lang/cem/cemcom.ansi/mes.h

@@ -0,0 +1,8 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* MESSAGE ADMINISTRATION */
+
+extern int fp_used;	/* code.c	*/

+ 9 - 0
lang/cem/cemcom.ansi/nmclash.c

@@ -0,0 +1,9 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* Accepted if many characters of long names are significant */
+/* $Header$ */
+abcdefghijklmnopr() { }
+abcdefghijklmnopq() { }
+main() { }

+ 28 - 0
lang/cem/cemcom.ansi/options

@@ -0,0 +1,28 @@
+User options:
+C	while running preprocessor, copy comment
+D	see identifier following as a macro
+E	run preprocessor only
+I	expand include table with directory name following
+M	set identifier length
+n	don't generate register messages
+p	generate linenumbers and filename indications
+	while generating EM code
+P	in running the preprocessor do not output '# line' lines
+R	restricted C
+T	take path following as directory for storing temporary file(s)
+U	undefine predefined name
+V	set objectsize and alignment requirements
+w	suppress warning diagnostics
+
+
+Debug options:
+
+d	perform a small dataflow analysis
+f	dump whole identifier table, including macros and reserved words
+h	supply hash table statistics
+i	print name of include files
+m	supply memory allocation statistics
+r	right-adjust bitfield
+t	dump table of identifiers
+u	unstack L_UNIVERSAL
+x	dump expressions

+ 356 - 0
lang/cem/cemcom.ansi/options.c

@@ -0,0 +1,356 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $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"
+#include	"nopp.h"
+#include	"idfsize.h"
+#include	"nobitfield.h"
+#include	"class.h"
+#include	"macro.h"
+#include	"idf.h"
+#include	"arith.h"
+#include	"sizes.h"
+#include	"align.h"
+#include	"use_tmp.h"
+#include	"dataflow.h"
+#include	"noRoption.h"
+
+#ifndef NOPP
+extern char **inctable;
+extern int inc_pos;
+extern int inc_max;
+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();
+
+do_option(text)
+	char *text;
+{
+	register char opt;
+
+next_option:			/* to allow combined one-char options */
+	switch (opt = *text++)	{
+
+	case 0:			/* to end the goto next_option loop */
+		break;
+
+	default:
+#ifndef	LINT
+		fatal("illegal option: %c", opt);
+#else	LINT
+		warning("illegal option: %c", opt);
+#endif	LINT
+		break;
+
+	case '-':
+		options[*text++] = 1;	/* flags, debug options etc.	*/
+		goto next_option;
+
+#ifndef	LINT
+#ifdef	DATAFLOW
+	case 'd':
+#endif	DATAFLOW
+	case 'p':			/* procentry/procexit */
+	case 'L' :			/* no fil/lin */
+	case 'n':			/* use no registers */
+	case 'w':			/* no warnings will be given */
+	case 's':			/* no stricts will be given */
+		options[opt] = 1;
+		goto next_option;
+#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 */
+	case 'L':	/* lintlibrary */
+		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;
+
+#ifdef	___XXX___
+deleted, is now a debug-flag
+	case 'C' :	/* E option + comment output		*/
+#ifndef	NOPP
+		options['E'] = 1;
+		warning("-C: comment is not output");
+#else NOPP
+		warning("-C option ignored");
+#endif	NOPP
+		break;
+#endif	___XXX___
+
+	case 'D' :	{	/* -Dname :	predefine name		*/
+#ifndef NOPP
+		register char *cp = text, *name, *mactext;
+
+		if (class(*cp) != STIDF && class(*cp) != STELL) {
+			error("identifier missing in -D%s", text);
+			break;
+		}
+
+		name = cp;
+
+		while (*cp && in_idf(*cp)) {
+			++cp;
+		}
+
+		if (!*cp) {			/* -Dname */
+			mactext = "1";
+		}
+		else
+		if (*cp == '=')	{		/* -Dname=text	*/
+			*cp++ = '\0';		/* end of name	*/
+			mactext = cp;
+		}
+		else	{			/* -Dname?? */
+			error("malformed option -D%s", text);
+			break;
+		}
+
+		macro_def(str2idf(name), mactext, -1, strlen(mactext),
+			NOFLAG);
+#else NOPP
+		warning("-D option ignored");
+#endif NOPP
+		break;
+	}
+
+#ifdef ___XXX___
+deleted, is now a debug-flag
+	case 'E' :	/* run preprocessor only, with #<int>	*/
+#ifndef NOPP
+		options['E'] = 1;
+#else NOPP
+		warning("-E option ignored");
+#endif NOPP
+		break;
+#endif ___XXX___
+
+	case 'I' :	/* -Ipath : insert "path" into include list	*/
+#ifndef NOPP
+		if (*text)	{
+			int i;
+			register char *new = text;
+			
+			if (++inc_total > inc_max) {
+				char **n = (char **)
+				   Malloc((10+inc_max)*sizeof(char *));
+				for (i = 0; i < inc_max; i++) {
+					n[i] = inctable[i];
+				}
+				free((char *) inctable);
+				inctable = n;
+				inc_max += 10;
+			}
+				
+			i = inc_pos++;
+			while (new)	{
+				char *tmp = inctable[i];
+				
+				inctable[i++] = new;
+				new = tmp;
+			}
+		}
+		else inctable[inc_pos] = 0;
+#else NOPP
+		warning("-I option ignored");
+#endif NOPP
+		break;
+
+	case 'M':	/* maximum identifier length */
+		idfsize = txt2int(&text);
+		if (*text || idfsize <= 0)
+			fatal("malformed -M option");
+		if (idfsize > IDFSIZE)
+			fatal("maximum identifier length is %d", IDFSIZE);
+		break;
+
+#ifdef ___XXX___
+deleted, is now a debug-flag
+	case 'P' :	/* run preprocessor stand-alone, without #'s	*/
+#ifndef NOPP
+		options['E'] = 1;
+		options['P'] = 1;
+#else NOPP
+		warning("-P option ignored");
+#endif NOPP
+		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;
+		if (*text)
+			C_tmpdir = text;
+		else
+			C_tmpdir = ".";
+#else USE_TMP
+		warning("-T option ignored");
+#endif USE_TMP
+		break;
+	}
+		
+	case 'U' :	{	/* -Uname :	undefine predefined	*/
+#ifndef NOPP
+		register struct idf *idef;
+
+		if (*text)	{
+			if ((idef = str2idf(text))->id_macro) {
+				free_macro(idef->id_macro);
+				idef->id_macro = (struct macro *) 0;
+			}
+		}
+#else NOPP
+		warning("-U option ignored");
+#endif NOPP
+		break;
+	}
+
+#ifndef	LINT
+	case 'V' :	/* set object sizes and alignment requirements	*/
+#ifdef NOCROSS
+		warning("-V option ignored");
+		break;
+#else NOCROSS
+	{
+		register arith sz, algn;
+		char c;
+
+		while (c = *text++)	{
+			sz = txt2int(&text);
+			algn = 0;
+			if (*text == '.')	{
+				text++;
+				algn = txt2int(&text);
+			}
+			switch (c)	{
+			case 's':	/* short	*/
+				if (sz != (arith)0)
+					short_size = sz;
+				if (algn != 0)
+					short_align = algn;
+				break;
+			case 'w':	/* word		*/
+				if (sz != (arith)0)
+					dword_size = (word_size = sz) << 1;
+				if (algn != 0)
+					word_align = algn;
+				break;
+			case 'i':	/* int		*/
+				if (sz != (arith)0)
+					int_size = sz;
+				if (algn != 0)
+					int_align = algn;
+				break;
+			case 'l':	/* long		*/
+				if (sz != (arith)0)
+					long_size = sz;
+				if (algn != 0)
+					long_align = algn;
+				break;
+			case 'f':	/* float	*/
+#ifndef NOFLOAT
+				if (sz != (arith)0)
+					float_size = sz;
+				if (algn != 0)
+					float_align = algn;
+#endif NOFLOAT
+				break;
+			case 'd':	/* double	*/
+#ifndef NOFLOAT
+				if (sz != (arith)0)
+					double_size = sz;
+				if (algn != 0)
+					double_align = algn;
+#endif NOFLOAT
+				break;
+			case 'x':	/* long double	*/
+#ifndef NOFLOAT
+				if (sz != (arith)0)
+					lngdbl_size = sz;
+				if (algn != 0)
+					lngdbl_align = algn;
+#endif NOFLOAT
+				break;
+			case 'p':	/* pointer	*/
+				if (sz != (arith)0)
+					pointer_size = sz;
+				if (algn != 0)
+					pointer_align = algn;
+				break;
+			case 'r':	/* adjust bitfields right	*/
+#ifndef NOBITFIELD
+				options['r'] = 1;
+#else NOBITFIELD
+				warning("bitfields are not implemented");
+#endif NOBITFIELD
+				break;
+			case 'S':	/* initial struct alignment	*/
+				if (sz != (arith)0)
+					struct_align = sz;
+				break;
+			case 'U':	/* initial union alignment	*/
+				if (sz != (arith)0)
+					union_align = sz;
+				break;
+			default:
+				error("-V: bad type indicator %c\n", c);
+			}
+		}
+		break;
+	}
+#endif NOCROSS
+#endif	LINT
+	}
+}
+
+static int
+txt2int(tp)
+	register char **tp;
+{
+	/*	the integer pointed to by *tp is read, while increasing
+		*tp; the resulting value is yielded.
+	*/
+	register int val = 0, ch;
+	
+	while (ch = **tp, ch >= '0' && ch <= '9')	{
+		val = val * 10 + ch - '0';
+		(*tp)++;
+	}
+	return val;
+}

+ 74 - 0
lang/cem/cemcom.ansi/pragma.c

@@ -0,0 +1,74 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* PREPROCESSOR: PRAGMA INTERPRETER */
+
+#include	"arith.h"
+#include	"LLlex.h"
+#include	"Lpars.h"
+#include	"debug.h"
+#include	"idf.h"
+#include	"input.h"
+#include	"nopp.h"
+
+#ifndef NOPP
+#include	"ifdepth.h"	
+#include	"botch_free.h"	
+#include	"nparams.h"	
+#include	"parbufsize.h"	
+#include	"textsize.h"	
+#include	"idfsize.h"	
+#include	"assert.h"
+#include	<alloc.h>
+#include	"class.h"
+#include	"macro.h"
+
+#define P_UNKNOWN	0
+#define P_FLAGS		1
+
+struct pkey {
+	char *pk_name;
+	int pk_key;
+} pragmas[] = {
+	{"flags",	P_FLAGS},
+	{0,		P_UNKNOWN}
+};
+
+extern struct idf *GetIdentifier();
+
+
+do_pragma()
+{
+	register struct pkey *pkp;
+	register struct idf *id;
+	struct token tk;
+	int flag;
+
+	if ((id = GetIdentifier()) != (struct idf *)0) {
+		/*	Lineair search - why bother ?
+		*/
+		for (pkp = &pragmas[0]; pkp->pk_key != P_UNKNOWN; pkp++)
+			if (strcmp(pkp->pk_name, id->id_text) == 0)
+				break;
+
+		switch (pkp->pk_key) {
+		case P_FLAGS:
+			if (GetToken(&tk) == STRING)
+				do_option(tk.tk_bts);
+			break;
+
+		case P_UNKNOWN:
+			strict("unknown pragma directive %s", id->id_text);
+			break;
+
+		default:
+			strict("unimplemented pragma directive");
+			break;
+		}
+	}
+	SkipToNewLine(0);
+
+}
+#endif

+ 222 - 0
lang/cem/cemcom.ansi/program.g

@@ -0,0 +1,222 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* PROGRAM PARSER */
+
+/*	The presence of typedef declarations renders it impossible to
+	make a context-free grammar of C. Consequently we need
+	context-sensitive parsing techniques, the simplest one being
+	a subtle cooperation between the parser and the lexical scanner.
+	The lexical scanner has to know whether to return IDENTIFIER
+	or TYPE_IDENTIFIER for a given tag, and it obtains this information
+	from the definition list, as constructed by the parser.
+	The present grammar is essentially LL(2), and is processed by
+	a parser generator which accepts LL(1) with tie breaking rules
+	in C, of the form %if(cond) and %while(cond). To solve the LL(1)
+	ambiguities, the lexical scanner does a one symbol look-ahead.
+	This symbol, however, cannot always be correctly assessed, since
+	the present symbol may cause a change in the definition list
+	which causes the identification of the look-ahead symbol to be
+	invalidated.
+	The lexical scanner relies on the parser (or its routines) to
+	detect this situation and then update the look-ahead symbol.
+	An alternative approach would be to reassess the look-ahead symbol
+	in the lexical scanner when it is promoted to dot symbol. This
+	would be more beautiful but less correct, since then for a short
+	while there would be a discrepancy between the look-ahead symbol
+	and the definition list; I think it would nevertheless work in
+	correct programs.
+	A third solution would be to enter the identifier as soon as it
+	is found; its storage class is then known, although its full type
+	isn't. We would have to fill that in afterwards.
+
+	At block exit the situation is even worse. Upon reading the
+	closing brace, the names declared inside the function are cleared
+	from the name list. This action may expose a type identifier that
+	is the same as the identifier in the look-ahead symbol. This
+	situation certainly invalidates the third solution, and casts
+	doubts upon the second.
+*/
+
+%lexical	LLlex;
+%start		C_program, program;
+%start		If_expr, control_if_expression;
+
+{
+#include	"lint.h"
+#include	"nopp.h"
+#include	"arith.h"
+#include	"LLlex.h"
+#include	"idf.h"
+#include	"label.h"
+#include	"type.h"
+#include	"declar.h"
+#include	"decspecs.h"
+#include	"code.h"
+#include	"expr.h"
+#include	"def.h"
+#ifdef	LINT
+#include	"l_state.h"
+#endif	LINT
+
+#ifndef NOPP
+extern arith ifval;
+#endif NOPP
+
+extern error();
+}
+
+control_if_expression
+	{
+		struct expr *exprX;
+	}
+:
+	constant_expression(&exprX)
+		{
+#ifndef NOPP
+			register struct expr *expr = exprX;
+			if (expr->ex_flags & EX_SIZEOF)
+				expr_error(expr,
+					"sizeof not allowed in preprocessor");
+			ifval = expr->VL_VALUE;
+			free_expression(expr);
+#endif NOPP
+		}
+;
+
+/* 10 */
+program:
+	[%persistent external_definition]*
+	{unstack_world();}
+;
+
+/*	A C identifier definition is remarkable in that it formulates
+	the declaration in a way different from most other languages:
+	e.g., rather than defining x as a pointer-to-integer, it defines
+	*x as an integer and lets the compiler deduce that x is actually
+	pointer-to-integer.  This has profound consequences, both for the
+	structure of an identifier definition and for the compiler.
+	
+	A definition starts with a decl_specifiers, which contains things
+	like
+		typedef int
+	which is implicitly repeated for every definition in the list, and
+	then for each identifier a declarator is given, of the form
+		*a()
+	or so.  The decl_specifiers is kept in a struct decspecs, to be
+	used again and again, while the declarator is stored in a struct
+	declarator, only to be passed to declare_idf together with the
+	struct decspecs.
+*/
+
+external_definition
+	{	struct decspecs Ds;
+		struct	declarator Dc;
+	}
+:
+	{	Ds = null_decspecs;
+		Dc = null_declarator;
+	}
+	[ %if (DOT != IDENTIFIER || AHEAD == IDENTIFIER)
+		decl_specifiers(&Ds)
+		[
+			declarator(&Dc)
+			{
+				declare_idf(&Ds, &Dc, level);
+#ifdef	LINT
+				lint_ext_def(Dc.dc_idf, Ds.ds_sc);
+#endif	LINT
+			}
+			[
+				function(&Ds, &Dc)
+			|
+				non_function(&Ds, &Dc)
+			]
+		|
+			';'
+		]
+	|
+		empty
+		{do_decspecs(&Ds);}
+		declarator(&Dc)
+		{
+			declare_idf(&Ds, &Dc, level);
+#ifdef	LINT
+			lint_ext_def(Dc.dc_idf, Ds.ds_sc);
+#endif	LINT
+		}
+		function(&Ds, &Dc)
+	]
+	{remove_declarator(&Dc);}
+;
+
+non_function(register struct decspecs *ds; register struct declarator *dc;)
+:
+	{	reject_params(dc);
+		def_proto(dc);
+	}
+	[
+		initializer(dc->dc_idf, ds->ds_sc)
+	|
+		{ 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
+	}
+	[
+		','
+		init_declarator(ds)
+	]*
+	';'
+;
+
+/* 10.1 */
+function(struct decspecs *ds; struct declarator *dc;)
+	{
+		arith fbytes;
+	}
+:
+	{	register struct idf *idf = dc->dc_idf;
+#ifdef	LINT
+		lint_start_function();
+#endif	LINT
+		init_idf(idf);
+		stack_level();		/* L_FORMAL1 declarations */
+		if (dc->dc_formal)
+			strict("'%s' old-fashioned function declaration",
+				idf->id_text);
+		declare_params(dc);
+		begin_proc(ds, idf);	/* sets global function info */
+		stack_level();		/* L_FORMAL2 declarations */
+		declare_protos(idf, 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
+	}
+;

+ 442 - 0
lang/cem/cemcom.ansi/proto.c

@@ -0,0 +1,442 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*  P R O T O T Y P E   F I D D L I N G  */
+
+#include	"lint.h"
+#include	"debug.h"
+#include	"idfsize.h"
+#include	"nparams.h"
+#include	"botch_free.h"
+#include	<alloc.h>
+#include	"Lpars.h"
+#include	"level.h"
+#include	"arith.h"
+#include	"align.h"
+#include	"stack.h"
+#include	"idf.h"
+#include	"def.h"
+#include	"type.h"
+#include	"struct.h"
+#include	"label.h"
+#include	"expr.h"
+#include	"declar.h"
+#include	"decspecs.h"
+#include	"proto.h"
+#include	"assert.h"
+
+extern char options[];
+
+add_proto(pl, ds, dc, level)
+	struct proto *pl;
+	struct decspecs *ds;
+	struct declarator *dc;
+	int level;
+{
+	/*	The full typed identifier or abstract type, described
+		by the structures decspecs and declarator are turned
+		a into parameter type list structure.
+		The parameters will be declared at level L_FORMAL2,
+		later on it's decided whether they were prototypes
+		or actual declarations.
+	*/
+	register struct idf *idf;
+	register struct def *def = (struct def *)0;
+	register int sc = ds->ds_sc;
+	register struct type *type;
+	char formal_array = 0;
+
+	ASSERT(ds->ds_type != (struct type *)0);
+
+	pl->pl_flag = FORMAL;
+	if ((idf = dc->dc_idf) != (struct idf *)0)
+		def = idf->id_def;
+	type = declare_type(ds->ds_type, dc);
+	if (type->tp_size < (arith)0 && actual_declaration(sc, type)) {
+		extern char *symbol2str();
+		error("unknown %s-type", symbol2str(type->tp_fund));
+	} else if (type->tp_size == 0) {
+		pl->pl_flag = VOID;
+		if (idf != (struct idf *)0)
+			strict("illegal use of void in argument list");
+	}
+
+	/*	Perform some special conversions for parameters.
+	*/
+	if (type->tp_fund == FUNCTION) {
+		if (type->tp_proto)
+			remove_proto_idfs(type->tp_proto);
+		type = construct_type(POINTER, type, 0, (arith) 0, NO_PROTO);
+	} else if (type->tp_fund == ARRAY) {
+		type = construct_type(POINTER, type, 0, (arith) 0, NO_PROTO);
+		formal_array = 1;
+	}
+
+	/*	According to the standard we should ignore the storage
+		class of a parameter, unless it's part of a function
+		definition.
+		However, in the routine declare_protos we don't know decspecs,
+		and therefore we can't complain up there. So we build up the
+		storage class, and keep quiet until we reach declare_protos.
+	*/
+	sc = (ds->ds_sc_given && ds->ds_sc != REGISTER) ?
+				0 : sc == 0 ? FORMAL : REGISTER;
+
+	if (def && (def->df_level == level || def->df_level < L_PROTO)) {
+		/* redeclaration at the same level */
+		error("parameter %s redeclared", idf->id_text);
+	} else if (idf != (struct idf *)0) {
+		/*	New definition, redefinition hides earlier one
+		*/
+		register struct def *newdef = new_def();
+		
+		newdef->next = def;
+		newdef->df_level = level;
+		newdef->df_sc = sc;
+		newdef->df_type = type;
+		newdef->df_formal_array = formal_array;
+		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
+		/*	We can't put the idf onto the stack, since these kinds
+			of declaration may occurs at any level, and the idf
+			does not necessarily go at this level. E.g.
+
+			f() {
+			...
+				{ int func(int a, int b);
+				...
+
+			The idf's a and b declared in the prototype declaration
+			do not go at any level, they are simply ignored.
+			However, in
+
+			f(int a, int b) {
+			...
+
+			They should go at level L_FORMAL2. But at this stage
+			we don't know whether we have a prototype or function
+			definition. So, this process is postponed.
+		*/
+		idf->id_def = newdef;
+		update_ahead(idf);
+	}
+
+	pl->pl_idf = idf;
+	pl->pl_type = type;
+}
+
+declare_protos(idf, dc)
+	register struct idf *idf;
+	register struct declarator *dc;
+{
+	/*	At this points we know that the idf's in protolist are formal
+		parameters. So it's time to declare them at level L_FORMAL2.
+	*/
+	struct stack_level *stl = stack_level_of(L_FORMAL1);
+	register struct decl_unary *du;
+	register struct type *type;
+	register struct proto *pl;
+	register struct def *def;
+
+#ifdef	DEBUG
+	if (options['t'])
+		dumpidftab("start declare_protos", 0);
+#endif	DEBUG
+	du = dc->dc_decl_unary;
+	while (du && du->du_fund != FUNCTION)
+		du = du->next;
+	pl = du ? du->du_proto : NO_PROTO;
+	if (pl) {
+		idf->id_proto = 0;
+		do {
+			type = pl->pl_type;
+
+			/* `...' only for type checking */
+			if (pl->pl_flag == ELLIPSIS) {
+				pl = pl->next;
+				continue;
+			}
+
+			/* special case: int f(void) { ; } */
+			if (type->tp_fund == VOID)
+				break;
+
+			if (!pl->pl_idf || !(def = pl->pl_idf->id_def)) {
+				error("no parameter supplied");
+				pl = pl->next;
+				continue;
+			}
+
+			/*	Postponed storage class checking.
+			*/
+			if (def->df_sc == 0)
+				error("illegal storage class in parameter declaration");
+
+			def->df_level = L_FORMAL2;
+			stack_idf(pl->pl_idf, stl);
+			pl = pl->next;
+		} while (pl);
+	}
+#ifdef	DEBUG
+	if (options['t'])
+		dumpidftab("end declare_protos", 0);
+#endif	DEBUG
+}
+
+
+def_proto(dc)
+	register struct declarator *dc;
+{
+	/*	Prototype declarations may have arguments, but the idf's
+		in the parameter type list can be ignored.
+	*/
+	register struct decl_unary *du = dc->dc_decl_unary;
+
+	while (du) {
+		if (du->du_fund == FUNCTION)
+			remove_proto_idfs(du->du_proto);
+		du = du->next;
+	}
+}
+
+update_proto(tp, otp)
+	register struct type *tp, *otp;
+{
+	/*	This routine performs the proto type updates.
+		Consider the following code:
+
+		int f(double g());
+		int f(double g(int f(), int));
+		int f(double g(int f(long double), int));
+
+		The most accurate definition is the third line.
+		This routine will silently update all lists,
+		and removes the redundant occupied space.
+	*/
+	register struct proto *pl, *opl;
+
+#if 0
+	/*	THE FOLLOWING APPROACH IS PRESUMABLY WRONG.
+		THE ONLY THING THIS CODE IS SUPPOSED TO DO
+		IS TO UPDATE THE PROTOTYPELISTS, I HAVEN'T
+		EVEN CONSIDERED THE DISPOSAL OF REDUNDANT
+		SPACE !!.
+		THIS ROUTINE DUMPS CORE. SORRY, BUT IT'S 10
+		P.M. AND I'M SICK AN TIRED OF THIS PROBLEM.
+	*/
+	print("Entering\n");
+	if (tp == otp) {
+		print("OOPS - they are equal\n");
+		return;
+	}
+	if (!tp || !otp) {
+		print("OOPS - Nil pointers tp=@%o otp=@%o\n", tp, otp);
+		return;
+	}
+
+	print("Search function\n");
+	while (tp && tp->tp_fund != FUNCTION) {
+		if (!(tp->tp_up)) {
+			print("TP is NIL\n");
+			return;
+		}
+		tp = tp->tp_up;
+		if (!(otp->tp_up)) {
+			print("OTP is NIL\n");
+			return;
+		}
+		otp = otp->tp_up;
+		if (!tp) return;
+	}
+
+	print("Do it\n");
+	pl = tp->tp_proto;
+	opl = otp->tp_proto;
+	if (pl && opl) {
+		/* both have prototypes */
+		print("Both have proto type\n");
+		print("New proto type list\n");
+		dump_proto(pl);
+		print("Old proto type list\n");
+		dump_proto(opl);
+		while (pl && opl) {
+			update_proto(pl->pl_type, opl->pl_type);
+			pl = pl->next;
+			opl = pl->next;
+		}
+		/*free_proto_list(tp->tp_proto);*/
+		tp->tp_proto = otp->tp_proto;
+	} else if (opl) {
+		/* old decl has type */
+		print("Old decl has type\n");
+		print("Old proto type list\n");
+		dump_proto(opl);
+		tp->tp_proto = opl;
+	} else if (pl) {
+		/* new decl has type */
+		print("New decl has type\n");
+		print("New proto type list\n");
+		dump_proto(pl);
+		print("otp = @%o\n", otp);
+		otp->tp_proto = pl;
+		print("after assign\n");
+	} else
+		print("none has prototype\n");
+
+	print("Going for another top type\n");
+	update_proto(tp->tp_up, otp->tp_up);
+# endif
+}
+
+free_proto_list(pl)
+	register struct proto *pl;
+{
+	while (pl) {
+		register struct proto *tmp = pl->next;
+		free_proto(pl);
+		pl = tmp;
+	}
+}
+
+remove_proto_idfs(pl)
+	register struct proto *pl;
+{
+	/*	Remove all the identifier definitions from the
+		prototype list. Keep in account the recursive
+		function definitions.
+	*/
+	register struct def *def;
+
+	while (pl) {
+		if (pl->pl_idf) {
+#ifdef DEBUG
+			if (options['t'])
+				print("Removing idf %s from list\n",
+					pl->pl_idf->id_text);
+#endif
+			/*	Remove all the definitions made within
+				a prototype.
+			*/
+			if (pl->pl_flag == FORMAL) {
+				register struct type *tp = pl->pl_type;
+
+				while (tp && tp->tp_fund != FUNCTION)
+					tp = tp->tp_up;
+				if (tp)
+					remove_proto_idfs(tp->tp_proto);
+			}
+			def = pl->pl_idf->id_def;
+			if (def && def->df_level <= L_PROTO){
+				pl->pl_idf->id_def = def->next;
+				free_def(def);
+			}
+			pl->pl_idf = (struct idf *) 0;
+		}
+		pl = pl->next;
+	}
+}
+
+call_proto(expp)
+	register struct expr **expp;
+{
+	/*	If the function specified by (*expp)->OP_LEFT has a prototype,
+		the parameters are converted according the rules specified in
+		par. 3.3.2.2. E.i. the parameters are converted to the prototype
+		counter parts as if by assignment. For the parameters falling
+		under ellipsis clause the old parameters conversion stuff
+		applies.
+	*/
+	register struct expr *left = (*expp)->OP_LEFT;
+	register struct expr *right = (*expp)->OP_RIGHT;
+	register struct proto *pl = NO_PROTO;
+
+	if (left != NILEXPR) {	/* in case of an error */
+		register struct type *tp = left->ex_type;
+
+		while (tp && tp->tp_fund != FUNCTION)
+			tp = tp->tp_up;
+		pl = (tp && tp->tp_proto) ? tp->tp_proto : NO_PROTO;
+	}
+
+	if (right != NILEXPR) { /* function call with parameters */
+		register struct expr *ex = right;
+		register struct expr **ep = &((*expp)->OP_RIGHT);
+		register int ecnt = 0, pcnt = 0;
+		struct expr **estack[NPARAMS];
+		struct proto *pstack[NPARAMS];
+
+		if (pl == NO_PROTO) {
+			register struct idf *idf;
+
+			if (left->ex_class != Value || left->VL_CLASS != Name) {
+				strict("no prototype supplied");
+				return;
+			}
+			if ((idf = left->VL_IDF)->id_proto)
+				return;
+			strict("'%s' no prototype supplied", idf->id_text);
+			idf->id_proto++;
+			return;
+		}
+
+		/* stack up the parameter expressions */
+		while (ex->ex_class == Oper && ex->OP_OPER == PARCOMMA) {
+			if (ecnt == STDC_NPARAMS)
+				strict("number of parameters exceeds ANSI limit");
+			if (ecnt >= NPARAMS-1) {
+				error("too many parameters");
+				return;
+			}
+			estack[ecnt++] = &(ex->OP_RIGHT);
+			ep = &(ex->OP_LEFT);
+			ex = ex->OP_LEFT;
+		}
+		estack[ecnt++] = ep;
+
+		/*	Declarations like int f(void) do not expect any
+			parameters.
+		*/
+		if (pl && pl->pl_flag == VOID) {
+			strict("no parameters expected");
+			return;
+		}
+
+		/* stack up the prototypes */
+		while (pl) {
+			/* stack prototypes */
+			pstack[pcnt++] = pl;
+			pl = pl->next;
+		}
+		pcnt--;
+
+		for (--ecnt; ecnt >= 0; ecnt--) {
+			/*	Only the parameters specified in the prototype
+				are checked and converted. The parameters that
+				fall under the ellipsis clause are neither
+				checked nor converted !
+			*/
+			if (pcnt < 0) {
+				error("more parameters than specified in prototype");
+				break;
+			}
+			if (pstack[pcnt]->pl_flag != ELLIPSIS) {
+				ch7cast(estack[ecnt],CASTAB,pstack[pcnt]->pl_type);
+				pcnt--;
+			} else
+				break;	/* against unnecessary looping */
+		}
+		if (pcnt >= 0 && pstack[0]->pl_flag != ELLIPSIS)
+			error("less parameters than specified in prototype");
+
+	} else {
+		if (pl && pl->pl_flag != VOID)
+			error("less parameters than specified in prototype");
+	}
+}
+

+ 17 - 0
lang/cem/cemcom.ansi/proto.str

@@ -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$ */
+/* PARAMETER TYPE LIST DEFINITION */
+
+struct proto {
+	struct proto *next;
+	struct type *pl_type;	/* parameter type */
+	struct idf *pl_idf;	/* parameter identifier */
+	short pl_flag;		/* ELLIPSIS or FORMAL */
+};
+
+#define NO_PROTO	((struct proto *)0)
+
+/* ALLOCDEF "proto" 10 */

+ 677 - 0
lang/cem/cemcom.ansi/replace.c

@@ -0,0 +1,677 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*  M A C R O   R E P L A C E M E N T */
+#include	"nopp.h"
+
+#ifndef NOPP
+
+#include	"debug.h"
+#include	"pathlength.h"
+#include	"strsize.h"
+#include	"nparams.h"
+#include	"idfsize.h"
+#include	"numsize.h"
+#include	<alloc.h>
+#include	"idf.h"
+#include	"input.h"
+#include	"macro.h"
+#include	"arith.h"
+#include	"LLlex.h"
+#include	"class.h"
+#include	"assert.h"
+#include	"static.h"
+#include	"lapbuf.h"
+#include	"argbuf.h"
+#include	"replace.h"
+
+struct	repl	*ReplaceList;	/* list of currently active macros */
+
+int
+replace(idf)
+	register struct idf *idf;
+{
+	/*	replace is called by the lexical analyzer to perform
+		macro replacement. The routine actualy functions as a
+		higher interface to the real thing: expand_macro().
+	*/
+	struct repl *repl;
+	int size;
+	
+	repl = new_repl();
+	repl->r_ptr = repl->r_text;
+	repl->r_args = new_args();
+	if (!expand_macro(repl, idf, (struct idf *)0))
+		return 0;
+	free_args(repl->r_args);
+	InsertText(repl->r_text, repl->r_ptr - repl->r_text);
+	repl->next = ReplaceList;
+	ReplaceList = repl;
+	return 1;
+}
+
+unstackrepl()
+{
+	struct repl *repl = ReplaceList;
+
+#ifdef PERSONAL_TOUCH
+	if (repl == NO_REPL) {
+		print("Leendert, you don't understand the principle yet\n");
+		return;
+	}
+#else
+	ASSERT(repl != NO_REPL);
+#endif
+	ReplaceList = repl->next;
+	free_repl(repl);
+}
+
+expand_macro(repl, idf, previdf)
+	register struct repl *repl;
+	register struct idf *idf;
+	struct idf *previdf;
+{
+	/*	expand_macro() does the actual macro replacement.
+		"idf" is a description of the identifier which
+		caused the replacement.
+		If the identifier represents a function-like macro
+		call, the number of actual parameters is checked
+		against the number of formal parameters. Note that
+		in ANSI C the parameters are expanded first;
+		this is done by calling getactuals().
+		When the possible parameters are expanded, the replace-
+		ment list associated with "idf" is expanded.
+		expand_macro() returns 1 if the replacement succeeded
+		and 0 if some error occurred.
+	*/
+	register struct macro *mac = idf->id_macro;
+	struct args *args = repl->r_args;
+	register int ch;
+
+	if (mac->mc_nps != -1) {	/* with parameter list	*/
+		if (mac->mc_flag & FUNC) {
+			/* the following assertion won't compile:
+			ASSERT(!strcmp("defined", idf->id_text));
+			*/
+			if (!AccDefined) return 0;
+		}
+
+		ch = GetChar();
+		ch = skipspaces(ch,1);
+		if (ch != '(') {	/* no replacement if no () */
+			/*	This is obscure. See the examples for the replace
+				algorithm in section 3`.8.3.5.
+			lexwarning("macro %s needs arguments", idf->id_text);
+			*/
+			UnGetChar();
+			return 0;
+		} else
+			getactuals(args, idf);
+
+		if (mac->mc_flag & FUNC) {
+			struct idf *param = str2idf(args->a_rawbuf);
+
+			*repl->r_ptr++ = param->id_macro ? '1' : '0';
+			*repl->r_ptr = '\0';
+			return 1;
+		}
+	}
+
+	if (mac->mc_flag & FUNC) /* this macro leads to special action */
+		macro_func(idf);
+
+	if (mac->mc_nps == -1) {
+		register int size = mac->mc_length;
+		register char *text = mac->mc_text;
+
+		ASSERT((repl->r_ptr+size) < &(repl->r_text[LAPBUF]));
+		while (size-- > 0)
+			*repl->r_ptr++ = *text++;
+		*repl->r_ptr = '\0';
+	} else
+		macro2buffer(repl, idf, args);
+
+	/*	According to the ANSI definition:
+
+			#define	a +
+			a+b; --> + + b ;
+		
+		'a' must be substituded, but the result should be
+		three tokens: + + ID. Because this preprocessor is
+		character based, we have a problem.
+		For now: just insert a space after all tokens,
+		until ANSI fixes this flaw.
+	*/
+	*repl->r_ptr++ = ' ';
+	*repl->r_ptr = '\0';
+
+	if (idf != previdf)
+		maccount(repl, idf);
+	return 1;
+}
+
+getactuals(args, idf)
+	register struct args *args;
+	register struct idf *idf;
+{
+	/*	Get the actual parameters from the input stream.
+		The hard part is done by actual(), only comma's and
+		other syntactic trivialities are checked here.
+	*/
+	register int nps = idf->id_macro->mc_nps;
+	register int argcnt;
+	register int ch;
+
+	argcnt = 0;
+	args->a_expvec[0] = args->a_expptr = &args->a_expbuf[0];
+	args->a_rawvec[0] = args->a_rawptr = &args->a_rawbuf[0];
+	if ((ch = GetChar()) != ')') {
+		PushBack();
+		while ((ch = actual(args, idf)) != ')' ) {
+			if (ch != ',') {
+				lexerror("illegal macro call");
+				return;
+			}
+			stash(args, '\0');
+			++argcnt;
+			args->a_expvec[argcnt] = args->a_expptr;
+			args->a_rawvec[argcnt] = args->a_rawptr;
+			if (argcnt == STDC_NPARAMS)
+				strict("number of parameters exceeds ANSI standard");
+			if (argcnt >= NPARAMS)
+				fatal("argument vector overflow");
+		}
+		stash(args, '\0');
+		++argcnt;
+	}
+	if (argcnt < nps)
+		lexerror("too few macro arguments");
+	if (argcnt > nps)
+		lexerror("too many macro arguments");
+}
+
+int
+actual(args, idf)
+	register struct args *args;
+	register struct idf *idf;
+{
+	/*	This routine deals with the scanning of an actual parameter.
+		It keeps in account the openning and clossing brackets,
+		preprocessor numbers, strings and character constants.
+	*/
+	register int ch;
+	register int level = 0;
+
+	while (1) {
+		ch = GetChar();
+
+		if (class(ch) == STIDF || class(ch) == STELL) {
+			/*	Scan a preprocessor identifier token. If the
+				token is a macro, it is expanded first.
+			*/
+			char buf[(IDFSIZE > NUMSIZE ? IDFSIZE : NUMSIZE) + 1];
+			register char *p = buf;
+			register struct idf *idef;
+			register int pos = -1;
+			register int hash;
+			extern int idfsize;
+			int size;
+
+			hash = STARTHASH();
+			do {
+				if (++pos < idfsize) {
+					*p++ = ch;
+					hash = ENHASH(hash, ch, pos);
+				}
+				ch = GetChar();
+			} while (in_idf(ch));
+			hash = STOPHASH(hash);
+			*p++ = '\0';
+			UnGetChar();
+
+			/*	When the identifier has an associated macro
+				replacement list, it's expanded.
+			*/
+			idef = idf_hashed(buf, p - buf, hash);
+			if (idef->id_macro)	/* expand macro identifier */
+				expand_actual(args, idef, idf);
+			else
+				for (p = buf; *p != '\0'; p++)
+					stash(args, *p);
+		} else if (class(ch) == STNUM || class(ch) == '.') {
+			/*	preprocessor number token. No this is no joke,
+				the commitee decided (in all it's wisdom) that
+				a preprocessing number has the following regular
+				expression:
+					[0-9"."]{[0-9"."a-zA-Z_]|{[Ee][+-]}}*
+			*/
+			do {
+				stash(args, ch);
+				if ((ch = GetChar()) == 'e' || ch == 'E') {
+					ch = GetChar();
+					if (ch == '+' || ch == '-') {
+						stash(args, ch);
+						ch = GetChar();
+					}
+				}
+			} while (class(ch) == STNUM || class(ch) == STIDF ||
+				 class(ch) == STELL || ch == '.');
+			UnGetChar();
+		} else if (ch == '(' || ch == '[' || ch == '{') {
+			/* a comma may occur within these constructions */
+			level++;
+			stash(args, ch);
+		} else if (ch == ')' || ch == ']' || ch == '}') {
+			level--;
+			/* clossing parenthesis of macro call */
+			if (ch == ')' && level < 0)
+				return ')';
+			stash(args, ch);
+		} else if (ch == ',') {
+			if (level <= 0) { /* comma separator for next argument */
+				if (level)
+					lexerror("unbalanced parenthesis");
+				return ',';
+			}
+			stash(args, ch);
+		} else if (ch == '\n') {
+			/* newlines are accepted as white spaces */
+			LineNumber++;
+			while ((ch = GetChar()), class(ch) == STSKIP)
+				/* VOID */;
+
+			/*	This piece of code needs some explanation:
+				consider the call of a macro defined as:
+					#define sum(a,b) (a+b)
+				in the following form:
+					sum(
+					#include phone_number
+					,2);
+				in which case the include must be handled
+				interpreted as such.
+			*/
+			if (ch == '#')
+				domacro();
+			UnGetChar();
+			stash(args, ' ');
+		} else if (ch == '/') {
+			/* comments are treated as one white space token */
+			if ((ch = GetChar()) == '*') {
+				skipcomment();
+				stash(args, ' ');
+			} else {
+				UnGetChar();
+				stash(args, '/');
+			}
+		} else if (ch == '\'' || ch == '"') {
+			/*	Strings are considered as ONE token, thus no
+				replacement within strings.
+			*/
+			register int match = ch;
+
+			stash(args, ch);
+			while ((ch = GetChar()) != EOI) {
+				if (ch == match)
+					break;
+				if (ch == '\\') {
+					stash(args, ch);
+					ch = GetChar();
+				} else if (ch == '\n') {
+					lexerror("newline in string");
+					LineNumber++;
+					stash(args, match);
+					break;
+				}
+				stash(args, ch);
+			}
+			if (ch != match) {
+				lexerror("unterminated macro call");
+				return ')';
+			}
+			stash(args, ch);
+		} else
+			stash(args, ch);
+	}
+}
+
+expand_actual(args, idef, idf)
+	register struct args *args;
+	register struct idf *idf, *idef;
+{
+	struct repl *nrepl = new_repl();
+	register char *p;
+
+	nrepl->r_args = new_args();
+	nrepl->r_ptr = nrepl->r_text;
+	if (expand_macro(nrepl, idef, idf)) {
+		register struct args *ap = nrepl->r_args;
+
+		for (p = nrepl->r_text; p < nrepl->r_ptr; p++)
+			*args->a_expptr++ = *p;
+
+		/* stash idef name */
+		for (p = idef->id_text; *p != '\0'; p++)
+			*args->a_rawptr++ = *p;
+
+		/*	The following code deals with expanded function
+			like macro calls. It makes the following code
+			work:
+
+				#define def(a,b)	x(a,b)
+				#define	glue(a,b)	a ## b
+
+				glue(abc,def(a,b))
+				
+			Results in:
+
+				abcdef(a,b);
+		*/
+		if (ap->a_rawvec[0]) {
+			/* stash arguments */
+			register int i;
+
+			*args->a_rawptr++ = '(';
+			for (i = 0; ap->a_rawvec[i] != (char *)0; i++) {
+				for (p = ap->a_rawvec[i]; *p != '\0'; p++)
+					*args->a_rawptr++ = *p;
+				*args->a_rawptr++ = ',';
+			}
+			*--args->a_rawptr = ')';
+			++args->a_rawptr;	/* one too far */
+		}
+	} else	/* something happened during the macro expansion */
+		for (p = idef->id_text; *p != '\0'; p++)
+			stash(args, *p);
+	free_args(nrepl->r_args);
+	free_repl(nrepl);
+}
+
+maccount(repl, idf)
+	register struct repl *repl;
+	register struct idf *idf;
+{
+	/*	To prevent re-expansion of already expanded macro's we count
+		the occurrences of the currently expanded macro name in the
+		replacement list. This is mainly to prevent recursion as in:
+
+			#define	f(a)	f(2 * (a))
+			f(y+1);
+
+		This results in:
+
+			f(2*(y+1));
+
+		When reading the inserted text we decrement the count of a
+		macro name until it's zero. Then we start expanding it again.
+	*/
+	register char *text = repl->r_text;
+	register int pos = -1;
+	extern int idfsize;
+
+	while (*text != '\0') {
+		if (*text == '\'' || *text == '"') {
+			register int delim;
+
+			for (delim = *text++; *text != delim; text++)
+				if (*text == '\\')
+					text++;
+			text++;
+		} else
+		if (class(*text) == STIDF || class(*text) == STELL) {
+			char buf[(IDFSIZE > NUMSIZE ? IDFSIZE : NUMSIZE) + 1];
+			register char *p = buf;
+
+			do {
+				if (++pos < idfsize)
+					*p++ = *text;
+				text++;
+			} while (in_idf(*text));
+			*p++ = '\0';
+
+			if (!strcmp(idf->id_text, buf))
+				idf->id_macro->mc_count++;
+		} else
+			text++;
+	}
+}
+
+macro_func(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;
+	static char FilNamBuf[PATHLENGTH];
+	char *long2str();
+
+	switch (idef->id_text[2]) {
+	case 'F':			/* __FILE__	*/
+		FilNamBuf[0] = '"';
+		strcpy(&FilNamBuf[1], FileName);
+		strcat(FilNamBuf, "\"");
+		mac->mc_text = FilNamBuf;
+		mac->mc_length = strlen(FilNamBuf);
+		break;
+	case 'L':			/* __LINE__	*/
+		mac->mc_text = long2str((long)LineNumber, 10);
+		mac->mc_length = 1;
+		break;
+	default:
+		crash("(macro_func)");
+		/*NOTREACHED*/
+	}
+}
+
+macro2buffer(repl, idf, args)
+	register struct repl *repl;
+	register struct idf *idf;
+	register struct args *args;
+{
+	/*	macro2buffer expands the replacement list and places the
+		result onto the replacement buffer. It deals with the #
+		and ## operators, and inserts the actual parameters.
+		The argument buffer contains the raw argument (needed
+		for the ## operator), and the expanded argument (for
+		all other parameter substitutions).
+
+		The grammar of the replacement list is:
+
+			repl_list:	TOKEN repl_list
+				|	PARAMETER repl_list
+				|	'#' PARAMETER
+				|	TOKEN '##' TOKEN
+				|	PARAMETER '##' TOKEN
+				|	TOKEN '##' PARAMETER
+				|	PARAMETER '##' PARAMETER
+				;
+		
+		As the grammar indicates, we could make a DFA and
+		use this finite state machine for the replacement
+		list parsing (inserting the arguments, etc.).
+
+		Currently we go through the replacement list in a
+		linear fashion. This is VERY expensive, something
+		smarter should be done (but even a DFA is O(|s|)).
+	*/
+	register char *ptr = idf->id_macro->mc_text;
+	char *stringify();
+
+	while (*ptr) {
+		ASSERT(repl->r_ptr < &(repl->r_text[LAPBUF]));
+		if (*ptr == '\'' || *ptr == '"') {
+			register int delim = *ptr;
+
+			do {
+				*repl->r_ptr++ = *ptr;
+				if (*ptr == '\\')
+					*repl->r_ptr++ = *++ptr;
+				if (*ptr == '\0') {
+					lexerror("unterminated string");
+					*repl->r_ptr = '\0';
+					return;
+				}
+				ptr++;
+			} while (*ptr != delim || *ptr == '\0');
+			*repl->r_ptr++ = *ptr++;
+		} else if (*ptr == '#') {
+			if (*++ptr == '#') {
+				/* ## - paste operator */
+				ptr++;
+
+				/* trim the actual replacement list */
+				--repl->r_ptr;
+				while (is_wsp(*repl->r_ptr) &&
+				       repl->r_ptr >= repl->r_text)
+					--repl->r_ptr;
+
+				/*	## occurred at the beginning of the
+					replacement list.
+				*/
+				if (repl->r_ptr == repl->r_text)
+					goto paste;
+				++repl->r_ptr;
+
+				/* skip space in macro replacement list */
+				while ((*ptr & FORMALP) == 0 && is_wsp(*ptr))
+					ptr++;
+
+				/*	## occurred at the end of the
+					replacement list.
+				*/
+				if (*ptr & FORMALP) {
+					register int n = *ptr++ & 0177;
+					register char *p;
+					
+					ASSERT(n != 0);
+					p = args->a_rawvec[n-1];
+					while (is_wsp(*p))
+						p++;
+					while (*p)
+						*repl->r_ptr++ = *p++;
+				} else if (*ptr == '\0')
+					goto paste;
+			} else
+				ptr = stringify(repl, ptr, args);
+		} else if (*ptr & FORMALP) {
+			/* insert actual parameter */
+			register int n = *ptr++ & 0177;
+			register char *p, *q;
+			
+			ASSERT(n != 0);
+
+			/*	This is VERY dirty, we look ahead for the
+				## operater. If it's found we use the raw
+				argument buffer instead of the expanded
+				one.
+			*/
+			for (p = ptr; (*p & FORMALP) == 0 && is_wsp(*p); p++)
+				/* VOID */;
+			if (*p == '#' && p[1] == '#')
+				q = args->a_rawvec[n-1];
+			else
+				q = args->a_expvec[n-1];
+
+			while (*q)
+				*repl->r_ptr++ = *q++;
+
+			*repl->r_ptr++ = ' ';
+		} else
+			*repl->r_ptr++ = *ptr++;
+	}
+	*repl->r_ptr = '\0';
+	return;
+
+paste:
+	/*	Sorry, i know this looks a bit like
+		a unix device driver code.
+	*/
+	lexerror("illegal use of the ## operator");
+	return;
+}
+
+char *
+stringify(repl, ptr, args)
+	register struct repl *repl;
+	register char *ptr;
+	register struct args *args;
+{
+	/*	If a parameter is immediately preceded by a # token
+		both are replaced by a single string literal that
+		contains the spelling of the token sequence for the
+		corresponding argument.
+		Each occurrence of white space between the argument's
+		tokens become a single space character in the string
+		literal. White spaces before the first token and after
+		the last token comprising the argument are deleted.
+		To retain the original spelling we insert backslashes
+		as appropriate. We only escape backslashes if they
+		occure within string tokens.
+	*/
+	register int space = 1;		/* skip leading spaces */
+	register int delim = 0;		/* string or character constant delim */
+	register int backslash = 0;	/* last character was a \ */
+
+	/* skip spaces macro replacement list */
+	while ((*ptr & FORMALP) == 0 && is_wsp(*ptr))
+		ptr++;
+
+	if (*ptr & FORMALP) {
+		register int n = *ptr++ & 0177;
+		register char *p;
+		
+		ASSERT(n != 0);
+		p = args->a_expvec[n-1];
+		*repl->r_ptr++ = '"';
+		while (*p) {
+			if (is_wsp(*p)) {
+				if (!space) {
+					space = 1;
+					*repl->r_ptr++ = ' ';
+				}
+				p++;
+				continue;
+			}
+			space = 0;
+
+			if (!delim && (*p == '"' || *p == '\''))
+				delim = *p;
+			else if (*p == delim && !backslash)
+				delim = 0;
+			backslash = *p == '\\';
+			if (*p == '"' || (delim && *p == '\\'))
+				*repl->r_ptr++ = '\\';
+			*repl->r_ptr++ = *p++;
+		}
+
+		/* trim spaces in the replacement list */
+		for (--repl->r_ptr; is_wsp(*repl->r_ptr); repl->r_ptr--)
+			/* VOID */;
+		*++repl->r_ptr = '"';
+		++repl->r_ptr;	/* oops, one to far */
+	} else
+		error("illegal use of # operator");
+	return ptr;
+}
+
+stash(args, ch)
+	register struct args *args;
+	register int ch;
+{
+	/*	Stash characters into the macro expansion buffer.
+	*/
+	if (args->a_expptr >= &(args->a_expbuf[ARGBUF]))
+		fatal("macro argument buffer overflow");
+	*args->a_expptr++ = ch;
+
+	if (args->a_rawptr >= &(args->a_rawbuf[ARGBUF]))
+		fatal("raw macro argument buffer overflow");
+	*args->a_rawptr++ = ch;
+
+			
+}
+#endif NOPP

+ 39 - 0
lang/cem/cemcom.ansi/replace.str

@@ -0,0 +1,39 @@
+struct repl {
+	struct	repl *next;
+	struct	args *r_args;		/* replacement parameters */
+	char	r_text[LAPBUF];		/* replacement text */
+	char	*r_ptr;			/* replacement text pointer */
+};
+
+/* ALLOCDEF "repl" 4 */
+
+#define NO_REPL		(struct repl *)0
+
+/*	The implementation of the ## operator is currently very clumsy.
+	When the the ## operator is used the arguments are taken from
+	the raw buffer; this buffer contains a precise copy of the
+	original argument. The fully expanded copy is in the arg buffer.
+	The two copies are here explicitely because:
+
+		#define ABC	f()
+		#define	ABCD	2
+		#define	g(x, y)	x ## y + h(x)
+
+		g(ABC, D);
+
+	In this case we need two copies: one raw copy for the pasting
+	operator, and an expanded one as argument for h().
+*/
+struct args {
+	char	*a_expptr;		/* expanded argument pointer */
+	char	*a_expvec[NPARAMS];	/* expanded argument vector */
+	char	a_expbuf[ARGBUF];	/* expanded argument buffer space */
+	char	*a_rawptr;		/* raw argument pointer */
+	char	*a_rawvec[NPARAMS];	/* raw argument vector */
+	char	a_rawbuf[ARGBUF];	/* raw argument buffer space */
+};
+
+/* ALLOCDEF "args" 2 */
+
+#define NO_ARGS		(struct args *)0
+

+ 237 - 0
lang/cem/cemcom.ansi/scan.c

@@ -0,0 +1,237 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* PREPROCESSOR: SCANNER FOR THE ACTUAL PARAMETERS OF MACROS	*/
+
+#include	"nopp.h"
+
+#ifndef NOPP
+/*	This file contains the function getactuals() which scans an actual
+	parameter list and splits it up into a list of strings, each one
+	representing an actual parameter.
+*/
+
+#include	"lapbuf.h"	/* UF */
+#include	"nparams.h"	/* UF */
+
+#include	"input.h"
+#include	"class.h"
+#include	"idf.h"
+#include	"macro.h"
+#include	"interface.h"
+#include	"file_info.h"
+
+#define	EOS		'\0'
+#define	overflow()	(fatal("actual parameter buffer overflow"))
+
+PRIVATE char apbuf[LAPBUF]; /* temporary storage for actual parameters	*/
+PRIVATE char *actparams[NPARAMS]; /* pointers to the text of the actuals */
+PRIVATE char *aptr;	/* pointer to last inserted character in apbuf	*/
+
+#define	copy(ch)	((aptr < &apbuf[LAPBUF]) ? (*aptr++ = ch) : overflow())
+
+PRIVATE int nr_of_params;	/* number of actuals read until now	*/
+
+PRIVATE char **
+getactuals(idef)
+	register struct idf *idef;
+{
+	/*	getactuals() collects the actual parameters and turns them
+		into a list of strings, a pointer to which is returned.
+	*/
+	register acnt = idef->id_macro->mc_nps;
+
+	nr_of_params = 0;
+	actparams[0] = aptr = &apbuf[0];
+	copyact('(', ')', 0);	/* read the actual parameters	*/
+	copy(EOS);		/* mark the end of it all	*/
+
+	if (!nr_of_params++)	{		/* 0 or 1 parameter	*/
+		/* there could be a ( <spaces, comment, ...> )
+		*/
+		register char *p = actparams[0];
+
+		while ((class(*p) == STSKIP) || (*p == '\n')) {
+				++p;
+		}
+
+		if (!*p) {	/* the case () : 0 parameters	*/
+			nr_of_params--;
+		}
+	}
+
+	if (nr_of_params != acnt)	{
+		/*	argument mismatch: too many or too few
+			actual parameters.
+		*/
+		lexwarning("argument mismatch, %s", idef->id_text);
+
+		while (nr_of_params < acnt) {
+			/*	too few paraeters: remaining actuals are ""
+			*/
+			actparams[nr_of_params] = "";
+			nr_of_params++;
+		}
+	}
+
+	return actparams;
+}
+
+PRIVATE
+copyact(ch1, ch2, lvl)
+	char ch1, ch2;
+	int lvl;
+{
+	/*	copyact() is taken from Ceriel Jacobs' LLgen, with
+		permission.  Its task is to build a list of actuals
+		parameters, which list is surrounded by '(' and ')' and in
+		which the parameters are separated by ',' if there are
+		more than 1. The balancing of '(',')' and '[',']' and
+		'{','}' is taken care of by calling this function
+		recursively. At each level lvl, copyact() reads the input,
+		upto the corresponding closing bracket.
+
+		Opening bracket is ch1, closing bracket is ch2. If
+		lvl != 0, copy opening and closing parameters too.
+	*/
+	register int ch;		/* Current char */
+	register int match;		/* used to read strings */
+
+	if (lvl) {
+		copy(ch1);
+	}
+
+	for (;;)	{
+		LoadChar(ch);
+
+		if (ch == ch2)	{
+			if (lvl) {
+				copy(ch);
+			}
+			return;
+		}
+
+		switch(ch)	{
+
+#ifdef __MATCHING_PAR__
+		case ')':
+		case '}':
+		case ']':
+			lexerror("unbalanced parenthesis");
+			break;
+#endif __MATCHING_PAR__
+
+		case '(':
+			copyact('(', ')', lvl+1);
+			break;
+
+#ifdef __MATCHING_PAR__
+		case '{':
+			/*	example:
+					#define declare(v, t)	t v
+					declare(v, union{int i, j; float r;});
+			*/
+			copyact('{', '}', lvl+1);
+			break;
+
+		case '[':
+			copyact('[', ']', lvl+1);
+			break;
+#endif __MATCHING_PAR__
+
+		case '\n':
+			LineNumber++;
+			while (LoadChar(ch), ch == '#')	{
+				/*	This piece of code needs some
+					explanation: consider the call of
+					the macro defined as:
+						#define sum(b,c) (b + c)
+					in the following form:
+						sum(
+						#include my_phone_number
+						,2)
+					in which case the include must be
+					interpreted as such.
+				*/
+				domacro();	/* has read nl, vt or ff */
+				/* Loop, for another control line */
+			}
+
+			PushBack();
+			copy(' ');
+			break;
+
+		case '/':
+			LoadChar(ch);
+
+			if (ch == '*')	{	/* skip comment	*/
+				skipcomment();
+				continue;
+			}
+
+			PushBack();
+			copy('/');
+			break;
+
+		case ',':
+			if (!lvl)	{
+				/* next parameter encountered */
+				copy(EOS);
+
+				if (++nr_of_params >= NPARAMS) {
+					fatal("too many actual parameters");
+				}
+
+				actparams[nr_of_params] = aptr;
+			}
+			else	{
+				copy(ch);
+			}
+			break;
+
+		case '\'':
+		case '"' :
+			/*	watch out for brackets in strings, they do
+				not count !
+			*/
+			match = ch;
+			copy(ch);
+			while (LoadChar(ch), ch != EOI)	{
+				if (ch == match) {
+					break;
+				}
+
+				if (ch == '\\')	{
+					copy(ch);
+					LoadChar(ch);
+				}
+				else
+				if (ch == '\n')	{
+					lexerror("newline in string");
+					LineNumber++;
+					copy(match);
+					break;
+				}
+
+				copy(ch);
+			}
+
+			if (ch == match)	{
+				copy(ch);
+				break;
+			}
+			/* Fall through */
+
+		case EOI :
+			lexerror("unterminated macro call");
+			return;
+
+		default:
+			copy(ch);
+			break;
+		}
+	}
+}
+#endif NOPP

+ 33 - 0
lang/cem/cemcom.ansi/sizes.h

@@ -0,0 +1,33 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* VARIOUS TARGET MACHINE SIZE DESCRIPTORS */
+
+#include "nofloat.h"
+#include "nocross.h"
+#include "target_sizes.h"
+
+#ifndef NOCROSS
+extern arith
+	short_size, word_size, dword_size, int_size, long_size,
+#ifndef NOFLOAT
+	float_size, double_size, lngdbl_size,
+#endif NOFLOAT
+	pointer_size;
+#else NOCROSS
+#define short_size	(SZ_SHORT)
+#define word_size	(SZ_WORD)
+#define dword_size	(2*SZ_WORD)
+#define int_size	(SZ_INT)
+#define long_size	(SZ_LONG)
+#ifndef NOFLOAT
+#define float_size	(SZ_FLOAT)
+#define double_size	(SZ_DOUBLE)
+#define	lngdbl_size	(SZ_LNGDBL)
+#endif NOFLOAT
+#define pointer_size	(SZ_POINTER)
+#endif NOCROSS
+
+extern arith max_int, max_unsigned;	/* cstoper.c	*/

+ 69 - 0
lang/cem/cemcom.ansi/skip.c

@@ -0,0 +1,69 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* PREPROCESSOR: INPUT SKIP FUNCTIONS */
+
+#include	"nopp.h"
+#include	"arith.h"
+#include	"LLlex.h"
+#include	"class.h"
+#include	"input.h"
+
+#ifndef NOPP
+int
+skipspaces(ch, skipnl)
+	register int ch;
+{
+	/*	skipspaces() skips any white space and returns the first
+		non-space character.
+	*/
+	for (;;) {
+		while (class(ch) == STSKIP)
+			ch = GetChar();
+		if (skipnl && class(ch) == STNL) {
+			ch = GetChar();
+			++LineNumber;
+			continue;
+		}
+
+		/* \\\n are handled by trigraph */
+
+		if (ch == '/') {
+			ch = GetChar();
+			if (ch == '*') {
+				skipcomment();
+				ch = GetChar();
+			}
+			else	{
+				UnGetChar();
+				return '/';
+			}
+		}
+		else
+			return ch;
+	}
+}
+#endif NOPP
+
+SkipToNewLine(garbage)
+	int garbage;
+{
+	register int ch;
+	register int pstrict = 0;
+
+	UnGetChar();
+	while ((ch = GetChar()) != '\n') {
+		if (ch == '/') {
+			if ((ch = GetChar()) == '*') {
+				skipcomment();
+				continue;
+			}
+		}
+		if (garbage && !is_wsp(ch))
+			pstrict = 1;
+	}
+	++LineNumber;
+	return pstrict;
+}

+ 18 - 0
lang/cem/cemcom.ansi/specials.h

@@ -0,0 +1,18 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* OCCURANCES OF SPECIAL IDENTIFIERS */
+
+#define	SP_SETJMP	1
+
+#define	SP_TOTAL	1
+
+struct sp_id	{
+	char *si_identifier;	/* its name			*/
+	int si_flag;		/* index into sp_occurred array	*/
+};
+
+extern char sp_occurred[];		/* idf.c	*/
+extern struct sp_id special_ids[];	/* main.c	*/

+ 279 - 0
lang/cem/cemcom.ansi/stack.c

@@ -0,0 +1,279 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $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>
+#include	"debug.h"
+#include	"botch_free.h"
+#include	<alloc.h>
+#include	"Lpars.h"
+#include	"arith.h"
+#include	"stack.h"
+#include	"type.h"
+#include	"idf.h"
+#include	"def.h"
+#include	"struct.h"
+#include	"level.h"
+#include	"mes.h"
+#include	"noRoption.h"
+
+/* #include	<em_reg.h> */
+
+extern char options[];
+
+static struct stack_level UniversalLevel;
+struct stack_level *local_level = &UniversalLevel;
+/*	The main reason for having this secondary stacking
+	mechanism besides the linked lists pointed to by the idf's
+	is efficiency.
+	To remove the idf's of a given level, one could scan the
+	hash table and chase down the idf chains; with a hash
+	table size of 100 this is feasible, but with a size of say
+	100000 this becomes painful. Therefore all idf's are also
+	kept in a stack of sets, one set for each level.
+*/
+
+int level;	/* Always equal to local_level->sl_level. */
+
+stack_level()	{
+	/*	A new level is added on top of the identifier stack.
+	*/
+	register struct stack_level *stl = new_stack_level();
+	register struct stack_level *loclev = local_level;
+	
+	loclev->sl_next = stl;
+	stl->sl_previous = loclev;
+	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)
+	struct idf *idf;
+	register struct stack_level *stl;
+{
+	/*	The identifier idf is inserted in the stack on level stl.
+	*/
+	register struct stack_entry *se = new_stack_entry();
+
+	/* link it into the stack level */
+	se->next = stl->sl_entry;
+	se->se_idf = idf;
+	stl->sl_entry = se;
+}
+
+struct stack_level *
+stack_level_of(lvl)
+{
+	/*	The stack_level corresponding to level lvl is returned.
+		The stack should probably be an array, to be extended with
+		realloc where needed.
+	*/
+	register struct stack_level *stl;
+
+	if (lvl == level)
+		return local_level;
+	stl = &UniversalLevel;
+		
+	while (stl->sl_level != lvl)
+		stl = stl->sl_next;
+	return stl;
+}
+
+unstack_level()
+{
+	/*	The top level of the identifier stack is removed.
+	*/
+	struct stack_level *lastlvl;
+
+#ifdef	DEBUG
+	if (options['t'])
+		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.
+	*/
+	while (local_level->sl_entry)	{
+		register struct stack_entry *se = local_level->sl_entry;
+		register struct idf *idf = se->se_idf;
+		register struct def *def;
+		register struct sdef *sdef;
+		register struct tag *tag;
+
+		/* unlink it from the local stack level */
+		local_level->sl_entry = se->next;
+		free_stack_entry(se);
+
+		while ((def = idf->id_def) && def->df_level >= level)	{
+			/* unlink it from the def list under the idf block */
+			if (def->df_sc == LABEL)
+				unstack_label(idf);
+			else if (def->df_sc == REGISTER || def->df_sc == AUTO)
+				FreeLocal(def->df_address);
+			idf->id_def = def->next;
+			free_def(def);
+			update_ahead(idf);
+		}
+		while (	(sdef = idf->id_sdef)
+		&&	sdef->sd_level >= level
+		)	{
+			/* unlink it from the sdef list under the idf block */
+			idf->id_sdef = sdef->next;
+			free_sdef(sdef);
+		}
+		while (	(tag = idf->id_struct)
+		&&	tag->tg_level >= level
+		)	{
+			/* unlink it from the struct list under the idf block */
+			idf->id_struct = tag->next;
+			free_tag(tag);
+		}
+		while ((tag = idf->id_enum) && tag->tg_level >= level)	{
+			/* unlink it from the enum list under the idf block */
+			idf->id_enum = tag->next;
+			free_tag(tag);
+		}
+	}
+	/*	Unlink the local stack level from the stack.
+	*/
+	lastlvl = local_level;
+	local_level = local_level->sl_previous;
+	if (level >= L_LOCAL)	{
+		local_level->sl_max_block = lastlvl->sl_max_block;
+	}
+	free_stack_level(lastlvl);
+	local_level->sl_next = (struct stack_level *) 0;
+	level = local_level->sl_level;
+
+#ifdef	DEBUG
+	if (options['t'])
+		dumpidftab("after unstackidfs", 0);
+#endif	DEBUG
+}
+
+unstack_world()
+{
+	/*	The global level of identifiers is scanned, and final
+		decisions are taken about such issues as
+		extern/static/global and un/initialized.
+		Effects on the code generator: initialised variables
+		have already been encoded while the uninitialised ones
+		are not and have to be encoded at this moment.
+	*/
+	register struct stack_entry *se = local_level->sl_entry;
+
+#ifdef	LINT
+	lint_global_level(local_level);
+#endif	LINT
+
+	open_name_list();
+
+	while (se)	{
+		register struct idf *idf = se->se_idf;
+		register struct def *def = idf->id_def;
+		
+		if (!def)	{
+			/* global selectors, etc. */
+			se = se->next;
+			continue;
+		}
+		
+#ifdef DEBUG
+		if (options['a']) {
+			char *symbol2str();
+
+			print("\"%s\", %s, %s, %s, %s\n",
+				idf->id_text,
+				(def->df_alloc == 0) ? "no alloc" :
+				(def->df_alloc == ALLOC_SEEN) ? "alloc seen" :
+				(def->df_alloc == ALLOC_DONE) ? "alloc done" :
+				"illegal alloc info",
+				symbol2str(def->df_sc),
+				def->df_initialized ? "init" : "no init",
+				def->df_used ? "used" : "not used");
+		}
+#endif DEBUG
+		/*
+		/_* find final storage class *_/
+		if (def->df_sc == GLOBAL || def->df_sc == IMPLICIT)
+			/_* even now we still don't know *_/
+			def->df_sc = EXTERN;
+		*/
+		
+		if (	def->df_sc == STATIC
+			&& def->df_type->tp_fund == FUNCTION
+			&& !def->df_initialized
+		)	{
+			/* orphaned static function */
+#ifndef NOROPTION
+			if (options['R'])
+				warning("static function %s never defined, %s",
+					idf->id_text,
+					"changed to extern"
+				);
+#endif
+			def->df_sc = EXTERN;
+		}
+		
+		if (
+			def->df_alloc == ALLOC_SEEN &&
+			!def->df_initialized
+		)	{
+			/* space must be allocated */
+			bss(idf);
+			if (def->df_sc != STATIC)
+				namelist(idf->id_text);	/* may be common */
+			def->df_alloc = ALLOC_DONE;	/* see Note below */
+		}
+		se = se->next;
+	}
+	/*	Note:
+		df_alloc must be set to ALLOC_DONE because the idf entry
+		may occur several times in the list.
+		The reason for this is that the same name may be used
+		for different purposes on the same level, e.g.
+			struct s {int s;} s;
+		is a legal definition and contains 3 defining occurrences
+		of s.
+		Each definition has been entered into the identifier stack.
+		Although only one of them concerns a variable, we meet the
+		s 3 times when scanning the identifier stack.
+	*/
+}
+
+/*	A list of potential common names is kept, to be fed to
+	an understanding loader.  The list is written to a file
+	the name of which is nmlist.  If nmlist == NULL, no name
+	list is generated.
+*/
+extern char *nmlist;	/* BAH! -- main.c	*/
+static File *nfp = 0;
+
+open_name_list()
+{
+	if (nmlist && sys_open(nmlist, OP_WRITE, &nfp) == 0)
+		fatal("cannot create namelist %s", nmlist);
+}
+
+namelist(nm)
+	char *nm;
+{
+	if (nmlist)	{
+		sys_write(nfp, nm, strlen(nm));
+		sys_write(nfp, "\n", 1);
+	}
+}

+ 34 - 0
lang/cem/cemcom.ansi/stack.str

@@ -0,0 +1,34 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* IDENTIFIER STACK DEFINITIONS */
+
+/*	The identifier stack is implemented as a stack of sets.
+	The stack is implemented by a doubly linked list,
+	the sets by singly linked lists.
+*/
+
+struct stack_level	{
+	struct stack_level *next;
+	struct stack_level *sl_next;		/* upward link		*/
+	struct stack_level *sl_previous;	/* downward link	*/
+	struct stack_entry *sl_entry;		/* sideward link	*/
+	arith sl_local_offset;		/* @ for first coming object	*/
+	arith sl_max_block;		/* maximum size of sub-block	*/
+	int sl_level;
+};
+
+/* ALLOCDEF "stack_level" 5 */
+
+struct stack_entry	{
+	struct stack_entry *next;
+	struct idf *se_idf;
+};
+
+/* ALLOCDEF "stack_entry" 5 */
+
+extern struct stack_level *local_level;
+extern struct stack_level *stack_level_of();
+extern int level;

+ 472 - 0
lang/cem/cemcom.ansi/statement.g

@@ -0,0 +1,472 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*	STATEMENT SYNTAX PARSER	*/
+
+{
+#include	<em.h>
+
+#include	"lint.h"
+#include	"debug.h"
+#include	"botch_free.h"
+
+#include	"arith.h"
+#include	"LLlex.h"
+#include	"type.h"
+#include	"idf.h"
+#include	"label.h"
+#include	"expr.h"
+#include	"code.h"
+#include	"stack.h"
+#include	"def.h"
+#ifdef	LINT
+#include	"l_lint.h"
+#include	"l_state.h"
+#endif	LINT
+
+extern int level;
+}
+
+/*	Each statement construction is stacked in order to trace a
+	statement to such a construction. Example: a case statement should
+	be recognized as a piece of the most enclosing switch statement.
+*/
+
+/* 9 */
+statement
+	{
+#ifdef	LINT
+		lint_statement();
+#endif	LINT
+	}
+:
+%if (AHEAD != ':')
+	expression_statement
+|
+	label ':' statement
+|
+	compound_statement
+|
+	if_statement
+|
+	while_statement
+|
+	do_statement
+|
+	for_statement
+|
+	switch_statement
+|
+	case_statement
+|
+	default_statement
+|
+	BREAK
+	{
+		code_break();
+#ifdef	LINT
+		lint_break_stmt();
+#endif	LINT
+	}
+	';'
+|
+	CONTINUE
+	{
+		code_continue();
+#ifdef	LINT
+		lint_continue_stmt();
+#endif	LINT
+	}
+	';'
+|
+	return_statement
+|
+	jump
+|
+	';'
+;
+
+
+expression_statement
+	{	struct expr *expr;
+	}
+:
+	expression(&expr)
+	';'
+		{
+#ifdef	DEBUG
+			print_expr("expression_statement", expr);
+#endif	DEBUG
+			code_expr(expr, RVAL, FALSE, NO_LABEL, NO_LABEL);
+			free_expression(expr);
+		}
+;
+
+label
+	{	struct idf *idf;
+	}
+:
+	identifier(&idf)
+	{
+		/*	This allows the following absurd case:
+
+				typedef int grz;
+				main()	{
+					grz: printf("A labelled statement\n");
+				}
+		*/
+#ifdef	LINT
+		lint_label();
+#endif	LINT
+		define_label(idf);
+		C_df_ilb((label)idf->id_def->df_address);
+	}
+;
+
+if_statement
+	{
+		struct expr *expr;
+		label l_true = text_label();
+		label l_false = text_label();
+		label l_end = text_label();
+	}
+:
+	IF
+	'('
+	expression(&expr)
+		{
+			opnd2test(&expr, IF);
+			if (is_cp_cst(expr))	{
+				/*	The comparison has been optimized
+					to a 0 or 1.
+				*/
+				if (expr->VL_VALUE == (arith)0)	{
+					C_bra(l_false);
+				}
+				/* else fall through */
+#ifdef	LINT
+				start_if_part(1);
+#endif	LINT
+			}
+			else	{
+				code_expr(expr, RVAL, TRUE, l_true, l_false);
+				C_df_ilb(l_true);
+#ifdef	LINT
+				start_if_part(0);
+#endif	LINT
+			}
+			free_expression(expr);
+		}
+	')'
+	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
+			}
+	]
+;
+
+while_statement
+	{
+		struct expr *expr;
+		label l_break = text_label();
+		label l_continue = text_label();
+		label l_body = text_label();
+	}
+:
+	WHILE
+		{
+			stack_stmt(l_break, l_continue);
+			C_df_ilb(l_continue);
+		}
+	'('
+	expression(&expr)
+		{
+			opnd2test(&expr, WHILE);
+			if (is_cp_cst(expr))	{
+				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
+			}
+		}
+	')'
+	statement
+		{
+			C_bra(l_continue);
+			C_df_ilb(l_break);
+			unstack_stmt();
+			free_expression(expr);
+#ifdef	LINT
+			end_loop_stmt();
+#endif	LINT
+		}
+;
+
+do_statement
+	{	struct expr *expr;
+		label l_break = text_label();
+		label l_continue = text_label();
+		label l_body = text_label();
+	}
+:
+	DO
+		{	C_df_ilb(l_body);
+			stack_stmt(l_break, l_continue);
+#ifdef	LINT
+			start_loop_stmt(DO, 1, 1);
+#endif	LINT
+		}
+	statement
+	WHILE
+	'('
+		{	C_df_ilb(l_continue);
+		}
+	expression(&expr)
+		{
+			opnd2test(&expr, WHILE);
+			if (is_cp_cst(expr))	{
+				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);
+		}
+	')'
+	';'
+		{
+			unstack_stmt();
+			free_expression(expr);
+		}
+;
+
+for_statement
+	{	struct expr *e_init = 0, *e_test = 0, *e_incr = 0;
+		label l_break = text_label();
+		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
+		{	stack_stmt(l_break, l_continue);
+		}
+	'('
+	[
+		expression(&e_init)
+		{	code_expr(e_init, RVAL, FALSE, NO_LABEL, NO_LABEL);
+		}
+	]?
+	';'
+		{	C_df_ilb(l_test);
+		}
+	[
+		expression(&e_test)
+		{
+			opnd2test(&e_test, FOR);
+			if (is_cp_cst(e_test))	{
+				if (e_test->VL_VALUE == (arith)0)	{
+					C_bra(l_break);
+				}
+#ifdef	LINT
+				const = 1,
+					cond = e_test->VL_VALUE != (arith)0;
+#endif	LINT
+			}
+			else	{
+				code_expr(e_test, RVAL, TRUE, l_body, l_break);
+				C_df_ilb(l_body);
+#ifdef	LINT
+				const = 0, cond = 0;
+#endif	LINT
+			}
+		}
+	]?
+	';'
+	expression(&e_incr)?
+	')'
+		{
+#ifdef	LINT
+			start_loop_stmt(FOR, const, cond);
+#endif	LINT
+		}
+	statement
+		{
+#ifdef	LINT
+			end_loop_stmt();
+#endif	LINT
+			C_df_ilb(l_continue);
+			if (e_incr)
+				code_expr(e_incr, RVAL, FALSE,
+							NO_LABEL, NO_LABEL);
+			C_bra(l_test);
+			C_df_ilb(l_break);
+			unstack_stmt();
+			free_expression(e_init);
+			free_expression(e_test);
+			free_expression(e_incr);
+		}
+;
+
+switch_statement
+	{
+		struct expr *expr;
+	}
+:
+	SWITCH
+	'('
+	expression(&expr)
+		{
+			code_startswitch(&expr);
+#ifdef	LINT
+			start_switch_part(expr);
+#endif	LINT
+		}
+	')'
+	statement
+		{
+#ifdef	LINT
+			end_switch_stmt();
+#endif	LINT
+			code_endswitch();
+			free_expression(expr);
+		}
+;
+
+case_statement
+	{
+		struct expr *expr;
+	}
+:
+	CASE
+	constant_expression(&expr)
+		{
+#ifdef	LINT
+			lint_case_stmt(0);
+#endif	LINT
+			code_case(expr);
+			free_expression(expr);
+		}
+	':'
+	statement
+;
+
+default_statement
+:
+	DEFAULT
+		{
+#ifdef	LINT
+			lint_case_stmt(1);
+#endif	LINT
+			code_default();
+		}
+	':'
+	statement
+;
+
+return_statement
+	{	struct expr *expr = 0;
+	}
+:
+	RETURN
+	[
+		expression(&expr)
+		{
+#ifdef	LINT
+			lint_ret_conv(expr);
+#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
+		}
+	]
+	';'
+;
+
+jump
+	{	struct idf *idf;
+	}
+:
+	GOTO
+	identifier(&idf)
+	';'
+		{
+			apply_label(idf);
+			C_bra((label)idf->id_def->df_address);
+#ifdef	LINT
+			lint_jump_stmt(idf);
+#endif	LINT
+		}
+;
+
+compound_statement:
+	'{'
+		{
+			stack_level();
+		}
+	[%while ((DOT != IDENTIFIER && AHEAD != ':') ||
+		 (DOT == IDENTIFIER && AHEAD == IDENTIFIER))
+			/* >>> conflict on TYPE_IDENTIFIER, IDENTIFIER */
+		declaration
+	]*
+	[%persistent
+		statement
+	]*
+	'}'
+		{
+			unstack_level();
+		}
+;

+ 15 - 0
lang/cem/cemcom.ansi/stb.c

@@ -0,0 +1,15 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* library routine for copying structs */
+
+__stb(n, f, t)
+	register char *f, *t; register n;
+{
+	if (n > 0)
+		do
+			*t++ = *f++;
+		while (--n);
+}

+ 14 - 0
lang/cem/cemcom.ansi/stmt.str

@@ -0,0 +1,14 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*	S T A T E M E N T - B L O C K   D E F I N I T I O N S	*/
+
+struct stmt_block	{
+	struct stmt_block *next;
+	label st_break;
+	label st_continue;
+};
+
+/* ALLOCDEF "stmt_block" 5 */

+ 499 - 0
lang/cem/cemcom.ansi/struct.c

@@ -0,0 +1,499 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*	ADMINISTRATION OF STRUCT AND UNION DECLARATIONS	*/
+
+#include	"nobitfield.h"
+#include	"debug.h"
+#include	"botch_free.h"
+#include	<alloc.h>
+#include	"arith.h"
+#include	"stack.h"
+#include	"idf.h"
+#include	"def.h"
+#include	"type.h"
+#include	"proto.h"
+#include	"struct.h"
+#include	"field.h"
+#include	"LLlex.h"
+#include	"Lpars.h"
+#include	"align.h"
+#include	"level.h"
+#include	"assert.h"
+#include	"sizes.h"
+#include	"noRoption.h"
+
+/*	Type of previous selector declared with a field width specified,
+	if any.  If a selector is declared with no field with it is set to 0.
+*/
+static field_busy = 0;
+
+extern char options[];
+int lcm();
+
+/*	The semantics of the identification of structure/union tags is
+	obscure.  Some highly regarded compilers are found out to accept,
+	e.g.:
+		f(xp) struct aap *xp;	{
+			struct aap {char *za;};
+			xp->za;
+		}
+	Equally highly regarded software uses this feature, so we shall
+	humbly oblige.
+	The rules we use are:
+	1.	A structure definition applies at the level where it is
+		found, unless there is a structure declaration without a
+		definition on an outer level, in which case the definition
+		is applied at that level.
+	2.	A selector is applied on the same level as on which its
+		structure is being defined.
+
+	If below struct is mentioned, union is implied (and sometimes enum
+	as well).
+*/
+
+add_sel(stp, tp, idf, sdefpp, szp, fd)	/* this is horrible */
+	register struct type *stp;	/* type of the structure */
+	struct type *tp;		/* type of the selector */
+	register struct idf *idf;	/* idf of the selector */
+	struct sdef ***sdefpp;	/* address of hook to selector definition */
+	arith *szp;		/* pointer to struct size upto here */
+	struct field *fd;
+{
+	/*	The selector idf with type tp is added to two chains: the
+		selector identification chain starting at idf->id_sdef,
+		and to the end of the member list starting at stp->tp_sdef.
+		The address of the hook in the latest member (sdef) is
+		given in sdefpp; the hook itself must still be empty.
+	*/
+	arith offset;
+#ifndef NOBITFIELD
+	extern arith add_field();
+#endif NOBITFIELD
+
+	struct tag *tg = stp->tp_idf->id_struct;	/* or union */
+	struct sdef *sdef = idf->id_sdef;
+	register struct sdef *newsdef;
+	int lvl = tg->tg_level;
+	
+#ifndef NOROPTION
+	if (options['R'] && !is_anon_idf(idf))	{
+		/* a K & R test */
+		if (idf->id_struct && idf->id_struct->tg_level == level)
+			warning("%s is also a struct/union tag", idf->id_text);
+	}
+#endif
+
+	if (stp->tp_fund == STRUCT)	{
+#ifndef NOBITFIELD
+		if (fd == 0)	{	/* no field width specified	*/
+			offset = align(*szp, tp->tp_align);
+			field_busy = 0;
+		}
+		else	{
+			/*	if something is wrong, the type of the
+				specified selector remains unchanged; its
+				bitfield specifier, however, is thrown away.
+			*/
+			offset = add_field(szp, fd, &tp, idf, stp);
+		}
+#else NOBITFIELD
+		offset = align(*szp, tp->tp_align);
+		field_busy = 0;
+#endif NOBITFIELD
+	}
+	else	{	/* (stp->tp_fund == UNION)		*/
+		if (fd)	{
+			error("fields not allowed in unions");
+			free_field(fd);
+			fd = 0;
+		}
+		offset = (arith)0;
+	}
+	
+	check_selector(idf, stp);
+#ifndef NOROPTION
+	if (options['R'])	{
+		if (	sdef && sdef->sd_level == lvl &&
+			( sdef->sd_offset != offset ||
+			  !equal_type(sdef->sd_type, tp))
+		)				/* RM 8.5 */
+			warning("selector %s redeclared", idf->id_text);
+	}
+#endif
+
+	newsdef = new_sdef();
+	newsdef->sd_sdef = (struct sdef *) 0;
+
+	/*	link into selector descriptor list of this id
+	*/
+	newsdef->next = sdef;
+	idf->id_sdef = newsdef;
+
+	newsdef->sd_level = lvl;
+	newsdef->sd_idf = idf;
+	newsdef->sd_stype = stp;
+	newsdef->sd_type = tp;
+	newsdef->sd_offset = offset;
+
+#ifndef NOBITFIELD
+	if (tp->tp_fund == FIELD)
+		tp->tp_field->fd_sdef = newsdef;
+#endif NOBITFIELD
+
+	stack_idf(idf, stack_level_of(lvl));
+
+	/*	link into selector definition list of the struct/union
+	*/
+	**sdefpp = newsdef;
+	*sdefpp = &newsdef->sd_sdef;
+
+	/* update the size of the struct/union upward	*/
+	if (stp->tp_fund == STRUCT && fd == 0)	{
+		/*	Note: the case that a bitfield is declared is
+			handled by add_field() !
+		*/
+		*szp = offset + size_of_type(tp, "member");
+		stp->tp_align = lcm(stp->tp_align, tp->tp_align);
+	}
+	else
+	if (stp->tp_fund == UNION)	{
+		arith sel_size = size_of_type(tp, "member");
+
+		if (*szp < sel_size)
+			*szp = sel_size;
+		stp->tp_align = lcm(stp->tp_align, tp->tp_align);
+	}
+}
+
+check_selector(idf, stp)
+	register struct idf *idf;
+	struct type *stp;	/* the type of the struct */
+{
+	/*	checks if idf occurs already as a selector in
+		struct or union *stp.
+	*/
+	register struct sdef *sdef = stp->tp_sdef;
+	
+	while (sdef)	{
+		if (sdef->sd_idf == idf)
+			error("multiple selector %s", idf->id_text);
+		sdef = sdef->sd_sdef;
+	}
+}
+
+declare_struct(fund, idf, tpp)
+	register struct idf *idf;
+	struct type **tpp;
+{
+	/*	A struct, union or enum (depending on fund) with tag (!)
+		idf is declared, and its type (incomplete as it may be) is
+		returned in *tpp.
+		The idf may be missing (i.e. idf == 0), in which case an
+		anonymous struct etc. is defined.
+	*/
+	extern char *symbol2str();
+	register struct tag **tgp;
+	register struct tag *tg;
+
+	if (!idf)
+		idf = gen_idf();
+	tgp = (fund == ENUM ? &idf->id_enum : &idf->id_struct);
+	
+#ifndef NOROPTION
+	if (options['R'] && !is_anon_idf(idf))	{
+		/* a K & R test */
+		if (	fund != ENUM &&
+			idf->id_sdef && idf->id_sdef->sd_level == level
+		)	{
+			warning("%s is also a selector", idf->id_text);
+		}
+		if (	fund == ENUM &&
+			idf->id_def && idf->id_def->df_level == level
+		)	{
+			warning("%s is also a variable", idf->id_text);
+		}
+	}
+#endif
+	
+	tg = *tgp;
+	if (tg && tg->tg_type->tp_size < 0 && tg->tg_type->tp_fund == fund) {
+		/*	An unfinished declaration has preceded it, possibly on
+			an earlier level.  We just fill in the answer.
+		*/
+		if (tg->tg_busy) {
+			error("recursive declaration of struct/union %s",
+				idf->id_text);
+			declare_struct(fund, gen_idf(), tpp);
+		}
+		else {
+#ifndef NOROPTION
+			if (options['R'] && tg->tg_level != level)
+				warning("%s declares %s in different range",
+					idf->id_text, symbol2str(fund));
+#endif
+			*tpp = tg->tg_type;
+		}
+	}
+	else
+	if (tg && tg->tg_level == level)	{
+		/*	There is an already defined struct/union of this name
+			on our level!
+		*/
+		error("redeclaration of struct/union %s", idf->id_text);
+		declare_struct(fund, gen_idf(), tpp);
+		/* to allow a second struct_declaration_pack */
+	}
+	else	{
+		/* The struct is new. */
+		/* Hook in a new struct tag */
+		tg = new_tag();
+		tg->next = *tgp;
+		*tgp = tg;
+		tg->tg_level = level;
+		/* and supply room for a type */
+		tg->tg_type = create_type(fund);
+		tg->tg_type->tp_align =
+			fund == ENUM ? int_align :
+			fund == STRUCT ? struct_align :
+			/* fund == UNION */ union_align;
+		tg->tg_type->tp_idf = idf;
+		*tpp = tg->tg_type;
+		stack_idf(idf, local_level);
+	}
+}
+
+apply_struct(fund, idf, tpp)
+	register struct idf *idf;
+	struct type **tpp;
+{
+	/*	The occurrence of a struct, union or enum (depending on
+		fund) with tag idf is noted. It may or may not have been
+		declared before. Its type (complete or incomplete) is
+		returned in *tpp.
+	*/
+	register struct tag **tgp;
+
+	tgp = (is_struct_or_union(fund) ? &idf->id_struct : &idf->id_enum);
+
+	if (*tgp)
+		*tpp = (*tgp)->tg_type;
+	else
+		declare_struct(fund, idf, tpp);
+}
+
+struct sdef *
+idf2sdef(idf, tp)
+	register struct idf *idf;
+	struct type *tp;
+{
+	/*	The identifier idf is identified as a selector, preferably
+		in the struct tp, but we will settle for any unique
+		identification.
+		If the attempt fails, a selector of type error_type is
+		created.
+	*/
+	register struct sdef **sdefp = &idf->id_sdef, *sdef;
+	
+	/* Follow chain from idf, to meet tp. */
+	while ((sdef = *sdefp))	{
+		if (equal_type(sdef->sd_stype, tp))
+			return sdef;
+		sdefp = &(*sdefp)->next;
+	}
+	
+	/* Tp not met; any unique identification will do. */
+	if (sdef = idf->id_sdef)	{
+		/* There is an identification */
+		if (uniq_selector(sdef))	{
+			/* and it is unique, so we accept */
+			warning("selector %s applied to alien type",
+					idf->id_text);
+		}
+		else	{
+			/* it is ambiguous */
+			error("ambiguous use of selector %s", idf->id_text);
+		}
+		return sdef;
+	}
+	
+	/* No luck; create an error entry. */
+	if (!is_anon_idf(idf))
+		error("unknown selector %s", idf->id_text);
+	*sdefp = sdef = new_sdef();
+	sdef->sd_idf = idf;
+	sdef->sd_stype = sdef->sd_type = error_type;
+	return sdef;
+}
+
+int
+uniq_selector(idf_sdef)
+	register struct sdef *idf_sdef;
+{
+	/*	Returns true if idf_sdef (which is guaranteed to exist)
+		is unique for this level, i.e there is no other selector
+		on this level with the same name or the other selectors
+		with the same name have the same offset.
+		See /usr/src/cmd/sed/sed.h for an example of this absurd
+		case!
+	*/
+	
+	register struct sdef *sdef = idf_sdef->next;
+	
+	while (sdef && sdef->sd_level == idf_sdef->sd_level)	{
+		if (	sdef->sd_type != idf_sdef->sd_type
+		||	sdef->sd_offset != idf_sdef->sd_offset
+		)	{
+			return 0;		/* ambiguity found */
+		}
+		sdef = sdef->next;
+	}
+	return 1;
+}
+
+#ifndef NOBITFIELD
+arith
+add_field(szp, fd, fdtpp, idf, stp)
+	arith *szp;			/* size of struct upto here	*/
+	register struct field *fd;	/* bitfield, containing width	*/
+	register struct type **fdtpp;	/* type of selector		*/
+	struct idf *idf;		/* name of selector		*/
+	register struct type *stp;	/* current struct descriptor	*/
+{
+	/*	The address where this selector is put is returned. If the
+		selector with specified width does not fit in the word, or
+		an explicit alignment is given, a new address is needed.
+		Note that the fields are packed into machine words (according
+		to the RM.)
+	*/
+	long bits_in_type = word_size * 8;
+	static int field_offset = (arith)0;
+	static struct type *current_struct = 0;
+	static long bits_declared;	/* nr of bits used in *field_offset */
+
+	if (current_struct != stp)	{
+		/*	This struct differs from the last one
+		*/
+		field_busy = 0;
+		current_struct = stp;
+	}
+
+	if (	fd->fd_width < 0 ||
+		(fd->fd_width == 0 && !is_anon_idf(idf)) ||
+		fd->fd_width > bits_in_type
+	)	{
+		error("illegal field-width specified");
+		*fdtpp = error_type;
+		return field_offset;
+	}
+
+	switch ((*fdtpp)->tp_fund)	{
+	case CHAR:
+	case SHORT:
+	case INT:
+	case ENUM:
+	case LONG:
+		/* right type; size OK? */
+		if ((*fdtpp)->tp_size > word_size) {
+			error("bit field type %s does not fit in a word",
+				symbol2str((*fdtpp)->tp_fund));
+			*fdtpp = error_type;
+			return field_offset;
+		}
+		break;
+
+	default:
+		/* wrong type altogether */
+		error("field type cannot be %s",
+				symbol2str((*fdtpp)->tp_fund));
+		*fdtpp = error_type;
+		return field_offset;
+	}
+
+	if (field_busy == 0)	{
+		/*	align this selector on the next boundary :
+			the previous selector wasn't a bitfield.
+		*/
+		field_offset = align(*szp, int_align);
+		*szp = field_offset + int_size;
+		stp->tp_align = lcm(stp->tp_align, int_align);
+		bits_declared = (arith)0;
+		field_busy = 1;
+	}
+
+	if (fd->fd_width > bits_in_type - bits_declared)	{
+		/*	field overflow: fetch next memory unit
+		*/
+		field_offset = align(*szp, int_align);
+		*szp = field_offset + int_size;
+		stp->tp_align = lcm(stp->tp_align, int_align);
+		bits_declared = fd->fd_width;
+	}
+	else
+	if (fd->fd_width == 0)
+		/*	next field should be aligned on the next boundary.
+			This will take care that no field will fit in the
+			space allocated upto here.
+		*/
+		bits_declared = bits_in_type + 1;
+	else	/* the bitfield fits in the current field	*/
+		bits_declared += fd->fd_width;
+	
+	/*	Arrived here, the place where the selector is stored in the
+		struct is computed.
+		Now we need a mask to use its value in expressions.
+	*/
+	*fdtpp = construct_type(FIELD, *fdtpp, 0, (arith)0, NO_PROTO);
+	(*fdtpp)->tp_field = fd;
+
+	/*	Set the mask right shifted. This solution avoids the
+		problem of having sign extension when using the mask for
+		extracting the value from the field-int.
+		Sign extension could occur on some machines when shifting
+		the mask to the left.
+	*/
+	fd->fd_mask = (1 << fd->fd_width) - 1;
+
+	if (options['r'])	/* adjust the field at the right	*/
+		fd->fd_shift = bits_declared - fd->fd_width;
+	else			/* adjust the field at the left		*/
+		fd->fd_shift = bits_in_type - bits_declared;
+	
+	return field_offset;
+}
+#endif NOBITFIELD
+
+/* some utilities */
+int
+is_struct_or_union(fund)
+	register int fund;
+{
+	return fund == STRUCT || fund == UNION;
+}
+
+/*	Greatest Common Divisor
+ */
+int
+gcd(m, n)
+	register int m, n;
+{
+	register int r;
+
+	while (n)	{
+		r = m % n;
+		m = n;
+		n = r;
+	}
+	return m;
+}
+
+/*	Least Common Multiple
+ */
+int
+lcm(m, n)
+	register int m, n;
+{
+	return m * (n / gcd(m, n));
+}

+ 30 - 0
lang/cem/cemcom.ansi/struct.str

@@ -0,0 +1,30 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* SELECTOR DESCRIPTOR */
+
+struct sdef	{		/* for selectors */
+	struct sdef *next;
+	int sd_level;
+	struct idf *sd_idf;	/* its name */
+	struct sdef *sd_sdef;	/* the next selector */
+	struct type *sd_stype;	/* the struct it belongs to */
+	struct type *sd_type;	/* its type */
+	arith sd_offset;
+};
+
+/* ALLOCDEF "sdef" 50 */
+
+struct tag	{		/* for struct-, union- and enum tags */
+	struct tag *next;
+	int tg_level;
+	int tg_busy;	/* non-zero during declaration of struct/union pack */
+	struct type *tg_type;
+};
+
+
+/* ALLOCDEF "tag" 50 */
+
+struct sdef *idf2sdef();

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff