--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* L E X I C A L A N A L Y Z E R */
+
+#include "idfsize.h"
+#include "numsize.h"
+#include "strsize.h"
+
+#include <alloc.h>
+#include "input.h"
+#include "arith.h"
+#include "macro.h"
+#include "idf.h"
+#include "LLlex.h"
+#include "Lpars.h"
+#include "class.h"
+#include "bits.h"
+
+#define BUFSIZ 1024
+
+struct token dot;
+
+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 */
+int AccFileSpecifier = 0; /* return filespecifier <...> */
+int LexSave = 0; /* last character read by GetChar */
+extern int InputLevel; /* # of current macro expansions */
+
+char *string_token();
+arith char_constant();
+#define FLG_ESEEN 0x01 /* possibly a floating point number */
+#define FLG_DOTSEEN 0x02 /* certainly a floating point number */
+
+int
+LLlex()
+{
+ return (DOT != EOF) ? GetToken(&dot) : EOF;
+}
+
+
+int
+GetToken(ptok)
+ register struct token *ptok;
+{
+ /* GetToken() 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[BUFSIZ];
+ register int ch, nch;
+
+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 */
+
+ switch (class(ch)) { /* detect character class */
+ case STNL: /* newline, vertical space or formfeed */
+ LineNumber++;
+ return ptok->tk_symb = EOF;
+ case STSKIP: /* just skip the skip characters */
+ goto again;
+ case STGARB: /* garbage character */
+garbage:
+ if (040 < ch && ch < 0177)
+ error("garbage char %c", ch);
+ else
+ error("garbage char \\%03o", ch);
+ goto again;
+ case STSIMP: /* a simple character, no part of compound token*/
+ 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;
+ else if (nch == '=')
+ return ptok->tk_symb = ANDAB;
+ UnGetChar();
+ return ptok->tk_symb = ch;
+ case '+':
+ if (nch == '+')
+ return ptok->tk_symb = PLUSPLUS;
+ else if (nch == '=')
+ return ptok->tk_symb = PLUSAB;
+ UnGetChar();
+ return ptok->tk_symb = ch;
+ case '-':
+ if (nch == '-')
+ return ptok->tk_symb = MINMIN;
+ else if (nch == '>')
+ return ptok->tk_symb = ARROW;
+ else if (nch == '=')
+ return ptok->tk_symb = MINAB;
+ UnGetChar();
+ return ptok->tk_symb = ch;
+ case '<':
+ if (AccFileSpecifier) {
+ UnGetChar(); /* pushback nch */
+ ptok->tk_str =
+ string_token("file specifier", '>');
+ return ptok->tk_symb = FILESPECIFIER;
+ } else if (nch == '<') {
+ if ((nch = GetChar()) == '=')
+ return ptok->tk_symb = LEFTAB;
+ UnGetChar();
+ return ptok->tk_symb = LEFT;
+ } else if (nch == '=')
+ return ptok->tk_symb = LESSEQ;
+ UnGetChar();
+ return ptok->tk_symb = ch;
+ case '=':
+ if (nch == '=')
+ return ptok->tk_symb = EQUAL;
+ UnGetChar();
+ return ptok->tk_symb = ch;
+ case '>':
+ if (nch == '=')
+ return ptok->tk_symb = GREATEREQ;
+ else if (nch == '>') {
+ if ((nch = GetChar()) == '=')
+ return ptok->tk_symb = RIGHTAB;
+ UnGetChar();
+ return ptok->tk_symb = RIGHT;
+ }
+ UnGetChar();
+ return ptok->tk_symb = ch;
+ case '|':
+ if (nch == '|')
+ return ptok->tk_symb = OR;
+ else if (nch == '=')
+ return ptok->tk_symb = ORAB;
+ UnGetChar();
+ return ptok->tk_symb = ch;
+ case '%':
+ if (nch == '=')
+ return ptok->tk_symb = MODAB;
+ UnGetChar();
+ return ptok->tk_symb = ch;
+ case '*':
+ if (nch == '=')
+ return ptok->tk_symb = TIMESAB;
+ UnGetChar();
+ return ptok->tk_symb = ch;
+ case '^':
+ if (nch == '=')
+ return ptok->tk_symb = XORAB;
+ UnGetChar();
+ return ptok->tk_symb = ch;
+ case '/':
+ if (nch == '*' && !InputLevel) {
+ skipcomment();
+ goto again;
+ }
+ else if (nch == '=')
+ return ptok->tk_symb = DIVAB;
+ UnGetChar();
+ return ptok->tk_symb = ch;
+ default:
+ crash("bad class for char 0%o", ch);
+ /* NOTREACHED */
+ }
+ case STCHAR: /* character constant */
+ ptok->tk_val = char_constant("character");
+ return ptok->tk_symb = INTEGER;
+ case STSTR: /* string */
+ ptok->tk_str = string_token("string", '"');
+ return ptok->tk_symb = STRING;
+ case STELL: /* wide character constant/string prefix */
+ nch = GetChar();
+ if (nch == '"') {
+ ptok->tk_str =
+ string_token("wide character string", '"');
+ return ptok->tk_symb = STRING;
+ } else if (nch == '\'') {
+ ptok->tk_val = char_constant("wide character");
+ return ptok->tk_symb = INTEGER;
+ }
+ UnGetChar();
+ /* fallthrough */
+ case STIDF:
+ {
+ extern int idfsize; /* ??? */
+ register char *tg = &buf[0];
+ register char *maxpos = &buf[idfsize];
+ int NoExpandNext = 0;
+
+#define tstmac(bx) if (!(bits[ch] & bx)) goto nomac
+#define cpy *tg++ = ch
+#define load (ch = GetChar()); if (!in_idf(ch)) goto endidf
+
+ if (Unstacked) EnableMacros(); /* unstack macro's when allowed. */
+ if (ch == NOEXPM) {
+ NoExpandNext = 1;
+ ch = GetChar();
+ }
+#ifdef DOBITS
+ cpy; tstmac(bit0); load;
+ cpy; tstmac(bit1); load;
+ cpy; tstmac(bit2); load;
+ cpy; tstmac(bit3); load;
+ cpy; tstmac(bit4); load;
+ cpy; tstmac(bit5); load;
+ cpy; tstmac(bit6); load;
+ cpy; tstmac(bit7); load;
+#endif
+ for(;;) {
+ if (tg < maxpos) {
+ cpy;
+
+ }
+ load;
+ }
+ endidf:
+ /*if (ch != EOI) UnGetChar();*/
+ UnGetChar();
+ *tg++ = '\0'; /* mark the end of the identifier */
+ if (ReplaceMacros) {
+ register struct idf *idef = findidf(buf);
+
+ if (idef && idef->id_macro && !NoExpandNext) {
+ if (replace(idef))
+ goto again;
+ }
+ }
+
+ nomac: /* buf can already be null-terminated. soit */
+ ch = GetChar();
+ while (in_idf(ch)) {
+ if (tg < maxpos) *tg++ = ch;
+ ch = GetChar();
+ }
+ UnGetChar();
+ *tg++ = '\0'; /* mark the end of the identifier */
+
+ NoExpandNext = 0;
+ if (UnknownIdIsZero) {
+ ptok->tk_val = (arith)0;
+ return ptok->tk_symb = INTEGER;
+ }
+ ptok->tk_str = Malloc(tg - buf);
+ strcpy(ptok->tk_str, buf);
+ return IDENTIFIER;
+ }
+ case STNUM: /* a numeric constant */
+ { /* it may only be an integer constant */
+ register int base = 10, val = 0, vch;
+
+ /* Since the preprocessor only knows integers and has
+ * nothing to do with ellipsis we just return when the
+ * pp-number starts with a '.'
+ */
+ if (ch == '.') {
+ return ptok->tk_symb = ch;
+ }
+ if (ch == '0') {
+ ch = GetChar();
+ if (ch == 'x' || ch == 'X') {
+ base = 16;
+ ch = GetChar();
+ } else {
+ base = 8;
+ }
+
+ }
+ while ((vch = val_in_base(ch, base)) >= 0) {
+ val = val * base + vch; /* overflow? nah */
+ ch = GetChar();
+ }
+ while (ch == 'l' || ch == 'L' || ch == 'u' || ch == 'U')
+ ch = GetChar();
+ UnGetChar();
+ ptok->tk_val = val;
+ return ptok->tk_symb = INTEGER;
+ }
+ case STEOI: /* end of text on source file */
+ return ptok->tk_symb = EOF;
+ case STMSPEC:
+ if (!InputLevel) goto garbage;
+ if (ch == TOKSEP) goto again;
+ /* fallthrough shouldn't happen */
+ 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();
+ do {
+ while (c != '*') {
+ if (class(c) == STNL) {
+ ++LineNumber;
+ } else if (c == EOI) {
+ NoUnstack--;
+ return;
+ }
+ c = GetChar();
+ } /* last Character seen was '*' */
+ c = GetChar();
+ } while (c != '/');
+ NoUnstack--;
+}
+
+arith
+char_constant(nm)
+ char *nm;
+{
+ register arith val = 0;
+ register int ch;
+ int size = 0;
+
+ ch = GetChar();
+ if (ch == '\'')
+ error("%s constant too short", nm);
+ else
+ while (ch != '\'') {
+ if (ch == '\n') {
+ error("newline in %s constant", nm);
+ LineNumber++;
+ break;
+ }
+ if (ch == '\\')
+ ch = quoted(GetChar());
+ if (ch >= 128) ch -= 256;
+ if (size < (int)size)
+ val |= ch << 8 * size;
+ size++;
+ ch = GetChar();
+ }
+ if (size > 1)
+ strict("%s constant includes more than one character", nm);
+ if (size > sizeof(arith))
+ error("%s constant too long", nm);
+ return val;
+}
+
+char *
+string_token(nm, stop_char)
+ char *nm;
+{
+ 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') {
+ error("newline in %s", nm);
+ LineNumber++;
+ break;
+ }
+ if (ch == EOI) {
+ error("end-of-file inside %s", nm);
+ break;
+ }
+ if (ch == '\\' && !AccFileSpecifier)
+ ch = quoted(GetChar());
+ str[pos++] = ch;
+ if (pos == str_size)
+ str = Realloc(str, str_size <<= 1);
+ ch = GetChar();
+ }
+ str[pos++] = '\0'; /* for filenames etc. */
+ str = Realloc(str, 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:
+ return is_dig(ch) ? ch - '0' : -1;
+ 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('?');
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* 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.
+*/
+
+/* the structure of a token: */
+struct token {
+ int tok_symb; /* the token itself */
+ union {
+ char *tok_str;
+ arith tok_val; /* for INTEGER */
+ } tok_data;
+};
+
+#include "file_info.h"
+
+#define tk_symb tok_symb
+#define tk_str tok_data.tok_str
+#define tk_val tok_data.tok_val
+
+extern struct token dot;
+
+extern int ReplaceMacros; /* "LLlex.c" */
+extern int AccDefined; /* "LLlex.c" */
+extern int Unstacked; /* "LLlex.c" */
+extern int UnknownIdIsZero; /* "LLlex.c" */
+extern int AccFileSpecifier; /* "LLlex.c" */
+
+extern int NoUnstack; /* buffer.c */
+
+extern int err_occurred; /* "error.c" */
+
+#define DOT dot.tk_symb
+
+#define EOF (-1)
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* PARSER ERROR ADMINISTRATION */
+
+#include "arith.h"
+#include "LLlex.h"
+#include "Lpars.h"
+
+extern char *symbol2str();
+
+LLmessage(tk) {
+ err_occurred = 1;
+ if (tk < 0)
+ error("garbage at end of line");
+ else if (tk) {
+ error("%s missing", symbol2str(tk));
+ if (DOT != EOF) SkipToNewLine(0);
+ DOT = EOF;
+ }
+ else
+ error("%s deleted", symbol2str(DOT));
+}
--- /dev/null
+# MAKEFILE FOR (STAND_ALONE) CEM PREPROCESSOR
+
+EMHOME=../../..
+MODULES=$(EMHOME)/modules
+MODULESLIB=$(MODULES)/lib
+BIN=$(EMHOME)/lib
+MANDIR=$(EMHOME)/man
+
+# Some paths
+
+# Libraries
+SYSLIB = $(MODULESLIB)/libsystem.a
+STRLIB = $(MODULESLIB)/libstring.a
+PRTLIB = $(MODULESLIB)/libprint.a
+ALLOCLIB = $(MODULESLIB)/liballoc.a
+ASSERTLIB = $(MODULESLIB)/libassert.a
+MALLOC = $(MODULESLIB)/malloc.o
+LIBS = $(PRTLIB) $(STRLIB) $(ALLOCLIB) $(MALLOC) $(ASSERTLIB) $(SYSLIB)
+LIB_INCLUDES = -I$(MODULES)/h -I$(MODULES)/pkg
+
+# Where to install the preprocessor
+CEMPP = $(BIN)/ncpp
+
+TABGEN = $(EMHOME)/bin/tabgen
+
+# What C compiler to use and how
+CC = fcc
+COPTIONS =
+LDFLAGS = -i
+
+# What parser generator to use and how
+GEN = $(EMHOME)/bin/LLgen
+GENOPTIONS =
+
+# Special #defines during compilation
+CDEFS = $(LIB_INCLUDES)
+CFLAGS = $(CDEFS) $(COPTIONS) -O# # we cannot pass the COPTIONS to lint!
+
+# Grammar files and their objects
+LSRC = tokenfile.g expression.g
+LCSRC = tokenfile.c expression.c Lpars.c
+LOBJ = tokenfile.o expression.o Lpars.o
+
+# Objects of hand-written C files
+CSRC = LLlex.c LLmessage.c ch7bin.c ch7mon.c domacro.c \
+ error.c idf.c init.c input.c main.c options.c \
+ preprocess.c replace.c skip.c tokenname.c expr.c
+COBJ = LLlex.o LLmessage.o ch7bin.o ch7mon.o domacro.o \
+ error.o idf.o init.o input.o main.o options.o \
+ preprocess.o replace.o skip.o tokenname.o next.o expr.o
+
+PRFILES = Makefile Parameters \
+ make.hfiles make.tokcase make.tokfile LLlex.h bits.h file_info.h \
+ idf.h input.h interface.h macro.str replace.str \
+ class.h char.tab expression.g $(CSRC)
+
+# Objects of other generated C files
+GOBJ = char.o symbol2str.o
+
+# generated source files
+GSRC = char.c symbol2str.c
+
+# .h files generated by `make.allod'
+STRSRC = macro.str replace.str
+GSTRSRC = macro.h replace.h
+
+# .h files generated by `make hfiles'; PLEASE KEEP THIS UP-TO-DATE!
+GHSRC = errout.h idfsize.h ifdepth.h lapbuf.h \
+ nparams.h numsize.h obufsize.h argbuf.h \
+ parbufsize.h pathlength.h strsize.h textsize.h \
+ botch_free.h debug.h inputtype.h dobits.h line_prefix.h
+
+# Other generated files, for 'make clean' only
+GENERATED = tokenfile.g Lpars.h LLfiles LL.output lint.out \
+ Xref hfiles cfiles next.c tags Makefile.old
+
+all: cc
+
+cc: hfiles LLfiles
+ make "EMHOME="$(EMHOME) ncpp
+
+hfiles: Parameters char.c
+ ./make.hfiles Parameters
+ @touch hfiles
+
+.SUFFIXES: .str .h
+.str.h:
+ ./make.allocd <$*.str >$*.h
+
+char.c: char.tab
+ $(TABGEN) -fchar.tab > char.c
+
+next.c: make.next $(STRSRC)
+ ./make.next $(STRSRC) >next.c
+
+macro.h: make.allocd
+repl.h: make.allocd
+
+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
+
+# Objects needed for 'ncpp'
+OBJ = $(COBJ) $(LOBJ) $(GOBJ)
+SRC = $(CSRC) $(LCSRC) $(GSRC)
+
+ncpp: $(OBJ) Makefile
+ $(CC) $(COPTIONS) $(LDFLAGS) $(OBJ) $(LIBS) -o ncpp
+ -size ncpp
+
+cfiles: hfiles LLfiles $(GSRC) $(GSTRSRC)
+ @touch cfiles
+
+install: all
+ rm -f $(CEMPP)
+ cp ncpp $(CEMPP)
+ rm -f $(MANDIR)/ncpp.6
+ cp ncpp.6 $(MANDIR)/ncpp.6
+
+cmp: all
+ -cmp ncpp $(CEMPP)
+ -cmp ncpp.6 $(MANDIR)/ncpp.6
+
+pr:
+ @pr $(PRFILES)
+
+opr:
+ make pr | opr
+
+tags: cfiles
+ ctags $(SRC)
+
+depend: cfiles
+ sed '/^#AUTOAUTO/,$$d' Makefile >Makefile.new
+ echo '#AUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTO' >>Makefile.new
+ $(EMHOME)/bin/mkdep $(SRC) | \
+ sed 's/\.c:/.o:/' >>Makefile.new
+ mv Makefile Makefile.old
+ mv Makefile.new Makefile
+
+xref:
+ ctags -x `grep "\.[ch]" Files`|sed "s/).*/)/">Xref
+
+lint: cfiles
+ lint -bx $(CDEFS) $(SRC) >lint.out
+
+clean:
+ rm -f $(LCSRC) $(OBJ) $(GENERATED) $(GSRC) $(GHSRC) $(GSTRSRC) ncpp Out
+
+#AUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTO
+LLlex.o: LLlex.h
+LLlex.o: Lpars.h
+LLlex.o: arith.h
+LLlex.o: bits.h
+LLlex.o: class.h
+LLlex.o: dobits.h
+LLlex.o: file_info.h
+LLlex.o: idf.h
+LLlex.o: idfsize.h
+LLlex.o: input.h
+LLlex.o: inputtype.h
+LLlex.o: macro.h
+LLlex.o: numsize.h
+LLlex.o: strsize.h
+LLmessage.o: LLlex.h
+LLmessage.o: Lpars.h
+LLmessage.o: file_info.h
+ch7bin.o: Lpars.h
+ch7bin.o: arith.h
+ch7mon.o: Lpars.h
+ch7mon.o: arith.h
+domacro.o: LLlex.h
+domacro.o: Lpars.h
+domacro.o: arith.h
+domacro.o: bits.h
+domacro.o: botch_free.h
+domacro.o: class.h
+domacro.o: dobits.h
+domacro.o: file_info.h
+domacro.o: idf.h
+domacro.o: idfsize.h
+domacro.o: ifdepth.h
+domacro.o: input.h
+domacro.o: inputtype.h
+domacro.o: macro.h
+domacro.o: nparams.h
+domacro.o: parbufsize.h
+domacro.o: textsize.h
+error.o: LLlex.h
+error.o: errout.h
+error.o: file_info.h
+idf.o: idf.h
+init.o: class.h
+init.o: idf.h
+init.o: macro.h
+input.o: file_info.h
+input.o: input.h
+input.o: inputtype.h
+main.o: arith.h
+main.o: file_info.h
+main.o: idfsize.h
+options.o: class.h
+options.o: idf.h
+options.o: idfsize.h
+options.o: macro.h
+preprocess.o: LLlex.h
+preprocess.o: bits.h
+preprocess.o: class.h
+preprocess.o: dobits.h
+preprocess.o: file_info.h
+preprocess.o: idf.h
+preprocess.o: idfsize.h
+preprocess.o: input.h
+preprocess.o: inputtype.h
+preprocess.o: line_prefix.h
+preprocess.o: macro.h
+preprocess.o: obufsize.h
+replace.o: LLlex.h
+replace.o: argbuf.h
+replace.o: class.h
+replace.o: file_info.h
+replace.o: idf.h
+replace.o: idfsize.h
+replace.o: input.h
+replace.o: inputtype.h
+replace.o: lapbuf.h
+replace.o: macro.h
+replace.o: nparams.h
+replace.o: numsize.h
+replace.o: pathlength.h
+replace.o: replace.h
+replace.o: strsize.h
+skip.o: LLlex.h
+skip.o: class.h
+skip.o: file_info.h
+skip.o: input.h
+skip.o: inputtype.h
+tokenname.o: LLlex.h
+tokenname.o: Lpars.h
+tokenname.o: file_info.h
+tokenname.o: idf.h
+expr.o: Lpars.h
+tokenfile.o: Lpars.h
+expression.o: LLlex.h
+expression.o: Lpars.h
+expression.o: arith.h
+expression.o: file_info.h
+Lpars.o: Lpars.h
+char.o: class.h
+symbol2str.o: Lpars.h
--- /dev/null
+!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 */
+#define STDC_NPARAMS 31 /* ANSI limit on number of parameters */
+
+
+!File: ifdepth.h
+#define IFDEPTH 256 /* maximum number of nested if-constructions */
+
+
+!File: lapbuf.h
+#define LAPBUF 4096 /* size of macro actual parameter buffer */
+
+
+!File: argbuf.h
+#define ARGBUF 2048 /* sizeof of macro actual parameter buffer */
+
+
+!File: strsize.h
+#define ISTRSIZE 16 /* minimum number of bytes allocated for
+ storing a string */
+
+
+!File: botch_free.h
+#undef BOTCH_FREE 1 /* botch freed memory, as a check */
+
+
+!File: debug.h
+#define DEBUG 1 /* perform various self-tests */
+
+
+!File: parbufsize.h
+#define PARBUFSIZE 1024
+
+
+!File: textsize.h
+#define ITEXTSIZE 16 /* 1st piece of memory for repl. text */
+
+
+!File: inputtype.h
+#undef INP_READ_IN_ONE 1 /* read input file in one. */
+ /* If defined, we cannot read from a pipe */
+
+
+!File: obufsize.h
+#define OBUFSIZE 8192 /* output buffer size */
+
+
+!File: dobits.h
+#define DOBITS 1 /* use trick to reduce symboltable accesses */
+
+
+!File: line_prefix.h
+#define LINE_PREFIX "#" /* prefix for generated line directives,
+ either "#" or "#line"
+ */
+
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* 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.
+*/
+
+/* All preprocessor arithmetic should be done in longs.
+*/
+#define arith long /* dummy */
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+#include "dobits.h"
+#ifdef DOBITS
+#define bit0 0x01
+#define bit1 0x02
+#define bit2 0x04
+#define bit3 0x08
+#define bit4 0x10
+#define bit5 0x20
+#define bit6 0x40
+#define bit7 0x80
+
+extern char bits[];
+#endif
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* EVALUATION OF BINARY OPERATORS */
+
+#include "Lpars.h"
+#include "arith.h"
+
+ch7bin(pval, oper, val)
+ register arith *pval, val;
+ int oper;
+{
+ switch (oper) {
+ case '%':
+ if (val == 0)
+ error("% by 0");
+ else
+ *pval = *pval % val;
+ break;
+ case '/':
+ if (val == 0)
+ error("/ by 0");
+ else
+ *pval = *pval / val;
+ break;
+ case '*':
+ *pval = *pval * val;
+ break;
+ case '+':
+ *pval = *pval + val;
+ break;
+ case '-':
+ *pval = *pval - val;
+ break;
+ case LEFT:
+ *pval = *pval << val;
+ break;
+ case RIGHT:
+ *pval = *pval >> val;
+ break;
+ case '<':
+ *pval = (*pval < val);
+ break;
+ case '>':
+ *pval = (*pval > val);
+ break;
+ case LESSEQ:
+ *pval = (*pval <= val);
+ break;
+ case GREATEREQ:
+ *pval = (*pval >= val);
+ break;
+ case EQUAL:
+ *pval = (*pval == val);
+ break;
+ case NOTEQUAL:
+ *pval = (*pval != val);
+ break;
+ case '&':
+ *pval = *pval & val;
+ break;
+ case '^':
+ *pval = *pval ^ val;
+ break;
+ case '|':
+ *pval = *pval | val;
+ break;
+ case AND:
+ *pval = (*pval && val);
+ break;
+ case OR:
+ *pval = (*pval || val);
+ break;
+ case ',':
+ *pval = val;
+ break;
+ }
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* EVALUATION OF MONADIC OPERATORS */
+
+#include "Lpars.h"
+#include "arith.h"
+
+ch7mon(oper, pval)
+ register arith *pval;
+{
+ switch (oper) {
+ case '~':
+ *pval = ~(*pval);
+ break;
+ case '-':
+ *pval = -(*pval);
+ break;
+ case '!':
+ *pval = !(*pval);
+ break;
+ }
+}
--- /dev/null
+%
+% 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_\003
+STELL:L
+STNUM:.0-9
+STSTR:"
+STEOI:\200
+STMSPEC:\004
+%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:0-9a-fA-F
+%Tchar ishex[] = {
+%p
+%T};
+%
+% ISOCT
+%
+%C
+1:0-7
+%Tchar isoct[] = {
+%p
+%T};
+%
+% ISWSP
+%
+%C
+1: \t\n
+%Tchar iswsp[] = {
+%p
+%T};
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* 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, as 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 */
+#define STSIMP 3 /* this character can occur as token */
+#define STCOMP 4 /* this one can start a compound token */
+#define STELL 5 /* wide character- or string- constant prefix */
+#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 */
+#define STMSPEC 11 /* special class for token expansion */
+
+#define NOEXPM '\003' /* don't expand the next macro identifier */
+#define TOKSEP '\004' /* the token separator */
+
+/* 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[];
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* PREPROCESSOR: CONTROLLINE INTERPRETER */
+
+#include "arith.h"
+#include "LLlex.h"
+#include "Lpars.h"
+#include "idf.h"
+#include "input.h"
+
+#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"
+#include "bits.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;
+int svnestlevel[30] = {-1};
+int nestcount;
+
+char *
+GetIdentifier(skiponerr)
+ int skiponerr; /* skip the rest of the line on error */
+{
+ /* Returns a pointer to the identifier that is read from the
+ input stream. When the input does not contain an
+ identifier, the rest of the line is skipped when skiponerr
+ is on, and a null-pointer is returned.
+ The substitution of macros is disabled.
+ Remember that on end-of-line EOF is returned.
+ */
+ int tmp = UnknownIdIsZero;
+ int tok;
+ struct token tk;
+
+ UnknownIdIsZero = ReplaceMacros = 0;
+ tok = GetToken(&tk);
+ ReplaceMacros = 1;
+ UnknownIdIsZero = tmp;
+ if (tok != IDENTIFIER) {
+ if (skiponerr && tok != EOF) SkipToNewLine(0);
+ return (char *)0;
+ }
+ return tk.tk_str;
+}
+
+/* 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.
+ Return 1 if the preprocessing directive is done. This is to leave
+ pragma's in the input.
+*/
+int
+domacro()
+{
+ struct token tk; /* the token itself */
+ register struct idf *id;
+ int toknum;
+
+ ReplaceMacros = 0;
+ toknum = GetToken(&tk);
+ ReplaceMacros = 1;
+ switch(toknum) { /* select control line action */
+ case IDENTIFIER: /* is it a macro keyword? */
+ id = findidf(tk.tk_str);
+ if (!id) {
+ error("%s: unknown control", tk.tk_str);
+ SkipToNewLine(0);
+ free(tk.tk_str);
+ break;
+ }
+ free(tk.tk_str);
+ switch (id->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) {
+ error("bad #line syntax");
+ SkipToNewLine(0);
+ }
+ else
+ do_line((unsigned int)tk.tk_val);
+ break;
+ case K_ERROR: /* "error" */
+ do_error();
+ break;
+ case K_PRAGMA: /* "pragma" */
+ return 0; /* this is for the compiler */
+ break;
+ case K_UNDEF: /* "undef" */
+ do_undef();
+ break;
+ default:
+ /* invalid word seen after the '#' */
+ error("%s: unknown control", id->id_text);
+ SkipToNewLine(0);
+ }
+ break;
+ case INTEGER: /* # <integer> [<filespecifier>]? */
+ do_line((unsigned int)tk.tk_val);
+ break;
+ case EOF: /* only `#' on this line: do nothing, ignore */
+ break;
+ default: /* invalid token following '#' */
+ error("illegal # line");
+ SkipToNewLine(0);
+ }
+ return 1;
+}
+
+skip_block(to_endif)
+int to_endif;
+{
+ /* 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;
+ int toknum;
+ struct idf *id;
+
+ NoUnstack++;
+ for (;;) {
+ ch = GetChar(); /* read first character after newline */
+ while (class(ch) == STSKIP)
+ ch = GetChar();
+ if (ch != '#') {
+ if (ch == EOI) {
+ NoUnstack--;
+ return;
+ }
+ UnGetChar();
+ SkipToNewLine(0);
+ continue;
+ }
+ ReplaceMacros = 0;
+ toknum = GetToken(&tk);
+ ReplaceMacros = 1;
+ if (toknum != 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.
+ */
+ id = findidf(tk.tk_str);
+ free(tk.tk_str);
+ switch(id->id_resmac) {
+ default:
+ SkipToNewLine(0);
+ break;
+ case K_IF:
+ case K_IFDEF:
+ case K_IFNDEF:
+ push_if();
+ SkipToNewLine(0);
+ break;
+ case K_ELIF:
+ if (ifstack[nestlevel])
+ error("#elif after #else");
+ if (!to_endif && nestlevel == skiplevel) {
+ nestlevel--;
+ push_if();
+ if (ifexpr()) {
+ NoUnstack--;
+ return;
+ }
+ }
+ else SkipToNewLine(0); /* otherwise done in ifexpr() */
+ break;
+ case K_ELSE:
+ if (ifstack[nestlevel])
+ error("#else after #else");
+ ++(ifstack[nestlevel]);
+ if (!to_endif && nestlevel == skiplevel) {
+ if (SkipToNewLine(1))
+ strict("garbage following #else");
+ NoUnstack--;
+ return;
+ }
+ else SkipToNewLine(0);
+ break;
+ case K_ENDIF:
+ assert(nestlevel > svnestlevel[nestcount]);
+ if (nestlevel == skiplevel) {
+ if (SkipToNewLine(1))
+ strict("garbage following #endif");
+ nestlevel--;
+ NoUnstack--;
+ return;
+ }
+ else SkipToNewLine(0);
+ 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;
+ DOT = 0; /* tricky */
+ If_expr(); /* invoke constant expression 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_str;
+ else {
+ error("bad include syntax");
+ filenm = (char *)0;
+ }
+ AccFileSpecifier = 0;
+ SkipToNewLine(0);
+ inctable[0] = WorkingDir;
+ if (filenm) {
+ if (!InsertFile(filenm, &inctable[tok==FILESPECIFIER],&result)){
+ error("cannot open include file \"%s\"", filenm);
+ }
+ else {
+ WorkingDir = getwdir(result);
+ svnestlevel[++nestcount] = nestlevel;
+ FileName = result;
+ LineNumber = 1;
+ }
+ }
+}
+
+do_define()
+{
+ /* do_define() interprets a #define control line.
+ */
+ register char *str; /* 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 (!(str = GetIdentifier(1))) {
+ error("#define: illegal macro name");
+ 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);
+ free(str);
+ 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 = Malloc(1);
+ *repl_text = '\0';
+ length = 0;
+ }
+ else {
+ UnGetChar();
+ repl_text = get_text((nformals > 0) ? formals : 0, &length);
+ }
+ macro_def(str2idf(str, 0), 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 <= svnestlevel[nestcount]) {
+ error("#elif without corresponding #if");
+ SkipToNewLine(0);
+ }
+ else { /* restart at this level as if a #if is detected. */
+ if (ifstack[nestlevel]) {
+ error("#elif after #else");
+ SkipToNewLine(0);
+ }
+ nestlevel--;
+ push_if();
+ skip_block(1);
+ }
+}
+
+do_else()
+{
+ if (SkipToNewLine(1))
+ strict("garbage following #else");
+ if (nestlevel <= svnestlevel[nestcount])
+ error("#else without corresponding #if");
+ else { /* mark this level as else-d */
+ if (ifstack[nestlevel]) {
+ error("#else after #else");
+ }
+ ++(ifstack[nestlevel]);
+ skip_block(1);
+ }
+}
+
+do_endif()
+{
+ if (SkipToNewLine(1))
+ strict("garbage following #endif");
+ if (nestlevel <= svnestlevel[nestcount]) {
+ error("#endif without corresponding #if");
+ }
+ else nestlevel--;
+}
+
+do_if()
+{
+ push_if();
+ if (!ifexpr()) /* a false #if/#elif expression */
+ skip_block(0);
+}
+
+do_ifdef(how)
+{
+ register struct idf *id;
+ register char *str;
+
+ /* how == 1 : ifdef; how == 0 : ifndef
+ */
+ push_if();
+ if (!(str = GetIdentifier(1))) {
+ error("illegal #ifdef construction");
+ id = (struct idf *)0;
+ } else {
+ id = findidf(str);
+ free(str);
+ }
+
+ /* The next test is a shorthand for:
+ (how && !id->id_macro) || (!how && id->id_macro)
+ */
+ if (how ^ (id && id->id_macro != 0))
+ skip_block(0);
+ else
+ SkipToNewLine(0);
+}
+
+do_undef()
+{
+ register struct idf *id;
+ register char *str;
+
+ /* Forget a macro definition. */
+ if (str = GetIdentifier(1)) {
+ if ((id = findidf(str)) && id->id_macro) {
+ if (id->id_macro->mc_flag & NOUNDEF) {
+ error("it is not allowed to #undef %s", str);
+ } else {
+ free(id->id_macro->mc_text);
+ free_macro(id->id_macro);
+ id->id_macro = (struct macro *) 0;
+ }
+ } /* else: don't complain */
+ free(str);
+ SkipToNewLine(0);
+ }
+ else
+ error("illegal #undef construction");
+}
+
+do_error()
+{
+ static char errbuf[512];
+ register char *bp = errbuf;
+ register int ch;
+
+ while ((ch = GetChar()) != '\n')
+ *bp++ = ch;
+ *bp = '\0';
+ UnGetChar();
+ error("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) {
+ error("#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 != ',') {
+ error("#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.
+ An error is given if there was already a definition
+ */
+ if (newdef) { /* is there a redefinition? */
+ if (newdef->mc_flag & NOUNDEF) {
+ error("it is not allowed to redefine %s", id->id_text);
+ } else if (!macroeq(newdef->mc_text, text))
+ error("illegal redefine of \"%s\"", id->id_text);
+ free(text);
+ return;
+ } else {
+#ifdef DOBITS
+ register char *p = id->id_text;
+#define setbit(bx) if (!*p) goto go_on; bits[*p++] |= (bx)
+ setbit(bit0);
+ setbit(bit1);
+ setbit(bit2);
+ setbit(bit3);
+ setbit(bit4);
+ setbit(bit5);
+ setbit(bit6);
+ setbit(bit7);
+
+ go_on:
+#endif
+ 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 */
+}
+
+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 unsigned 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 <<= 1);
+ 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 <<= 1);
+ 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 <<= 1);
+ text[pos++] = FORMALP | (char) n;
+ }
+ else {
+ register char *ptr = &id_buf[0];
+
+ while (pos + id_size >= text_size)
+ text_size <<= 1;
+ text = Realloc(text, text_size);
+ while (text[pos++] = *ptr++)
+ /* EMPTY */ ;
+ pos--;
+ }
+ }
+ else {
+ if (pos+1 >= text_size)
+ text = Realloc(text, text_size <<= 1);
+ text[pos++] = c;
+ c = GetChar();
+ }
+ }
+ text[pos++] = '\0';
+ text = Realloc(text, pos);
+ *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');
+ }
+}
+
+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_str;
+ SkipToNewLine(0);
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* 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 <system.h>
+#include <varargs.h>
+
+#include "arith.h"
+#include "errout.h"
+#include "LLlex.h"
+
+/* This file contains the (non-portable) error-message and diagnostic
+ functions. Beware, they are called with a variable number of
+ arguments!
+*/
+
+int err_occurred;
+
+err_hdr(s)
+ char *s;
+{
+ if (FileName) {
+ fprint(ERROUT, "\"%s\", line %d: %s", FileName, LineNumber, s);
+ }
+ else fprint(ERROUT, s);
+}
+
+/*VARARGS1*/
+error(va_alist)
+ va_dcl
+{
+ char *fmt;
+ va_list ap;
+
+ err_hdr("");
+ va_start(ap);
+ fmt = va_arg(ap, char *);
+ doprnt(ERROUT, fmt, ap);
+ fprint(ERROUT, "\n");
+ va_end(ap);
+}
+
+/*VARARGS1*/
+warning(va_alist)
+ va_dcl
+{
+ char *fmt;
+ va_list ap;
+
+ err_hdr("(warning) ");
+ va_start(ap);
+ fmt = va_arg(ap, char *);
+ doprnt(ERROUT, fmt, ap);
+ fprint(ERROUT, "\n");
+ va_end(ap);
+}
+
+/*VARARGS1*/
+strict(va_alist)
+ va_dcl
+{
+ char *fmt;
+ va_list ap;
+
+ err_hdr("(strict) ");
+ va_start(ap);
+ fmt = va_arg(ap, char *);
+ doprnt(ERROUT, fmt, ap);
+ fprint(ERROUT, "\n");
+ va_end(ap);
+}
+
+/*VARARGS1*/
+crash(va_alist)
+ va_dcl
+{
+ char *fmt;
+ va_list ap;
+
+ err_hdr("CRASH\007 ");
+ va_start(ap);
+ fmt = va_arg(ap, char *);
+ doprnt(ERROUT, fmt, ap);
+ fprint(ERROUT, "\n");
+ va_end(ap);
+ sys_stop(S_ABORT);
+}
+
+/*VARARGS1*/
+fatal(va_alist)
+ va_dcl
+{
+ char *fmt;
+ va_list ap;
+
+ err_hdr("fatal error -- ");
+ va_start(ap);
+ fmt = va_arg(ap, char *);
+ doprnt(ERROUT, fmt, ap);
+ fprint(ERROUT, "\n");
+ va_end(ap);
+ sys_stop(S_EXIT);
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* OPERATOR HANDLING */
+
+#include "Lpars.h"
+
+int
+rank_of(oper)
+ int oper;
+{
+ /* The rank of the operator oper is returned.
+ */
+ switch (oper) {
+ default:
+ return 0;
+ case '(':
+ return 1;
+ case '!':
+ return 2;
+ 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 ',':
+ return 15;
+ }
+ /*NOTREACHED*/
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* EXPRESSION SYNTAX PARSER */
+
+%lexical LLlex;
+%start If_expr, if_expression;
+
+{
+#include "arith.h"
+#include "LLlex.h"
+
+extern arith ifval;
+}
+
+if_expression
+:
+ constant_expression(&ifval)
+;
+
+/* 7.1 */
+primary(arith *pval;)
+:
+ constant(pval)
+|
+ '(' expression(pval) ')'
+;
+
+unary(arith *pval;)
+ {int oper;}
+:
+ unop(&oper)
+ unary(pval)
+ { ch7mon(oper, pval); }
+|
+ primary(pval)
+;
+
+binary_expression(int maxrank; arith *pval;)
+ {int oper; arith val1;}
+:
+ unary(pval)
+ [%while (rank_of(DOT) <= maxrank)
+ binop(&oper)
+ binary_expression(rank_of(oper)-1, &val1)
+ {
+ ch7bin(pval, oper, val1);
+ }
+ ]*
+;
+
+/* 7.13 */
+conditional_expression(arith *pval;)
+ {arith val1 = 0, val2 = 0;}
+:
+ /* allow all binary operators */
+ binary_expression(rank_of('?') - 1, pval)
+ [ '?'
+ expression(&val1)
+ ':'
+ assignment_expression(&val2)
+ { *pval = (*pval ? val1 : val2); }
+ ]?
+;
+
+/* 7.14 */
+assignment_expression(arith *pval;)
+:
+ conditional_expression(pval)
+;
+
+/* 7.15 */
+expression(arith *pval;)
+ {arith val1;}
+:
+ assignment_expression(pval)
+ [ ','
+ assignment_expression(&val1)
+ {
+ ch7bin(pval, ',', val1);
+ }
+ ]*
+;
+
+unop(int *oper;) :
+ [ '-' | '!' | '~' ]
+ {*oper = DOT;}
+;
+
+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;}
+;
+
+constant(arith *pval;) :
+ INTEGER
+ {*pval = dot.tk_val;}
+;
+
+constant_expression (arith *pval;) :
+ assignment_expression(pval)
+;
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* F I L E I N F O R M A T I O N S T R U C T U R E */
+
+struct file_info {
+ unsigned int fil_lino;
+ char *fil_name;
+ char *fil_wdir;
+};
+
+#define LineNumber finfo.fil_lino
+#define FileName finfo.fil_name
+#define WorkingDir finfo.fil_wdir
+
+extern struct file_info finfo; /* input.c */
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+#include "idf.h"
+#include <idf_pkg.body>
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+struct id_usr {
+ struct macro *idu_macro;
+ int idu_resmac;
+};
+
+#define IDF_TYPE struct id_usr
+#define IDF_HSIZE 6
+#define id_macro id_user.idu_macro
+#define id_resmac id_user.idu_resmac
+
+#include <idf_pkg.spec>
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* PREPROCESSOR: INITIALIZATION ROUTINES */
+
+#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);
+ if (tp->tm_mday < 10) dbuf[5] = ' '; /* hack */
+ macro_def(str2idf("__DATE__", 0), dbuf, -1, strlen(dbuf), NOUNDEF);
+
+ /* __TIME__ */
+ sprintf(tbuf, "\"%.2d:%.2d:%.2d\"", tp->tm_hour, tp->tm_min, tp->tm_sec);
+ macro_def(str2idf("__TIME__", 0), tbuf, -1, strlen(tbuf), NOUNDEF);
+
+ /* __LINE__ */
+ macro_def(str2idf("__LINE__", 0), "0", -1, 1, NOUNDEF | FUNC);
+
+ /* __FILE__ */
+ macro_def(str2idf("__FILE__", 0), "", -1, 1, NOUNDEF | FUNC);
+
+ /* __STDC__ */
+ macro_def(str2idf("__STDC__", 0), "1", -1, 1, NOUNDEF);
+
+ /* defined(??) */
+ macro_def(str2idf("defined", 0), "", 1, 1, NOUNDEF | FUNC);
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+
+#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;
+#include <inp_pkg.body>
+
+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 ".";
+}
+
+int NoUnstack;
+int InputLevel;
+
+AtEoIT()
+{
+ InputLevel--;
+ /* if (NoUnstack) warning("unexpected EOF"); ??? */
+ unstackrepl();
+ return 0;
+}
+
+AtEoIF()
+{
+ extern int nestlevel;
+ extern int nestcount;
+ extern int svnestlevel[];
+
+ if (nestlevel > svnestlevel[nestcount]) warning("missing #endif");
+ else if (NoUnstack) warning("unexpected EOF");
+ nestlevel = svnestlevel[nestcount--];
+ return 0;
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+#define INP_PUSHBACK 3
+#include "inputtype.h"
+#include <inp_pkg.spec>
+
+/* Note: The following macro only garuantees one PushBack.
+*/
+#define UnGetChar() ((LexSave != EOI) ? ChPushBack(LexSave) : 0)
+
+extern int LexSave; /* last character read by GetChar */
+extern int GetChar(); /* character input, with trigraph parsing */
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* PREPROCESSOR: DEFINITION OF MACRO DESCRIPTOR */
+
+/* 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 0x1 /* function attached */
+#define NOUNDEF 0x2 /* reserved macro */
+#define NOREPLACE 0x4 /* prevent recursion */
+
+#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 */
+ 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
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* MAIN PROGRAM */
+
+#include <alloc.h>
+#include <system.h>
+#include "arith.h"
+#include "file_info.h"
+#include "idfsize.h"
+
+extern char *symbol2str();
+extern char *getwdir();
+extern int err_occurred;
+int idfsize = IDFSIZE;
+
+arith ifval;
+
+char *prog_name;
+
+extern char **inctable;
+extern int inc_max, inc_total;
+
+main(argc, argv)
+ char *argv[];
+{
+ /* parse and interpret the command line options */
+ prog_name = argv[0];
+
+ init_idf();
+
+ inctable = (char **) Malloc(10 * sizeof(char *));
+ inc_max = 10;
+ inc_total = 2;
+ inctable[0] = ".";
+ inctable[1] = "/usr/include";
+ init_pp(); /* initialise the preprocessor macros */
+
+ /* Note: source file "-" indicates that the source is supplied
+ as standard input. This is only allowed if INP_READ_IN_ONE is
+ not defined!
+ */
+ while (argc > 1 && *argv[1] == '-' && argv[1][1] != '\0') {
+ char *par = &argv[1][1];
+
+ if (*par == '-')
+ par++;
+ do_option(par);
+ argc--, argv++;
+ }
+ compile(argc - 1, &argv[1]);
+ sys_stop(err_occurred ? S_EXIT : S_END);
+ /*NOTREACHED*/
+}
+
+compile(argc, argv)
+ char *argv[];
+{
+ register char *source = 0;
+ char *dummy;
+
+ switch (argc) {
+ case 1:
+ source = argv[0];
+ FileName = source;
+ break;
+ case 0:
+ FileName = "";
+ WorkingDir = 0;
+ break;
+ default:
+ FileName = argv[0];
+ fatal("use: %s [options] [source]", prog_name);
+ break;
+ }
+
+ if (!InsertFile(source, (char **) 0, &dummy)) /* read the source file */
+ fatal("%s: no source file %s\n", prog_name,
+ source ? source : "stdin");
+ if (source) WorkingDir = getwdir(dummy);
+ preprocess(source);
+}
--- /dev/null
+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))\
+:'
--- /dev/null
+: 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
--- /dev/null
+sed -n '
+s:^.*ALLOCDEF.*"\(.*\)".*$:struct \1 *h_\1 = 0;:p
+' $*
--- /dev/null
+cat <<'--EOT--'
+#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--
--- /dev/null
+sed '
+/{[A-Z]/!d
+s/.*{//
+s/,.*//
+s/.*/%token &;/
+'
--- /dev/null
+.TH NCPP 6ACK
+.ad
+.SH NAME
+ncpp \- New C Pre-Processor
+.SH SYNOPSIS
+ncpp [\-options] [ file ]
+.SH DESCRIPTION
+.I Ncpp
+reads a file, expands macros and include
+files, and writes an input file for the C compiler.
+All output is to standard output.
+.br
+The following options are supported.
+.IP -\fBI\fIdirectory\fR
+.br
+add this directory to the list of
+directories searched for #include "..." and #include <...>
+commands. Note that there is no space between the
+"-I" and the directory string. More than one -I command
+is permitted.
+.IP -\fBI\fR
+end the list of directories to be searched, and also do not look in
+default places.
+.IP -\fBD\fIname\fR=\fItext\fR
+.br
+define
+.I name
+as a macro with
+.I text
+as its replacement text.
+.IP -\fBD\fIname\fR
+the same as -\fBD\fIname\fR=1.
+.IP
+.IP -\fBU\fIname\fR
+.br
+undefine the macro name
+.IR name .
+.IP -\fBC\fR
+leave comments in. By default, C-comments are deleted.
+.IP -\fBP\fR
+do not generate line directives
+.IP -\fBM\fIn\fR
+set maximum identifier length to
+.IR n .
+.PP
+The following names are always available unless undefined:
+.RS
+.IP __STDC__
+A decimal constant 1, indicating that this is an ANSI C conforming
+implementation.
+.IP __FILE__
+The input (or #include) file being compiled
+(as a quoted string).
+.IP __LINE__
+The line number being compiled.
+.IP __DATE__
+The date of translation of the source file. This is a string
+literal of the form "\fBMmm dd yyyy\fP".
+.IP __TIME__
+The time of translation of the source file. This is a string
+literal of the form "\fBhh:mm:ss\fP".
+.RE
+.SH BUGS
+The output may contain extra spaces, this prevents unintended
+pasting of tokens.
+.SH "SEE ALSO"
+L. Rosler,
+.I
+Draft Proposed Standard - Programming Language C,
+.R
+ANSI X3J11 Language Subcommittee
+.SH AUTHOR
+Leendert van Doorn
+
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* USER-OPTION HANDLING */
+
+#include <alloc.h>
+#include "idfsize.h"
+#include "class.h"
+#include "macro.h"
+#include "idf.h"
+
+char options[128]; /* one for every char */
+int inc_pos = 1; /* place where next -I goes */
+int inc_max;
+int inc_total;
+int debug;
+char **inctable;
+
+extern int idfsize;
+int txt2int();
+
+do_option(text)
+ char *text;
+{
+ switch(*text++) {
+ case '-':
+ options[*text] = 1;
+ break;
+ default:
+ error("illegal option: %c", text[-1]);
+ break;
+ case 'C' : /* comment output */
+ options['C'] = 1;
+ break;
+ case 'D' : /* -Dname : predefine name */
+ {
+ 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, 0), mactext, -1, strlen(mactext), NOFLAG);
+ break;
+ }
+ case 'I' : /* -Ipath : insert "path" into include list */
+ if (*text) {
+ register 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) {
+ register char *tmp = inctable[i];
+
+ inctable[i++] = new;
+ new = tmp;
+ }
+ }
+ else inctable[inc_pos] = 0;
+ break;
+ case 'M': /* maximum identifier length */
+ idfsize = txt2int(&text);
+ if (*text)
+ error("malformed -M option");
+ if (idfsize > IDFSIZE) {
+ warning("maximum identifier length is %d", IDFSIZE);
+ idfsize = IDFSIZE;
+ }
+ if (idfsize < 8) {
+ warning("minimum identifier length is 8");
+ idfsize = 8;
+ }
+ break;
+ case 'P' : /* run preprocessor stand-alone, without #'s */
+ options['P'] = 1;
+ break;
+ case 'U' : /* -Uname : undefine predefined */
+ if (*text) {
+ register struct idf *idef = findidf(text);
+
+ if (idef && idef->id_macro) {
+ free_macro(idef->id_macro);
+ idef->id_macro = (struct macro *) 0;
+ }
+ }
+ break;
+ }
+}
+
+int
+txt2int(tp)
+ char **tp;
+{
+ /* the integer pointed to by *tp is read, while increasing
+ *tp; the resulting value is yielded.
+ */
+ register int val = 0;
+ register int ch;
+
+ while (ch = **tp, ch >= '0' && ch <= '9') {
+ val = val * 10 + ch - '0';
+ (*tp)++;
+ }
+ return val;
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* PREPROCESSOR DRIVER */
+
+#include <system.h>
+#include "input.h"
+#include "obufsize.h"
+#include "arith.h"
+#include "LLlex.h"
+#include "class.h"
+#include "macro.h"
+#include "idf.h"
+#include "idfsize.h"
+#include "bits.h"
+#include "line_prefix.h"
+
+char _obuf[OBUFSIZE];
+#ifdef DOBITS
+char bits[128];
+#endif
+extern int InputLevel;
+
+Xflush()
+{
+ sys_write(STDOUT, _obuf, OBUFSIZE);
+}
+
+preprocess(fn)
+ char *fn;
+{
+ register int c;
+ register char *op = _obuf;
+ register char *ob = &_obuf[OBUFSIZE];
+ char Xbuf[256];
+ int lineno = 0;
+ extern char options[];
+
+#define flush(X) (sys_write(STDOUT,_obuf,X))
+#define echo(ch) if (op == ob) { Xflush(); op = _obuf; } *op++ = (ch);
+#define newline() echo('\n')
+
+ if (!options['P']) {
+ /* Generate a line directive communicating the
+ source filename
+ */
+ register char *p = Xbuf;
+
+ sprint(p, "%s 1 \"%s\"\n",
+ LINE_PREFIX,
+ FileName);
+ while (*p) {
+ echo(*p++);
+ }
+ }
+#define do_line(lineno, fn) \
+ if (lineno != LineNumber || fn != FileName) { \
+ fn = FileName; \
+ lineno = LineNumber; \
+ if (! options['P']) { \
+ register char *p = Xbuf; \
+ \
+ sprint(p, "%s %d \"%s\"\n", \
+ LINE_PREFIX, \
+ LineNumber, \
+ FileName); \
+ while (*p) { \
+ echo(*p++); \
+ } \
+ } \
+ }
+
+ for (;;) {
+ LineNumber++;
+ lineno++;
+ c = GetChar();
+ while (class(c) == STSKIP) {
+ echo(c);
+ c = GetChar();
+ }
+
+ while (c == '#') {
+ if (!domacro()) { /* pass pragma's to compiler */
+ register char *p = "#pragma";
+
+ do_line(lineno, fn);
+
+ while(*p) {
+ echo(*p++);
+ }
+ while ((c = GetChar()) != EOI) {
+ if (class(c) == STNL) break;
+ echo(c);
+ }
+ }
+ lineno++;
+ newline();
+ c = GetChar();
+ while (class(c) == STSKIP) {
+ echo(c);
+ c = GetChar();
+ }
+ }
+ do_line(lineno, fn);
+ for (;;) {
+
+ /* illegal character */
+ if (c & 0200) {
+ if (c == EOI) {
+ newline();
+ flush(op-_obuf);
+ return;
+ }
+ fatal("non-ascii character read");
+ }
+
+ /* comments */
+ if (c == '/' && !InputLevel) {
+ c = GetChar();
+ if (c == '*') {
+ NoUnstack++;
+ if (options['C']) {
+ echo('/');
+ echo('*');
+ }
+ for (;;) {
+ c = GetChar();
+ if (c == '\n') {
+ ++LineNumber;
+ ++lineno;
+ echo(c);
+ }
+ else if (c == EOI) {
+ newline();
+ flush(op - _obuf);
+ return;
+ }
+ else if (c == '*') {
+ if (options['C']) {
+ echo(c);
+ }
+ c = GetChar();
+ if (c == '/') {
+ if (options['C']) {
+ echo(c);
+ }
+ break;
+ }
+ else {
+ UnGetChar();
+ }
+ }
+ else if (options['C']) {
+ echo(c);
+ }
+ }
+ NoUnstack--;
+ c = GetChar();
+ continue;
+ }
+ echo('/');
+ continue;
+ }
+
+ /* switch on character */
+ switch(class(c)) {
+ case STNL:
+ echo(c);
+ break;
+ case STSTR:
+ case STCHAR:
+ {
+ register int stopc = c;
+ int escaped;
+
+ do {
+
+ escaped = 0;
+ echo(c);
+ c = GetChar();
+ if (c == '\n') {
+ break;
+ }
+ else if (c == EOI) {
+ newline();
+ flush(op-_obuf);
+ return;
+ }
+ if (c == '\\') {
+ echo(c);
+ c = GetChar();
+ if (c == '\n') {
+ ++LineNumber;
+ lineno++;
+ }
+ else if (c == '\'') escaped = 1;
+ }
+ } while (escaped || c != stopc);
+ echo(c);
+ if (c == '\n')
+ break; /* Don't eat # */
+ c = GetChar();
+ continue;
+ }
+ case STNUM:
+ echo(c);
+ if (c == '.') {
+ c = GetChar();
+ if (c == '.') {
+ if ((c = GetChar()) == '.') {
+ echo('.'); echo('.');
+ continue;
+ }
+ UnGetChar();
+ c = '.';
+ continue;
+ } else if (!is_dig(c)) {
+ continue;
+ }
+ }
+ c = GetChar();
+ while (in_idf(c) || c == '.') {
+ echo(c);
+ if (c == 'e' || c == 'E') {
+ c = GetChar();
+ if (c == '+' || c == '-') {
+ echo(c);
+ c = GetChar();
+ }
+ } else c = GetChar();
+ }
+ continue;
+ case STELL:
+ if (c == '"' || c == '\'') {
+ echo(c);
+ continue;
+ }
+ UnGetChar();
+ c = 'L';
+ case STIDF: {
+ extern int idfsize; /* ??? */
+ char buf[IDFSIZE + 1];
+ register char *tg = &buf[0];
+ register char *maxpos = &buf[idfsize];
+ register struct idf *idef;
+ int NoExpandNext = 0;
+
+#define tstmac(bx) if (!(bits[c] & bx)) goto nomac
+#define cpy *tg++ = c
+#define load c = GetChar(); if (!in_idf(c)) goto endidf
+
+ /* unstack macro's when allowed. */
+ if (Unstacked)
+ EnableMacros();
+ if (c == NOEXPM) {
+ NoExpandNext = 1;
+ c = GetChar();
+ }
+
+#ifdef DOBITS
+ cpy; tstmac(bit0); load;
+ cpy; tstmac(bit1); load;
+ cpy; tstmac(bit2); load;
+ cpy; tstmac(bit3); load;
+ cpy; tstmac(bit4); load;
+ cpy; tstmac(bit5); load;
+ cpy; tstmac(bit6); load;
+ cpy; tstmac(bit7); load;
+#endif
+
+ for(;;) {
+ if (tg < maxpos) {
+ cpy;
+ }
+ load;
+ }
+ endidf:
+ if (c != EOF) UnGetChar();
+ *tg = '\0'; /* mark the end of the identifier */
+ if ((idef = findidf(buf))
+ && idef->id_macro
+ && ReplaceMacros && !NoExpandNext) {
+ if (replace(idef)) {
+ c = GetChar();
+ continue;
+ }
+ tg = buf;
+ while (*tg) {
+ echo(*tg++);
+ }
+ c = GetChar();
+ if (in_idf(c)) echo(' ');
+ continue;
+ }
+ nomac:
+ *tg = '\0';
+ tg = buf;
+ while (*tg) {
+ echo(*tg++);
+ }
+ c = GetChar();
+ while (in_idf(c)) {
+ echo(c);
+ c = GetChar();
+ }
+ continue;
+ }
+ case STMSPEC:
+ if (InputLevel) {
+ echo(' '); /* seperate tokens */
+ c = GetChar();
+ continue;
+ }
+ /* else fallthrough */
+ default:
+ echo(c);
+ c = GetChar();
+ continue;
+ }
+ break;
+ }
+ }
+ /*NOTREACHED*/
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* M A C R O R E P L A C E M E N T */
+
+#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 "lapbuf.h"
+#include "argbuf.h"
+#include "replace.h"
+
+extern char *GetIdentifier();
+extern int InputLevel;
+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;
+
+ if (!(idf->id_macro)) return 0;
+ if (idf->id_macro->mc_flag & NOREPLACE)
+ return 0;
+ repl = new_repl();
+ repl->r_ptr = repl->r_text;
+ repl->r_args = new_args();
+ repl->r_idf = idf;
+ if (!expand_macro(repl, idf))
+ return 0;
+ InputLevel++;
+ InsertText(repl->r_text, repl->r_ptr - repl->r_text);
+ idf->id_macro->mc_flag |= NOREPLACE;
+ repl->r_level = InputLevel;
+ repl->next = ReplaceList;
+ ReplaceList = repl;
+ return 1;
+}
+
+unstackrepl()
+{
+ Unstacked++;
+}
+
+EnableMacros()
+{
+ register struct repl *r = ReplaceList, *prev = 0;
+
+ assert(Unstacked > 0);
+ while(r) {
+ struct repl *nxt = r->next;
+
+ if (r->r_level > InputLevel) {
+ r->r_idf->id_macro->mc_flag &= ~NOREPLACE;
+ if (!prev) ReplaceList = nxt;
+ else prev->next = nxt;
+ free_args(r->r_args);
+ free_repl(r);
+ }
+ else prev = r;
+ r = nxt;
+ }
+ Unstacked = 0;
+}
+
+expand_macro(repl, idf)
+ register struct repl *repl;
+ register struct idf *idf;
+{
+ /* 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.
+
+ A special case is "defined". This acts as a unary operator
+ on a single, unexpanded identifier, which may be surrounded
+ by parenthesis. The function expand_defined() handles this.
+ */
+ 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;
+ expand_defined(repl);
+ return 1;
+ }
+
+ ch = GetChar();
+ ch = skipspaces(ch,1);
+ if (ch != '(') { /* no replacement if no () */
+ UnGetChar();
+ return 0;
+ } else
+ getactuals(repl, idf);
+
+ }
+
+ if (mac->mc_flag & FUNC) /* this macro leads to special action */
+ macro_func(idf);
+
+ 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.
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^ tsk tsk tsk
+ */
+ if (*repl->r_ptr != TOKSEP) *repl->r_ptr++ = TOKSEP;
+ *repl->r_ptr = '\0';
+
+ return 1;
+}
+
+expand_defined(repl)
+ register struct repl *repl;
+{
+ register int ch = GetChar();
+ struct idf *id;
+ char *str;
+ int parens = 0;
+
+ ch = skipspaces(ch, 0);
+
+ if (ch == '(') {
+ parens++;
+ ch = GetChar();
+ ch = skipspaces(ch, 0);
+ }
+ if ((class(ch) != STIDF) && (class(ch) != STELL)) {
+ error("identifier missing");
+ if (parens && ch != ')') error(") missing");
+ if (!parens || ch != ')') UnGetChar();
+ *repl->r_ptr++ = '0';
+ *repl->r_ptr = '\0';
+ return;
+ }
+ UnGetChar();
+ str = GetIdentifier(0);
+ if (str)
+ id = str2idf(str, 0);
+ else id = 0;
+ assert(id || class(ch) == STELL);
+ ch = GetChar();
+ ch = skipspaces(ch, 0);
+ if (parens && ch != ')') error(") missing");
+ if (!parens || ch != ')') UnGetChar();
+ *repl->r_ptr++ = (id && id->id_macro) ? '1' : '0';
+ *repl->r_ptr = '\0';
+}
+
+getactuals(repl, idf)
+ struct repl *repl;
+ 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 struct args *args = repl->r_args;
+ 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()) != ')') {
+ UnGetChar();
+ while ((ch = actual(repl)) != ')' ) {
+ if (ch != ',') {
+ error("illegal macro call");
+ return;
+ }
+ stash(repl, '\0', 1);
+ ++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(repl, '\0', 1);
+ ++argcnt;
+ }
+ if (argcnt < nps)
+ error("too few macro arguments");
+ else if (argcnt > nps)
+ error("too many macro arguments");
+}
+
+saveraw(repl)
+struct repl *repl;
+{
+ register struct repl *nrepl = ReplaceList;
+ register struct args *ap = nrepl->r_args;
+ struct args *args = repl->r_args;
+ register char *p;
+
+ /* stash identifier name */
+ for (p = nrepl->r_idf->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-1) = ')'; /* delete last ',' */
+ }
+}
+
+int
+actual(repl)
+ struct repl *repl;
+{
+ /* This routine deals with the scanning of an actual parameter.
+ It keeps in account the opening and closing brackets,
+ preprocessor numbers, strings and character constants.
+ */
+ register int ch;
+ register int level = 0, nostashraw = 0;
+
+ while (1) {
+ ch = GetChar();
+
+ if (Unstacked) {
+ nostashraw -= Unstacked;
+ if (nostashraw < 0) nostashraw = 0;
+ EnableMacros();
+ }
+ 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;
+ extern int idfsize;
+ int NoExpandMacro;
+
+ if (ch == NOEXPM) {
+ NoExpandMacro= 1;
+ ch = GetChar();
+ } else NoExpandMacro = 0;
+
+ do {
+ if (++pos < idfsize) {
+ *p++ = ch;
+ }
+ ch = GetChar();
+ } while (in_idf(ch));
+ *p++ = '\0';
+ UnGetChar();
+
+ /* When the identifier has an associated macro
+ replacement list, it's expanded.
+ */
+ idef = findidf(buf);
+ if (!idef || NoExpandMacro || !replace(idef)) {
+ if (NoExpandMacro
+ || (idef && idef->id_macro
+ && (idef->id_macro->mc_flag & NOREPLACE)))
+ stash(repl, NOEXPM, !nostashraw);
+ for (p = buf; *p != '\0'; p++)
+ stash(repl, *p, !nostashraw);
+ } else {
+ if (!nostashraw) saveraw(repl);
+ nostashraw++;
+ }
+ } else if (class(ch) == STNUM) {
+ /* a preprocessing number has the following
+ regular expression:
+ [0-9|"."[0-9]]{[0-9"."a-zA-Z_]|{[Ee][+-]}}*
+ */
+ stash(repl, ch, !nostashraw);
+ if (ch == '.') {
+ ch = GetChar();
+ if (class(ch) != STNUM) {
+ UnGetChar();
+ continue;
+ }
+ else stash(repl, ch, !nostashraw);
+ }
+ ch = GetChar();
+ while (in_idf(ch) || ch == '.') {
+ stash(repl, ch, !nostashraw);
+ if ((ch = GetChar()) == 'e' || ch == 'E') {
+ stash(repl, ch, !nostashraw);
+ ch = GetChar();
+ if (ch == '+' || ch == '-') {
+ stash(repl, ch, !nostashraw);
+ ch = GetChar();
+ }
+ }
+ }
+ UnGetChar();
+ } else if (ch == '(' || ch == '[' || ch == '{') {
+ /* a comma may occur within these constructions ???
+ */
+ level++;
+ stash(repl, ch, !nostashraw);
+ } else if (ch == ')' || ch == ']' || ch == '}') {
+ level--;
+ /* clossing parenthesis of macro call */
+ if (ch == ')' && level < 0)
+ return ')';
+ stash(repl, ch, !nostashraw);
+ } else if (ch == ',') {
+ if (level <= 0) { /* comma separator for next argument */
+ if (level)
+ error("unbalanced parenthesis");
+ if (!nostashraw)
+ return ','; /* ??? */
+ }
+ stash(repl, ch, !nostashraw);
+ } else if (ch == '\n') {
+ /* newlines are accepted as white spaces */
+ LineNumber++;
+ while ((ch = GetChar()), class(ch) == STSKIP)
+ /* EMPTY */;
+
+ /* 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();
+ else if (ch == EOI) {
+ error("unterminated macro call");
+ return ')';
+ }
+ UnGetChar();
+ stash(repl, ' ', !nostashraw);
+ } else if (ch == '/') {
+ /* comments are treated as one white space token */
+ if ((ch = GetChar()) == '*' && !InputLevel) {
+ skipcomment();
+ stash(repl, ' ', !nostashraw);
+ } else {
+ UnGetChar();
+ stash(repl, '/', !nostashraw);
+ }
+ } else if (ch == '\'' || ch == '"') {
+ /* Strings are considered as ONE token, thus no
+ replacement within strings.
+ */
+ register int match = ch;
+
+ stash(repl, ch, !nostashraw);
+ while ((ch = GetChar()) != EOI) {
+ if (ch == match)
+ break;
+ if (ch == '\\') {
+ stash(repl, ch, !nostashraw);
+ ch = GetChar();
+ } else if (ch == '\n') {
+ error("newline in string");
+ LineNumber++;
+ stash(repl, match, !nostashraw);
+ break;
+ }
+ stash(repl, ch, !nostashraw);
+ }
+ if (ch != match) {
+ error("unterminated macro call");
+ return ')';
+ }
+ stash(repl, ch, !nostashraw);
+ } else
+ stash(repl, ch, !nostashraw);
+ }
+}
+
+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 = strlen(mac->mc_text);
+ 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;
+ register char *tmpptr;
+ int err = 0;
+ 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') {
+ error("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
+ && is_wsp(*repl->r_text)) {
+ err = 1;
+ break;
+ }
+
+ while(*repl->r_ptr == TOKSEP
+ && repl->r_ptr >= repl->r_text)
+ --repl->r_ptr;
+
+ tmpptr = repl->r_ptr;
+ ++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];
+ if (p) { /* else macro argument missing */
+ while (is_wsp(*p))
+ p++;
+ if (*p == NOEXPM) p++;
+ while (*p)
+ *repl->r_ptr++ = *p++;
+ }
+ if (in_idf(*tmpptr + 1)) {
+ while (in_idf(*tmpptr)
+ && tmpptr >= repl->r_text)
+ tmpptr--;
+ if (*tmpptr == NOEXPM) *tmpptr = TOKSEP;
+ }
+ } else if (*ptr == '\0') {
+ err = 1;
+ break;
+ } else {
+ if (in_idf(*ptr)) {
+ while (in_idf(*tmpptr)
+ && tmpptr >= repl->r_text)
+ tmpptr--;
+ if (*tmpptr == NOEXPM) *tmpptr = TOKSEP;
+ }
+ }
+ } else /* # operator */
+ 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++)
+ /* EMPTY */;
+ if (*p == '#' && p[1] == '#')
+ q = args->a_rawvec[n-1];
+ else
+ q = args->a_expvec[n-1];
+
+ p = repl->r_ptr;
+ if (q) /* else macro argument missing */
+ while (*q)
+ *repl->r_ptr++ = *q++;
+
+ if (*repl->r_ptr != TOKSEP)
+ *repl->r_ptr++ = TOKSEP;
+ } else
+ *repl->r_ptr++ = *ptr++;
+ }
+ *repl->r_ptr = '\0';
+ if (err)
+ error("illegal use of ## operator");
+}
+
+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_rawvec[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++ = '\\';
+ if (*p == TOKSEP || *p == NOEXPM) p++;
+ else *repl->r_ptr++ = *p++;
+ }
+
+ /* trim spaces in the replacement list */
+ for (--repl->r_ptr; is_wsp(*repl->r_ptr); repl->r_ptr--)
+ /* EMPTY */;
+ *++repl->r_ptr = '"';
+ ++repl->r_ptr; /* oops, one to far */
+ } else
+ error("illegal use of # operator");
+ *repl->r_ptr = '\0';
+ return ptr;
+}
+
+stash(repl, ch, stashraw)
+ struct repl *repl;
+ register int ch;
+ int stashraw;
+{
+ /* Stash characters into the macro expansion buffer.
+ */
+ register struct args *args = repl->r_args;
+
+ if (args->a_expptr >= &(args->a_expbuf[ARGBUF]))
+ fatal("macro argument buffer overflow");
+ *args->a_expptr++ = ch;
+
+ if (stashraw) {
+ if (args->a_rawptr >= &(args->a_rawbuf[ARGBUF]))
+ fatal("raw macro argument buffer overflow");
+ *args->a_rawptr++ = ch;
+ }
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* DEFINITIONS FOR THE MACRO REPLACEMENT ROUTINES */
+
+struct repl {
+ struct repl *next;
+ struct idf *r_idf; /* name of the macro */
+ struct args *r_args; /* replacement parameters */
+ int r_level; /* level of insertion */
+ char *r_ptr; /* replacement text pointer */
+ char r_text[LAPBUF]; /* replacement text */
+};
+
+/* 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
+
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* PREPROCESSOR: INPUT SKIP FUNCTIONS */
+
+#include "arith.h"
+#include "LLlex.h"
+#include "class.h"
+#include "input.h"
+
+extern int InputLevel;
+
+int
+skipspaces(ch, skipnl)
+ register int ch;
+{
+ /* skipspaces() skips any white space and returns the first
+ non-space character.
+ */
+ register int nlseen = 0;
+
+ for (;;) {
+ while (class(ch) == STSKIP)
+ ch = GetChar();
+ if (skipnl && class(ch) == STNL) {
+ ch = GetChar();
+ LineNumber++;
+ nlseen++;
+ continue;
+ }
+ if (ch == TOKSEP && InputLevel) {
+ ch = GetChar();
+ continue;
+ }
+
+ /* \\\n are handled by trigraph */
+
+ if (ch == '/') {
+ ch = GetChar();
+ if (ch == '*' && !InputLevel) {
+ skipcomment();
+ ch = GetChar();
+ }
+ else {
+ UnGetChar();
+ return '/';
+ }
+ }
+ else if (nlseen && ch == '#') {
+ domacro();
+ ch = GetChar();
+ } else
+ return ch;
+ }
+}
+
+SkipToNewLine(garbage)
+ int garbage;
+{
+ register int ch;
+ register int pstrict = 0;
+
+ while ((ch = GetChar()) != '\n') {
+ if (ch == '/') {
+ if ((ch = GetChar()) == '*' && !InputLevel) {
+ skipcomment();
+ continue;
+ }
+ }
+ if (garbage && !is_wsp(ch))
+ pstrict = 1;
+ }
+ ++LineNumber;
+ return pstrict;
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* TOKEN NAME DEFINITIONS */
+
+#include "idf.h"
+#include "arith.h"
+#include "LLlex.h"
+#include "Lpars.h"
+
+
+struct tokenname { /* Used for defining the name of a
+ token as identified by its symbol
+ */
+ int tn_symbol;
+ char *tn_name;
+};
+
+
+/* To centralize the declaration of %tokens, their presence in this
+ file is taken as their declaration. The Makefile will produce
+ a grammar file (tokenfile.g) from this file.
+ Moreover, rather than looking up a symbol in all these lists
+ to find its printable name, a fast version of symbol2str() is
+ generated from these tables.
+ Consequenty some of these tables are not referenced explicitly
+ in the C text any more. To save space and to avoid lint confusion,
+ these have been made pseudo-invisible by #ifdefs.
+*/
+
+#ifdef ____
+struct tokenname tkspec[] = { /* the names of the special tokens */
+ {IDENTIFIER, "identifier"},
+ {STRING, "string"},
+ {FILESPECIFIER, "filespecifier"},
+ {INTEGER, "integer"},
+ {0, ""}
+};
+
+struct tokenname tkcomp[] = { /* names of the composite tokens */
+ {PLUSAB, "+="},
+ {MINAB, "-="},
+ {TIMESAB, "*="},
+ {DIVAB, "/="},
+ {MODAB, "%="},
+ {LEFTAB, "<<="},
+ {RIGHTAB, ">>="},
+ {ANDAB, "&="},
+ {XORAB, "^="},
+ {ORAB, "|="},
+ {NOTEQUAL, "!="},
+ {AND, "&&"},
+ {PLUSPLUS, "++"},
+ {MINMIN, "--"},
+ {ARROW, "->"},
+ {LEFT, "<<"},
+ {LESSEQ, "<="},
+ {EQUAL, "=="},
+ {GREATEREQ, ">="},
+ {RIGHT, ">>"},
+ {OR, "||"},
+ {ELLIPSIS, "..."},
+ {0, ""}
+};
+
+struct tokenname tkfunny[] = { /* internal keywords */
+ {ERRONEOUS, "erroneous"},
+ {0, ""}
+};
+#endif ____