--- /dev/null
+/* $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 "idf.h"
+#include "LLlex.h"
+#include "Lpars.h"
+#include "class.h"
+#include "bits.h"
+
+/* Data about the token yielded */
+struct token dot;
+
+int ReplaceMacros = 1; /* replacing macros */
+int AccFileSpecifier = 0; /* return filespecifier <...> */
+int AccDefined = 0; /* accept "defined(...)" */
+int UnknownIdIsZero = 0; /* interpret unknown id as integer 0 */
+
+char *string_token();
+
+PushLex()
+{
+ DOT = 0;
+}
+
+PopLex()
+{}
+
+int
+LLlex()
+{
+ return (DOT != EOF) ? GetToken(&dot) : EOF;
+}
+
+#define BUFSIZ 1024
+
+int
+GetToken(ptok)
+ register struct token *ptok;
+{
+ char buf[BUFSIZ];
+ register int c, nch;
+
+again: /* rescan the input after an error or replacement */
+ LoadChar(c);
+go_on:
+ if ((c & 0200) && c != EOI)
+ fatal("non-ascii '\\%03o' read", c & 0377);
+ switch (class(c)) { /* detect character class */
+ case STNL:
+ LineNumber++;
+ return ptok->tk_symb = EOF;
+ case STSKIP:
+ goto again;
+ case STGARB: /* garbage character */
+ if (c == '\\') {
+ /* a '\\' is allowed in #if/#elif expression */
+ LoadChar(c);
+ if (class(c) == STNL) { /* vt , ff ? */
+ ++LineNumber;
+ goto again;
+ }
+ PushBack();
+ c = '\\';
+ }
+ if (040 < c && c < 0177)
+ error("garbage char %c", c);
+ else
+ error("garbage char \\%03o", c);
+ goto again;
+ case STSIMP: /* a simple character, no part of compound token*/
+ if (c == '/') { /* probably the start of comment */
+ LoadChar(c);
+ if (c == '*') { /* start of comment */
+ skipcomment();
+ goto again;
+ }
+ else {
+ PushBack();
+ c = '/'; /* restore c */
+ }
+ }
+ return ptok->tk_symb = c;
+ case STCOMP: /* maybe the start of a compound token */
+ LoadChar(nch); /* character lookahead */
+ switch (c) {
+ case '!':
+ if (nch == '=')
+ return ptok->tk_symb = NOTEQUAL;
+ PushBack();
+ return ptok->tk_symb = c;
+ case '&':
+ if (nch == '&')
+ return ptok->tk_symb = AND;
+ PushBack();
+ return ptok->tk_symb = c;
+ case '<':
+ if (AccFileSpecifier) {
+ PushBack(); /* pushback nch */
+ ptok->tk_str =
+ string_token("file specifier", '>');
+ return ptok->tk_symb = FILESPECIFIER;
+ }
+ if (nch == '<')
+ return ptok->tk_symb = LEFT;
+ if (nch == '=')
+ return ptok->tk_symb = LESSEQ;
+ PushBack();
+ return ptok->tk_symb = c;
+ case '=':
+ if (nch == '=')
+ return ptok->tk_symb = EQUAL;
+ /* The following piece of code tries to recognise
+ old-fashioned assignment operators `=op'
+ */
+ error("illegal character");
+ goto go_on;
+ case '>':
+ if (nch == '=')
+ return ptok->tk_symb = GREATEREQ;
+ if (nch == '>')
+ return ptok->tk_symb = RIGHT;
+ PushBack();
+ return ptok->tk_symb = c;
+ case '|':
+ if (nch == '|')
+ return ptok->tk_symb = OR;
+ PushBack();
+ return ptok->tk_symb = c;
+ }
+ case STIDF:
+ {
+ extern int idfsize; /* ??? */
+ register char *tg = &buf[0];
+ register char *maxpos = &buf[idfsize];
+ register struct idf *idef;
+
+#define tstmac(bx) if (!(bits[c] & bx)) goto nomac
+#define cpy if (Unstacked) EnableMacros(); *tg++ = c
+#define load LoadChar(c); if (!in_idf(c)) goto endidf
+
+#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:
+ PushBack();
+ *tg = '\0'; /* mark the end of the identifier */
+ if (ReplaceMacros) {
+ idef = findidf(buf);
+ if ((idef && idef->id_macro && replace(idef))) {
+ goto again;
+ }
+ }
+ nomac:
+ LoadChar(c);
+ while (in_idf(c)) {
+ if (tg < maxpos) *tg++ = c;
+ LoadChar(c);
+ }
+ PushBack();
+ *tg++ = '\0'; /* mark the end of the identifier */
+ if (UnknownIdIsZero) {
+ ptok->tk_val = 0;
+ return ptok->tk_symb = INTEGER;
+ }
+ ptok->tk_str = Malloc(idfsize + 1);
+ strcpy(ptok->tk_str, buf);
+ return ptok->tk_symb = IDENTIFIER;
+ }
+ case STCHAR: /* character constant */
+ {
+ register int val = 0, size = 0;
+
+ LoadChar(c);
+ if (c == '\'')
+ error("character constant too short");
+ else
+ while (c != '\'') {
+ if (c == '\n') {
+ error("newline in character constant");
+ LineNumber++;
+ break;
+ }
+ if (c == '\\') {
+ LoadChar(c);
+ if (c == '\n') {
+ LoadChar(c);
+ LineNumber++;
+ continue;
+ }
+ c = quoted(c);
+ }
+ val = val*256 + c;
+ size++;
+ LoadChar(c);
+ }
+ if (size > sizeof(int))
+ error("character constant too long");
+ ptok->tk_val = val;
+ return ptok->tk_symb = INTEGER;
+ }
+ case STNUM:
+ {
+ register char *np = &buf[1];
+ register int base = 10;
+ register int vch;
+ register int val = 0;
+
+ if (c == '0') {
+ *np++ = c;
+ LoadChar(c);
+ if (c == 'x' || c == 'X') {
+ base = 16;
+ LoadChar(c);
+ }
+ else
+ base = 8;
+ }
+ while (vch = val_in_base(c, base), vch >= 0) {
+ val = val*base + vch;
+ if (np < &buf[NUMSIZE])
+ *np++ = c;
+ LoadChar(c);
+ }
+ if (c == 'l' || c == 'L')
+ LoadChar(c);
+ PushBack();
+ ptok->tk_val = val;
+ return ptok->tk_symb = INTEGER;
+ }
+ case STSTR:
+ ptok->tk_str = string_token("string", '"');
+ return ptok->tk_symb = STRING;
+ case STEOI: /* end of text on source file */
+ return ptok->tk_symb = EOF;
+ default:
+ crash("Impossible character class");
+ }
+ /*NOTREACHED*/
+}
+
+skipcomment()
+{
+ register int c;
+
+ NoUnstack++;
+ LoadChar(c);
+ do {
+ while (c != '*') {
+ if (class(c) == STNL)
+ ++LineNumber;
+ else
+ if (c == EOI) {
+ NoUnstack--;
+ return;
+ }
+ LoadChar(c);
+ }
+ /* Last Character seen was '*' */
+ LoadChar(c);
+ } while (c != '/');
+ NoUnstack--;
+}
+
+char *
+string_token(nm, stop_char)
+ char *nm;
+{
+ register int c;
+ register int str_size;
+ register char *str = Malloc(str_size = ISTRSIZE);
+ register int pos = 0;
+
+ LoadChar(c);
+ while (c != stop_char) {
+ if (c == '\n') {
+ error("newline in %s", nm);
+ LineNumber++;
+ break;
+ }
+ if (c == EOI) {
+ error("end-of-file inside %s", nm);
+ break;
+ }
+ if (c == '\\') {
+ LoadChar(c);
+ if (c == '\n') {
+ LineNumber++;
+ LoadChar(c);
+ continue;
+ }
+ c = quoted(c);
+ }
+ str[pos++] = c;
+ if (pos == str_size)
+ str = Srealloc(str, str_size += RSTRSIZE);
+ LoadChar(c);
+ }
+ str[pos++] = '\0'; /* for filenames etc. */
+ return str;
+}
+
+int
+quoted(c)
+ register int c;
+{
+ /* quoted() replaces an escaped character sequence by the
+ character meant.
+ */
+ /* first char after backslash already in c */
+ if (!is_oct(c)) { /* a quoted char */
+ switch (c) {
+ case 'n':
+ c = '\n';
+ break;
+ case 't':
+ c = '\t';
+ break;
+ case 'b':
+ c = '\b';
+ break;
+ case 'r':
+ c = '\r';
+ break;
+ case 'f':
+ c = '\f';
+ break;
+ }
+ }
+ else { /* a quoted octal */
+ register int oct = 0, cnt = 0;
+
+ do {
+ oct = oct*8 + (c-'0');
+ LoadChar(c);
+ } while (is_oct(c) && ++cnt < 3);
+ PushBack();
+ c = oct;
+ }
+ return c&0377;
+}
+
+/* provisional */
+int
+val_in_base(c, base)
+ register int c;
+{
+ return
+ is_dig(c) ? c - '0' :
+ base != 16 ? -1 :
+ is_hex(c) ? (c - 'a' + 10) & 017 :
+ -1;
+}
--- /dev/null
+/* 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 {
+ int tok_val; /* numeric values */
+ char *tok_str; /* string/filespecifier */
+ } tok_data;
+};
+
+#include "file_info.h"
+
+#define tk_symb tok_symb
+#define tk_val tok_data.tok_val
+#define tk_str tok_data.tok_str
+
+extern struct token dot;
+
+extern int ReplaceMacros; /* "LLlex.c" */
+extern int AccFileSpecifier; /* "LLlex.c" */
+extern int AccDefined; /* "LLlex.c" */
+extern int UnknownIdIsZero; /* "LLlex.c" */
+
+extern int NoUnstack; /* "input.c" */
+extern int Unstacked; /* "input.c" */
+
+extern int err_occurred; /* "error.c" */
+
+#define DOT dot.tk_symb
+
+#define EOF (-1)
--- /dev/null
+/* PARSER ERROR ADMINISTRATION */
+
+#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));
+ skipline();
+ 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
+
+# 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)/cpp
+
+# What C compiler to use and how
+CC = cc
+COPTIONS =
+LFLAGS = -n
+
+# 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 scan.c skip.c tokenname.c next.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 scan.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.h \
+ class.h chtab.c 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 hfiles'; PLEASE KEEP THIS UP-TO-DATE!
+GHSRC = errout.h idfsize.h ifdepth.h lapbuf.h \
+ maxincl.h nparams.h numsize.h obufsize.h \
+ parbufsize.h pathlength.h strsize.h textsize.h \
+ botch_free.h debug.h inputtype.h dobits.h
+
+# Other generated files, for 'make clean' only
+GENERATED = tokenfile.g Lpars.h LLfiles LL.output lint.out \
+ Xref hfiles cfiles charoffset.h
+
+all: cc
+
+cc: hfiles LLfiles
+ make "EMHOME="$(EMHOME) cpp
+
+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 chtab
+ chtab -fchar.tab > char.c
+
+charoffset.h: chtab char.tab
+ chtab -fchar.tab > /dev/null
+
+chtab: chtab.o
+ $(CC) -o chtab chtab.o
+
+# Objects needed for 'cpp'
+OBJ = $(COBJ) $(LOBJ) $(GOBJ)
+SRC = $(CSRC) $(LCSRC) $(GSRC)
+
+cpp: $(OBJ) Makefile
+ $(CC) $(COPTIONS) $(LFLAGS) $(OBJ) $(LIBS) -o cpp
+ size cpp
+
+cfiles: hfiles LLfiles $(GSRC)
+ @touch cfiles
+
+install: all
+ cp cpp $(CEMPP)
+
+cmp: all
+ cmp cpp $(CEMPP)
+
+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) chtab.o chtab
+
+#AUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTO
+LLlex.o: LLlex.h Lpars.h bits.h charoffset.h class.h dobits.h file_info.h idf.h idfsize.h input.h inputtype.h numsize.h strsize.h
+LLmessage.o: LLlex.h Lpars.h file_info.h
+ch7bin.o: Lpars.h
+ch7mon.o: Lpars.h
+domacro.o: LLlex.h Lpars.h bits.h botch_free.h charoffset.h class.h debug.h dobits.h file_info.h idf.h idfsize.h ifdepth.h input.h inputtype.h interface.h macro.h nparams.h parbufsize.h textsize.h
+error.o: LLlex.h errout.h file_info.h
+idf.o: idf.h
+init.o: charoffset.h class.h idf.h interface.h macro.h
+input.o: file_info.h input.h inputtype.h
+main.o: file_info.h idfsize.h
+options.o: charoffset.h class.h idf.h idfsize.h macro.h maxincl.h
+preprocess.o: LLlex.h bits.h charoffset.h class.h dobits.h file_info.h idf.h idfsize.h input.h inputtype.h maxincl.h obufsize.h
+replace.o: LLlex.h charoffset.h class.h debug.h file_info.h idf.h input.h inputtype.h interface.h macro.h pathlength.h textsize.h
+scan.o: charoffset.h class.h idf.h input.h inputtype.h interface.h lapbuf.h macro.h nparams.h
+skip.o: LLlex.h charoffset.h class.h file_info.h input.h inputtype.h
+tokenname.o: LLlex.h Lpars.h file_info.h idf.h
+next.o: debug.h
+expr.o: Lpars.h
+tokenfile.o: Lpars.h
+expression.o: LLlex.h Lpars.h file_info.h
+Lpars.o: Lpars.h
+char.o: charoffset.h 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 */
+
+
+!File: ifdepth.h
+#define IFDEPTH 256 /* maximum number of nested if-constructions */
+
+
+!File: maxincl.h
+#define MAXINCL 16 /* maximum number of #include directories */
+
+
+!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: botch_free.h
+#undef BOTCH_FREE 1 /* botch freed memory, as a check */
+
+
+!File: debug.h
+#undef DEBUG 1 /* perform various self-tests */
+
+
+!File: parbufsize.h
+#define PARBUFSIZE 1024
+
+
+!File: textsize.h
+#define ITEXTSIZE 32 /* 1st piece of memory for repl. text */
+#define RTEXTSIZE 32 /* stepsize for enlarging 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 */
+
+
--- /dev/null
+#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
+/* EVALUATION OF BINARY OPERATORS */
+
+#include "Lpars.h"
+
+ch7bin(pval, oper, val)
+ register int *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
+/* EVALUATION OF MONADIC OPERATORS */
+
+#include "Lpars.h"
+
+ch7mon(oper, pval)
+ register int *pval;
+{
+ switch (oper) {
+ case '~':
+ *pval = ~(*pval);
+ break;
+ case '-':
+ *pval = -(*pval);
+ break;
+ case '!':
+ *pval = !(*pval);
+ break;
+ }
+}
--- /dev/null
+%
+% CHARACTER CLASSES
+%
+% some general settings:
+%F %s,
+%
+% START OF TOKEN
+%
+%C
+STGARB:\000-\377
+STSKIP:\r \t
+STNL:\n\f\013
+STCOMP:!&<=>|
+STSIMP:-%()+*,/:?^~
+STCHAR:'
+STIDF:a-zA-Z_
+STNUM:0-9
+STSTR:"
+STEOI:\200
+%T/* character classes */
+%T#include "class.h"
+%Tchar tkclass[] = {
+%p
+%T};
+%
+% other kinds of classes
+%
+%C
+_D_|_H_|_I_|_O_:0-7
+_D_|_H_|_I_:89
+_H_|_I_:a-fA-F
+_I_:g-zG-Z_
+%Tchar tk2class[] = {
+%F %s,
+%p
+%T};
--- /dev/null
+/*
+ chtab - character table generator
+
+ Author: Erik Baalbergen (..tjalk!erikb)
+ Modified by Ceriel Jacobs
+*/
+
+#include <stdio.h>
+
+static char *RcsId = "$Header$";
+
+#define MAXBUF 256
+#define TABSIZE 257
+#define COMCOM '-'
+#define FILECOM '%'
+
+int InputForm = 'c';
+char OutputForm[MAXBUF] = "%s,\n";
+char *Table[TABSIZE];
+char *Name;
+char *ProgCall;
+int signedch = 0;
+char *OutputName;
+char *chroffsetfile = "charoffset.h";
+
+main(argc, argv)
+ char *argv[];
+{
+ char c = 0200;
+ int i = c;
+
+ if (i < 0) signedch = 1;
+
+ ProgCall = *argv++;
+ argc--;
+ while (argc-- > 0) {
+ if (**argv == COMCOM) {
+ option(*argv++);
+ }
+ else {
+ process(*argv++, InputForm);
+ }
+ }
+ MkCharIndex();
+}
+
+MkCharIndex()
+{
+ FILE *fp;
+
+ if ((fp = fopen(chroffsetfile, "w")) == NULL) {
+ fprintf(stderr, "%s: cannot write file %s\n", ProgCall, chroffsetfile);
+ exit(1);
+ }
+ if (signedch) {
+ fputs("#define CharOffset 128\n");
+ }
+ else fputs("#define CharOffset 0\n");
+ fclose(fp);
+}
+
+char *
+Salloc(s)
+ char *s;
+{
+ char *malloc();
+ char *ns = malloc(strlen(s) + 1);
+
+ if (ns) {
+ strcpy(ns, s);
+ }
+ return ns;
+}
+
+option(str)
+ char *str;
+{
+ /* note that *str indicates the source of the option:
+ either COMCOM (from command line) or FILECOM (from a file).
+ */
+ switch (*++str) {
+
+ case ' ': /* command */
+ case '\t':
+ case '\0':
+ break;
+ case 'I':
+ InputForm = *++str;
+ break;
+ case 'f':
+ if (*++str == '\0') {
+ fprintf(stderr, "%s: -f: name expected\n", ProgCall);
+ exit(1);
+ }
+ DoFile(str);
+ break;
+ case 'F':
+ sprintf(OutputForm, "%s\n", ++str);
+ break;
+ case 'T':
+ printf("%s\n", ++str);
+ break;
+ case 'p':
+ PrintTable();
+ break;
+ case 'C':
+ ClearTable();
+ break;
+ case 'H':
+ if (*++str == '\0') {
+ fprintf(stderr, "%s: -H: name expected\n", ProgCall);
+ }
+ else chroffsetfile = ++str;
+ break;
+ default:
+ fprintf(stderr, "%s: bad option -%s\n", ProgCall, str);
+ }
+}
+
+ClearTable()
+{
+ register i;
+
+ for (i = 0; i < TABSIZE; i++) {
+ Table[i] = 0;
+ }
+}
+
+PrintTable()
+{
+ register i;
+
+ for (i = 0; i < TABSIZE; i++) {
+ if (Table[i]) {
+ printf(OutputForm, Table[i]);
+ }
+ else {
+ printf(OutputForm, "0");
+ }
+ }
+}
+
+process(str, format)
+ char *str;
+{
+ char *cstr = str;
+ char *Name = cstr; /* overwrite original string! */
+
+ /* strip of the entry name
+ */
+ while (*str && *str != ':') {
+ if (*str == '\\') {
+ ++str;
+ }
+ *cstr++ = *str++;
+ }
+
+ if (*str != ':') {
+ fprintf(stderr, "%s: bad specification: \"%s\", ignored\n",
+ ProgCall, Name);
+ return 0;
+ }
+ *cstr = '\0';
+ str++;
+
+ switch (format) {
+
+ case 'c':
+ return c_proc(str, Name);
+ default:
+ fprintf(stderr, "%s: bad input format\n", ProgCall);
+ }
+ return 0;
+}
+
+c_proc(str, Name)
+ char *str;
+ char *Name;
+{
+ int ch, ch2;
+ int quoted();
+ char *name = Salloc(Name);
+
+ while (*str) {
+ if (*str == '\\') {
+ ch = quoted(&str);
+ }
+ else {
+ ch = *str++;
+ }
+ if (*str == '-') {
+ if (*++str == '\\') {
+ ch2 = quoted(&str);
+ }
+ else {
+ if (ch2 = *str++);
+ else str--;
+ }
+ if (ch > ch2) {
+ fprintf(stderr, "%s: bad range\n", ProgCall);
+ return 0;
+ }
+#define ind(X) (signedch?(X>=128?X-128:X+128):X)
+ while (ch <= ch2) {
+ Table[ind(ch)] = name;
+ ch++;
+ }
+ }
+ else {
+ if (ch >= 0 && ch <= 255)
+ Table[ind(ch)] = name;
+ }
+ }
+ Table[256] = Table[0];
+ return 1;
+}
+
+int
+quoted(pstr)
+ char **pstr;
+{
+ register int ch;
+ register int i;
+ register char *str = *pstr;
+
+ if ((*++str >= '0') && (*str <= '9')) {
+ ch = 0;
+ for (i = 0; i < 3; i++) {
+ ch = 8 * ch + (*str - '0');
+ if (*++str < '0' || *str > '9')
+ break;
+ }
+ }
+ else {
+ switch (*str++) {
+
+ 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;
+ default :
+ ch = *str;
+ }
+ }
+ *pstr = str;
+ return ch & 0377;
+}
+
+int
+stoi(str)
+ char *str;
+{
+ register i = 0;
+
+ while (*str >= '0' && *str <= '9') {
+ i = i * 10 + *str++ - '0';
+ }
+ return i;
+}
+
+char *
+getline(s, n, fp)
+ char *s;
+ FILE *fp;
+{
+ register c = getc(fp);
+ char *str = s;
+
+ while (n--) {
+ if (c == EOF) {
+ return NULL;
+ }
+ else
+ if (c == '\n') {
+ *str++ = '\0';
+ return s;
+ }
+ *str++ = c;
+ c = getc(fp);
+ }
+ s[n - 1] = '\0';
+ return s;
+}
+
+#define BUFSIZE 1024
+
+DoFile(name)
+ char *name;
+{
+ char text[BUFSIZE];
+ FILE *fp;
+
+ if ((fp = fopen(name, "r")) == NULL) {
+ fprintf(stderr, "%s: cannot read file %s\n", ProgCall, name);
+ exit(1);
+ }
+ while (getline(text, BUFSIZE, fp) != NULL) {
+ if (text[0] == FILECOM) {
+ option(text);
+ }
+ else {
+ process(text, InputForm);
+ }
+ }
+}
--- /dev/null
+/* 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.
+*/
+
+#include "charoffset.h"
+
+#define class(ch) ((tkclass+CharOffset)[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 STIDF 5 /* being the initial character of an identifier */
+#define STCHAR 6 /* the starter of a character constant */
+#define STSTR 7 /* the starter of a string */
+#define STNUM 8 /* the starter of a numeric constant */
+#define STEOI 9 /* End-Of-Information mark */
+
+/* But occurring inside a token is not, so we need 1 bit for each
+ class.
+*/
+#define _I_ 01
+#define _O_ 02
+#define _D_ 04
+#define _H_ 010
+
+#define in_idf(ch) ((tk2class+CharOffset)[ch] & _I_)
+#define is_oct(ch) ((tk2class+CharOffset)[ch] & _O_)
+#define is_dig(ch) ((tk2class+CharOffset)[ch] & _D_)
+#define is_hex(ch) ((tk2class+CharOffset)[ch] & _H_)
+
+extern char tkclass[], tk2class[];
--- /dev/null
+/* $Header$ */
+/* PREPROCESSOR: CONTROLLINE INTERPRETER */
+
+#include "interface.h"
+#include <em_arith.h>
+#include "LLlex.h"
+#include "Lpars.h"
+#include "debug.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"
+
+IMPORT char *inctable[]; /* list of include directories */
+IMPORT char *getwdir();
+PRIVATE char ifstack[IFDEPTH]; /* if-stack: the content of an entry is */
+ /* 1 if a corresponding ELSE has been */
+ /* encountered. */
+PRIVATE int nestlevel = -1; /* initially no nesting level. */
+
+PRIVATE char *
+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_str : (char *)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.
+*/
+EXPORT
+domacro()
+{
+ struct token tk; /* the token itself */
+ register struct idf *id;
+
+ switch(GetToken(&tk)) { /* 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);
+ PushBack();
+ skipline();
+ 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("#line without linenumber");
+ PushBack();
+ skipline();
+ }
+ else
+ do_line((unsigned int)tk.tk_val);
+ break;
+ case K_UNDEF: /* "undef" */
+ do_undef();
+ break;
+ default:
+ /* invalid word seen after the '#' */
+ error("%s: unknown control", id->id_text);
+ PushBack();
+ skipline();
+ }
+ break;
+ case INTEGER: /* # <integer> [<filespecifier>]? */
+ do_line((unsigned int)tk.tk_val);
+ break;
+ case EOI: /* only `#' on this line: do nothing, ignore */
+ break;
+ default: /* invalid token following '#' */
+ error("illegal # line");
+ PushBack();
+ skipline();
+ }
+}
+
+PRIVATE
+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;
+ struct idf *id;
+
+ NoUnstack++;
+ for (;;) {
+ LoadChar(ch); /* read first character after newline */
+ if (ch != '#') {
+ if (ch == EOI) {
+ NoUnstack--;
+ return;
+ }
+ PushBack();
+ skipline();
+ continue;
+ }
+ if (GetToken(&tk) != IDENTIFIER) {
+ PushBack();
+ skipline();
+ 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) {
+ case K_IF:
+ case K_IFDEF:
+ case K_IFNDEF:
+ push_if();
+ continue;
+ case K_ELIF:
+ if (nestlevel == skiplevel) {
+ nestlevel--;
+ push_if();
+ if (ifexpr()) {
+ NoUnstack--;
+ return;
+ }
+ }
+ break;
+ case K_ELSE:
+ ++(ifstack[nestlevel]);
+ if (nestlevel == skiplevel) {
+ PushBack();
+ skipline();
+ NoUnstack--;
+ return;
+ }
+ break;
+ case K_ENDIF:
+ assert(nestlevel >= 0);
+ if (nestlevel == skiplevel) {
+ PushBack();
+ skipline();
+ nestlevel--;
+ NoUnstack--;
+ return;
+ }
+ nestlevel--;
+ break;
+ }
+ }
+}
+
+PRIVATE
+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".
+ */
+ IMPORT 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);
+}
+
+PRIVATE
+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;
+ PushBack();
+ skipline();
+ inctable[0] = WorkingDir;
+ if (filenm) {
+ if (!InsertFile(filenm, &inctable[tok==FILESPECIFIER],&result)){
+ error("cannot find include file \"%s\"", filenm);
+ }
+ else {
+ WorkingDir = getwdir(result);
+ FileName = result;
+ LineNumber = 1;
+ }
+ }
+}
+
+PRIVATE
+do_define()
+{
+ /* do_define() interprets a #define control line.
+ */
+ char *str;
+ 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())) {
+ error("#define: illegal macro name");
+ PushBack();
+ skipline();
+ return;
+ }
+ /* there is a formal parameter list if the identifier is
+ followed immediately by a '('.
+ */
+ LoadChar(ch);
+ if (ch == '(') {
+ if ((nformals = getparams(formals, parbuf)) == -1) {
+ PushBack();
+ skipline();
+ return; /* an error occurred */
+ }
+ LoadChar(ch);
+ }
+ /* read the replacement text if there is any */
+ ch = skipspaces(ch); /* find first character of the text */
+ assert(ch != EOI);
+ if (class(ch) == STNL) {
+ /* Treat `#define something' as `#define something ""'
+ */
+ repl_text = "";
+ length = 0;
+ }
+ else {
+ PushBack();
+ repl_text = get_text((nformals > 0) ? formals : 0, &length);
+ }
+ macro_def(str2idf(str, 0), repl_text, nformals, length, NOFLAG);
+ LineNumber++;
+}
+
+PRIVATE
+push_if()
+{
+ if (nestlevel >= IFDEPTH)
+ fatal("too many nested #if/#ifdef/#ifndef");
+ else
+ ifstack[++nestlevel] = 0;
+}
+
+PRIVATE
+do_elif()
+{
+ if (nestlevel < 0 || (ifstack[nestlevel])) {
+ error("#elif without corresponding #if");
+ PushBack();
+ skipline();
+ }
+ else { /* restart at this level as if a #if is detected. */
+ nestlevel--;
+ push_if();
+ skip_block();
+ }
+}
+
+PRIVATE
+do_else()
+{
+ PushBack();
+ skipline();
+ if (nestlevel < 0 || (ifstack[nestlevel]))
+ error("#else without corresponding #if");
+ else { /* mark this level as else-d */
+ ++(ifstack[nestlevel]);
+ skip_block();
+ }
+}
+
+PRIVATE
+do_endif()
+{
+ PushBack();
+ skipline();
+ if (nestlevel-- < 0)
+ error("#endif without corresponding #if");
+}
+
+PRIVATE
+do_if()
+{
+ push_if();
+ if (!ifexpr()) /* a false #if/#elif expression */
+ skip_block();
+}
+
+PRIVATE
+do_ifdef(how)
+{
+ register struct idf *id;
+ char *str;
+
+ /* how == 1 : ifdef; how == 0 : ifndef
+ */
+ push_if();
+ str = GetIdentifier();
+ if (!str) {
+ error("illegal #ifdef construction");
+ id = 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();
+ else {
+ PushBack();
+ skipline();
+ }
+}
+
+PRIVATE
+do_undef()
+{
+ register struct idf *id;
+ register char *str = GetIdentifier();
+
+ /* Forget a macro definition. */
+ if (str) {
+ if (id = findidf(str)) {
+ if (id->id_macro) { /* forget the macro */
+ free_macro(id->id_macro);
+ id->id_macro = (struct macro *) 0;
+ } /* else: don't complain */
+ }
+ free(str);
+ }
+ else
+ error("illegal #undef construction");
+ PushBack();
+ skipline();
+}
+
+PRIVATE
+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;
+ PushBack();
+ skipline();
+}
+
+PRIVATE 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;
+
+ LoadChar(c);
+ c = skipspaces(c);
+ if (c == ')') { /* no parameters: #define name() */
+ *pbuf = (char *) 0;
+ return 0;
+ }
+ for (;;) { /* eat the formal parameter list */
+ if (class(c) != STIDF) { /* not an identifier */
+ 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 */
+ LoadChar(c);
+ *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);
+ if (c == ')') { /* end of the formal parameter list */
+ *pbuf = (char *) 0;
+ return pbuf - buf;
+ }
+ if (c != ',') {
+ error("#define: bad formal parameter list");
+ return -1;
+ }
+ LoadChar(c);
+ c = skipspaces(c);
+ }
+ /*NOTREACHED*/
+}
+
+EXPORT
+macro_def(id, text, nformals, length, flags)
+ register struct idf *id;
+ char *text;
+{
+ /* 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.
+ */
+ register struct macro *newdef = id->id_macro;
+
+ if (newdef) { /* is there a redefinition? */
+ if (macroeq(newdef->mc_text, text))
+ return;
+ warning("redefine \"%s\"", id->id_text);
+ }
+ 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 */
+ newdef->mc_count = 0;
+}
+
+PRIVATE 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;
+}
+
+PRIVATE 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;
+
+ LoadChar(c);
+
+ while ((c != EOI) && (class(c) != STNL)) {
+ if (c == '\\') { /* check for "\\\n" */
+ LoadChar(c);
+ if (c == '\n') {
+ /* More than one line is used for the
+ replacement text.
+ Replace "\\\n" by " ".
+ */
+ text[pos++] = ' ';
+ ++LineNumber;
+ LoadChar(c);
+ }
+ else
+ text[pos++] = '\\';
+ if (pos == text_size)
+ text = Srealloc(text, text_size += RTEXTSIZE);
+ }
+ else
+ if ( c == '/') {
+ LoadChar(c);
+ if (c == '*') {
+ skipcomment();
+ text[pos++] = ' ';
+ LoadChar(c);
+ }
+ else
+ text[pos++] = '/';
+ if (pos == text_size)
+ text = Srealloc(text, text_size += RTEXTSIZE);
+ }
+ else
+ if (formals && class(c) == STIDF) {
+ 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 {
+ LoadChar(c);
+ 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 */
+ text[pos++] = FORMALP | (char) n;
+ if (pos == text_size)
+ text = Srealloc(text,
+ text_size += RTEXTSIZE);
+ }
+ 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 {
+ text[pos++] = c;
+ if (pos == text_size)
+ text = Srealloc(text, text_size += RTEXTSIZE);
+ LoadChar(c);
+ }
+ }
+ 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).
+*/
+PRIVATE
+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');
+ }
+}
--- /dev/null
+/* 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 "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;
+{
+ fprint(ERROUT, "\"%s\", line %d: %s", FileName, LineNumber, s);
+}
+
+/*VARARGS1*/
+error(fmt, args)
+ char *fmt;
+{
+ err_hdr("");
+ doprnt(ERROUT, fmt, &args);
+ fprint(ERROUT, "\n");
+}
+
+/*VARARGS1*/
+warning(fmt, args)
+ char *fmt;
+{
+ err_hdr("warning ");
+ doprnt(ERROUT, fmt, &args);
+ fprint(ERROUT, "\n");
+}
+
+/*VARARGS1*/
+crash(fmt, args)
+ char *fmt;
+ int args;
+{
+ err_hdr("crash ");
+ doprnt(ERROUT, fmt, &args);
+ fprint(ERROUT, "\n");
+ sys_stop(S_ABORT);
+}
+
+/*VARARGS1*/
+fatal(fmt, args)
+ char *fmt;
+ int args;
+{
+ err_hdr("fatal ");
+ doprnt(ERROUT, fmt, &args);
+ fprint(ERROUT, "\n");
+ sys_stop(S_EXIT);
+}
--- /dev/null
+/* 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
+/* EXPRESSION SYNTAX PARSER */
+
+%lexical LLlex;
+%start If_expr, if_expression;
+
+{
+#include "LLlex.h"
+
+extern int ifval;
+}
+
+if_expression
+:
+ constant_expression(&ifval)
+;
+
+/* 7.1 */
+primary(int *pval;)
+:
+ constant(pval)
+|
+ '(' expression(pval) ')'
+;
+
+unary(int *pval;)
+ {int oper;}
+:
+ unop(&oper)
+ unary(pval)
+ { ch7mon(oper, pval); }
+|
+ primary(pval)
+;
+
+binary_expression(int maxrank; int *pval;)
+ {int oper; int 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(int *pval;)
+ {int 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(int *pval;)
+:
+ conditional_expression(pval)
+;
+
+/* 7.15 */
+expression(int *pval;)
+ {int 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(int *pval;) :
+ INTEGER
+ {*pval = dot.tk_val;}
+;
+
+constant_expression (int *pval;) :
+ assignment_expression(pval)
+;
--- /dev/null
+/* 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
+#include "idf.h"
+#include <idf_pkg.body>
--- /dev/null
+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
+/* PREPROCESSOR: INITIALIZATION ROUTINES */
+
+#include <system.h>
+#include <alloc.h>
+#include "class.h"
+#include "macro.h"
+#include "idf.h"
+#include "interface.h"
+
+PRIVATE struct mkey {
+ char *mk_reserved;
+ int mk_key;
+} mkey[] = {
+ {"define", K_DEFINE},
+ {"elif", K_ELIF},
+ {"else", K_ELSE},
+ {"endif", K_ENDIF},
+ {"if", K_IF},
+ {"ifdef", K_IFDEF},
+ {"ifndef", K_IFNDEF},
+ {"include", K_INCLUDE},
+ {"line", K_LINE},
+ {"undef", K_UNDEF},
+ {0, K_UNKNOWN}
+};
+
+char *strcpy();
+
+EXPORT
+init_pp()
+{
+ long clock, sys_time();
+ static char date[30];
+ char *ctime();
+
+ /* 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) {
+ struct idf *idf = str2idf(mk->mk_reserved, 0);
+
+ if (idf->id_resmac)
+ fatal("maximum identifier length insufficient");
+ idf->id_resmac = mk->mk_key;
+ mk++;
+ }
+ }
+
+ /* Initialize __DATE__, __FILE__ and __LINE__ macro
+ definitions.
+ */
+ /* __DATE__ */
+ clock = sys_time();
+ strcpy(&date[1], ctime(&clock));
+ date[26] = '\0'; /* zap nl */
+ date[0] = date[25] = '"';
+ macro_def(str2idf("__DATE__", 0), date, -1, 26, NOFLAG);
+
+ /* __LINE__ */
+ macro_def(str2idf("__LINE__", 0), "0", -1, 1, FUNC);
+
+ /* __FILE__ */
+ macro_def(str2idf("__FILE__", 0), "", -1, 1, FUNC);
+
+ /* defined(??) */
+ macro_def(str2idf("defined", 0), "", 1, 1, FUNC);
+}
--- /dev/null
+#include "file_info.h"
+#include "input.h"
+#define INP_TYPE struct file_info
+#define INP_VAR finfo
+struct file_info finfo;
+#include <inp_pkg.body>
+
+char *
+getwdir(fn)
+ 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 "";
+ else
+ if (p) {
+ *p = '\0';
+ fn = Salloc(fn, p - &fn[0] + 1);
+ *p = '/';
+ return fn;
+ }
+ else return ".";
+}
+
+int NoUnstack;
+int Unstacked;
+
+AtEoIT()
+{
+ if (NoUnstack) error("unexpected EOF");
+ DoUnstack();
+ return 0;
+}
+
+AtEoIF()
+{
+ if (NoUnstack) error("unexpected EOF");
+ return 0;
+}
--- /dev/null
+#include "inputtype.h"
+#include <inp_pkg.spec>
--- /dev/null
+#define PRIVATE
+#define IMPORT extern
+#define EXPORT
--- /dev/null
+/* 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 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 */
+};
+
+
+/* allocation definitions of struct macro */
+extern char *st_alloc();
+extern struct macro *h_macro;
+#ifdef DEBUG
+extern int cnt_macro;
+extern char *std_alloc();
+#define new_macro() ((struct macro *) std_alloc((char **)&h_macro, sizeof(struct macro), 20, &cnt_macro))
+#else
+#define new_macro() ((struct macro *) st_alloc((char **)&h_macro, sizeof(struct macro), 20))
+#endif
+#define free_macro(p) st_free(p, &h_macro, sizeof(struct macro))
+
+
+/* `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_IF 5
+#define K_IFDEF 6
+#define K_IFNDEF 7
+#define K_INCLUDE 8
+#define K_LINE 9
+#define K_UNDEF 10
--- /dev/null
+/* MAIN PROGRAM */
+
+#include "file_info.h"
+#include "idfsize.h"
+
+extern struct tokenname tkidf[], tkkey[];
+extern char *symbol2str();
+extern char *inctable[];
+extern int err_occurred;
+int idfsize = IDFSIZE;
+
+int ifval;
+
+char *prog_name;
+
+main(argc, argv)
+ char *argv[];
+{
+ /* parse and interpret the command line options */
+ prog_name = argv[0];
+
+ init_idf();
+ 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]);
+ return err_occurred;
+}
+
+compile(argc, argv)
+ char *argv[];
+{
+ register char *source = 0;
+ char *dummy;
+
+ switch (argc) {
+ case 1:
+ source = argv[0];
+ FileName = source;
+ break;
+ case 0:
+ FileName = "";
+ break;
+ default:
+ fatal("use: %s [options] [source]", prog_name);
+ break;
+ }
+ WorkingDir = inctable[0];
+
+ if (!InsertFile(source, (char **) 0, &dummy)) /* read the source file */
+ fatal("%s: no source file %s\n", prog_name,
+ source ? source : "stdin");
+ preprocess(source);
+}
--- /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
+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
+#include "debug.h"
+struct macro *h_macro = 0;
+#ifdef DEBUG
+int cnt_macro = 0;
+#endif
--- /dev/null
+/* USER-OPTION HANDLING */
+
+#include <alloc.h>
+#include "idfsize.h"
+#include "maxincl.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 */
+char *inctable[MAXINCL] = { /* list for includes */
+ ".",
+ "/usr/include",
+ 0
+};
+
+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) {
+ 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 = inc_pos++;
+ register char *new = text;
+
+ while (new) {
+ register char *tmp = inctable[i];
+
+ inctable[i++] = new;
+ if (i == MAXINCL)
+ fatal("too many -I options");
+ 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
+/* PREPROCESSOR DRIVER */
+
+#include <system.h>
+#include "input.h"
+#include "maxincl.h"
+#include "obufsize.h"
+#include "LLlex.h"
+#include "class.h"
+#include "idf.h"
+#include "idfsize.h"
+#include "bits.h"
+
+char _obuf[OBUFSIZE];
+
+#ifdef DOBITS
+char bits[128];
+#endif
+
+preprocess(fn)
+ char *fn;
+{
+ register int c;
+ register char *op = _obuf;
+ register char *ob = &_obuf[OBUFSIZE];
+ int lineno = 0;
+ extern char options[];
+
+#define flush(X) (sys_write(STDOUT,_obuf,X), op = _obuf)
+#define echo(ch) (op != ob || flush(OBUFSIZE), *op++ = (ch))
+#define newline() echo('\n')
+
+ for (;;) {
+ LineNumber++;
+ lineno++;
+ LoadChar(c);
+ while (c == '#') {
+ domacro();
+ lineno++;
+ newline();
+ LoadChar(c);
+ }
+ if (! options['P'] &&
+ (lineno != LineNumber || fn != FileName)) {
+ char Xbuf[256];
+ register char *p = Xbuf;
+
+ fn = FileName;
+ lineno = LineNumber;
+ sprint(p, "#line %d \"%s\"\n", LineNumber,
+ FileName);
+ while (*p) echo(*p++);
+ }
+ for (;;) {
+ if (c & 0200) {
+ if (c == EOI) {
+ flush(op-_obuf);
+ return;
+ }
+ fatal("non-ascii character read");
+ }
+ if (c == '/') {
+ LoadChar(c);
+ if (c == '*') {
+ NoUnstack++;
+ if (options['C']) {
+ echo('/');
+ echo('*');
+ }
+ for (;;) {
+ LoadChar(c);
+ if (class(c) == STNL) {
+ ++LineNumber;
+ ++lineno;
+ echo(c);
+ }
+ else if (c == EOI) {
+ flush(op - _obuf);
+ return;
+ }
+ else if (c == '*') {
+ if (options['C']) echo(c);
+ LoadChar(c);
+ if (c == '/') {
+ if (options['C']) echo(c);
+ break;
+ }
+ else {
+ PushBack();
+ }
+ }
+ else if (options['C']) echo(c);
+ }
+ NoUnstack--;
+ LoadChar(c);
+ continue;
+ }
+ echo('/');
+ continue;
+ }
+ switch(class(c)) {
+ case STNL:
+ echo(c);
+ break;
+ case STSTR:
+ case STCHAR: {
+ register int stopc = c;
+
+ do {
+ echo(c);
+ LoadChar(c);
+ if (c == '\\') {
+ echo(c);
+ LoadChar(c);
+ }
+ if (c == '\n') {
+ ++LineNumber;
+ lineno++;
+ }
+ else if (c == EOI) {
+ flush(op-_obuf);
+ return;
+ }
+ }
+ while (c != stopc);
+ echo(c);
+ LoadChar(c);
+ continue;
+ }
+ case STNUM:
+#define getdec(c) do { echo(c); LoadChar(c);} while (is_dig(c))
+#define gethex(c) do { echo(c); LoadChar(c);} while (is_hex(c))
+
+ if (c != '0') {
+ getdec(c);
+ if (c == '.') getdec(c);
+ if (c == 'e') {
+ echo(c);
+ LoadChar(c);
+ if (c == '+' || c == '-') {
+ echo(c);
+ LoadChar(c);
+ }
+ if (is_dig(c)) getdec(c);
+ }
+ }
+ else {
+ echo(c);
+ LoadChar(c);
+ if (c == 'x' || c == 'X') gethex(c);
+ else if (is_dig(c)) getdec(c);
+ }
+ continue;
+ case STIDF: {
+ extern int idfsize; /* ??? */
+ char buf[IDFSIZE + 1];
+ register char *tg = &buf[0];
+ register char *maxpos = &buf[idfsize];
+ register struct idf *idef;
+
+#define tstmac(bx) if (!(bits[c] & bx)) goto nomac
+#define cpy if (Unstacked) EnableMacros(); *tg++ = c
+#define load LoadChar(c); if (!in_idf(c)) goto endidf
+
+#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:
+ PushBack();
+ *tg = '\0'; /* mark the end of the identifier */
+ idef = findidf(buf);
+ if ((idef && idef->id_macro && replace(idef))) {
+ LoadChar(c);
+ continue;
+ }
+ nomac:
+ *tg = 0;
+ tg = buf;
+ while (*tg) echo(*tg++);
+ LoadChar(c);
+ while (in_idf(c)) {
+ echo(c);
+ LoadChar(c);
+ }
+ continue;
+ }
+ default:
+ echo(c);
+ LoadChar(c);
+ continue;
+ }
+ break;
+ }
+ }
+ /*NOTREACHED*/
+}
--- /dev/null
+/* PREPROCESSOR: MACRO-TEXT REPLACEMENT ROUTINES */
+
+#include "debug.h" /* UF */
+#include "pathlength.h" /* UF */
+#include "textsize.h" /* UF */
+
+#include <alloc.h>
+#include <em_arith.h>
+#include <assert.h>
+#include "idf.h"
+#include "input.h"
+#include "macro.h"
+#include "LLlex.h"
+#include "class.h"
+#include "interface.h"
+
+char *strcpy(), *strcat();
+char *long2str();
+
+PRIVATE struct macro *ReplaceList; /* list of currently active macros */
+
+EXPORT int
+replace(idef)
+ register struct idf *idef;
+{
+ /* replace() is called by the lexical analyzer to perform
+ macro replacement. "idef" is the description of the
+ identifier which leads to the replacement. If the
+ optional actual parameters of the macro are OK, the text
+ of the macro is prepared to serve as an input buffer,
+ which is pushed onto the input stack.
+ replace() returns 1 if the replacement succeeded and 0 if
+ some error has occurred.
+ */
+ register struct macro *mac = idef->id_macro;
+ register char c;
+ char **actpars, **getactuals();
+ char *reptext, *macro2buffer();
+ int size;
+
+ if (mac->mc_flag & NOREPLACE) {
+ warning("macro %s is recursive", idef->id_text);
+ return 0;
+ }
+ if (mac->mc_nps != -1) { /* with parameter list */
+ if (mac->mc_flag & FUNC) {
+ /* must be "defined".
+ Unfortunately, the next assertion
+ will not compile ...
+ assert( ! strcmp("defined", idef->id_text));
+ */
+ if (! AccDefined)
+ return 0;
+ }
+ if (++mac->mc_count > 100) {
+ /* 100 must be some number in Parameters */
+ warning("macro %s is assumed recursive",
+ idef->id_text);
+ return 0;
+ }
+ LoadChar(c);
+ c = skipspaces(c);
+ if (c != '(') { /* no replacement if no () */
+ error("macro %s needs arguments",
+ idef->id_text);
+ PushBack();
+ return 0;
+ }
+ actpars = getactuals(idef); /* get act.param. list */
+ if (mac->mc_flag & FUNC) {
+ struct idf *param = findidf(*actpars);
+
+ if (param && param->id_macro)
+ reptext = "1";
+ else
+ reptext = "0";
+ InsertText(reptext, 1);
+ mac->next = ReplaceList;
+ ReplaceList = mac;
+ return 1;
+ }
+ }
+ if (mac->mc_flag & FUNC) /* this macro leads to special action */
+ macro_func(idef);
+ if (mac->mc_nps <= 0) {
+ mac->mc_flag |= NOREPLACE;
+ reptext = mac->mc_text;
+ size = mac->mc_length;
+ }
+ else reptext = macro2buffer(idef, actpars, &size); /* create input buffer */
+ InsertText(reptext, size);
+ mac->next = ReplaceList;
+ ReplaceList = mac;
+ return 1;
+}
+
+char FilNamBuf[PATHLENGTH];
+
+PRIVATE
+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;
+
+ switch (idef->id_text[2]) { /* This switch is very blunt... */
+ case 'F' : /* __FILE__ */
+ mac->mc_length = strlen(FileName) + 2;
+ mac->mc_text = FilNamBuf;
+ mac->mc_text[0] = '"';
+ strcpy(&(mac->mc_text[1]), FileName);
+ strcat(mac->mc_text, "\"");
+ break;
+ case 'L' : /* __LINE__ */
+ {
+ mac->mc_text = long2str((long) LineNumber, 10);
+ mac->mc_length = strlen(mac->mc_text);
+ break;
+ }
+ default :
+ crash("(macro_func)");
+ }
+}
+
+PRIVATE char *
+macro2buffer(idef, actpars, siztext)
+ struct idf *idef;
+ char **actpars;
+ int *siztext;
+{
+ /* Macro2buffer() turns the macro replacement text, as it is
+ stored, into an input buffer, while each occurrence of the
+ non-ascii formal parameter mark is replaced by its
+ corresponding actual parameter specified in the actual
+ parameter list actpars. A pointer to the beginning of the
+ constructed text is returned, while *siztext is filled
+ with its length.
+ If there are no parameters, this function behaves
+ the same as strcpy().
+ */
+ register int size = idef->id_macro->mc_length + ITEXTSIZE;
+ register char *text = Malloc(size);
+ register int pos = 0;
+ register char *ptr = idef->id_macro->mc_text;
+
+ while (*ptr) {
+ if (*ptr & FORMALP) { /* non-asc formal param. mark */
+ register int n = *ptr++ & 0177;
+ register char *p;
+
+ assert(n != 0);
+ /* copy the text of the actual parameter
+ into the replacement text
+ */
+ for (p = actpars[n - 1]; p && *p; p++) {
+ text[pos++] = *p;
+ if (pos == size)
+ text = Srealloc(text, size += RTEXTSIZE);
+ }
+ }
+ else {
+ text[pos++] = *ptr++;
+ if (pos == size)
+ text = Srealloc(text, size += RTEXTSIZE);
+ }
+ }
+ text[pos] = '\0';
+ *siztext = pos;
+ return text;
+}
+
+EXPORT
+DoUnstack()
+{
+ Unstacked++;
+}
+
+EXPORT
+EnableMacros()
+{
+ register struct macro *p = ReplaceList;
+
+ assert(Unstacked > 0);
+ while (Unstacked > 0) {
+ assert(p != 0);
+ p->mc_flag &= ~NOREPLACE;
+ p->mc_count = 0;
+ p = p->next;
+ Unstacked--;
+ }
+ ReplaceList = p;
+}
--- /dev/null
+/* PREPROCESSOR: SCANNER FOR THE ACTUAL PARAMETERS OF MACROS */
+
+/* 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"
+
+#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)
+ 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.
+ */
+ error("argument mismatch, %s", idef->id_text);
+
+ while (++nr_of_params < acnt) {
+ /* too few paraeters: remaining actuals are ""
+ */
+ actparams[nr_of_params] = (char *) 0;
+ }
+ }
+
+ return actparams;
+}
+
+PRIVATE
+copyact(ch1, ch2, level)
+ char ch1, ch2;
+ int level;
+{
+ /* 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, copyact() reads the input,
+ upto the corresponding closing bracket.
+
+ Opening bracket is ch1, closing bracket is ch2. If
+ level != 0, copy opening and closing parameters too.
+ */
+ register int ch; /* Current char */
+ register int match; /* used to read strings */
+
+ if (level) {
+ copy(ch1);
+ }
+
+ for (;;) {
+ LoadChar(ch);
+
+ if (ch == ch2) {
+ if (level) {
+ copy(ch);
+ }
+ return;
+ }
+
+ switch(ch) {
+
+ case ')':
+ case '}':
+ case ']':
+ error("unbalanced parenthesis");
+ break;
+
+ case '(':
+ copyact('(', ')', level+1);
+ break;
+
+ case '{':
+ /* example:
+ #define declare(v, t) t v
+ declare(v, union{int i, j; float r;});
+ */
+ copyact('{', '}', level+1);
+ break;
+
+ case '[':
+ copyact('[', ']', level+1);
+ break;
+
+ case '\n':
+ LoadChar(ch);
+ while (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 */
+ LoadChar(ch);
+ /* Loop, for another control line */
+ }
+
+ PushBack();
+ copy('\n');
+ break;
+
+ case '/':
+ LoadChar(ch);
+
+ if (ch == '*') { /* skip comment */
+ skipcomment();
+ continue;
+ }
+
+ PushBack();
+ copy('/');
+ break;
+
+ case ',':
+ if (!level) {
+ /* next parameter encountered */
+ copy(EOS);
+
+ if (++nr_of_params >= NPARAMS) {
+ fatal("(getact) too many actuals");
+ }
+
+ 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);
+ LoadChar(ch);
+ while (ch != EOI) {
+ if (ch == match) {
+ break;
+ }
+
+ if (ch == '\\') {
+ copy(ch);
+ LoadChar(ch);
+ }
+ else
+ if (ch == '\n') {
+ error("newline in string");
+ copy(match);
+ break;
+ }
+
+ copy(ch);
+ LoadChar(ch);
+ }
+
+ if (ch == match) {
+ copy(ch);
+ break;
+ }
+ /* Fall through */
+
+ case EOI :
+ error("unterminated macro call");
+ return;
+
+ default:
+ copy(ch);
+ break;
+ }
+ }
+}
--- /dev/null
+/* $Header$ */
+/* PREPROCESSOR: INPUT SKIP FUNCTIONS */
+
+#include "LLlex.h"
+#include "class.h"
+#include "input.h"
+
+int
+skipspaces(ch)
+ register int ch;
+{
+ /* skipspaces() skips any white space and returns the first
+ non-space character.
+ */
+ for (;;) {
+ while (class(ch) == STSKIP)
+ LoadChar(ch);
+ /* How about "\\\n"????????? */
+ if (ch == '/') {
+ LoadChar(ch);
+ if (ch == '*') {
+ skipcomment();
+ LoadChar(ch);
+ }
+ else {
+ PushBack();
+ return '/';
+ }
+ }
+ else
+ return ch;
+ }
+}
+
+skipline()
+{
+ /* skipline() skips all characters until a newline character
+ is seen, not escaped by a '\\'.
+ Any comment is skipped.
+ */
+ register int c;
+
+ LoadChar(c);
+ while (class(c) != STNL && c != EOI) {
+ if (c == '\\') {
+ LoadChar(c);
+ if (class(c) == STNL)
+ ++LineNumber;
+ }
+ if (c == '/') {
+ LoadChar(c);
+ if (c == '*')
+ skipcomment();
+ else
+ continue;
+ }
+ LoadChar(c);
+ }
+ ++LineNumber;
+ if (c == EOI) { /* garbage input... */
+ error("unexpected EOF while skipping text");
+ PushBack();
+ }
+}
--- /dev/null
+/* $Header$ */
+/* TOKEN NAME DEFINITIONS */
+
+#include "idf.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 */
+ {NOTEQUAL, "!="},
+ {AND, "&&"},
+ {LEFT, "<<"},
+ {LESSEQ, "<="},
+ {EQUAL, "=="},
+ {GREATEREQ, ">="},
+ {RIGHT, ">>"},
+ {OR, "||"},
+ {0, ""}
+};
+
+struct tokenname tkfunny[] = { /* internal keywords */
+ {ERRONEOUS, "erroneous"},
+ {0, ""}
+};
+#endif ____