From: PatR Date: Fri, 4 Feb 2022 22:34:46 +0000 (-0800) Subject: more obsolete files: DECUS C's preprocessor X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5b28db5f2347caa9b31efb9b31192bb278c4ccf0;p=nethack more obsolete files: DECUS C's preprocessor Get rid sys/share/cpp[123].shr, the pre-ANSI C preprocessor that was included in the source distribution for use on systems with ancient C compilers whose preprocessor that couldn't cope with nethack's large number of macros. --- diff --git a/sys/unix/.gitattributes b/sys/unix/.gitattributes index 6ddd7d79f..23a2412fd 100644 --- a/sys/unix/.gitattributes +++ b/sys/unix/.gitattributes @@ -6,4 +6,4 @@ depend.awk NHSUBST sysconf NHSUBST *shr NH_header=no * NH_filestag=(file%s_for_UNIX_versions) -cpp?.shr NH_filestag=(file%s_for_replacement_cpp,_only_needed_by_some_ancient_UNIX_systems) + diff --git a/sys/unix/cpp1.shr b/sys/unix/cpp1.shr deleted file mode 100644 index f2b133d45..000000000 --- a/sys/unix/cpp1.shr +++ /dev/null @@ -1,1783 +0,0 @@ -# This is a shell archive. Save it in a file, remove anything before -# this line, and then unpack it by entering "sh file". Note, it may -# create directories; files and directories will be owned by you and -# have default permissions. -# -# This archive contains: -# -# makefile.txt -# readme.txt -# cpp.mem -# cpp.h -# cppdef.h -# cpp2.c -# -echo x - makefile.txt -sed 's/^X//' >makefile.txt << 'END-of-makefile.txt' -X# -X# The redefinition of strchr() and strrchr() are needed for -X# Ultrix-32, Unix 4.2 bsd (and maybe some other Unices). -X# -XBSDDEFINE = -Dstrchr=index -Dstrrchr=rindex -X# -X# On certain systems, such as Unix System III, you may need to define -X# $(LINTFLAGS) in the make command line to set system-specific lint flags. -X# -X# This Makefile assumes cpp will replace the "standard" preprocessor. -X# Delete the reference to -DLINE_PREFIX=\"\" if cpp is used stand-alone. -X# LINEFIX is a sed script filter that reinserts #line -- used for testing -X# if LINE_PREFIX is set to "". Note that we must stand on our heads to -X# match the # and a line had better not begin with $. By the way, what -X# we really want is -X# LINEFIX = | sed "s/^#/#line/" -X# -XCPPDEFINE = -DLINE_PREFIX=\"\" -XLINEFIX = | sed "s/^[^ !\"%-~]/&line/" -X# -X# Define OLD_PREPROCESSOR non-zero to make a preprocessor which is -X# "as compatible as possible" with the standard Unix V7 or Ultrix -X# preprocessors. This is needed to rebuild 4.2bsd, for example, as -X# the preprocessor is used to modify assembler code, rather than C. -X# This is not recommended for current development. OLD_PREPROCESSOR -X# forces the following definitions: -X# OK_DOLLAR FALSE $ is not allowed in variables -X# OK_CONCAT FALSE # cannot concatenate tokens -X# COMMENT_INVISIBLE TRUE old-style comment concatenation -X# STRING_FORMAL TRUE old-style string expansion -X# -XOLDDEFINE = -DOLD_PREPROCESSOR=1 -X# -X# DEFINES collects all -D arguments for cc and lint: -X# Change DEFINES = $(BSDDEFINE) $(CPPDEFINE) $(OLDDEFINE) -X# for an old-style preprocessor. -X# -X# DEFINES = $(BSDDEFINE) $(CPPDEFINE) -XDEFINES = $(CPPDEFINE) -X -XCFLAGS = -O $(DEFINES) -X -X# -X# ** compile cpp -X# -XSRCS = cpp1.c cpp2.c cpp3.c cpp4.c cpp5.c cpp6.c -XOBJS = cpp1.o cpp2.o cpp3.o cpp4.o cpp5.o cpp6.o -Xcpp: $(OBJS) -X $(CC) $(CFLAGS) $(OBJS) -o cpp -X -X# -X# ** Test cpp by preprocessing itself, compiling the result, -X# ** repeating the process and diff'ing the result. Note: this -X# ** is not a good test of cpp, but a simple verification. -X# ** The diff's should not report any changes. -X# ** Note that a sed script may be executed for each compile -X# -Xtest: -X cpp cpp1.c $(LINEFIX) >old.tmp1.c -X cpp cpp2.c $(LINEFIX) >old.tmp2.c -X cpp cpp3.c $(LINEFIX) >old.tmp3.c -X cpp cpp4.c $(LINEFIX) >old.tmp4.c -X cpp cpp5.c $(LINEFIX) >old.tmp5.c -X cpp cpp6.c $(LINEFIX) >old.tmp6.c -X $(CC) $(CFLAGS) old.tmp[123456].c -X a.out cpp1.c >new.tmp1.c -X a.out cpp2.c >new.tmp2.c -X a.out cpp3.c >new.tmp3.c -X a.out cpp4.c >new.tmp4.c -X a.out cpp5.c >new.tmp5.c -X a.out cpp6.c >new.tmp6.c -X diff old.tmp1.c new.tmp1.c -X diff old.tmp2.c new.tmp2.c -X diff old.tmp3.c new.tmp3.c -X diff old.tmp4.c new.tmp4.c -X diff old.tmp5.c new.tmp5.c -X diff old.tmp6.c new.tmp6.c -X rm a.out old.tmp[123456].* new.tmp[123456].* -X -X# -X# A somewhat more extensive test is provided by the "clock" -X# program (which is not distributed). Substitute your favorite -X# macro-rich program here. -X# -Xclock: clock.c cpp -X cpp clock.c $(LINEFIX) >temp.cpp.c -X cc temp.cpp.c -lcurses -ltermcap -o clock -X rm temp.cpp.c -X -X# -X# ** Lint the code -X# -X -Xlint: $(SRCS) -X lint $(LINTFLAGS) $(DEFINES) $(SRCS) -X -X# -X# ** Remove unneeded files -X# -Xclean: -X rm -f $(OBJS) cpp -X -X# -X# ** Rebuild the archive files needed to distribute cpp -X# ** Uses the Decus C archive utility. -X# -X -Xarchc: archc.c -X $(CC) $(CFLAGS) archc.c -o archc -X -Xarchx: archx.c -X $(CC) $(CFLAGS) archx.c -o archx -X -Xarchive: archc -X archc readme.txt cpp.mem archx.c archc.c cpp.rno makefile.txt \ -X cpp*.h >cpp1.arc -X archc cpp1.c cpp2.c cpp3.c >cpp2.arc -X archc cpp4.c cpp5.c cpp6.c >cpp3.arc -X -X# -X# Object module dependencies -X# -X -Xcpp1.o : cpp1.c cpp.h cppdef.h -X -Xcpp2.o : cpp2.c cpp.h cppdef.h -X -Xcpp3.o : cpp3.c cpp.h cppdef.h -X -Xcpp4.o : cpp4.c cpp.h cppdef.h -X -Xcpp5.o : cpp5.c cpp.h cppdef.h -X -Xcpp6.o : cpp6.c cpp.h cppdef.h -X -X -END-of-makefile.txt -echo x - readme.txt -sed 's/^X//' >readme.txt << 'END-of-readme.txt' -X -XDecus cpp is a public-domain implementation of the C preprocessor. -XIt runs on VMS native (Vax C), VMS compatibilty mode (Decus C), -XRSX-11M, RSTS/E, P/OS, and RT11, as well as on several varieties -Xof Unix, including Ultrix. Decus cpp attempts to implement features -Xin the Draft ANSI Standard for the C language. It should be noted, -Xhowever, that this standard is under active development: the current -Xdraft of the standard explicitly states that "readers are requested -Xnot to specify or claim conformance to this draft." Thus readers -Xand users of Decus cpp should not assume that it conforms to the -Xdraft standard, or that it will conform to the actual C language -Xstandard. -X -XThese notes describe how to extract the cpp source files, configure it -Xfor your needs, and mention a few design decisions that may be of interest -Xto maintainers. -X -X Installation -X -XBecause the primary development of cpp was not on Unix, it -Xis distributed using the Decus C archive program (quite similar -Xto the archiver published in Kernighan and Plauger's Software -XTools). To extract the files from the net.sources distribution, -Xsave this message as cpp1.arc and the other two distribution -Xfiles as cpp2.arc and cpp3.arc. Then, using your favorite editor, -Xlocate the archx.c program, just following the line beginning with -X"-h- archx.c" -- the format of the distribution is just: -X -X -h- readme.txt -X ... this file -X -h- cpp.mem -X ... description of cpp -X -h- archx.c -X ... archx.c program -- extracts archives -X -h- archc.c -X ... archc.c program -- creates archives -X -XCompile archx.c -- it shouldn't require any special editing. -XThen run it as follows: -X -X archx *.arc -X -XYou do not need to remove mail headers from the saved messages. -X -XYou should then read through cppdef.h to make sure the HOST and -XTARGET (and other implementation-specific) definitions are set -Xcorrectly for your machine, editing them as needed. -X -XYou may then copy makefile.txt to Makefile, editing it as needed -Xfor your particular system. On Unix, cpp should be compiled -Xby make without further difficulty. On other operating systems, -Xyou should compile the six source modules, linking them together. -XNote that, on Decus C based systems, you must extend the default -Xstack allocation. The Decus C build utility will create the -Xappropriate command file. -X -X Support Notes -X -XThe USENET distribution kit was designed to keep all submissions around -X50,000 bytes: -X -Xcpp1.arc: -X readme.txt This file -X cpp.mem Documentation page (see below) -X archx.c Archive extraction program -X archc.c Archive construction program -X cpp.rno Source for cpp.mem (see below) -X makefile.txt Unix makefile -- copy to Makefile -X cpp.h Main header file (structure def's and globals) -X cppdef.h Configuration file (host and target definitions) -X -Xcpp2.arc: -X cpp1.c Mainline code, documentation master sources -X cpp2.c most #control processing -X cpp3.c filename stuff and command line parsing -Xcpp3.arc: -X cpp4.c #define processor -X cpp5.c #if processor -X cpp6.c Support code (symbol table and I/O routines) -X -XCpp intentionally does not rely on the presence of a full-scale -Xmacro preprocessor, it does require the simple parameter substitution -Xpreprocessor capabilities of Unix V6 and Decus C. If your C -Xlanguage lacks full preprocessing, you should make sure "nomacargs" -Xis #define'd in cpp.h. (This is done automatically by the Decus C -Xcompiler.) -X -XThe documentation (manual page) for cpp is included as cpp.mem -Xand cpp.rno. Cpp.rno is in Dec Runoff format, built by a Decus C -Xutility (getrno) from original source which is embedded in cpp1.c. -XTo my knowledge, there is no equivalent program that creates -Xthe nroff source appropriate for Unix. -X -XI would be happy to receive fixes to any problems you encounter. -XAs I do not maintain distribution kit base-levels, bare-bones -Xdiff listings without sufficient context are not very useful. -XIt is unlikely that I can find time to help you with other -Xdifficulties. -X -X Acknowledgements -X -XI received a great deal of help from many people in debugging cpp. -XAlan Feuer and Sam Kendall used "state of the art" run-time code -Xcheckers to locate several errors. Ed Keiser found problems when -Xcpp was used on machines with different int and pointer sizes. -XDave Conroy helped with the initial debugging, while Arthur Olsen -Xand George Rosenberg found (and solved) several problems in the -Xfirst USENET release. -X -XMartin Minow -Xdecvax!minow -X -END-of-readme.txt -echo x - cpp.mem -sed 's/^X//' >cpp.mem << 'END-of-cpp.mem' -X -X -X -X -X 1.0 C Pre-Processor -X -X -X -X ******* -X * cpp * -X ******* -X -X -X -X NAME: cpp -- C Pre-Processor -X -X SYNOPSIS: -X -X cpp [-options] [infile [outfile]] -X -X DESCRIPTION: -X -X CPP reads a C source file, expands macros and include -X files, and writes an input file for the C compiler. If -X no file arguments are given, CPP reads from stdin and -X writes to stdout. If one file argument is given, it -X will define the input file, while two file arguments -X define both input and output files. The file name "-" -X is a synonym for stdin or stdout as appropriate. -X -X The following options are supported. Options may be -X given in either case. -X -X -C If set, source-file comments are written -X to the output file. This allows the -X output of CPP to be used as the input to -X a program, such as lint, that expects -X commands embedded in specially-formatted -X comments. -X -X -Dname=value Define the name as if the programmer -X wrote -X -X #define name value -X -X at the start of the first file. If -X "=value" is not given, a value of "1" -X will be used. -X -X On non-unix systems, all alphabetic text -X will be forced to upper-case. -X -X -E Always return "success" to the operating -X system, even if errors were detected. -X Note that some fatal errors, such as a -X missing #include file, will terminate -X CPP, returning "failure" even if the -E -X option is given. -X Page 2 -X cpp C Pre-Processor -X -X -X -Idirectory Add this directory to the list of -X directories searched for #include "..." -X and #include <...> commands. Note that -X there is no space between the "-I" and -X the directory string. More than one -I -X command is permitted. On non-Unix -X systems "directory" is forced to -X upper-case. -X -X -N CPP normally predefines some symbols -X defining the target computer and -X operating system. If -N is specified, -X no symbols will be predefined. If -N -N -X is specified, the "always present" -X symbols, __LINE__, __FILE__, and -X __DATE__ are not defined. -X -X -Stext CPP normally assumes that the size of -X the target computer's basic variable -X types is the same as the size of these -X types of the host computer. (This can -X be overridden when CPP is compiled, -X however.) The -S option allows dynamic -X respecification of these values. "text" -X is a string of numbers, separated by -X commas, that specifies correct sizes. -X The sizes must be specified in the exact -X order: -X -X char short int long float double -X -X If you specify the option as "-S*text", -X pointers to these types will be -X specified. -S* takes one additional -X argument for pointer to function (e.g. -X int (*)()) -X -X For example, to specify sizes -X appropriate for a PDP-11, you would -X write: -X -X c s i l f d func -X -S1,2,2,2,4,8, -X -S*2,2,2,2,2,2,2 -X -X Note that all values must be specified. -X -X -Uname Undefine the name as if -X -X #undef name -X -X were given. On non-Unix systems, "name" -X will be forced to upper-case. -X Page 3 -X cpp C Pre-Processor -X -X -X -Xnumber Enable debugging code. If no value is -X given, a value of 1 will be used. (For -X maintenence of CPP only.) -X -X -X PRE-DEFINED VARIABLES: -X -X When CPP begins processing, the following variables will -X have been defined (unless the -N option is specified): -X -X Target computer (as appropriate): -X -X pdp11, vax, M68000 m68000 m68k -X -X Target operating system (as appropriate): -X -X rsx, rt11, vms, unix -X -X Target compiler (as appropriate): -X -X decus, vax11c -X -X The implementor may add definitions to this list. The -X default definitions match the definition of the host -X computer, operating system, and C compiler. -X -X The following are always available unless undefined (or -X -N was specified twice): -X -X __FILE__ The input (or #include) file being -X compiled (as a quoted string). -X -X __LINE__ The line number being compiled. -X -X __DATE__ The date and time of compilation as a -X Unix ctime quoted string (the trailing -X newline is removed). Thus, -X -X printf("Bug at line %s,", __LINE__); -X printf(" source file %s", __FILE__); -X printf(" compiled on %s", __DATE__); -X -X -X DRAFT PROPOSED ANSI STANDARD CONSIDERATIONS: -X -X The current version of the Draft Proposed Standard -X explicitly states that "readers are requested not to -X specify or claim conformance to this draft." Readers and -X users of Decus CPP should not assume that Decus CPP -X conforms to the standard, or that it will conform to the -X actual C Language Standard. -X -X When CPP is itself compiled, many features of the Draft -X Proposed Standard that are incompatible with existing -X Page 4 -X cpp C Pre-Processor -X -X -X preprocessors may be disabled. See the comments in -X CPP's source for details. -X -X The latest version of the Draft Proposed Standard (as -X reflected in Decus CPP) is dated November 12, 1984. -X -X Comments are removed from the input text. The comment -X is replaced by a single space character. The -C option -X preserves comments, writing them to the output file. -X -X The '$' character is considered to be a letter. This is -X a permitted extension. -X -X The following new features of C are processed by CPP: -X -X #elif expression (#else #if) -X '\xNNN' (Hexadecimal constant) -X '\a' (Ascii BELL) -X '\v' (Ascii Vertical Tab) -X #if defined NAME 1 if defined, 0 if not -X #if defined (NAME) 1 if defined, 0 if not -X #if sizeof (basic type) -X unary + -X 123U, 123LU Unsigned ints and longs. -X 12.3L Long double numbers -X token#token Token concatenation -X #include token Expands to filename -X -X The Draft Proposed Standard has extended C, adding a -X constant string concatenation operator, where -X -X "foo" "bar" -X -X is regarded as the single string "foobar". (This does -X not affect CPP's processing but does permit a limited -X form of macro argument substitution into strings as will -X be discussed.) -X -X The Standard Committee plans to add token concatenation -X to #define command lines. One suggested implementation -X is as follows: the sequence "Token1#Token2" is treated -X as if the programmer wrote "Token1Token2". This could -X be used as follows: -X -X #line 123 -X #define ATLINE foo#__LINE__ -X -X ATLINE would be defined as foo123. -X -X Note that "Token2" must either have the format of an -X identifier or be a string of digits. Thus, the string -X -X #define ATLINE foo#1x3 -X Page 5 -X cpp C Pre-Processor -X -X -X generates two tokens: "foo1" and "x3". -X -X If the tokens T1 and T2 are concatenated into T3, this -X implementation operates as follows: -X -X 1. Expand T1 if it is a macro. -X 2. Expand T2 if it is a macro. -X 3. Join the tokens, forming T3. -X 4. Expand T3 if it is a macro. -X -X A macro formal parameter will be substituted into a -X string or character constant if it is the only component -X of that constant: -X -X #define VECSIZE 123 -X #define vprint(name, size) \ -X printf("name" "[" "size" "] = {\n") -X ... vprint(vector, VECSIZE); -X -X expands (effectively) to -X -X vprint("vector[123] = {\n"); -X -X Note that this will be useful if your C compiler -X supports the new string concatenation operation noted -X above. As implemented here, if you write -X -X #define string(arg) "arg" -X ... string("foo") ... -X -X This implementation generates "foo", rather than the -X strictly correct ""foo"" (which will probably generate -X an error message). This is, strictly speaking, an error -X in CPP and may be removed from future releases. -X -X ERROR MESSAGES: -X -X Many. CPP prints warning or error messages if you try -X to use multiple-byte character constants -X (non-transportable) if you #undef a symbol that was not -X defined, or if your program has potentially nested -X comments. -X -X AUTHOR: -X -X Martin Minow -X -X BUGS: -X -X The #if expression processor uses signed integers only. -X I.e, #if 0xFFFFu < 0 may be TRUE. -X -END-of-cpp.mem -echo x - cpp.h -sed 's/^X//' >cpp.h << 'END-of-cpp.h' -X -X/* -X * I n t e r n a l D e f i n i t i o n s f o r C P P -X * -X * In general, definitions in this file should not be changed. -X */ -X -X#ifndef TRUE -X#define TRUE 1 -X#define FALSE 0 -X#endif -X#ifndef EOS -X/* -X * This is predefined in Decus C -X */ -X#define EOS '\0' /* End of string */ -X#endif -X#define EOF_CHAR 0 /* Returned by get() on eof */ -X#define NULLST ((char *) NULL) /* Pointer to nowhere (linted) */ -X#define DEF_NOARGS (-1) /* #define foo vs #define foo() */ -X -X/* -X * The following may need to change if the host system doesn't use ASCII. -X */ -X#define DEF_MAGIC 0x1D /* Magic for #defines */ -X#define TOK_SEP 0x1E /* Token concatenation delim. */ -X#define COM_SEP 0x1F /* Magic comment separator */ -X -X/* -X * Note -- in Ascii, the following will map macro formals onto DEL + the -X * C1 control character region (decimal 128 .. (128 + PAR_MAC)) which will -X * be ok as long as PAR_MAC is less than 33). Note that the last PAR_MAC -X * value is reserved for string substitution. -X */ -X -X#define MAC_PARM 0x7F /* Macro formals start here */ -X#if PAR_MAC >= 33 -X assertion fails -- PAR_MAC isn't less than 33 -X#endif -X#define LASTPARM (PAR_MAC - 1) -X -X/* -X * Character type codes. -X */ -X -X#define INV 0 /* Invalid, must be zero */ -X#define OP_EOE INV /* End of expression */ -X#define DIG 1 /* Digit */ -X#define LET 2 /* Identifier start */ -X#define FIRST_BINOP OP_ADD -X#define OP_ADD 3 -X#define OP_SUB 4 -X#define OP_MUL 5 -X#define OP_DIV 6 -X#define OP_MOD 7 -X#define OP_ASL 8 -X#define OP_ASR 9 -X#define OP_AND 10 /* &, not && */ -X#define OP_OR 11 /* |, not || */ -X#define OP_XOR 12 -X#define OP_EQ 13 -X#define OP_NE 14 -X#define OP_LT 15 -X#define OP_LE 16 -X#define OP_GE 17 -X#define OP_GT 18 -X#define OP_ANA 19 /* && */ -X#define OP_ORO 20 /* || */ -X#define OP_QUE 21 /* ? */ -X#define OP_COL 22 /* : */ -X#define OP_CMA 23 /* , (relevant?) */ -X#define LAST_BINOP OP_CMA /* Last binary operand */ -X/* -X * The following are unary. -X */ -X#define FIRST_UNOP OP_PLU /* First Unary operand */ -X#define OP_PLU 24 /* + (draft ANSI standard) */ -X#define OP_NEG 25 /* - */ -X#define OP_COM 26 /* ~ */ -X#define OP_NOT 27 /* ! */ -X#define LAST_UNOP OP_NOT -X#define OP_LPA 28 /* ( */ -X#define OP_RPA 29 /* ) */ -X#define OP_END 30 /* End of expression marker */ -X#define OP_MAX (OP_END + 1) /* Number of operators */ -X#define OP_FAIL (OP_END + 1) /* For error returns */ -X -X/* -X * The following are for lexical scanning only. -X */ -X -X#define QUO 65 /* Both flavors of quotation */ -X#define DOT 66 /* . might start a number */ -X#define SPA 67 /* Space and tab */ -X#define BSH 68 /* Just a backslash */ -X#define END 69 /* EOF */ -X -X/* -X * These bits are set in ifstack[] -X */ -X#define WAS_COMPILING 1 /* TRUE if compile set at entry */ -X#define ELSE_SEEN 2 /* TRUE when #else processed */ -X#define TRUE_SEEN 4 /* TRUE when #if TRUE processed */ -X -X/* -X * Define bits for the basic types and their adjectives -X */ -X -X#define T_CHAR 1 -X#define T_INT 2 -X#define T_FLOAT 4 -X#define T_DOUBLE 8 -X#define T_SHORT 16 -X#define T_LONG 32 -X#define T_SIGNED 64 -X#define T_UNSIGNED 128 -X#define T_PTR 256 /* Pointer */ -X#define T_FPTR 512 /* Pointer to functions */ -X -X/* -X * The DEFBUF structure stores information about #defined -X * macros. Note that the defbuf->repl information is always -X * in malloc storage. -X */ -X -Xtypedef struct defbuf { -X struct defbuf *link; /* Next define in chain */ -X char *repl; /* -> replacement */ -X int hash; /* Symbol table hash */ -X int nargs; /* For define(args) */ -X char name[1]; /* #define name */ -X} DEFBUF; -X -X/* -X * The FILEINFO structure stores information about open files -X * and macros being expanded. -X */ -X -Xtypedef struct fileinfo { -X char *bptr; /* Buffer pointer */ -X int line; /* for include or macro */ -X FILE *fp; /* File if non-null */ -X struct fileinfo *parent; /* Link to includer */ -X char *filename; /* File/macro name */ -X char *progname; /* From #line statement */ -X unsigned int unrecur; /* For macro recursion */ -X char buffer[1]; /* current input line */ -X} FILEINFO; -X -X/* -X * The SIZES structure is used to store the values for #if sizeof -X */ -X -Xtypedef struct sizes { -X short bits; /* If this bit is set, */ -X short size; /* this is the datum size value */ -X short psize; /* this is the pointer size */ -X} SIZES; -X/* -X * nomacarg is a built-in #define on Decus C. -X */ -X -X#ifdef nomacarg -X#define cput output /* cput concatenates tokens */ -X#else -X#if COMMENT_INVISIBLE -X#define cput(c) { if (c != TOK_SEP && c != COM_SEP) putchar(c); } -X#else -X#define cput(c) { if (c != TOK_SEP) putchar(c); } -X#endif -X#endif -X -X#ifndef nomacarg -X#define streq(s1, s2) (strcmp(s1, s2) == 0) -X#endif -X -X/* -X * Error codes. VMS uses system definitions. -X * Decus C codes are defined in stdio.h. -X * Others are cooked to order. -X */ -X -X#if HOST == SYS_VMS -X#include -X#include -X#define IO_NORMAL (SS$_NORMAL | STS$M_INHIB_MSG) -X#define IO_ERROR SS$_ABORT -X#endif -X/* -X * Note: IO_NORMAL and IO_ERROR are defined in the Decus C stdio.h file -X */ -X#ifndef IO_NORMAL -X#define IO_NORMAL 0 -X#endif -X#ifndef IO_ERROR -X#define IO_ERROR 1 -X#endif -X -X/* -X * Externs -X */ -X -Xextern int line; /* Current line number */ -Xextern int wrongline; /* Force #line to cc pass 1 */ -Xextern char type[]; /* Character classifier */ -Xextern char token[IDMAX + 1]; /* Current input token */ -Xextern int instring; /* TRUE if scanning string */ -Xextern int inmacro; /* TRUE if scanning #define */ -Xextern int errors; /* Error counter */ -Xextern int recursion; /* Macro depth counter */ -Xextern char ifstack[BLK_NEST]; /* #if information */ -X#define compiling ifstack[0] -Xextern char *ifptr; /* -> current ifstack item */ -Xextern char *incdir[NINCLUDE]; /* -i directories */ -Xextern char **incend; /* -> active end of incdir */ -Xextern int cflag; /* -C option (keep comments) */ -Xextern int eflag; /* -E option (ignore errors) */ -Xextern int nflag; /* -N option (no pre-defines) */ -Xextern int rec_recover; /* unwind recursive macros */ -Xextern char *preset[]; /* Standard predefined symbols */ -Xextern char *magic[]; /* Magic predefined symbols */ -Xextern FILEINFO *infile; /* Current input file */ -Xextern char work[NWORK + 1]; /* #define scratch */ -Xextern char *workp; /* Free space in work */ -X#if DEBUG -Xextern int debug; /* Debug level */ -X#endif -Xextern int keepcomments; /* Don't remove comments if set */ -Xextern SIZES size_table[]; /* For #if sizeof sizes */ -Xextern char *getmem(); /* Get memory or die. */ -Xextern DEFBUF *lookid(); /* Look for a #define'd thing */ -Xextern DEFBUF *defendel(); /* Symbol table enter/delete */ -Xextern char *savestring(); /* Stuff string in malloc mem. */ -Xextern char *strcpy(); -Xextern char *strcat(); -Xextern char *strrchr(); -Xextern char *strchr(); -Xextern long time(); -X/* extern char *sprintf(); /* Lint needs this */ -END-of-cpp.h -echo x - cppdef.h -sed 's/^X//' >cppdef.h << 'END-of-cppdef.h' -X/* -X * S y s t e m D e p e n d e n t -X * D e f i n i t i o n s f o r C P P -X * -X * Definitions in this file may be edited to configure CPP for particular -X * host operating systems and target configurations. -X * -X * NOTE: cpp assumes it is compiled by a compiler that supports macros -X * with arguments. If this is not the case (as for Decus C), #define -X * nomacarg -- and provide function equivalents for all macros. -X * -X * cpp also assumes the host and target implement the Ascii character set. -X * If this is not the case, you will have to do some editing here and there. -X */ -X -X/* -X * This redundant definition of TRUE and FALSE works around -X * a limitation of Decus C. -X */ -X#ifndef TRUE -X#define TRUE 1 -X#define FALSE 0 -X#endif -X -X/* -X * Define the HOST operating system. This is needed so that -X * cpp can use appropriate filename conventions. -X */ -X#define SYS_UNKNOWN 0 -X#define SYS_UNIX 1 -X#define SYS_VMS 2 -X#define SYS_RSX 3 -X#define SYS_RT11 4 -X#define SYS_LATTICE 5 -X#define SYS_ONYX 6 -X#define SYS_68000 7 -X#define SYS_GCOS 8 -X#define SYS_IBM 9 -X#define SYS_OS 10 -X#define SYS_TSS 11 -X -X#ifndef HOST -X#ifdef unix -X#define HOST SYS_UNIX -X#else -X#ifdef vms -X#define HOST SYS_VMS -X#else -X#ifdef rsx -X#define HOST SYS_RSX -X#else -X#ifdef rt11 -X#define HOST SYS_RT11 -X#else -X#ifdef dmert -X#define HOST SYS_DMERT -X#else -X#ifdef gcos -X#define HOST SYS_GCOS -X#else -X#ifdef ibm -X#define HOST SYS_IBM -X#else -X#ifdef os -X#define HOST SYS_OS -X#else -X#ifdef tss -X#define HOST SYS_TSS -X#endif -X#endif -X#endif -X#endif -X#endif -X#endif -X#endif -X#endif -X#endif -X -X#ifndef HOST -X#define HOST SYS_UNKNOWN -X#endif -X -X/* -X * We assume that the target is the same as the host system -X */ -X#ifndef TARGET -X#define TARGET HOST -X#endif -X -X/* -X * In order to predefine machine-dependent constants, -X * several strings are defined here: -X * -X * MACHINE defines the target cpu (by name) -X * SYSTEM defines the target operating system -X * COMPILER defines the target compiler -X * -X * The above may be #defined as "" if they are not wanted. -X * They should not be #defined as NULL. -X * -X * LINE_PREFIX defines the # output line prefix, if not "line" -X * This should be defined as "" if cpp is to replace -X * the "standard" C pre-processor. -X * -X * FILE_LOCAL marks functions which are referenced only in the -X * file they reside. Some C compilers allow these -X * to be marked "static" even though they are referenced -X * by "extern" statements elsewhere. -X * -X * OK_DOLLAR Should be set TRUE if $ is a valid alphabetic character -X * in identifiers (default), or zero if $ is invalid. -X * Default is TRUE. -X * -X * OK_CONCAT Should be set TRUE if # may be used to concatenate -X * tokens in macros (per the Ansi Draft Standard) or -X * FALSE for old-style # processing (needed if cpp is -X * to process assembler source code). -X * -X * OK_DATE Predefines the compilation date if set TRUE. -X * Not permitted by the Nov. 12, 1984 Draft Standard. -X * -X * S_CHAR etc. Define the sizeof the basic TARGET machine word types. -X * By default, sizes are set to the values for the HOST -X * computer. If this is inappropriate, see the code in -X * cpp3.c for details on what to change. Also, if you -X * have a machine where sizeof (signed int) differs from -X * sizeof (unsigned int), you will have to edit code and -X * tables in cpp3.c (and extend the -S option definition.) -X * -X * CPP_LIBRARY May be defined if you have a site-specific include directory -X * which is to be searched *before* the operating-system -X * specific directories. -X */ -X -X#if TARGET == SYS_LATTICE -X/* -X * We assume the operating system is pcdos for the IBM-PC. -X * We also assume the small model (just like the PDP-11) -X */ -X#define MACHINE "i8086" -X#define SYSTEM "pcdos" -X#endif -X -X#if TARGET == SYS_ONYX -X#define MACHINE "z8000" -X#define SYSTEM "unix" -X#endif -X -X#if TARGET == SYS_VMS -X#define MACHINE "vax" -X#define SYSTEM "vms" -X#define COMPILER "vax11c" -X#endif -X -X#if TARGET == SYS_RSX -X#define MACHINE "pdp11" -X#define SYSTEM "rsx" -X#define COMPILER "decus" -X#endif -X -X#if TARGET == SYS_RT11 -X#define MACHINE "pdp11" -X#define SYSTEM "rt11" -X#define COMPILER "decus" -X#endif -X -X#if TARGET == SYS_68000 -X/* -X * All three machine designators have been seen in various systems. -X * Warning -- compilers differ as to sizeof (int). cpp3 assumes that -X * sizeof (int) == 2 -X */ -X#define MACHINE "M68000", "m68000", "m68k" -X#define SYSTEM "unix" -X#endif -X -X#if TARGET == SYS_UNIX -X#define SYSTEM "unix" -X#ifdef pdp11 -X#define MACHINE "pdp11" -X#endif -X#ifdef vax -X#define MACHINE "vax" -X#endif -X#ifdef u370 -X#define MACHINE "u370" -X#endif -X#ifdef interdata -X#define MACHINE "interdata" -X#endif -X#ifdef u3b -X#define MACHINE "u3b" -X#endif -X#ifdef u3b5 -X#define MACHINE "u3b5" -X#endif -X#ifdef u3b2 -X#define MACHINE "u3b2" -X#endif -X#ifdef u3b20d -X#define MACHINE "u3b20d" -X#endif -X#endif -X#endif -X -X/* -X * defaults -X */ -X -X#ifndef MSG_PREFIX -X#define MSG_PREFIX "cpp: " -X#endif -X -X#ifndef LINE_PREFIX -X#ifdef decus -X#define LINE_PREFIX "" -X#else -X#define LINE_PREFIX "line" -X#endif -X#endif -X -X/* -X * OLD_PREPROCESSOR forces the definition of OK_DOLLAR, OK_CONCAT, -X * COMMENT_INVISIBLE, and STRING_FORMAL to values appropriate for -X * an old-style preprocessor. -X */ -X -X#ifndef OLD_PREPROCESSOR -X#define OLD_PREPROCESSOR FALSE -X#endif -X -X#if OLD_PREPROCESSOR -X#define OK_DOLLAR FALSE -X#define OK_CONCAT FALSE -X#define COMMENT_INVISIBLE TRUE -X#define STRING_FORMAL TRUE -X#endif -X -X/* -X * RECURSION_LIMIT may be set to -1 to disable the macro recursion test. -X */ -X#ifndef RECURSION_LIMIT -X#define RECURSION_LIMIT 1000 -X#endif -X -X/* -X * BITS_CHAR may be defined to set the number of bits per character. -X * it is needed only for multi-byte character constants. -X */ -X#ifndef BITS_CHAR -X#define BITS_CHAR 8 -X#endif -X -X/* -X * BIG_ENDIAN is set TRUE on machines (such as the IBM 360 series) -X * where 'ab' stores 'a' in the high-bits and 'b' in the low-bits. -X * It is set FALSE on machines (such as the PDP-11 and Vax-11) -X * where 'ab' stores 'a' in the low-bits and 'b' in the high-bits. -X * (Or is it the other way around?) -- Warning: BIG_ENDIAN code is untested. -X */ -X#ifndef BIG_ENDIAN -X#define BIG_ENDIAN FALSE -X#endif -X -X/* -X * COMMENT_INVISIBLE may be defined to allow "old-style" comment -X * processing, whereby the comment becomes a zero-length token -X * delimiter. This permitted tokens to be concatenated in macro -X * expansions. This was removed from the Draft Ansi Standard. -X */ -X#ifndef COMMENT_INVISIBLE -X#define COMMENT_INVISIBLE FALSE -X#endif -X -X/* -X * STRING_FORMAL may be defined to allow recognition of macro parameters -X * anywhere in replacement strings. This was removed from the Draft Ansi -X * Standard and a limited recognition capability added. -X */ -X#ifndef STRING_FORMAL -X#define STRING_FORMAL FALSE -X#endif -X -X/* -X * OK_DOLLAR enables use of $ as a valid "letter" in identifiers. -X * This is a permitted extension to the Ansi Standard and is required -X * for e.g., VMS, RSX-11M, etc. It should be set FALSE if cpp is -X * used to preprocess assembler source on Unix systems. OLD_PREPROCESSOR -X * sets OK_DOLLAR FALSE for that reason. -X */ -X#ifndef OK_DOLLAR -X#define OK_DOLLAR TRUE -X#endif -X -X/* -X * OK_CONCAT enables (one possible implementation of) token concatenation. -X * If cpp is used to preprocess Unix assembler source, this should be -X * set FALSE as the concatenation character, #, is used by the assembler. -X */ -X#ifndef OK_CONCAT -X#define OK_CONCAT TRUE -X#endif -X -X/* -X * OK_DATE may be enabled to predefine today's date as a string -X * at the start of each compilation. This is apparently not permitted -X * by the Draft Ansi Standard. -X */ -X#ifndef OK_DATE -X#define OK_DATE TRUE -X#endif -X -X/* -X * Some common definitions. -X */ -X -X#ifndef DEBUG -X#define DEBUG FALSE -X#endif -X -X/* -X * The following definitions are used to allocate memory for -X * work buffers. In general, they should not be modified -X * by implementors. -X * -X * PAR_MAC The maximum number of #define parameters (31 per Standard) -X * Note: we need another one for strings. -X * IDMAX The longest identifier, 31 per Ansi Standard -X * NBUFF Input buffer size -X * NWORK Work buffer size -- the longest macro -X * must fit here after expansion. -X * NEXP The nesting depth of #if expressions -X * NINCLUDE The number of directories that may be specified -X * on a per-system basis, or by the -I option. -X * BLK_NEST The number of nested #if's permitted. -X */ -X -X#define IDMAX 31 -X#define PAR_MAC (31 + 1) -X#define NBUFF 1024 -X#define NWORK 1024 -X#define NEXP 128 -X#define NINCLUDE 7 -X#define NPARMWORK (NWORK * 2) -X#define BLK_NEST 32 -X -X/* -X * Some special constants. These may need to be changed if cpp -X * is ported to a wierd machine. -X * -X * NOTE: if cpp is run on a non-ascii machine, ALERT and VT may -X * need to be changed. They are used to implement the proposed -X * ANSI standard C control characters '\a' and '\v' only. -X * DEL is used to tag macro tokens to prevent #define foo foo -X * from looping. Note that we don't try to prevent more elaborate -X * #define loops from occurring. -X */ -X -X#ifndef ALERT -X#define ALERT '\007' /* '\a' is "Bell" */ -X#endif -X -X#ifndef VT -X#define VT '\013' /* Vertical Tab CTRL/K */ -X#endif -X -X -X#ifndef FILE_LOCAL -X#ifdef decus -X#define FILE_LOCAL static -X#else -X#ifdef vax11c -X#define FILE_LOCAL static -X#else -X#define FILE_LOCAL /* Others are global */ -X#endif -X#endif -X#endif -X -END-of-cppdef.h -echo x - cpp2.c -sed 's/^X//' >cpp2.c << 'END-of-cpp2.c' -X/* -X * C P P 2 . C -X * -X * Process #control lines -X * -X * Edit history -X * 13-Nov-84 MM Split from cpp1.c -X */ -X -X#include -X#include -X#include "cppdef.h" -X#include "cpp.h" -X#if HOST == SYS_VMS -X/* -X * Include the rms stuff. (We can't just include rms.h as it uses the -X * VaxC-specific library include syntax that Decus CPP doesn't support. -X * By including things by hand, we can CPP ourself.) -X */ -X#include -X#include -X#include -X#include -X#endif -X -X/* -X * Generate (by hand-inspection) a set of unique values for each control -X * operator. Note that this is not guaranteed to work for non-Ascii -X * machines. CPP won't compile if there are hash conflicts. -X */ -X -X#define L_assert ('a' + ('s' << 1)) -X#define L_define ('d' + ('f' << 1)) -X#define L_elif ('e' + ('i' << 1)) -X#define L_else ('e' + ('s' << 1)) -X#define L_endif ('e' + ('d' << 1)) -X#define L_ident ('i' + ('e' << 1)) -X#define L_if ('i' + (EOS << 1)) -X#define L_ifdef ('i' + ('d' << 1)) -X#define L_ifndef ('i' + ('n' << 1)) -X#define L_include ('i' + ('c' << 1)) -X#define L_line ('l' + ('n' << 1)) -X#define L_nogood (EOS + (EOS << 1)) /* To catch #i */ -X#define L_pragma ('p' + ('a' << 1)) -X#define L_sccs ('s' + ('c' << 1)) -X#define L_undef ('u' + ('d' << 1)) -X#if DEBUG -X#define L_debug ('d' + ('b' << 1)) /* #debug */ -X#define L_nodebug ('n' + ('d' << 1)) /* #nodebug */ -X#endif -X -Xint -Xcontrol(counter) -Xint counter; /* Pending newline counter */ -X/* -X * Process #control lines. Simple commands are processed inline, -X * while complex commands have their own subroutines. -X * -X * The counter is used to force out a newline before #line, and -X * #pragma commands. This prevents these commands from ending up at -X * the end of the previous line if cpp is invoked with the -C option. -X */ -X{ -X register int c; -X register char *tp; -X register int hash; -X char *ep; -X -X c = skipws(); -X if (c == '\n' || c == EOF_CHAR) -X return (counter + 1); -X if (!isdigit(c)) -X scanid(c); /* Get #word to token[] */ -X else { -X unget(); /* Hack -- allow #123 as a */ -X strcpy(token, "line"); /* synonym for #line 123 */ -X } -X hash = (token[1] == EOS) ? L_nogood : (token[0] + (token[2] << 1)); -X switch (hash) { -X case L_assert: tp = "assert"; break; -X case L_define: tp = "define"; break; -X case L_elif: tp = "elif"; break; -X case L_else: tp = "else"; break; -X case L_endif: tp = "endif"; break; -X case L_ident: tp = "ident"; break; -X case L_if: tp = "if"; break; -X case L_ifdef: tp = "ifdef"; break; -X case L_ifndef: tp = "ifndef"; break; -X case L_include: tp = "include"; break; -X case L_line: tp = "line"; break; -X case L_pragma: tp = "pragma"; break; -X case L_sccs: tp = "sccs"; break; -X case L_undef: tp = "undef"; break; -X#if DEBUG -X case L_debug: tp = "debug"; break; -X case L_nodebug: tp = "nodebug"; break; -X#endif -X default: hash = L_nogood; -X case L_nogood: tp = ""; break; -X } -X if (!streq(tp, token)) -X hash = L_nogood; -X /* -X * hash is set to a unique value corresponding to the -X * control keyword (or L_nogood if we think it's nonsense). -X */ -X if (infile->fp == NULL) -X cwarn("Control line \"%s\" within macro expansion", token); -X if (!compiling) { /* Not compiling now */ -X switch (hash) { -X case L_if: /* These can't turn */ -X case L_ifdef: /* compilation on, but */ -X case L_ifndef: /* we must nest #if's */ -X if (++ifptr >= &ifstack[BLK_NEST]) -X goto if_nest_err; -X *ifptr = 0; /* !WAS_COMPILING */ -X case L_line: /* Many */ -X /* -X * Are pragma's always processed? -X */ -X case L_ident: -X case L_sccs: -X case L_pragma: /* options */ -X case L_include: /* are uninteresting */ -X case L_define: /* if we */ -X case L_undef: /* aren't */ -X case L_assert: /* compiling. */ -Xdump_line: skipnl(); /* Ignore rest of line */ -X return (counter + 1); -X } -X } -X /* -X * Make sure that #line and #pragma are output on a fresh line. -X */ -X if (counter > 0 && (hash == L_line || hash == L_pragma)) { -X putchar('\n'); -X counter--; -X } -X switch (hash) { -X case L_line: -X /* -X * Parse the line to update the line number and "progname" -X * field and line number for the next input line. -X * Set wrongline to force it out later. -X */ -X c = skipws(); -X workp = work; /* Save name in work */ -X while (c != '\n' && c != EOF_CHAR) { -X save(c); -X c = get(); -X } -X unget(); -X save(EOS); -X /* -X * Split #line argument into and -X * We subtract 1 as we want the number of the next line. -X */ -X line = atoi(work) - 1; /* Reset line number */ -X for (tp = work; isdigit(*tp) || type[*tp] == SPA; tp++) -X ; /* Skip over digits */ -X if (*tp != EOS) { /* Got a filename, so: */ -X if (*tp == '"' && (ep = strrchr(tp + 1, '"')) != NULL) { -X tp++; /* Skip over left quote */ -X *ep = EOS; /* And ignore right one */ -X } -X if (infile->progname != NULL) /* Give up the old name */ -X free(infile->progname); /* if it's allocated. */ -X infile->progname = savestring(tp); -X } -X wrongline = TRUE; /* Force output later */ -X break; -X -X case L_include: -X doinclude(); -X break; -X -X case L_define: -X dodefine(); -X break; -X -X case L_undef: -X doundef(); -X break; -X -X case L_else: -X if (ifptr == &ifstack[0]) -X goto nest_err; -X else if ((*ifptr & ELSE_SEEN) != 0) -X goto else_seen_err; -X *ifptr |= ELSE_SEEN; -X if ((*ifptr & WAS_COMPILING) != 0) { -X if (compiling || (*ifptr & TRUE_SEEN) != 0) -X compiling = FALSE; -X else { -X compiling = TRUE; -X } -X } -X break; -X -X case L_elif: -X if (ifptr == &ifstack[0]) -X goto nest_err; -X else if ((*ifptr & ELSE_SEEN) != 0) { -Xelse_seen_err: cerror("#%s may not follow #else", token); -X goto dump_line; -X } -X if ((*ifptr & (WAS_COMPILING | TRUE_SEEN)) != WAS_COMPILING) { -X compiling = FALSE; /* Done compiling stuff */ -X goto dump_line; /* Skip this clause */ -X } -X doif(L_if); -X break; -X -X case L_if: -X case L_ifdef: -X case L_ifndef: -X if (++ifptr >= &ifstack[BLK_NEST]) -Xif_nest_err: cfatal("Too many nested #%s statements", token); -X *ifptr = WAS_COMPILING; -X doif(hash); -X break; -X -X case L_endif: -X if (ifptr == &ifstack[0]) { -Xnest_err: cerror("#%s must be in an #if", token); -X goto dump_line; -X } -X if (!compiling && (*ifptr & WAS_COMPILING) != 0) -X wrongline = TRUE; -X compiling = ((*ifptr & WAS_COMPILING) != 0); -X --ifptr; -X break; -X -X case L_assert: -X if (eval() == 0) -X cerror("Preprocessor assertion failure", NULLST); -X break; -X -X case L_ident: -X case L_sccs: -X goto dump_line; -X break; -X -X case L_pragma: -X /* -X * #pragma is provided to pass "options" to later -X * passes of the compiler. cpp doesn't have any yet. -X */ -X printf("#pragma "); -X while ((c = get()) != '\n' && c != EOF_CHAR) -X cput(c); -X unget(); -X break; -X -X#if DEBUG -X case L_debug: -X if (debug == 0) -X dumpdef("debug set on"); -X debug++; -X break; -X -X case L_nodebug: -X debug--; -X break; -X#endif -X -X default: -X /* -X * Undefined #control keyword. -X * Note: the correct behavior may be to warn and -X * pass the line to a subsequent compiler pass. -X * This would allow #asm or similar extensions. -X */ -X cerror("Illegal # command \"%s\"", token); -X break; -X } -X if (hash != L_include) { -X#if OLD_PREPROCESSOR || !VERBOSE -X /* -X * Ignore the rest of the #control line so you can write -X * #if foo -X * #endif foo -X */ -X goto dump_line; /* Take common exit */ -X#else -X if (skipws() != '\n') { -X cwarn("Unexpected text in #control line ignored", NULLST); -X skipnl(); -X } -X#endif -X } -X return (counter + 1); -X} -X -XFILE_LOCAL -Xdoif(hash) -Xint hash; -X/* -X * Process an #if, #ifdef, or #ifndef. The latter two are straightforward, -X * while #if needs a subroutine of its own to evaluate the expression. -X * -X * doif() is called only if compiling is TRUE. If false, compilation -X * is always supressed, so we don't need to evaluate anything. This -X * supresses unnecessary warnings. -X */ -X{ -X register int c; -X register int found; -X -X if ((c = skipws()) == '\n' || c == EOF_CHAR) { -X unget(); -X goto badif; -X } -X if (hash == L_if) { -X unget(); -X found = (eval() != 0); /* Evaluate expr, != 0 is TRUE */ -X hash = L_ifdef; /* #if is now like #ifdef */ -X } -X else { -X if (type[c] != LET) /* Next non-blank isn't letter */ -X goto badif; /* ... is an error */ -X found = (lookid(c) != NULL); /* Look for it in symbol table */ -X } -X if (found == (hash == L_ifdef)) { -X compiling = TRUE; -X *ifptr |= TRUE_SEEN; -X } -X else { -X compiling = FALSE; -X } -X return; -X -Xbadif: cerror("#if, #ifdef, or #ifndef without an argument", NULLST); -X#if !OLD_PREPROCESSOR -X skipnl(); /* Prevent an extra */ -X unget(); /* Error message */ -X#endif -X return; -X} -X -XFILE_LOCAL -Xdoinclude() -X/* -X * Process the #include control line. -X * There are three variations: -X * #include "file" search somewhere relative to the -X * current source file, if not found, -X * treat as #include . -X * #include Search in an implementation-dependent -X * list of places. -X * #include token Expand the token, it must be one of -X * "file" or , process as such. -X * -X * Note: the November 12 draft forbids '>' in the #include format. -X * This restriction is unnecessary and not implemented. -X */ -X{ -X register int c; -X register int delim; -X#if HOST == SYS_VMS -X char def_filename[NAM$C_MAXRSS + 1]; -X#endif -X -X delim = macroid(skipws()); -X if (delim != '<' && delim != '"') -X goto incerr; -X if (delim == '<') -X delim = '>'; -X workp = work; -X instring = TRUE; /* Accept all characters */ -X while ((c = get()) != '\n' && c != delim && c != EOF_CHAR) -X save(c); /* Put it away. */ -X skipnl(); -X /* -X * The draft is unclear if the following should be done. -X */ -X -X while (--workp >= work && (type[*workp] == SPA)) -X ; /* Trim blanks from filename */ -X -X/* -X * if (*workp != delim) -X * goto incerr; -X */ -X *(workp + 1) = EOS; /* Terminate filename */ -X instring = FALSE; -X#if HOST == SYS_VMS -X /* -X * Assume the default .h filetype. -X */ -X if (!vmsparse(work, ".H", def_filename)) { -X perror(work); /* Oops. */ -X goto incerr; -X } -X else if (openinclude(def_filename, (delim == '"'))) -X return; -X#else -X if (openinclude(work, (delim == '"'))) -X return; -X#endif -X /* -X * No sense continuing if #include file isn't there. -X */ -X cfatal("Cannot open include file \"%s\"", work); -X -Xincerr: cerror("#include syntax error", NULLST); -X return; -X} -X -XFILE_LOCAL int -Xopeninclude(filename, searchlocal) -Xchar *filename; /* Input file name */ -Xint searchlocal; /* TRUE if #include "file" */ -X/* -X * Actually open an include file. This routine is only called from -X * doinclude() above, but was written as a separate subroutine for -X * programmer convenience. It searches the list of directories -X * and actually opens the file, linking it into the list of -X * active files. Returns TRUE if the file was opened, FALSE -X * if openinclude() fails. No error message is printed. -X */ -X{ -X register char **incptr; -X#if HOST == SYS_VMS -X#if NWORK < (NAM$C_MAXRSS + 1) -X << error, NWORK isn't greater than NAM$C_MAXRSS >> -X#endif -X#endif -X char tmpname[NWORK]; /* Filename work area */ -X -X if (searchlocal) { -X /* -X * Look in local directory first -X */ -X#if HOST == SYS_UNIX -X /* -X * Try to open filename relative to the directory of the current -X * source file (as opposed to the current directory). (ARF, SCK). -X */ -X if (filename[0] != '/' -X && hasdirectory(infile->filename, tmpname)) -X strcat(tmpname, filename); -X else { -X strcpy(tmpname, filename); -X } -X#else -X if (!hasdirectory(filename, tmpname) -X && hasdirectory(infile->filename, tmpname)) -X strcat(tmpname, filename); -X else { -X strcpy(tmpname, filename); -X } -X#endif -X if (openfile(tmpname)) -X return (TRUE); -X } -X /* -X * Look in any directories specified by -I command line -X * arguments, then in the builtin search list. -X */ -X for (incptr = incdir; incptr < incend; incptr++) { -X if (strlen(*incptr) + strlen(filename) >= (NWORK - 1)) -X cfatal("Filename work buffer overflow", NULLST); -X else { -X#if HOST == SYS_UNIX -X if (filename[0] == '/') -X strcpy(tmpname, filename); -X else { -X sprintf(tmpname, "%s/%s", *incptr, filename); -X } -X#else -X if (!hasdirectory(filename, tmpname)) -X sprintf(tmpname, "%s%s", *incptr, filename); -X#endif -X if (openfile(tmpname)) -X return (TRUE); -X } -X } -X return (FALSE); -X} -X -XFILE_LOCAL int -Xhasdirectory(source, result) -Xchar *source; /* Directory to examine */ -Xchar *result; /* Put directory stuff here */ -X/* -X * If a device or directory is found in the source filename string, the -X * node/device/directory part of the string is copied to result and -X * hasdirectory returns TRUE. Else, nothing is copied and it returns FALSE. -X */ -X{ -X#if HOST == SYS_UNIX -X register char *tp; -X -X if ((tp = strrchr(source, '/')) == NULL) -X return (FALSE); -X else { -X strncpy(result, source, tp - source + 1); -X result[tp - source + 1] = EOS; -X return (TRUE); -X } -X#else -X#if HOST == SYS_VMS -X if (vmsparse(source, NULLST, result) -X && result[0] != EOS) -X return (TRUE); -X else { -X return (FALSE); -X } -X#else -X /* -X * Random DEC operating system (RSX, RT11, RSTS/E) -X */ -X register char *tp; -X -X if ((tp = strrchr(source, ']')) == NULL -X && (tp = strrchr(source, ':')) == NULL) -X return (FALSE); -X else { -X strncpy(result, source, tp - source + 1); -X result[tp - source + 1] = EOS; -X return (TRUE); -X } -X#endif -X#endif -X} -X -X#if HOST == SYS_VMS -X -X/* -X * EXP_DEV is set if a device was specified, EXP_DIR if a directory -X * is specified. (Both set indicate a file-logical, but EXP_DEV -X * would be set by itself if you are reading, say, SYS$INPUT:) -X */ -X#define DEVDIR (NAM$M_EXP_DEV | NAM$M_EXP_DIR) -X -XFILE_LOCAL int -Xvmsparse(source, defstring, result) -Xchar *source; -Xchar *defstring; /* non-NULL -> default string. */ -Xchar *result; /* Size is at least NAM$C_MAXRSS + 1 */ -X/* -X * Parse the source string, applying the default (properly, using -X * the system parse routine), storing it in result. -X * TRUE if it parsed, FALSE on error. -X * -X * If defstring is NULL, there are no defaults and result gets -X * (just) the node::[directory] part of the string (possibly "") -X */ -X{ -X struct FAB fab = cc$rms_fab; /* File access block */ -X struct NAM nam = cc$rms_nam; /* File name block */ -X char fullname[NAM$C_MAXRSS + 1]; -X register char *rp; /* Result pointer */ -X -X fab.fab$l_nam = &nam; /* fab -> nam */ -X fab.fab$l_fna = source; /* Source filename */ -X fab.fab$b_fns = strlen(source); /* Size of source */ -X fab.fab$l_dna = defstring; /* Default string */ -X if (defstring != NULLST) -X fab.fab$b_dns = strlen(defstring); /* Size of default */ -X nam.nam$l_esa = fullname; /* Expanded filename */ -X nam.nam$b_ess = NAM$C_MAXRSS; /* Expanded name size */ -X if (sys$parse(&fab) == RMS$_NORMAL) { /* Parse away */ -X fullname[nam.nam$b_esl] = EOS; /* Terminate string */ -X result[0] = EOS; /* Just in case */ -X rp = &result[0]; -X /* -X * Remove stuff added implicitly, accepting node names and -X * dev:[directory] strings (but not process-permanent files). -X */ -X if ((nam.nam$l_fnb & NAM$M_PPF) == 0) { -X if ((nam.nam$l_fnb & NAM$M_NODE) != 0) { -X strncpy(result, nam.nam$l_node, nam.nam$b_node); -X rp += nam.nam$b_node; -X *rp = EOS; -X } -X if ((nam.nam$l_fnb & DEVDIR) == DEVDIR) { -X strncpy(rp, nam.nam$l_dev, nam.nam$b_dev + nam.nam$b_dir); -X rp += nam.nam$b_dev + nam.nam$b_dir; -X *rp = EOS; -X } -X } -X if (defstring != NULLST) { -X strncpy(rp, nam.nam$l_name, nam.nam$b_name + nam.nam$b_type); -X rp += nam.nam$b_name + nam.nam$b_type; -X *rp = EOS; -X if ((nam.nam$l_fnb & NAM$M_EXP_VER) != 0) { -X strncpy(rp, nam.nam$l_ver, nam.nam$b_ver); -X rp[nam.nam$b_ver] = EOS; -X } -X } -X return (TRUE); -X } -X return (FALSE); -X} -X#endif -X -END-of-cpp2.c -exit diff --git a/sys/unix/cpp2.shr b/sys/unix/cpp2.shr deleted file mode 100644 index ccadfc054..000000000 --- a/sys/unix/cpp2.shr +++ /dev/null @@ -1,1763 +0,0 @@ -# This is a shell archive. Save it in a file, remove anything before -# this line, and then unpack it by entering "sh file". Note, it may -# create directories; files and directories will be owned by you and -# have default permissions. -# -# This archive contains: -# -# cpp1.c -# cpp3.c -# cpp4.c -# -echo x - cpp1.c -sed 's/^X//' >cpp1.c << 'END-of-cpp1.c' -X/* -X * CPP main program. -X * -X * Edit history -X * 21-May-84 MM "Field test" release -X * 23-May-84 MM Some minor hacks. -X * 30-May-84 ARF Didn't get enough memory for __DATE__ -X * Added code to read stdin if no input -X * files are provided. -X * 29-Jun-84 MM Added ARF's suggestions, Unixifying cpp. -X * 11-Jul-84 MM "Official" first release (that's what I thought!) -X * 22-Jul-84 MM/ARF/SCK Fixed line number bugs, added cpp recognition -X * of #line, fixed problems with #include. -X * 23-Jul-84 MM More (minor) include hacking, some documentation. -X * Also, redid cpp's #include files -X * 25-Jul-84 MM #line filename isn't used for #include searchlist -X * #line format is -X * 25-Jul-84 ARF/MM Various bugs, mostly serious. Removed homemade doprint -X * 01-Aug-84 MM Fixed recursion bug, remove extra newlines and -X * leading whitespace from cpp output. -X * 02-Aug-84 MM Hacked (i.e. optimized) out blank lines and unneeded -X * whitespace in general. Cleaned up unget()'s. -X * 03-Aug-84 Keie Several bug fixes from Ed Keizer, Vrije Universitet. -X * -- corrected arg. count in -D and pre-defined -X * macros. Also, allow \n inside macro actual parameter -X * lists. -X * 06-Aug-84 MM If debugging, dump the preset vector at startup. -X * 12-Aug-84 MM/SCK Some small changes from Sam Kendall -X * 15-Aug-84 Keie/MM cerror, cwarn, etc. take a single string arg. -X * cierror, etc. take a single int. arg. -X * changed LINE_PREFIX slightly so it can be -X * changed in the makefile. -X * 31-Aug-84 MM USENET net.sources release. -X * 7-Sep-84 SCH/ado Lint complaints -X * 10-Sep-84 Keie Char's can't be signed in some implementations -X * 11-Sep-84 ado Added -C flag, pathological line number fix -X * 13-Sep-84 ado Added -E flag (does nothing) and "-" file for stdin. -X * 14-Sep-84 MM Allow # 123 as a synonym for #line 123 -X * 19-Sep-84 MM scanid always reads to token, make sure #line is -X * written to a new line, even if -C switch given. -X * Also, cpp - - reads stdin, writes stdout. -X * 03-Oct-84 ado/MM Several changes to line counting and keepcomments -X * stuff. Also a rewritten control() hasher -- much -X * simpler and no less "perfect". Note also changes -X * in cpp3.c to fix numeric scanning. -X * 04-Oct-84 MM Added recognition of macro formal parameters if -X * they are the only thing in a string, per the -X * draft standard. -X * 08-Oct-84 MM One more attack on scannumber -X * 15-Oct-84 MM/ado Added -N to disable predefined symbols. Fixed -X * linecount if COMMENT_INVISIBLE enabled. -X * 22-Oct-84 MM Don't evaluate the #if/#ifdef argument if -X * compilation is supressed. This prevents -X * unnecessary error messages in sequences such as -X * #ifdef FOO -- undefined -X * #if FOO == 10 -- shouldn't print warning -X * 25-Oct-84 MM Fixed bug in false ifdef supression. On vms, -X * #include should open foo.h -- this duplicates -X * the behavior of Vax-C -X * 31-Oct-84 ado/MM Parametized $ in indentifiers. Added a better -X * token concatenator and took out the trial -X * concatenation code. Also improved #ifdef code -X * and cleaned up the macro recursion tester. -X * 2-Nov-84 MM/ado Some bug fixes in token concatenation, also -X * a variety of minor (uninteresting) hacks. -X * 6-Nov-84 MM Happy Birthday. Broke into 4 files and added -X * #if sizeof (basic_types) -X * 9-Nov-84 MM Added -S* for pointer type sizes -X * 13-Nov-84 MM Split cpp1.c, added vms defaulting -X * 23-Nov-84 MM/ado -E supresses error exit, added CPP_INCLUDE, -X * fixed strncpy bug. -X * 3-Dec-84 ado/MM Added OLD_PREPROCESSOR -X * 7-Dec-84 MM Stuff in Nov 12 Draft Standard -X * 17-Dec-84 george Fixed problems with recursive macros -X * 17-Dec-84 MM Yet another attack on #if's (f/t)level removed. -X * 07-Jan-85 ado Init defines before doing command line options -X * so -Uunix works. -X */ -X -X/*)BUILD -X $(PROGRAM) = cpp -X $(FILES) = { cpp1 cpp2 cpp3 cpp4 cpp5 cpp6 } -X $(INCLUDE) = { cppdef.h cpp.h } -X $(STACK) = 2000 -X $(TKBOPTIONS) = { -X STACK = 2000 -X } -X*/ -X -X#ifdef DOCUMENTATION -X -Xtitle cpp C Pre-Processor -Xindex C pre-processor -X -Xsynopsis -X .s.nf -X cpp [-options] [infile [outfile]] -X .s.f -Xdescription -X -X CPP reads a C source file, expands macros and include -X files, and writes an input file for the C compiler. -X If no file arguments are given, CPP reads from stdin -X and writes to stdout. If one file argument is given, -X it will define the input file, while two file arguments -X define both input and output files. The file name "-" -X is a synonym for stdin or stdout as appropriate. -X -X The following options are supported. Options may -X be given in either case. -X .lm +16 -X .p -16 -X -C If set, source-file comments are written -X to the output file. This allows the output of CPP to be -X used as the input to a program, such as lint, that expects -X commands embedded in specially-formatted comments. -X .p -16 -X -Dname=value Define the name as if the programmer wrote -X -X #define name value -X -X at the start of the first file. If "=value" is not -X given, a value of "1" will be used. -X -X On non-unix systems, all alphabetic text will be forced -X to upper-case. -X .p -16 -X -E Always return "success" to the operating -X system, even if errors were detected. Note that some fatal -X errors, such as a missing #include file, will terminate -X CPP, returning "failure" even if the -E option is given. -X .p -16 -X -Idirectory Add this directory to the list of -X directories searched for #include "..." and #include <...> -X commands. Note that there is no space between the -X "-I" and the directory string. More than one -I command -X is permitted. On non-Unix systems "directory" is forced -X to upper-case. -X .p -16 -X -N CPP normally predefines some symbols defining -X the target computer and operating system. If -N is specified, -X no symbols will be predefined. If -N -N is specified, the -X "always present" symbols, __LINE__, __FILE__, and __DATE__ -X are not defined. -X .p -16 -X -Stext CPP normally assumes that the size of -X the target computer's basic variable types is the same as the size -X of these types of the host computer. (This can be overridden -X when CPP is compiled, however.) The -S option allows dynamic -X respecification of these values. "text" is a string of -X numbers, separated by commas, that specifies correct sizes. -X The sizes must be specified in the exact order: -X -X char short int long float double -X -X If you specify the option as "-S*text", pointers to these -X types will be specified. -S* takes one additional argument -X for pointer to function (e.g. int (*)()) -X -X For example, to specify sizes appropriate for a PDP-11, -X you would write: -X -X c s i l f d func -X -S1,2,2,2,4,8, -X -S*2,2,2,2,2,2,2 -X -X Note that all values must be specified. -X .p -16 -X -Uname Undefine the name as if -X -X #undef name -X -X were given. On non-Unix systems, "name" will be forced to -X upper-case. -X .p -16 -X -Xnumber Enable debugging code. If no value is -X given, a value of 1 will be used. (For maintenence of -X CPP only.) -X .s.lm -16 -X -XPre-Defined Variables -X -X When CPP begins processing, the following variables will -X have been defined (unless the -N option is specified): -X .s -X Target computer (as appropriate): -X .s -X pdp11, vax, M68000 m68000 m68k -X .s -X Target operating system (as appropriate): -X .s -X rsx, rt11, vms, unix -X .s -X Target compiler (as appropriate): -X .s -X decus, vax11c -X .s -X The implementor may add definitions to this list. -X The default definitions match the definition of the -X host computer, operating system, and C compiler. -X .s -X The following are always available unless undefined (or -X -N was specified twice): -X .lm +16 -X .p -12 -X __FILE__ The input (or #include) file being compiled -X (as a quoted string). -X .p -12 -X __LINE__ The line number being compiled. -X .p -12 -X __DATE__ The date and time of compilation as -X a Unix ctime quoted string (the trailing newline is removed). -X Thus, -X .s -X printf("Bug at line %s,", __LINE__); -X printf(" source file %s", __FILE__); -X printf(" compiled on %s", __DATE__); -X .s.lm -16 -X -XDraft Proposed Ansi Standard Considerations -X -X The current version of the Draft Proposed Standard -X explicitly states that "readers are requested not to specify -X or claim conformance to this draft." Readers and users -X of Decus CPP should not assume that Decus CPP conforms -X to the standard, or that it will conform to the actual -X C Language Standard. -X -X When CPP is itself compiled, many features of the Draft -X Proposed Standard that are incompatible with existing -X preprocessors may be disabled. See the comments in CPP's -X source for details. -X -X The latest version of the Draft Proposed Standard (as reflected -X in Decus CPP) is dated November 12, 1984. -X -X Comments are removed from the input text. The comment -X is replaced by a single space character. The -C option -X preserves comments, writing them to the output file. -X -X The '$' character is considered to be a letter. This is -X a permitted extension. -X -X The following new features of C are processed by CPP: -X .s.comment Note: significant spaces, not tabs, .br quotes #if, #elif -X .br;####_#elif expression (_#else _#if) -X .br;####'_\xNNN' (Hexadecimal constant) -X .br;####'_\a' (Ascii BELL) -X .br;####'_\v' (Ascii Vertical Tab) -X .br;####_#if defined NAME 1 if defined, 0 if not -X .br;####_#if defined (NAME) 1 if defined, 0 if not -X .br;####_#if sizeof (basic type) -X .br;####unary + -X .br;####123U, 123LU Unsigned ints and longs. -X .br;####12.3L Long double numbers -X .br;####token_#token Token concatenation -X .br;####_#include token Expands to filename -X -X The Draft Proposed Standard has extended C, adding a constant -X string concatenation operator, where -X -X "foo" "bar" -X -X is regarded as the single string "foobar". (This does not -X affect CPP's processing but does permit a limited form of -X macro argument substitution into strings as will be discussed.) -X -X The Standard Committee plans to add token concatenation -X to #define command lines. One suggested implementation -X is as follows: the sequence "Token1#Token2" is treated -X as if the programmer wrote "Token1Token2". This could -X be used as follows: -X -X #line 123 -X #define ATLINE foo#__LINE__ -X -X ATLINE would be defined as foo123. -X -X Note that "Token2" must either have the format of an -X identifier or be a string of digits. Thus, the string -X -X #define ATLINE foo#1x3 -X -X generates two tokens: "foo1" and "x3". -X -X If the tokens T1 and T2 are concatenated into T3, -X this implementation operates as follows: -X -X 1. Expand T1 if it is a macro. -X 2. Expand T2 if it is a macro. -X 3. Join the tokens, forming T3. -X 4. Expand T3 if it is a macro. -X -X A macro formal parameter will be substituted into a string -X or character constant if it is the only component of that -X constant: -X -X #define VECSIZE 123 -X #define vprint(name, size) \ -X printf("name" "[" "size" "] = {\n") -X ... vprint(vector, VECSIZE); -X -X expands (effectively) to -X -X vprint("vector[123] = {\n"); -X -X Note that this will be useful if your C compiler supports -X the new string concatenation operation noted above. -X As implemented here, if you write -X -X #define string(arg) "arg" -X ... string("foo") ... -X -X This implementation generates "foo", rather than the strictly -X correct ""foo"" (which will probably generate an error message). -X This is, strictly speaking, an error in CPP and may be removed -X from future releases. -X -Xerror messages -X -X Many. CPP prints warning or error messages if you try to -X use multiple-byte character constants (non-transportable) -X if you #undef a symbol that was not defined, or if your -X program has potentially nested comments. -X -Xauthor -X -X Martin Minow -X -Xbugs -X -X The #if expression processor uses signed integers only. -X I.e, #if 0xFFFFu < 0 may be TRUE. -X -X#endif -X -X#include -X#include -X#include "cppdef.h" -X#include "cpp.h" -X -X/* -X * Commonly used global variables: -X * line is the current input line number. -X * wrongline is set in many places when the actual output -X * line is out of sync with the numbering, e.g, -X * when expanding a macro with an embedded newline. -X * -X * token holds the last identifier scanned (which might -X * be a candidate for macro expansion). -X * errors is the running cpp error counter. -X * infile is the head of a linked list of input files (extended by -X * #include and macros being expanded). infile always points -X * to the current file/macro. infile->parent to the includer, -X * etc. infile->fd is NULL if this input stream is a macro. -X */ -Xint line; /* Current line number */ -Xint wrongline; /* Force #line to compiler */ -Xchar token[IDMAX + 1]; /* Current input token */ -Xint errors; /* cpp error counter */ -XFILEINFO *infile = NULL; /* Current input file */ -X#if DEBUG -Xint debug; /* TRUE if debugging now */ -X#endif -X/* -X * This counter is incremented when a macro expansion is initiated. -X * If it exceeds a built-in value, the expansion stops -- this tests -X * for a runaway condition: -X * #define X Y -X * #define Y X -X * X -X * This can be disabled by falsifying rec_recover. (Nothing does this -X * currently: it is a hook for an eventual invocation flag.) -X */ -Xint recursion; /* Infinite recursion counter */ -Xint rec_recover = TRUE; /* Unwind recursive macros */ -X -X/* -X * instring is set TRUE when a string is scanned. It modifies the -X * behavior of the "get next character" routine, causing all characters -X * to be passed to the caller (except ). Note especially that -X * comments and \ are not removed from the source. (This -X * prevents cpp output lines from being arbitrarily long). -X * -X * inmacro is set by #define -- it absorbs comments and converts -X * form-feed and vertical-tab to space, but returns \ -X * to the caller. Strictly speaking, this is a bug as \ -X * shouldn't delimit tokens, but we'll worry about that some other -X * time -- it is more important to prevent infinitly long output lines. -X * -X * instring and inmarcor are parameters to the get() routine which -X * were made global for speed. -X */ -Xint instring = FALSE; /* TRUE if scanning string */ -Xint inmacro = FALSE; /* TRUE if #defining a macro */ -X -X/* -X * work[] and workp are used to store one piece of text in a temporay -X * buffer. To initialize storage, set workp = work. To store one -X * character, call save(c); (This will fatally exit if there isn't -X * room.) To terminate the string, call save(EOS). Note that -X * the work buffer is used by several subroutines -- be sure your -X * data won't be overwritten. The extra byte in the allocation is -X * needed for string formal replacement. -X */ -Xchar work[NWORK + 1]; /* Work buffer */ -Xchar *workp; /* Work buffer pointer */ -X -X/* -X * keepcomments is set TRUE by the -C option. If TRUE, comments -X * are written directly to the output stream. This is needed if -X * the output from cpp is to be passed to lint (which uses commands -X * embedded in comments). cflag contains the permanent state of the -X * -C flag. keepcomments is always falsified when processing #control -X * commands and when compilation is supressed by a false #if -X * -X * If eflag is set, CPP returns "success" even if non-fatal errors -X * were detected. -X * -X * If nflag is non-zero, no symbols are predefined except __LINE__. -X * __FILE__, and __DATE__. If nflag > 1, absolutely no symbols -X * are predefined. -X */ -Xint keepcomments = FALSE; /* Write out comments flag */ -Xint cflag = FALSE; /* -C option (keep comments) */ -Xint eflag = FALSE; /* -E option (never fail) */ -Xint nflag = 0; /* -N option (no predefines) */ -X -X/* -X * ifstack[] holds information about nested #if's. It is always -X * accessed via *ifptr. The information is as follows: -X * WAS_COMPILING state of compiling flag at outer level. -X * ELSE_SEEN set TRUE when #else seen to prevent 2nd #else. -X * TRUE_SEEN set TRUE when #if or #elif succeeds -X * ifstack[0] holds the compiling flag. It is TRUE if compilation -X * is currently enabled. Note that this must be initialized TRUE. -X */ -Xchar ifstack[BLK_NEST] = { TRUE }; /* #if information */ -Xchar *ifptr = ifstack; /* -> current ifstack[] */ -X -X/* -X * incdir[] stores the -i directories (and the system-specific -X * #include <...> directories. -X */ -Xchar *incdir[NINCLUDE]; /* -i directories */ -Xchar **incend = incdir; /* -> free space in incdir[] */ -X -X/* -X * This is the table used to predefine target machine and operating -X * system designators. It may need hacking for specific circumstances. -X * Note: it is not clear that this is part of the Ansi Standard. -X * The -N option supresses preset definitions. -X */ -Xchar *preset[] = { /* names defined at cpp start */ -X#ifdef MACHINE -X MACHINE, -X#endif -X#ifdef SYSTEM -X SYSTEM, -X#endif -X#ifdef COMPILER -X COMPILER, -X#endif -X#if DEBUG -X "decus_cpp", /* Ourselves! */ -X#endif -X NULL /* Must be last */ -X}; -X -X/* -X * The value of these predefined symbols must be recomputed whenever -X * they are evaluated. The order must not be changed. -X */ -Xchar *magic[] = { /* Note: order is important */ -X "__LINE__", -X "__FILE__", -X NULL /* Must be last */ -X}; -X -Xmain(argc, argv) -Xint argc; -Xchar *argv[]; -X{ -X register int i; -X -X#if HOST == SYS_VMS -X argc = getredirection(argc, argv); /* vms >file and stdin */ -X /* -X * Open input file, "-" means use stdin. -X */ -X if (!streq(argv[1], "-")) { -X if (freopen(argv[1], "r", stdin) == NULL) { -X perror(argv[1]); -X cerror("Can't open input file \"%s\"", argv[1]); -X exit(IO_ERROR); -X } -X strcpy(work, argv[1]); /* Remember input filename */ -X break; -X } /* Else, just get stdin */ -X case 0: /* No args? */ -X case 1: /* No files, stdin -> stdout */ -X#if HOST == SYS_UNIX -X work[0] = EOS; /* Unix can't find stdin name */ -X#else -X fgetname(stdin, work); /* Vax-11C, Decus C know name */ -X#endif -X break; -X -X default: -X exit(IO_ERROR); /* Can't happen */ -X } -X setincdirs(); /* Setup -I include directories */ -X addfile(stdin, work); /* "open" main input file */ -X#if DEBUG -X if (debug > 0) -X dumpdef("preset #define symbols"); -X#endif -X cppmain(); /* Process main file */ -X if ((i = (ifptr - &ifstack[0])) != 0) { -X#if OLD_PREPROCESSOR -X ciwarn("Inside #ifdef block at end of input, depth = %d", i); -X#else -X cierror("Inside #ifdef block at end of input, depth = %d", i); -X#endif -X } -X fclose(stdout); -X if (errors > 0) { -X fprintf(stderr, (errors == 1) -X ? "%d error in preprocessor\n" -X : "%d errors in preprocessor\n", errors); -X if (!eflag) -X exit(IO_ERROR); -X } -X exit(IO_NORMAL); /* No errors or -E option set */ -X} -X -XFILE_LOCAL -Xcppmain() -X/* -X * Main process for cpp -- copies tokens from the current input -X * stream (main file, include file, or a macro) to the output -X * file. -X */ -X{ -X register int c; /* Current character */ -X register int counter; /* newlines and spaces */ -X extern int output(); /* Output one character */ -X -X /* -X * Explicitly output a #line at the start of cpp output so -X * that lint (etc.) knows the name of the original source -X * file. If we don't do this explicitly, we may get -X * the name of the first #include file instead. -X */ -X sharp(); -X /* -X * This loop is started "from the top" at the beginning of each line -X * wrongline is set TRUE in many places if it is necessary to write -X * a #line record. (But we don't write them when expanding macros.) -X * -X * The counter variable has two different uses: at -X * the start of a line, it counts the number of blank lines that -X * have been skipped over. These are then either output via -X * #line records or by outputting explicit blank lines. -X * When expanding tokens within a line, the counter remembers -X * whether a blank/tab has been output. These are dropped -X * at the end of the line, and replaced by a single blank -X * within lines. -X */ -X for (;;) { -X counter = 0; /* Count empty lines */ -X for (;;) { /* For each line, ... */ -X while (type[(c = get())] == SPA) /* Skip leading blanks */ -X ; /* in this line. */ -X if (c == '\n') /* If line's all blank, */ -X ++counter; /* Do nothing now */ -X else if (c == '#') { /* Is 1st non-space '#' */ -X keepcomments = FALSE; /* Don't pass comments */ -X counter = control(counter); /* Yes, do a #command */ -X keepcomments = (cflag && compiling); -X } -X else if (c == EOF_CHAR) /* At end of file? */ -X break; -X else if (!compiling) { /* #ifdef false? */ -X skipnl(); /* Skip to newline */ -X counter++; /* Count it, too. */ -X } -X else { -X break; /* Actual token */ -X } -X } -X if (c == EOF_CHAR) /* Exit process at */ -X break; /* End of file */ -X /* -X * If the loop didn't terminate because of end of file, we -X * know there is a token to compile. First, clean up after -X * absorbing newlines. counter has the number we skipped. -X */ -X if ((wrongline && infile->fp != NULL) || counter > 4) -X sharp(); /* Output # line number */ -X else { /* If just a few, stuff */ -X while (--counter >= 0) /* them out ourselves */ -X putchar('\n'); -X } -X /* -X * Process each token on this line. -X */ -X unget(); /* Reread the char. */ -X for (;;) { /* For the whole line, */ -X do { /* Token concat. loop */ -X for (counter = 0; (type[(c = get())] == SPA);) { -X#if COMMENT_INVISIBLE -X if (c != COM_SEP) -X counter++; -X#else -X counter++; /* Skip over blanks */ -X#endif -X } -X if (c == EOF_CHAR || c == '\n') -X goto end_line; /* Exit line loop */ -X else if (counter > 0) /* If we got any spaces */ -X putchar(' '); /* Output one space */ -X c = macroid(c); /* Grab the token */ -X } while (type[c] == LET && catenate()); -X if (c == EOF_CHAR || c == '\n') /* From macro exp error */ -X goto end_line; /* Exit line loop */ -X switch (type[c]) { -X case LET: -X fputs(token, stdout); /* Quite ordinary token */ -X break; -X -X -X case DIG: /* Output a number */ -X case DOT: /* Dot may begin floats */ -X scannumber(c, output); -X break; -X -X case QUO: /* char or string const */ -X scanstring(c, output); /* Copy it to output */ -X break; -X -X default: /* Some other character */ -X cput(c); /* Just output it */ -X break; -X } /* Switch ends */ -X } /* Line for loop */ -Xend_line: if (c == '\n') { /* Compiling at EOL? */ -X putchar('\n'); /* Output newline, if */ -X if (infile->fp == NULL) /* Expanding a macro, */ -X wrongline = TRUE; /* Output # line later */ -X } -X } /* Continue until EOF */ -X} -X -Xoutput(c) -Xint c; -X/* -X * Output one character to stdout -- output() is passed as an -X * argument to scanstring() -X */ -X{ -X#if COMMENT_INVISIBLE -X if (c != TOK_SEP && c != COM_SEP) -X#else -X if (c != TOK_SEP) -X#endif -X putchar(c); -X} -X -Xstatic char *sharpfilename = NULL; -X -XFILE_LOCAL -Xsharp() -X/* -X * Output a line number line. -X */ -X{ -X register char *name; -X -X if (keepcomments) /* Make sure # comes on */ -X putchar('\n'); /* a fresh, new line. */ -X printf("#%s %d", LINE_PREFIX, line); -X if (infile->fp != NULL) { -X name = (infile->progname != NULL) -X ? infile->progname : infile->filename; -X if (sharpfilename == NULL -X || sharpfilename != NULL && !streq(name, sharpfilename)) { -X if (sharpfilename != NULL) -X free(sharpfilename); -X sharpfilename = savestring(name); -X printf(" \"%s\"", name); -X } -X } -X putchar('\n'); -X wrongline = FALSE; -X} -END-of-cpp1.c -echo x - cpp3.c -sed 's/^X//' >cpp3.c << 'END-of-cpp3.c' -X/* -X * C P P 3 . C -X * -X * File open and command line options -X * -X * Edit history -X * 13-Nov-84 MM Split from cpp1.c -X */ -X -X#include -X#include -X#include "cppdef.h" -X#include "cpp.h" -X#if DEBUG && (HOST == SYS_VMS || HOST == SYS_UNIX) -X#include -Xextern int abort(); /* For debugging */ -X#endif -X -Xint -Xopenfile(filename) -Xchar *filename; -X/* -X * Open a file, add it to the linked list of open files. -X * This is called only from openfile() above. -X */ -X{ -X register FILE *fp; -X -X if ((fp = fopen(filename, "r")) == NULL) { -X#if DEBUG -X perror(filename); -X#endif -X return (FALSE); -X } -X#if DEBUG -X if (debug) -X fprintf(stderr, "Reading from \"%s\"\n", filename); -X#endif -X addfile(fp, filename); -X return (TRUE); -X} -X -Xaddfile(fp, filename) -XFILE *fp; /* Open file pointer */ -Xchar *filename; /* Name of the file */ -X/* -X * Initialize tables for this open file. This is called from openfile() -X * above (for #include files), and from the entry to cpp to open the main -X * input file. It calls a common routine, getfile() to build the FILEINFO -X * structure which is used to read characters. (getfile() is also called -X * to setup a macro replacement.) -X */ -X{ -X register FILEINFO *file; -X extern FILEINFO *getfile(); -X -X file = getfile(NBUFF, filename); -X file->fp = fp; /* Better remember FILE * */ -X file->buffer[0] = EOS; /* Initialize for first read */ -X line = 1; /* Working on line 1 now */ -X wrongline = TRUE; /* Force out initial #line */ -X} -X -Xsetincdirs() -X/* -X * Append system-specific directories to the include directory list. -X * Called only when cpp is started. -X */ -X{ -X -X#ifdef CPP_INCLUDE -X *incend++ = CPP_INCLUDE; -X#define IS_INCLUDE 1 -X#else -X#define IS_INCLUDE 0 -X#endif -X -X#if HOST == SYS_UNIX -X *incend++ = "/usr/include"; -X#define MAXINCLUDE (NINCLUDE - 1 - IS_INCLUDE) -X#endif -X -X#if HOST == SYS_VMS -X extern char *getenv(); -X -X if (getenv("C$LIBRARY") != NULL) -X *incend++ = "C$LIBRARY:"; -X *incend++ = "SYS$LIBRARY:"; -X#define MAXINCLUDE (NINCLUDE - 2 - IS_INCLUDE) -X#endif -X -X#if HOST == SYS_RSX -X extern int $$rsts; /* TRUE on RSTS/E */ -X extern int $$pos; /* TRUE on PRO-350 P/OS */ -X extern int $$vms; /* TRUE on VMS compat. */ -X -X if ($$pos) { /* P/OS? */ -X *incend++ = "SY:[ZZDECUSC]"; /* C #includes */ -X *incend++ = "LB:[1,5]"; /* RSX library */ -X } -X else if ($$rsts) { /* RSTS/E? */ -X *incend++ = "SY:@"; /* User-defined account */ -X *incend++ = "C:"; /* Decus-C library */ -X *incend++ = "LB:[1,1]"; /* RSX library */ -X } -X else if ($$vms) { /* VMS compatibility? */ -X *incend++ = "C:"; -X } -X else { /* Plain old RSX/IAS */ -X *incend++ = "LB:[1,1]"; -X } -X#define MAXINCLUDE (NINCLUDE - 3 - IS_INCLUDE) -X#endif -X -X#if HOST == SYS_RT11 -X extern int $$rsts; /* RSTS/E emulation? */ -X -X if ($$rsts) -X *incend++ = "SY:@"; /* User-defined account */ -X *incend++ = "C:"; /* Decus-C library disk */ -X *incend++ = "SY:"; /* System (boot) disk */ -X#define MAXINCLUDE (NINCLUDE - 3 - IS_INCLUDE) -X#endif -X} -X -Xint -Xdooptions(argc, argv) -Xint argc; -Xchar *argv[]; -X/* -X * dooptions is called to process command line arguments (-Detc). -X * It is called only at cpp startup. -X */ -X{ -X register char *ap; -X register DEFBUF *dp; -X register int c; -X int i, j; -X char *arg; -X SIZES *sizp; /* For -S */ -X int size; /* For -S */ -X int isdatum; /* FALSE for -S* */ -X int endtest; /* For -S */ -X -X for (i = j = 1; i < argc; i++) { -X arg = ap = argv[i]; -X if (*ap++ != '-' || *ap == EOS) -X argv[j++] = argv[i]; -X else { -X c = *ap++; /* Option byte */ -X if (islower(c)) /* Normalize case */ -X c = toupper(c); -X switch (c) { /* Command character */ -X case 'C': /* Keep comments */ -X cflag = TRUE; -X keepcomments = TRUE; -X break; -X -X case 'D': /* Define symbol */ -X#if HOST != SYS_UNIX -X zap_uc(ap); /* Force define to U.C. */ -X#endif -X /* -X * If the option is just "-Dfoo", make it -Dfoo=1 -X */ -X while (*ap != EOS && *ap != '=') -X ap++; -X if (*ap == EOS) -X ap = "1"; -X else -X *ap++ = EOS; -X /* -X * Now, save the word and its definition. -X */ -X dp = defendel(argv[i] + 2, FALSE); -X dp->repl = savestring(ap); -X dp->nargs = DEF_NOARGS; -X break; -X -X case 'E': /* Ignore non-fatal */ -X eflag = TRUE; /* errors. */ -X break; -X -X case 'I': /* Include directory */ -X if (incend >= &incdir[MAXINCLUDE]) -X cfatal("Too many include directories", NULLST); -X *incend++ = ap; -X break; -X -X case 'N': /* No predefineds */ -X nflag++; /* Repeat to undefine */ -X break; /* __LINE__, etc. */ -X -X case 'S': -X sizp = size_table; -X if (isdatum = (*ap != '*')) /* If it's just -S, */ -X endtest = T_FPTR; /* Stop here */ -X else { /* But if it's -S* */ -X ap++; /* Step over '*' */ -X endtest = 0; /* Stop at end marker */ -X } -X while (sizp->bits != endtest && *ap != EOS) { -X if (!isdigit(*ap)) { /* Skip to next digit */ -X ap++; -X continue; -X } -X size = 0; /* Compile the value */ -X while (isdigit(*ap)) { -X size *= 10; -X size += (*ap++ - '0'); -X } -X if (isdatum) -X sizp->size = size; /* Datum size */ -X else -X sizp->psize = size; /* Pointer size */ -X sizp++; -X } -X if (sizp->bits != endtest) -X cwarn("-S, too few values specified in %s", argv[i]); -X else if (*ap != EOS) -X cwarn("-S, too many values, \"%s\" unused", ap); -X break; -X -X case 'U': /* Undefine symbol */ -X#if HOST != SYS_UNIX -X zap_uc(ap); -X#endif -X if (defendel(ap, TRUE) == NULL) -X cwarn("\"%s\" wasn't defined", ap); -X break; -X -X#if DEBUG -X case 'X': /* Debug */ -X debug = (isdigit(*ap)) ? atoi(ap) : 1; -X#if (HOST == SYS_VMS || HOST == SYS_UNIX) -X signal(SIGINT, abort); /* Trap "interrupt" */ -X#endif -X fprintf(stderr, "Debug set to %d\n", debug); -X break; -X#endif -X -X default: /* What is this one? */ -X cwarn("Unknown option \"%s\"", arg); -X fprintf(stderr, "The following options are valid:\n\ -X -C\t\t\tWrite source file comments to output\n\ -X -Dsymbol=value\tDefine a symbol with the given (optional) value\n\ -X -Idirectory\t\tAdd a directory to the #include search list\n\ -X -N\t\t\tDon't predefine target-specific names\n\ -X -Stext\t\tSpecify sizes for #if sizeof\n\ -X -Usymbol\t\tUndefine symbol\n"); -X#if DEBUG -X fprintf(stderr, " -Xvalue\t\tSet internal debug flag\n"); -X#endif -X break; -X } /* Switch on all options */ -X } /* If it's a -option */ -X } /* For all arguments */ -X if (j > 3) { -X cerror( -X "Too many file arguments. Usage: cpp [input [output]]", -X NULLST); -X } -X return (j); /* Return new argc */ -X} -X -X#if HOST != SYS_UNIX -XFILE_LOCAL -Xzap_uc(ap) -Xregister char *ap; -X/* -X * Dec operating systems mangle upper-lower case in command lines. -X * This routine forces the -D and -U arguments to uppercase. -X * It is called only on cpp startup by dooptions(). -X */ -X{ -X while (*ap != EOS) { -X /* -X * Don't use islower() here so it works with Multinational -X */ -X if (*ap >= 'a' && *ap <= 'z') -X *ap = toupper(*ap); -X ap++; -X } -X} -X#endif -X -Xinitdefines() -X/* -X * Initialize the built-in #define's. There are two flavors: -X * #define decus 1 (static definitions) -X * #define __FILE__ ?? (dynamic, evaluated by magic) -X * Called only on cpp startup. -X * -X * Note: the built-in static definitions are supressed by the -N option. -X * __LINE__, __FILE__, and __DATE__ are always present. -X */ -X{ -X register char **pp; -X register char *tp; -X register DEFBUF *dp; -X int i; -X long tvec; -X extern char *ctime(); -X -X /* -X * Predefine the built-in symbols. Allow the -X * implementor to pre-define a symbol as "" to -X * eliminate it. -X */ -X if (nflag == 0) { -X for (pp = preset; *pp != NULL; pp++) { -X if (*pp[0] != EOS) { -X dp = defendel(*pp, FALSE); -X dp->repl = savestring("1"); -X dp->nargs = DEF_NOARGS; -X } -X } -X } -X /* -X * The magic pre-defines (__FILE__ and __LINE__ are -X * initialized with negative argument counts. expand() -X * notices this and calls the appropriate routine. -X * DEF_NOARGS is one greater than the first "magic" definition. -X */ -X if (nflag < 2) { -X for (pp = magic, i = DEF_NOARGS; *pp != NULL; pp++) { -X dp = defendel(*pp, FALSE); -X dp->nargs = --i; -X } -X#if OK_DATE -X /* -X * Define __DATE__ as today's date. -X */ -X dp = defendel("__DATE__", FALSE); -X dp->repl = tp = getmem(27); -X dp->nargs = DEF_NOARGS; -X time(&tvec); -X *tp++ = '"'; -X strcpy(tp, ctime(&tvec)); -X tp[24] = '"'; /* Overwrite newline */ -X#endif -X } -X} -X -X#if HOST == SYS_VMS -X/* -X * getredirection() is intended to aid in porting C programs -X * to VMS (Vax-11 C) which does not support '>' and '<' -X * I/O redirection. With suitable modification, it may -X * useful for other portability problems as well. -X */ -X -Xint -Xgetredirection(argc, argv) -Xint argc; -Xchar **argv; -X/* -X * Process vms redirection arg's. Exit if any error is seen. -X * If getredirection() processes an argument, it is erased -X * from the vector. getredirection() returns a new argc value. -X * -X * Warning: do not try to simplify the code for vms. The code -X * presupposes that getredirection() is called before any data is -X * read from stdin or written to stdout. -X * -X * Normal usage is as follows: -X * -X * main(argc, argv) -X * int argc; -X * char *argv[]; -X * { -X * argc = getredirection(argc, argv); -X * } -X */ -X{ -X register char *ap; /* Argument pointer */ -X int i; /* argv[] index */ -X int j; /* Output index */ -X int file; /* File_descriptor */ -X extern int errno; /* Last vms i/o error */ -X -X for (j = i = 1; i < argc; i++) { /* Do all arguments */ -X switch (*(ap = argv[i])) { -X case '<': /* ': /* >file or >>file */ -X if (*++ap == '>') { /* >>file */ -X /* -X * If the file exists, and is writable by us, -X * call freopen to append to the file (using the -X * file's current attributes). Otherwise, create -X * a new file with "vanilla" attributes as if the -X * argument was given as ">filename". -X * access(name, 2) returns zero if we can write on -X * the specified file. -X */ -X if (access(++ap, 2) == 0) { -X if (freopen(ap, "a", stdout) != NULL) -X break; /* Exit case statement */ -X perror(ap); /* Error, can't append */ -X exit(errno); /* After access test */ -X } /* If file accessable */ -X } -X /* -X * On vms, we want to create the file using "standard" -X * record attributes. creat(...) creates the file -X * using the caller's default protection mask and -X * "variable length, implied carriage return" -X * attributes. dup2() associates the file with stdout. -X */ -X if ((file = creat(ap, 0, "rat=cr", "rfm=var")) == -1 -X || dup2(file, fileno(stdout)) == -1) { -X perror(ap); /* Can't create file */ -X exit(errno); /* is a fatal error */ -X } /* If '>' creation */ -X break; /* Exit case test */ -X -X default: -X argv[j++] = ap; /* Not a redirector */ -X break; /* Exit case test */ -X } -X } /* For all arguments */ -X argv[j] = NULL; /* Terminate argv[] */ -X return (j); /* Return new argc */ -X} -X#endif -X -X -X -END-of-cpp3.c -echo x - cpp4.c -sed 's/^X//' >cpp4.c << 'END-of-cpp4.c' -X/* -X * C P P 4 . C -X * M a c r o D e f i n i t i o n s -X * -X * Edit History -X * 31-Aug-84 MM USENET net.sources release -X * 04-Oct-84 MM __LINE__ and __FILE__ must call ungetstring() -X * so they work correctly with token concatenation. -X * Added string formal recognition. -X * 25-Oct-84 MM "Short-circuit" evaluate #if's so that we -X * don't print unnecessary error messages for -X * #if !defined(FOO) && FOO != 0 && 10 / FOO ... -X * 31-Oct-84 ado/MM Added token concatenation -X * 6-Nov-84 MM Split off eval stuff -X */ -X -X#include -X#include -X#include "cppdef.h" -X#include "cpp.h" -X/* -X * parm[], parmp, and parlist[] are used to store #define() argument -X * lists. nargs contains the actual number of parameters stored. -X */ -Xstatic char parm[NPARMWORK + 1]; /* define param work buffer */ -Xstatic char *parmp; /* Free space in parm */ -Xstatic char *parlist[LASTPARM]; /* -> start of each parameter */ -Xstatic int nargs; /* Parameters for this macro */ -X -Xdodefine() -X/* -X * Called from control when a #define is scanned. This module -X * parses formal parameters and the replacement string. When -X * the formal parameter name is encountered in the replacement -X * string, it is replaced by a character in the range 128 to -X * 128+NPARAM (this allows up to 32 parameters within the -X * Dec Multinational range). If cpp is ported to an EBCDIC -X * machine, you will have to make other arrangements. -X * -X * There is some special case code to distinguish -X * #define foo bar -X * from #define foo() bar -X * -X * Also, we make sure that -X * #define foo foo -X * expands to "foo" but doesn't put cpp into an infinite loop. -X * -X * A warning message is printed if you redefine a symbol to a -X * different text. I.e, -X * #define foo 123 -X * #define foo 123 -X * is ok, but -X * #define foo 123 -X * #define foo +123 -X * is not. -X * -X * The following subroutines are called from define(): -X * checkparm called when a token is scanned. It checks through the -X * array of formal parameters. If a match is found, the -X * token is replaced by a control byte which will be used -X * to locate the parameter when the macro is expanded. -X * textput puts a string in the macro work area (parm[]), updating -X * parmp to point to the first free byte in parm[]. -X * textput() tests for work buffer overflow. -X * charput puts a single character in the macro work area (parm[]) -X * in a manner analogous to textput(). -X */ -X{ -X register int c; -X register DEFBUF *dp; /* -> new definition */ -X int isredefine; /* TRUE if redefined */ -X char *old; /* Remember redefined */ -X extern int save(); /* Save char in work[] */ -X -X if (type[(c = skipws())] != LET) -X goto bad_define; -X isredefine = FALSE; /* Set if redefining */ -X if ((dp = lookid(c)) == NULL) /* If not known now */ -X dp = defendel(token, FALSE); /* Save the name */ -X else { /* It's known: */ -X isredefine = TRUE; /* Remember this fact */ -X old = dp->repl; /* Remember replacement */ -X dp->repl = NULL; /* No replacement now */ -X } -X parlist[0] = parmp = parm; /* Setup parm buffer */ -X if ((c = get()) == '(') { /* With arguments? */ -X nargs = 0; /* Init formals counter */ -X do { /* Collect formal parms */ -X if (nargs >= LASTPARM) -X cfatal("Too many arguments for macro", NULLST); -X else if ((c = skipws()) == ')') -X break; /* Got them all */ -X else if (type[c] != LET) /* Bad formal syntax */ -X goto bad_define; -X scanid(c); /* Get the formal param */ -X parlist[nargs++] = parmp; /* Save its start */ -X textput(token); /* Save text in parm[] */ -X } while ((c = skipws()) == ','); /* Get another argument */ -X if (c != ')') /* Must end at ) */ -X goto bad_define; -X c = ' '; /* Will skip to body */ -X } -X else { -X /* -X * DEF_NOARGS is needed to distinguish between -X * "#define foo" and "#define foo()". -X */ -X nargs = DEF_NOARGS; /* No () parameters */ -X } -X if (type[c] == SPA) /* At whitespace? */ -X c = skipws(); /* Not any more. */ -X workp = work; /* Replacement put here */ -X inmacro = TRUE; /* Keep \ now */ -X while (c != EOF_CHAR && c != '\n') { /* Compile macro body */ -X#if OK_CONCAT -X if (c == '#') { /* Token concatenation? */ -X while (workp > work && type[workp[-1]] == SPA) -X --workp; /* Erase leading spaces */ -X save(TOK_SEP); /* Stuff a delimiter */ -X c = skipws(); /* Eat whitespace */ -X if (type[c] == LET) /* Another token here? */ -X ; /* Stuff it normally */ -X else if (type[c] == DIG) { /* Digit string after? */ -X while (type[c] == DIG) { /* Stuff the digits */ -X save(c); -X c = get(); -X } -X save(TOK_SEP); /* Delimit 2nd token */ -X } -X else { -X ciwarn("Strange character after # (%d.)", c); -X } -X continue; -X } -X#endif -X switch (type[c]) { -X case LET: -X checkparm(c, dp); /* Might be a formal */ -X break; -X -X case DIG: /* Number in mac. body */ -X case DOT: /* Maybe a float number */ -X scannumber(c, save); /* Scan it off */ -X break; -X -X case QUO: /* String in mac. body */ -X#if STRING_FORMAL -X stparmscan(c, dp); /* Do string magic */ -X#else -X stparmscan(c); -X#endif -X break; -X -X case BSH: /* Backslash */ -X save('\\'); -X if ((c = get()) == '\n') -X wrongline = TRUE; -X save(c); -X break; -X -X case SPA: /* Absorb whitespace */ -X /* -X * Note: the "end of comment" marker is passed on -X * to allow comments to separate tokens. -X */ -X if (workp[-1] == ' ') /* Absorb multiple */ -X break; /* spaces */ -X else if (c == '\t') -X c = ' '; /* Normalize tabs */ -X /* Fall through to store character */ -X default: /* Other character */ -X save(c); -X break; -X } -X c = get(); -X } -X inmacro = FALSE; /* Stop newline hack */ -X unget(); /* For control check */ -X if (workp > work && workp[-1] == ' ') /* Drop trailing blank */ -X workp--; -X *workp = EOS; /* Terminate work */ -X dp->repl = savestring(work); /* Save the string */ -X dp->nargs = nargs; /* Save arg count */ -X#if DEBUG -X if (debug) -X dumpadef("macro definition", dp); -X#endif -X if (isredefine) { /* Error if redefined */ -X if ((old != NULL && dp->repl != NULL && !streq(old, dp->repl)) -X || (old == NULL && dp->repl != NULL) -X || (old != NULL && dp->repl == NULL)) { -X cerror("Redefining defined variable \"%s\"", dp->name); -X } -X if (old != NULL) /* We don't need the */ -X free(old); /* old definition now. */ -X } -X return; -X -Xbad_define: -X cerror("#define syntax error", NULLST); -X inmacro = FALSE; /* Stop hack */ -X} -X -Xcheckparm(c, dp) -Xregister int c; -XDEFBUF *dp; -X/* -X * Replace this param if it's defined. Note that the macro name is a -X * possible replacement token. We stuff DEF_MAGIC in front of the token -X * which is treated as a LETTER by the token scanner and eaten by -X * the output routine. This prevents the macro expander from -X * looping if someone writes "#define foo foo". -X */ -X{ -X register int i; -X register char *cp; -X -X scanid(c); /* Get parm to token[] */ -X for (i = 0; i < nargs; i++) { /* For each argument */ -X if (streq(parlist[i], token)) { /* If it's known */ -X save(i + MAC_PARM); /* Save a magic cookie */ -X return; /* And exit the search */ -X } -X } -X if (streq(dp->name, token)) /* Macro name in body? */ -X save(DEF_MAGIC); /* Save magic marker */ -X for (cp = token; *cp != EOS;) /* And save */ -X save(*cp++); /* The token itself */ -X} -X -X#if STRING_FORMAL -Xstparmscan(delim, dp) -Xint delim; -Xregister DEFBUF *dp; -X/* -X * Scan the string (starting with the given delimiter). -X * The token is replaced if it is the only text in this string or -X * character constant. The algorithm follows checkparm() above. -X * Note that scanstring() has approved of the string. -X */ -X{ -X register int c; -X -X /* -X * Warning -- this code hasn't been tested for a while. -X * It exists only to preserve compatibility with earlier -X * implementations of cpp. It is not part of the Draft -X * ANSI Standard C language. -X */ -X save(delim); -X instring = TRUE; -X while ((c = get()) != delim -X && c != '\n' -X && c != EOF_CHAR) { -X if (type[c] == LET) /* Maybe formal parm */ -X checkparm(c, dp); -X else { -X save(c); -X if (c == '\\') -X save(get()); -X } -X } -X instring = FALSE; -X if (c != delim) -X cerror("Unterminated string in macro body", NULLST); -X save(c); -X} -X#else -Xstparmscan(delim) -Xint delim; -X/* -X * Normal string parameter scan. -X */ -X{ -X register char *wp; -X register int i; -X extern int save(); -X -X wp = workp; /* Here's where it starts */ -X if (!scanstring(delim, save)) -X return; /* Exit on scanstring error */ -X workp[-1] = EOS; /* Erase trailing quote */ -X wp++; /* -> first string content byte */ -X for (i = 0; i < nargs; i++) { -X if (streq(parlist[i], wp)) { -X *wp++ = MAC_PARM + PAR_MAC; /* Stuff a magic marker */ -X *wp++ = (i + MAC_PARM); /* Make a formal marker */ -X *wp = wp[-3]; /* Add on closing quote */ -X workp = wp + 1; /* Reset string end */ -X return; -X } -X } -X workp[-1] = wp[-1]; /* Nope, reset end quote. */ -X} -X#endif -X -Xdoundef() -X/* -X * Remove the symbol from the defined list. -X * Called from the #control processor. -X */ -X{ -X register int c; -X -X if (type[(c = skipws())] != LET) -X cerror("Illegal #undef argument", NULLST); -X else { -X scanid(c); /* Get name to token[] */ -X if (defendel(token, TRUE) == NULL) { -X cwarn("Symbol \"%s\" not defined in #undef", token); -X } -X } -X} -X -Xtextput(text) -Xchar *text; -X/* -X * Put the string in the parm[] buffer. -X */ -X{ -X register int size; -X -X size = strlen(text) + 1; -X if ((parmp + size) >= &parm[NPARMWORK]) -X cfatal("Macro work area overflow", NULLST); -X else { -X strcpy(parmp, text); -X parmp += size; -X } -X} -X -Xcharput(c) -Xregister int c; -X/* -X * Put the byte in the parm[] buffer. -X */ -X{ -X if (parmp >= &parm[NPARMWORK]) -X cfatal("Macro work area overflow", NULLST); -X else { -X *parmp++ = c; -X } -X} -X -X/* -X * M a c r o E x p a n s i o n -X */ -X -Xstatic DEFBUF *macro; /* Catches start of infinite macro */ -X -Xexpand(tokenp) -Xregister DEFBUF *tokenp; -X/* -X * Expand a macro. Called from the cpp mainline routine (via subroutine -X * macroid()) when a token is found in the symbol table. It calls -X * expcollect() to parse actual parameters, checking for the correct number. -X * It then creates a "file" containing a single line containing the -X * macro with actual parameters inserted appropriately. This is -X * "pushed back" onto the input stream. (When the get() routine runs -X * off the end of the macro line, it will dismiss the macro itself.) -X */ -X{ -X register int c; -X register FILEINFO *file; -X extern FILEINFO *getfile(); -X -X#if DEBUG -X if (debug) -X dumpadef("expand entry", tokenp); -X#endif -X /* -X * If no macro is pending, save the name of this macro -X * for an eventual error message. -X */ -X if (recursion++ == 0) -X macro = tokenp; -X else if (recursion == RECURSION_LIMIT) { -X cerror("Recursive macro definition of \"%s\"", tokenp->name); -X fprintf(stderr, "(Defined by \"%s\")\n", macro->name); -X if (rec_recover) { -X do { -X c = get(); -X } while (infile != NULL && infile->fp == NULL); -X unget(); -X recursion = 0; -X return; -X } -X } -X /* -X * Here's a macro to expand. -X */ -X nargs = 0; /* Formals counter */ -X parmp = parm; /* Setup parm buffer */ -X switch (tokenp->nargs) { -X case (-2): /* __LINE__ */ -X sprintf(work, "%d", line); -X ungetstring(work); -X break; -X -X case (-3): /* __FILE__ */ -X for (file = infile; file != NULL; file = file->parent) { -X if (file->fp != NULL) { -X sprintf(work, "\"%s\"", (file->progname != NULL) -X ? file->progname : file->filename); -X ungetstring(work); -X break; -X } -X } -X break; -X -X default: -X /* -X * Nothing funny about this macro. -X */ -X if (tokenp->nargs < 0) -X cfatal("Bug: Illegal __ macro \"%s\"", tokenp->name); -X while ((c = skipws()) == '\n') /* Look for (, skipping */ -X wrongline = TRUE; /* spaces and newlines */ -X if (c != '(') { -X /* -X * If the programmer writes -X * #define foo() ... -X * ... -X * foo [no ()] -X * just write foo to the output stream. -X */ -X unget(); -X cwarn("Macro \"%s\" needs arguments", tokenp->name); -X fputs(tokenp->name, stdout); -X return; -X } -X else if (expcollect()) { /* Collect arguments */ -X if (tokenp->nargs != nargs) { /* Should be an error? */ -X cwarn("Wrong number of macro arguments for \"%s\"", -X tokenp->name); -X } -X#if DEBUG -X if (debug) -X dumpparm("expand"); -X#endif -X } /* Collect arguments */ -X case DEF_NOARGS: /* No parameters just stuffs */ -X expstuff(tokenp); /* Do actual parameters */ -X } /* nargs switch */ -X} -X -XFILE_LOCAL int -Xexpcollect() -X/* -X * Collect the actual parameters for this macro. TRUE if ok. -X */ -X{ -X register int c; -X register int paren; /* For embedded ()'s */ -X extern int charput(); -X -X for (;;) { -X paren = 0; /* Collect next arg. */ -X while ((c = skipws()) == '\n') /* Skip over whitespace */ -X wrongline = TRUE; /* and newlines. */ -X if (c == ')') { /* At end of all args? */ -X /* -X * Note that there is a guard byte in parm[] -X * so we don't have to check for overflow here. -X */ -X *parmp = EOS; /* Make sure terminated */ -X break; /* Exit collection loop */ -X } -X else if (nargs >= LASTPARM) -X cfatal("Too many arguments in macro expansion", NULLST); -X parlist[nargs++] = parmp; /* At start of new arg */ -X for (;; c = cget()) { /* Collect arg's bytes */ -X if (c == EOF_CHAR) { -X cerror("end of file within macro argument", NULLST); -X return (FALSE); /* Sorry. */ -X } -X else if (c == '\\') { /* Quote next character */ -X charput(c); /* Save the \ for later */ -X charput(cget()); /* Save the next char. */ -X continue; /* And go get another */ -X } -X else if (type[c] == QUO) { /* Start of string? */ -X scanstring(c, charput); /* Scan it off */ -X continue; /* Go get next char */ -X } -X else if (c == '(') /* Worry about balance */ -X paren++; /* To know about commas */ -X else if (c == ')') { /* Other side too */ -X if (paren == 0) { /* At the end? */ -X unget(); /* Look at it later */ -X break; /* Exit arg getter. */ -X } -X paren--; /* More to come. */ -X } -X else if (c == ',' && paren == 0) /* Comma delimits args */ -X break; -X else if (c == '\n') /* Newline inside arg? */ -X wrongline = TRUE; /* We'll need a #line */ -X charput(c); /* Store this one */ -X } /* Collect an argument */ -X charput(EOS); /* Terminate argument */ -X#if DEBUG -X if (debug) -X printf("parm[%d] = \"%s\"\n", nargs, parlist[nargs - 1]); -X#endif -X } /* Collect all args. */ -X return (TRUE); /* Normal return */ -X} -X -XFILE_LOCAL -Xexpstuff(tokenp) -XDEFBUF *tokenp; /* Current macro being expanded */ -X/* -X * Stuff the macro body, replacing formal parameters by actual parameters. -X */ -X{ -X register int c; /* Current character */ -X register char *inp; /* -> repl string */ -X register char *defp; /* -> macro output buff */ -X int size; /* Actual parm. size */ -X char *defend; /* -> output buff end */ -X int string_magic; /* String formal hack */ -X FILEINFO *file; /* Funny #include */ -X extern FILEINFO *getfile(); -X -X file = getfile(NBUFF, tokenp->name); -X inp = tokenp->repl; /* -> macro replacement */ -X defp = file->buffer; /* -> output buffer */ -X defend = defp + (NBUFF - 1); /* Note its end */ -X if (inp != NULL) { -X while ((c = (*inp++ & 0xFF)) != EOS) { -X if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC)) { -X string_magic = (c == (MAC_PARM + PAR_MAC)); -X if (string_magic) -X c = (*inp++ & 0xFF); -X /* -X * Replace formal parameter by actual parameter string. -X */ -X if ((c -= MAC_PARM) < nargs) { -X size = strlen(parlist[c]); -X if ((defp + size) >= defend) -X goto nospace; -X /* -X * Erase the extra set of quotes. -X */ -X if (string_magic && defp[-1] == parlist[c][0]) { -X strcpy(defp-1, parlist[c]); -X defp += (size - 2); -X } -X else { -X strcpy(defp, parlist[c]); -X defp += size; -X } -X } -X } -X else if (defp >= defend) { -Xnospace: cfatal("Out of space in macro \"%s\" arg expansion", -X tokenp->name); -X } -X else { -X *defp++ = c; -X } -X } -X } -X *defp = EOS; -X#if DEBUG -X if (debug > 1) -X printf("macroline: \"%s\"\n", file->buffer); -X#endif -X} -X -X#if DEBUG -Xdumpparm(why) -Xchar *why; -X/* -X * Dump parameter list. -X */ -X{ -X register int i; -X -X printf("dump of %d parameters (%d bytes total) %s\n", -X nargs, parmp - parm, why); -X for (i = 0; i < nargs; i++) { -X printf("parm[%d] (%d) = \"%s\"\n", -X i + 1, strlen(parlist[i]), parlist[i]); -X } -X} -X#endif -END-of-cpp4.c -exit diff --git a/sys/unix/cpp3.shr b/sys/unix/cpp3.shr deleted file mode 100644 index d437d3693..000000000 --- a/sys/unix/cpp3.shr +++ /dev/null @@ -1,1901 +0,0 @@ -# This is a shell archive. Save it in a file, remove anything before -# this line, and then unpack it by entering "sh file". Note, it may -# create directories; files and directories will be owned by you and -# have default permissions. -# -# This archive contains: -# -# cpp5.c -# cpp6.c -# -echo x - cpp5.c -sed 's/^X//' >cpp5.c << 'END-of-cpp5.c' -X/* -X * C P P 5 . C -X * E x p r e s s i o n E v a l u a t i o n -X * -X * Edit History -X * 31-Aug-84 MM USENET net.sources release -X * 04-Oct-84 MM __LINE__ and __FILE__ must call ungetstring() -X * so they work correctly with token concatenation. -X * Added string formal recognition. -X * 25-Oct-84 MM "Short-circuit" evaluate #if's so that we -X * don't print unnecessary error messages for -X * #if !defined(FOO) && FOO != 0 && 10 / FOO ... -X * 31-Oct-84 ado/MM Added token concatenation -X * 6-Nov-84 MM Split from #define stuff, added sizeof stuff -X * 19-Nov-84 ado #if error returns TRUE for (sigh) compatibility -X */ -X -X#include -X#include -X#include "cppdef.h" -X#include "cpp.h" -X -X/* -X * Evaluate an #if expression. -X */ -X -Xstatic char *opname[] = { /* For debug and error messages */ -X"end of expression", "val", "id", -X "+", "-", "*", "/", "%", -X "<<", ">>", "&", "|", "^", -X "==", "!=", "<", "<=", ">=", ">", -X "&&", "||", "?", ":", ",", -X "unary +", "unary -", "~", "!", "(", ")", "(none)", -X}; -X -X/* -X * opdope[] has the operator precedence: -X * Bits -X * 7 Unused (so the value is always positive) -X * 6-2 Precedence (000x .. 017x) -X * 1-0 Binary op. flags: -X * 01 The binop flag should be set/cleared when this op is seen. -X * 10 The new value of the binop flag. -X * Note: Expected, New binop -X * constant 0 1 Binop, end, or ) should follow constants -X * End of line 1 0 End may not be preceeded by an operator -X * binary 1 0 Binary op follows a value, value follows. -X * unary 0 0 Unary op doesn't follow a value, value follows -X * ( 0 0 Doesn't follow value, value or unop follows -X * ) 1 1 Follows value. Op follows. -X */ -X -Xstatic char opdope[OP_MAX] = { -X 0001, /* End of expression */ -X 0002, /* Digit */ -X 0000, /* Letter (identifier) */ -X 0141, 0141, 0151, 0151, 0151, /* ADD, SUB, MUL, DIV, MOD */ -X 0131, 0131, 0101, 0071, 0071, /* ASL, ASR, AND, OR, XOR */ -X 0111, 0111, 0121, 0121, 0121, 0121, /* EQ, NE, LT, LE, GE, GT */ -X 0061, 0051, 0041, 0041, 0031, /* ANA, ORO, QUE, COL, CMA */ -X/* -X * Unary op's follow -X */ -X 0160, 0160, 0160, 0160, /* NEG, PLU, COM, NOT */ -X 0170, 0013, 0023, /* LPA, RPA, END */ -X}; -X/* -X * OP_QUE and OP_RPA have alternate precedences: -X */ -X#define OP_RPA_PREC 0013 -X#define OP_QUE_PREC 0034 -X -X/* -X * S_ANDOR and S_QUEST signal "short-circuit" boolean evaluation, so that -X * #if FOO != 0 && 10 / FOO ... -X * doesn't generate an error message. They are stored in optab.skip. -X */ -X#define S_ANDOR 2 -X#define S_QUEST 1 -X -Xtypedef struct optab { -X char op; /* Operator */ -X char prec; /* Its precedence */ -X char skip; /* Short-circuit: TRUE to skip */ -X} OPTAB; -Xstatic int evalue; /* Current value from evallex() */ -X -X#ifdef nomacargs -XFILE_LOCAL int -Xisbinary(op) -Xregister int op; -X{ -X return (op >= FIRST_BINOP && op <= LAST_BINOP); -X} -X -XFILE_LOCAL int -Xisunary(op) -Xregister int op; -X{ -X return (op >= FIRST_UNOP && op <= LAST_UNOP); -X} -X#else -X#define isbinary(op) (op >= FIRST_BINOP && op <= LAST_BINOP) -X#define isunary(op) (op >= FIRST_UNOP && op <= LAST_UNOP) -X#endif -X -X/* -X * The following definitions are used to specify basic variable sizes. -X */ -X -X#ifndef S_CHAR -X#define S_CHAR (sizeof (char)) -X#endif -X#ifndef S_SINT -X#define S_SINT (sizeof (short int)) -X#endif -X#ifndef S_INT -X#define S_INT (sizeof (int)) -X#endif -X#ifndef S_LINT -X#define S_LINT (sizeof (long int)) -X#endif -X#ifndef S_FLOAT -X#define S_FLOAT (sizeof (float)) -X#endif -X#ifndef S_DOUBLE -X#define S_DOUBLE (sizeof (double)) -X#endif -X#ifndef S_PCHAR -X#define S_PCHAR (sizeof (char *)) -X#endif -X#ifndef S_PSINT -X#define S_PSINT (sizeof (short int *)) -X#endif -X#ifndef S_PINT -X#define S_PINT (sizeof (int *)) -X#endif -X#ifndef S_PLINT -X#define S_PLINT (sizeof (long int *)) -X#endif -X#ifndef S_PFLOAT -X#define S_PFLOAT (sizeof (float *)) -X#endif -X#ifndef S_PDOUBLE -X#define S_PDOUBLE (sizeof (double *)) -X#endif -X#ifndef S_PFPTR -X#define S_PFPTR (sizeof (int (*)())) -X#endif -X -Xtypedef struct types { -X short type; /* This is the bit if */ -X char *name; /* this is the token word */ -X} TYPES; -X -Xstatic TYPES basic_types[] = { -X { T_CHAR, "char", }, -X { T_INT, "int", }, -X { T_FLOAT, "float", }, -X { T_DOUBLE, "double", }, -X { T_SHORT, "short", }, -X { T_LONG, "long", }, -X { T_SIGNED, "signed", }, -X { T_UNSIGNED, "unsigned", }, -X { 0, NULL, }, /* Signal end */ -X}; -X -X/* -X * Test_table[] is used to test for illegal combinations. -X */ -Xstatic short test_table[] = { -X T_FLOAT | T_DOUBLE | T_LONG | T_SHORT, -X T_FLOAT | T_DOUBLE | T_CHAR | T_INT, -X T_FLOAT | T_DOUBLE | T_SIGNED | T_UNSIGNED, -X T_LONG | T_SHORT | T_CHAR, -X 0 /* end marker */ -X}; -X -X/* -X * The order of this table is important -- it is also referenced by -X * the command line processor to allow run-time overriding of the -X * built-in size values. The order must not be changed: -X * char, short, int, long, float, double (func pointer) -X */ -XSIZES size_table[] = { -X { T_CHAR, S_CHAR, S_PCHAR }, /* char */ -X { T_SHORT, S_SINT, S_PSINT }, /* short int */ -X { T_INT, S_INT, S_PINT }, /* int */ -X { T_LONG, S_LINT, S_PLINT }, /* long */ -X { T_FLOAT, S_FLOAT, S_PFLOAT }, /* float */ -X { T_DOUBLE, S_DOUBLE, S_PDOUBLE }, /* double */ -X { T_FPTR, 0, S_PFPTR }, /* int (*()) */ -X { 0, 0, 0 }, /* End of table */ -X}; -X -Xint -Xeval() -X/* -X * Evaluate an expression. Straight-forward operator precedence. -X * This is called from control() on encountering an #if statement. -X * It calls the following routines: -X * evallex Lexical analyser -- returns the type and value of -X * the next input token. -X * evaleval Evaluate the current operator, given the values on -X * the value stack. Returns a pointer to the (new) -X * value stack. -X * For compatiblity with older cpp's, this return returns 1 (TRUE) -X * if a syntax error is detected. -X */ -X{ -X register int op; /* Current operator */ -X register int *valp; /* -> value vector */ -X register OPTAB *opp; /* Operator stack */ -X int prec; /* Op precedence */ -X int binop; /* Set if binary op. needed */ -X int op1; /* Operand from stack */ -X int skip; /* For short-circuit testing */ -X int value[NEXP]; /* Value stack */ -X OPTAB opstack[NEXP]; /* Operand stack */ -X extern int *evaleval(); /* Does actual evaluation */ -X -X valp = value; -X opp = opstack; -X opp->op = OP_END; /* Mark bottom of stack */ -X opp->prec = opdope[OP_END]; /* And its precedence */ -X opp->skip = 0; /* Not skipping now */ -X binop = 0; -Xagain: ; -X#ifdef DEBUG_EVAL -X printf("In #if at again: skip = %d, binop = %d, line is: %s", -X opp->skip, binop, infile->bptr); -X#endif -X if ((op = evallex(opp->skip)) == OP_SUB && binop == 0) -X op = OP_NEG; /* Unary minus */ -X else if (op == OP_ADD && binop == 0) -X op = OP_PLU; /* Unary plus */ -X else if (op == OP_FAIL) -X return (1); /* Error in evallex */ -X#ifdef DEBUG_EVAL -X printf("op = %s, opdope = %03o, binop = %d, skip = %d\n", -X opname[op], opdope[op], binop, opp->skip); -X#endif -X if (op == DIG) { /* Value? */ -X if (binop != 0) { -X cerror("misplaced constant in #if", NULLST); -X return (1); -X } -X else if (valp >= &value[NEXP-1]) { -X cerror("#if value stack overflow", NULLST); -X return (1); -X } -X else { -X#ifdef DEBUG_EVAL -X printf("pushing %d onto value stack[%d]\n", -X evalue, valp - value); -X#endif -X *valp++ = evalue; -X binop = 1; -X } -X goto again; -X } -X else if (op > OP_END) { -X cerror("Illegal #if line", NULLST); -X return (1); -X } -X prec = opdope[op]; -X if (binop != (prec & 1)) { -X cerror("Operator %s in incorrect context", opname[op]); -X return (1); -X } -X binop = (prec & 2) >> 1; -X for (;;) { -X#ifdef DEBUG_EVAL -X printf("op %s, prec %d., stacked op %s, prec %d, skip %d\n", -X opname[op], prec, opname[opp->op], opp->prec, opp->skip); -X#endif -X if (prec > opp->prec) { -X if (op == OP_LPA) -X prec = OP_RPA_PREC; -X else if (op == OP_QUE) -X prec = OP_QUE_PREC; -X op1 = opp->skip; /* Save skip for test */ -X /* -X * Push operator onto op. stack. -X */ -X opp++; -X if (opp >= &opstack[NEXP]) { -X cerror("expression stack overflow at op \"%s\"", -X opname[op]); -X return (1); -X } -X opp->op = op; -X opp->prec = prec; -X skip = (valp[-1] != 0); /* Short-circuit tester */ -X /* -X * Do the short-circuit stuff here. Short-circuiting -X * stops automagically when operators are evaluated. -X */ -X if ((op == OP_ANA && !skip) -X || (op == OP_ORO && skip)) -X opp->skip = S_ANDOR; /* And/or skip starts */ -X else if (op == OP_QUE) /* Start of ?: operator */ -X opp->skip = (op1 & S_ANDOR) | ((!skip) ? S_QUEST : 0); -X else if (op == OP_COL) { /* : inverts S_QUEST */ -X opp->skip = (op1 & S_ANDOR) -X | (((op1 & S_QUEST) != 0) ? 0 : S_QUEST); -X } -X else { /* Other ops leave */ -X opp->skip = op1; /* skipping unchanged. */ -X } -X#ifdef DEBUG_EVAL -X printf("stacking %s, valp[-1] == %d at %s", -X opname[op], valp[-1], infile->bptr); -X dumpstack(opstack, opp, value, valp); -X#endif -X goto again; -X } -X /* -X * Pop operator from op. stack and evaluate it. -X * End of stack and '(' are specials. -X */ -X skip = opp->skip; /* Remember skip value */ -X switch ((op1 = opp->op)) { /* Look at stacked op */ -X case OP_END: /* Stack end marker */ -X if (op == OP_EOE) -X return (valp[-1]); /* Finished ok. */ -X goto again; /* Read another op. */ -X -X case OP_LPA: /* ( on stack */ -X if (op != OP_RPA) { /* Matches ) on input */ -X cerror("unbalanced paren's, op is \"%s\"", opname[op]); -X return (1); -X } -X opp--; /* Unstack it */ -X /* goto again; -- Fall through */ -X -X case OP_QUE: -X goto again; /* Evaluate true expr. */ -X -X case OP_COL: /* : on stack. */ -X opp--; /* Unstack : */ -X if (opp->op != OP_QUE) { /* Matches ? on stack? */ -X cerror("Misplaced '?' or ':', previous operator is %s", -X opname[opp->op]); -X return (1); -X } -X /* -X * Evaluate op1. -X */ -X default: /* Others: */ -X opp--; /* Unstack the operator */ -X#ifdef DEBUG_EVAL -X printf("Stack before evaluation of %s\n", opname[op1]); -X dumpstack(opstack, opp, value, valp); -X#endif -X valp = evaleval(valp, op1, skip); -X#ifdef DEBUG_EVAL -X printf("Stack after evaluation\n"); -X dumpstack(opstack, opp, value, valp); -X#endif -X } /* op1 switch end */ -X } /* Stack unwind loop */ -X} -X -XFILE_LOCAL int -Xevallex(skip) -Xint skip; /* TRUE if short-circuit evaluation */ -X/* -X * Return next eval operator or value. Called from eval(). It -X * calls a special-purpose routines for 'char' strings and -X * numeric values: -X * evalchar called to evaluate 'x' -X * evalnum called to evaluate numbers. -X */ -X{ -X register int c, c1, t; -X -Xagain: do { /* Collect the token */ -X c = skipws(); -X if ((c = macroid(c)) == EOF_CHAR || c == '\n') { -X unget(); -X return (OP_EOE); /* End of expression */ -X } -X } while ((t = type[c]) == LET && catenate()); -X if (t == INV) { /* Total nonsense */ -X if (!skip) { -X if (isascii(c) && isprint(c)) -X cierror("illegal character '%c' in #if", c); -X else -X cierror("illegal character (%d decimal) in #if", c); -X } -X return (OP_FAIL); -X } -X else if (t == QUO) { /* ' or " */ -X if (c == '\'') { /* Character constant */ -X evalue = evalchar(skip); /* Somewhat messy */ -X#ifdef DEBUG_EVAL -X printf("evalchar returns %d.\n", evalue); -X#endif -X return (DIG); /* Return a value */ -X } -X cerror("Can't use a string in an #if", NULLST); -X return (OP_FAIL); -X } -X else if (t == LET) { /* ID must be a macro */ -X if (streq(token, "defined")) { /* Or defined name */ -X c1 = c = skipws(); -X if (c == '(') /* Allow defined(name) */ -X c = skipws(); -X if (type[c] == LET) { -X evalue = (lookid(c) != NULL); -X if (c1 != '(' /* Need to balance */ -X || skipws() == ')') /* Did we balance? */ -X return (DIG); /* Parsed ok */ -X } -X cerror("Bad #if ... defined() syntax", NULLST); -X return (OP_FAIL); -X } -X else if (streq(token, "sizeof")) /* New sizeof hackery */ -X return (dosizeof()); /* Gets own routine */ -X /* -X * The Draft ANSI C Standard says that an undefined symbol -X * in an #if has the value zero. We are a bit pickier, -X * warning except where the programmer was careful to write -X * #if defined(foo) ? foo : 0 -X */ -X#ifdef VERBOSE -X if (!skip) -X cwarn("undefined symbol \"%s\" in #if, 0 used", token); -X#endif -X evalue = 0; -X return (DIG); -X } -X else if (t == DIG) { /* Numbers are harder */ -X evalue = evalnum(c); -X#ifdef DEBUG_EVAL -X printf("evalnum returns %d.\n", evalue); -X#endif -X } -X else if (strchr("!=<>&|\\", c) != NULL) { -X /* -X * Process a possible multi-byte lexeme. -X */ -X c1 = cget(); /* Peek at next char */ -X switch (c) { -X case '!': -X if (c1 == '=') -X return (OP_NE); -X break; -X -X case '=': -X if (c1 != '=') { /* Can't say a=b in #if */ -X unget(); -X cerror("= not allowed in #if", NULLST); -X return (OP_FAIL); -X } -X return (OP_EQ); -X -X case '>': -X case '<': -X if (c1 == c) -X return ((c == '<') ? OP_ASL : OP_ASR); -X else if (c1 == '=') -X return ((c == '<') ? OP_LE : OP_GE); -X break; -X -X case '|': -X case '&': -X if (c1 == c) -X return ((c == '|') ? OP_ORO : OP_ANA); -X break; -X -X case '\\': -X if (c1 == '\n') /* Multi-line if */ -X goto again; -X cerror("Unexpected \\ in #if", NULLST); -X return (OP_FAIL); -X } -X unget(); -X } -X return (t); -X} -X -XFILE_LOCAL int -Xdosizeof() -X/* -X * Process the sizeof (basic type) operation in an #if string. -X * Sets evalue to the size and returns -X * DIG success -X * OP_FAIL bad parse or something. -X */ -X{ -X register int c; -X register TYPES *tp; -X register SIZES *sizp; -X register short *testp; -X short typecode; -X -X if ((c = skipws()) != '(') -X goto nogood; -X /* -X * Scan off the tokens. -X */ -X typecode = 0; -X while ((c = skipws())) { -X if ((c = macroid(c)) == EOF_CHAR || c == '\n') -X goto nogood; /* End of line is a bug */ -X else if (c == '(') { /* thing (*)() func ptr */ -X if (skipws() == '*' -X && skipws() == ')') { /* We found (*) */ -X if (skipws() != '(') /* Let () be optional */ -X unget(); -X else if (skipws() != ')') -X goto nogood; -X typecode |= T_FPTR; /* Function pointer */ -X } -X else { /* Junk is a bug */ -X goto nogood; -X } -X } -X else if (type[c] != LET) /* Exit if not a type */ -X break; -X else if (!catenate()) { /* Maybe combine tokens */ -X /* -X * Look for this unexpandable token in basic_types. -X * The code accepts "int long" as well as "long int" -X * which is a minor bug as bugs go (and one shared with -X * a lot of C compilers). -X */ -X for (tp = basic_types; tp->name != NULLST; tp++) { -X if (streq(token, tp->name)) -X break; -X } -X if (tp->name == NULLST) { -X cerror("#if sizeof, unknown type \"%s\"", token); -X return (OP_FAIL); -X } -X typecode |= tp->type; /* Or in the type bit */ -X } -X } -X /* -X * We are at the end of the type scan. Chew off '*' if necessary. -X */ -X if (c == '*') { -X typecode |= T_PTR; -X c = skipws(); -X } -X if (c == ')') { /* Last syntax check */ -X for (testp = test_table; *testp != 0; testp++) { -X if (!bittest(typecode & *testp)) { -X cerror("#if ... sizeof: illegal type combination", NULLST); -X return (OP_FAIL); -X } -X } -X /* -X * We assume that all function pointers are the same size: -X * sizeof (int (*)()) == sizeof (float (*)()) -X * We assume that signed and unsigned don't change the size: -X * sizeof (signed int) == (sizeof unsigned int) -X */ -X if ((typecode & T_FPTR) != 0) /* Function pointer */ -X typecode = T_FPTR | T_PTR; -X else { /* Var or var * datum */ -X typecode &= ~(T_SIGNED | T_UNSIGNED); -X if ((typecode & (T_SHORT | T_LONG)) != 0) -X typecode &= ~T_INT; -X } -X if ((typecode & ~T_PTR) == 0) { -X cerror("#if sizeof() error, no type specified", NULLST); -X return (OP_FAIL); -X } -X /* -X * Exactly one bit (and possibly T_PTR) may be set. -X */ -X for (sizp = size_table; sizp->bits != 0; sizp++) { -X if ((typecode & ~T_PTR) == sizp->bits) { -X evalue = ((typecode & T_PTR) != 0) -X ? sizp->psize : sizp->size; -X return (DIG); -X } -X } /* We shouldn't fail */ -X cierror("#if ... sizeof: bug, unknown type code 0x%x", typecode); -X return (OP_FAIL); -X } -X -Xnogood: unget(); -X cerror("#if ... sizeof() syntax error", NULLST); -X return (OP_FAIL); -X} -X -XFILE_LOCAL int -Xbittest(value) -X/* -X * TRUE if value is zero or exactly one bit is set in value. -X */ -X{ -X#if (4096 & ~(-4096)) == 0 -X return ((value & ~(-value)) == 0); -X#else -X /* -X * Do it the hard way (for non 2's complement machines) -X */ -X return (value == 0 || value ^ (value - 1) == (value * 2 - 1)); -X#endif -X} -X -XFILE_LOCAL int -Xevalnum(c) -Xregister int c; -X/* -X * Expand number for #if lexical analysis. Note: evalnum recognizes -X * the unsigned suffix, but only returns a signed int value. -X */ -X{ -X register int value; -X register int base; -X register int c1; -X -X if (c != '0') -X base = 10; -X else if ((c = cget()) == 'x' || c == 'X') { -X base = 16; -X c = cget(); -X } -X else base = 8; -X value = 0; -X for (;;) { -X c1 = c; -X if (isascii(c) && isupper(c1)) -X c1 = tolower(c1); -X if (c1 >= 'a') -X c1 -= ('a' - 10); -X else c1 -= '0'; -X if (c1 < 0 || c1 >= base) -X break; -X value *= base; -X value += c1; -X c = cget(); -X } -X if (c == 'u' || c == 'U') /* Unsigned nonsense */ -X c = cget(); -X unget(); -X return (value); -X} -X -XFILE_LOCAL int -Xevalchar(skip) -Xint skip; /* TRUE if short-circuit evaluation */ -X/* -X * Get a character constant -X */ -X{ -X register int c; -X register int value; -X register int count; -X -X instring = TRUE; -X if ((c = cget()) == '\\') { -X switch ((c = cget())) { -X case 'a': /* New in Standard */ -X#if ('a' == '\a' || '\a' == ALERT) -X value = ALERT; /* Use predefined value */ -X#else -X value = '\a'; /* Use compiler's value */ -X#endif -X break; -X -X case 'b': -X value = '\b'; -X break; -X -X case 'f': -X value = '\f'; -X break; -X -X case 'n': -X value = '\n'; -X break; -X -X case 'r': -X value = '\r'; -X break; -X -X case 't': -X value = '\t'; -X break; -X -X case 'v': /* New in Standard */ -X#if ('v' == '\v' || '\v' == VT) -X value = VT; /* Use predefined value */ -X#else -X value = '\v'; /* Use compiler's value */ -X#endif -X break; -X -X case 'x': /* '\xFF' */ -X count = 3; -X value = 0; -X while ((((c = get()) >= '0' && c <= '9') -X || (c >= 'a' && c <= 'f') -X || (c >= 'A' && c <= 'F')) -X && (--count >= 0)) { -X value *= 16; -X value += (c <= '9') ? (c - '0') : ((c & 0xF) + 9); -X } -X unget(); -X break; -X -X default: -X if (c >= '0' && c <= '7') { -X count = 3; -X value = 0; -X while (c >= '0' && c <= '7' && --count >= 0) { -X value *= 8; -X value += (c - '0'); -X c = get(); -X } -X unget(); -X } -X else value = c; -X break; -X } -X } -X else if (c == '\'') -X value = 0; -X else value = c; -X /* -X * We warn on multi-byte constants and try to hack -X * (big|little)endian machines. -X */ -X#if BIG_ENDIAN -X count = 0; -X#endif -X while ((c = get()) != '\'' && c != EOF_CHAR && c != '\n') { -X if (!skip) -X ciwarn("multi-byte constant '%c' isn't portable", c); -X#if BIG_ENDIAN -X count += BITS_CHAR; -X value += (c << count); -X#else -X value <<= BITS_CHAR; -X value += c; -X#endif -X } -X instring = FALSE; -X return (value); -X} -X -XFILE_LOCAL int * -Xevaleval(valp, op, skip) -Xregister int *valp; -Xint op; -Xint skip; /* TRUE if short-circuit evaluation */ -X/* -X * Apply the argument operator to the data on the value stack. -X * One or two values are popped from the value stack and the result -X * is pushed onto the value stack. -X * -X * OP_COL is a special case. -X * -X * evaleval() returns the new pointer to the top of the value stack. -X */ -X{ -X register int v1, v2; -X -X if (isbinary(op)) -X v2 = *--valp; -X v1 = *--valp; -X#ifdef DEBUG_EVAL -X printf("%s op %s", (isbinary(op)) ? "binary" : "unary", -X opname[op]); -X if (isbinary(op)) -X printf(", v2 = %d.", v2); -X printf(", v1 = %d.\n", v1); -X#endif -X switch (op) { -X case OP_EOE: -X break; -X -X case OP_ADD: -X v1 += v2; -X break; -X -X case OP_SUB: -X v1 -= v2; -X break; -X -X case OP_MUL: -X v1 *= v2; -X break; -X -X case OP_DIV: -X case OP_MOD: -X if (v2 == 0) { -X if (!skip) { -X cwarn("%s by zero in #if, zero result assumed", -X (op == OP_DIV) ? "divide" : "mod"); -X } -X v1 = 0; -X } -X else if (op == OP_DIV) -X v1 /= v2; -X else -X v1 %= v2; -X break; -X -X case OP_ASL: -X v1 <<= v2; -X break; -X -X case OP_ASR: -X v1 >>= v2; -X break; -X -X case OP_AND: -X v1 &= v2; -X break; -X -X case OP_OR: -X v1 |= v2; -X break; -X -X case OP_XOR: -X v1 ^= v2; -X break; -X -X case OP_EQ: -X v1 = (v1 == v2); -X break; -X -X case OP_NE: -X v1 = (v1 != v2); -X break; -X -X case OP_LT: -X v1 = (v1 < v2); -X break; -X -X case OP_LE: -X v1 = (v1 <= v2); -X break; -X -X case OP_GE: -X v1 = (v1 >= v2); -X break; -X -X case OP_GT: -X v1 = (v1 > v2); -X break; -X -X case OP_ANA: -X v1 = (v1 && v2); -X break; -X -X case OP_ORO: -X v1 = (v1 || v2); -X break; -X -X case OP_COL: -X /* -X * v1 has the "true" value, v2 the "false" value. -X * The top of the value stack has the test. -X */ -X v1 = (*--valp) ? v1 : v2; -X break; -X -X case OP_NEG: -X v1 = (-v1); -X break; -X -X case OP_PLU: -X break; -X -X case OP_COM: -X v1 = ~v1; -X break; -X -X case OP_NOT: -X v1 = !v1; -X break; -X -X default: -X cierror("#if bug, operand = %d.", op); -X v1 = 0; -X } -X *valp++ = v1; -X return (valp); -X} -X -X#ifdef DEBUG_EVAL -Xdumpstack(opstack, opp, value, valp) -XOPTAB opstack[NEXP]; /* Operand stack */ -Xregister OPTAB *opp; /* Operator stack */ -Xint value[NEXP]; /* Value stack */ -Xregister int *valp; /* -> value vector */ -X{ -X printf("index op prec skip name -- op stack at %s", infile->bptr); -X while (opp > opstack) { -X printf(" [%2d] %2d %03o %d %s\n", opp - opstack, -X opp->op, opp->prec, opp->skip, opname[opp->op]); -X opp--; -X } -X while (--valp >= value) { -X printf("value[%d] = %d\n", (valp - value), *valp); -X } -X} -X#endif -X -END-of-cpp5.c -echo x - cpp6.c -sed 's/^X//' >cpp6.c << 'END-of-cpp6.c' -X/* -X * C P P 6 . C -X * S u p p o r t R o u t i n e s -X * -X * Edit History -X * 25-May-84 MM Added 8-bit support to type table. -X * 30-May-84 ARF sharp() should output filename in quotes -X * 02-Aug-84 MM Newline and #line hacking. sharp() now in cpp1.c -X * 31-Aug-84 MM USENET net.sources release -X * 11-Sep-84 ado/MM Keepcomments, also line number pathological -X * 12-Sep-84 ado/MM bug if comment changes to space and we unget later. -X * 03-Oct-84 gkr/MM Fixed scannumber bug for '.e' (as in struct.element). -X * 04-Oct-84 MM Added ungetstring() for token concatenation -X * 08-Oct-84 MM Yet another attack on number scanning -X * 31-Oct-84 ado Parameterized $ in identifiers -X * 2-Nov-84 MM Token concatenation is messier than I thought -X * 6-Dec-84 MM \ is everywhere invisible. -X */ -X -X#include -X#include -X#include "cppdef.h" -X#include "cpp.h" -X -X/* -X * skipnl() skips over input text to the end of the line. -X * skipws() skips over "whitespace" (spaces or tabs), but -X * not skip over the end of the line. It skips over -X * TOK_SEP, however (though that shouldn't happen). -X * scanid() reads the next token (C identifier) into token[]. -X * The caller has already read the first character of -X * the identifier. Unlike macroid(), the token is -X * never expanded. -X * macroid() reads the next token (C identifier) into token[]. -X * If it is a #defined macro, it is expanded, and -X * macroid() returns TRUE, otherwise, FALSE. -X * catenate() Does the dirty work of token concatenation, TRUE if it did. -X * scanstring() Reads a string from the input stream, calling -X * a user-supplied function for each character. -X * This function may be output() to write the -X * string to the output file, or save() to save -X * the string in the work buffer. -X * scannumber() Reads a C numeric constant from the input stream, -X * calling the user-supplied function for each -X * character. (output() or save() as noted above.) -X * save() Save one character in the work[] buffer. -X * savestring() Saves a string in malloc() memory. -X * getfile() Initialize a new FILEINFO structure, called when -X * #include opens a new file, or a macro is to be -X * expanded. -X * getmem() Get a specified number of bytes from malloc memory. -X * output() Write one character to stdout (calling putchar) -- -X * implemented as a function so its address may be -X * passed to scanstring() and scannumber(). -X * lookid() Scans the next token (identifier) from the input -X * stream. Looks for it in the #defined symbol table. -X * Returns a pointer to the definition, if found, or NULL -X * if not present. The identifier is stored in token[]. -X * defnedel() Define enter/delete subroutine. Updates the -X * symbol table. -X * get() Read the next byte from the current input stream, -X * handling end of (macro/file) input and embedded -X * comments appropriately. Note that the global -X * instring is -- essentially -- a parameter to get(). -X * cget() Like get(), but skip over TOK_SEP. -X * unget() Push last gotten character back on the input stream. -X * cerror(), cwarn(), cfatal(), cierror(), ciwarn() -X * These routines format an print messages to the user. -X * cerror & cwarn take a format and a single string argument. -X * cierror & ciwarn take a format and a single int (char) argument. -X * cfatal takes a format and a single string argument. -X */ -X -X/* -X * This table must be rewritten for a non-Ascii machine. -X * -X * Note that several "non-visible" characters have special meaning: -X * Hex 1D DEF_MAGIC -- a flag to prevent #define recursion. -X * Hex 1E TOK_SEP -- a delimiter for token concatenation -X * Hex 1F COM_SEP -- a zero-width whitespace for comment concatenation -X */ -X#if TOK_SEP != 0x1E || COM_SEP != 0x1F || DEF_MAGIC != 0x1D -X << error type table isn't correct >> -X#endif -X -X#if OK_DOLLAR -X#define DOL LET -X#else -X#define DOL 000 -X#endif -X -Xchar type[256] = { /* Character type codes Hex */ -X END, 000, 000, 000, 000, 000, 000, 000, /* 00 */ -X 000, SPA, 000, 000, 000, 000, 000, 000, /* 08 */ -X 000, 000, 000, 000, 000, 000, 000, 000, /* 10 */ -X 000, 000, 000, 000, 000, LET, 000, SPA, /* 18 */ -X SPA,OP_NOT, QUO, 000, DOL,OP_MOD,OP_AND, QUO, /* 20 !"#$%&' */ -XOP_LPA,OP_RPA,OP_MUL,OP_ADD, 000,OP_SUB, DOT,OP_DIV, /* 28 ()*+,-./ */ -X DIG, DIG, DIG, DIG, DIG, DIG, DIG, DIG, /* 30 01234567 */ -X DIG, DIG,OP_COL, 000, OP_LT, OP_EQ, OP_GT,OP_QUE, /* 38 89:;<=>? */ -X 000, LET, LET, LET, LET, LET, LET, LET, /* 40 @ABCDEFG */ -X LET, LET, LET, LET, LET, LET, LET, LET, /* 48 HIJKLMNO */ -X LET, LET, LET, LET, LET, LET, LET, LET, /* 50 PQRSTUVW */ -X LET, LET, LET, 000, BSH, 000,OP_XOR, LET, /* 58 XYZ[\]^_ */ -X 000, LET, LET, LET, LET, LET, LET, LET, /* 60 `abcdefg */ -X LET, LET, LET, LET, LET, LET, LET, LET, /* 68 hijklmno */ -X LET, LET, LET, LET, LET, LET, LET, LET, /* 70 pqrstuvw */ -X LET, LET, LET, 000, OP_OR, 000,OP_NOT, 000, /* 78 xyz{|}~ */ -X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ -X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ -X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ -X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ -X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ -X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ -X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ -X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ -X}; -X -Xskipnl() -X/* -X * Skip to the end of the current input line. -X */ -X{ -X register int c; -X -X do { /* Skip to newline */ -X c = get(); -X } while (c != '\n' && c != EOF_CHAR); -X} -X -Xint -Xskipws() -X/* -X * Skip over whitespace -X */ -X{ -X register int c; -X -X do { /* Skip whitespace */ -X c = get(); -X#if COMMENT_INVISIBLE -X } while (type[c] == SPA || c == COM_SEP); -X#else -X } while (type[c] == SPA); -X#endif -X return (c); -X} -X -Xscanid(c) -Xregister int c; /* First char of id */ -X/* -X * Get the next token (an id) into the token buffer. -X * Note: this code is duplicated in lookid(). -X * Change one, change both. -X */ -X{ -X register char *bp; -X -X if (c == DEF_MAGIC) /* Eat the magic token */ -X c = get(); /* undefiner. */ -X bp = token; -X do { -X if (bp < &token[IDMAX]) /* token dim is IDMAX+1 */ -X *bp++ = c; -X c = get(); -X } while (type[c] == LET || type[c] == DIG); -X unget(); -X *bp = EOS; -X} -X -Xint -Xmacroid(c) -Xregister int c; -X/* -X * If c is a letter, scan the id. if it's #defined, expand it and scan -X * the next character and try again. -X * -X * Else, return the character. If type[c] is a LET, the token is in token. -X */ -X{ -X register DEFBUF *dp; -X -X if (infile != NULL && infile->fp != NULL) -X recursion = 0; -X while (type[c] == LET && (dp = lookid(c)) != NULL) { -X expand(dp); -X c = get(); -X } -X return (c); -X} -X -Xint -Xcatenate() -X/* -X * A token was just read (via macroid). -X * If the next character is TOK_SEP, concatenate the next token -X * return TRUE -- which should recall macroid after refreshing -X * macroid's argument. If it is not TOK_SEP, unget() the character -X * and return FALSE. -X */ -X{ -X register int c; -X register char *token1; -X -X#if OK_CONCAT -X if (get() != TOK_SEP) { /* Token concatenation */ -X unget(); -X return (FALSE); -X } -X else { -X token1 = savestring(token); /* Save first token */ -X c = macroid(get()); /* Scan next token */ -X switch(type[c]) { /* What was it? */ -X case LET: /* An identifier, ... */ -X if (strlen(token1) + strlen(token) >= NWORK) -X cfatal("work buffer overflow doing %s #", token1); -X sprintf(work, "%s%s", token1, token); -X break; -X -X case DIG: /* A digit string */ -X strcpy(work, token1); -X workp = work + strlen(work); -X do { -X save(c); -X } while ((c = get()) != TOK_SEP); -X /* -X * The trailing TOK_SEP is no longer needed. -X */ -X save(EOS); -X break; -X -X default: /* An error, ... */ -X if (isprint(c)) -X cierror("Strange character '%c' after #", c); -X else -X cierror("Strange character (%d.) after #", c); -X strcpy(work, token1); -X unget(); -X break; -X } -X /* -X * work has the concatenated token and token1 has -X * the first token (no longer needed). Unget the -X * new (concatenated) token after freeing token1. -X * Finally, setup to read the new token. -X */ -X free(token1); /* Free up memory */ -X ungetstring(work); /* Unget the new thing, */ -X return (TRUE); -X } -X#else -X return (FALSE); /* Not supported */ -X#endif -X} -X -Xint -Xscanstring(delim, outfun) -Xregister int delim; /* ' or " */ -Xint (*outfun)(); /* Output function */ -X/* -X * Scan off a string. Warning if terminated by newline or EOF. -X * outfun() outputs the character -- to a buffer if in a macro. -X * TRUE if ok, FALSE if error. -X */ -X{ -X register int c; -X -X instring = TRUE; /* Don't strip comments */ -X (*outfun)(delim); -X while ((c = get()) != delim -X && c != '\n' -X && c != EOF_CHAR) { -X (*outfun)(c); -X if (c == '\\') -X (*outfun)(get()); -X } -X instring = FALSE; -X if (c == delim) { -X (*outfun)(c); -X return (TRUE); -X } -X else { -X cerror("Unterminated string", NULLST); -X unget(); -X return (FALSE); -X } -X} -X -Xscannumber(c, outfun) -Xregister int c; /* First char of number */ -Xregister int (*outfun)(); /* Output/store func */ -X/* -X * Process a number. We know that c is from 0 to 9 or dot. -X * Algorithm from Dave Conroy's Decus C. -X */ -X{ -X register int radix; /* 8, 10, or 16 */ -X int expseen; /* 'e' seen in floater */ -X int signseen; /* '+' or '-' seen */ -X int octal89; /* For bad octal test */ -X int dotflag; /* TRUE if '.' was seen */ -X -X expseen = FALSE; /* No exponent seen yet */ -X signseen = TRUE; /* No +/- allowed yet */ -X octal89 = FALSE; /* No bad octal yet */ -X radix = 10; /* Assume decimal */ -X if ((dotflag = (c == '.')) != FALSE) { /* . something? */ -X (*outfun)('.'); /* Always out the dot */ -X if (type[(c = get())] != DIG) { /* If not a float numb, */ -X unget(); /* Rescan strange char */ -X return; /* All done for now */ -X } -X } /* End of float test */ -X else if (c == '0') { /* Octal or hex? */ -X (*outfun)(c); /* Stuff initial zero */ -X radix = 8; /* Assume it's octal */ -X c = get(); /* Look for an 'x' */ -X if (c == 'x' || c == 'X') { /* Did we get one? */ -X radix = 16; /* Remember new radix */ -X (*outfun)(c); /* Stuff the 'x' */ -X c = get(); /* Get next character */ -X } -X } -X for (;;) { /* Process curr. char. */ -X /* -X * Note that this algorithm accepts "012e4" and "03.4" -X * as legitimate floating-point numbers. -X */ -X if (radix != 16 && (c == 'e' || c == 'E')) { -X if (expseen) /* Already saw 'E'? */ -X break; /* Exit loop, bad nbr. */ -X expseen = TRUE; /* Set exponent seen */ -X signseen = FALSE; /* We can read '+' now */ -X radix = 10; /* Decimal exponent */ -X } -X else if (radix != 16 && c == '.') { -X if (dotflag) /* Saw dot already? */ -X break; /* Exit loop, two dots */ -X dotflag = TRUE; /* Remember the dot */ -X radix = 10; /* Decimal fraction */ -X } -X else if (c == '+' || c == '-') { /* 1.0e+10 */ -X if (signseen) /* Sign in wrong place? */ -X break; /* Exit loop, not nbr. */ -X /* signseen = TRUE; */ /* Remember we saw it */ -X } -X else { /* Check the digit */ -X switch (c) { -X case '8': case '9': /* Sometimes wrong */ -X octal89 = TRUE; /* Do check later */ -X case '0': case '1': case '2': case '3': -X case '4': case '5': case '6': case '7': -X break; /* Always ok */ -X -X case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': -X case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': -X if (radix == 16) /* Alpha's are ok only */ -X break; /* if reading hex. */ -X default: /* At number end */ -X goto done; /* Break from for loop */ -X } /* End of switch */ -X } /* End general case */ -X (*outfun)(c); /* Accept the character */ -X signseen = TRUE; /* Don't read sign now */ -X c = get(); /* Read another char */ -X } /* End of scan loop */ -X /* -X * When we break out of the scan loop, c contains the first -X * character (maybe) not in the number. If the number is an -X * integer, allow a trailing 'L' for long and/or a trailing 'U' -X * for unsigned. If not those, push the trailing character back -X * on the input stream. Floating point numbers accept a trailing -X * 'L' for "long double". -X */ -Xdone: if (dotflag || expseen) { /* Floating point? */ -X if (c == 'l' || c == 'L') { -X (*outfun)(c); -X c = get(); /* Ungotten later */ -X } -X } -X else { /* Else it's an integer */ -X /* -X * We know that dotflag and expseen are both zero, now: -X * dotflag signals "saw 'L'", and -X * expseen signals "saw 'U'". -X */ -X for (;;) { -X switch (c) { -X case 'l': -X case 'L': -X if (dotflag) -X goto nomore; -X dotflag = TRUE; -X break; -X -X case 'u': -X case 'U': -X if (expseen) -X goto nomore; -X expseen = TRUE; -X break; -X -X default: -X goto nomore; -X } -X (*outfun)(c); /* Got 'L' or 'U'. */ -X c = get(); /* Look at next, too. */ -X } -X } -Xnomore: unget(); /* Not part of a number */ -X if (octal89 && radix == 8) -X cwarn("Illegal digit in octal number", NULLST); -X} -X -Xsave(c) -Xregister int c; -X{ -X if (workp >= &work[NWORK]) -X cfatal("Work buffer overflow", NULLST); -X else *workp++ = c; -X} -X -Xchar * -Xsavestring(text) -Xchar *text; -X/* -X * Store a string into free memory. -X */ -X{ -X register char *result; -X -X result = getmem(strlen(text) + 1); -X strcpy(result, text); -X return (result); -X} -X -XFILEINFO * -Xgetfile(bufsize, name) -Xint bufsize; /* Line or define buffer size */ -Xchar *name; /* File or macro name string */ -X/* -X * Common FILEINFO buffer initialization for a new file or macro. -X */ -X{ -X register FILEINFO *file; -X register int size; -X -X size = strlen(name); /* File/macro name */ -X file = (FILEINFO *) getmem(sizeof (FILEINFO) + bufsize + size); -X file->parent = infile; /* Chain files together */ -X file->fp = NULL; /* No file yet */ -X file->filename = savestring(name); /* Save file/macro name */ -X file->progname = NULL; /* No #line seen yet */ -X file->unrecur = 0; /* No macro fixup */ -X file->bptr = file->buffer; /* Initialize line ptr */ -X file->buffer[0] = EOS; /* Force first read */ -X file->line = 0; /* (Not used just yet) */ -X if (infile != NULL) /* If #include file */ -X infile->line = line; /* Save current line */ -X infile = file; /* New current file */ -X line = 1; /* Note first line */ -X return (file); /* All done. */ -X} -X -Xchar * -Xgetmem(size) -Xint size; -X/* -X * Get a block of free memory. -X */ -X{ -X register char *result; -X extern char *malloc(); -X -X if ((result = malloc((unsigned) size)) == NULL) -X cfatal("Out of memory", NULLST); -X return (result); -X} -X -X/* -X * C P P S y m b o l T a b l e s -X */ -X -X/* -X * SBSIZE defines the number of hash-table slots for the symbol table. -X * It must be a power of 2. -X */ -X#ifndef SBSIZE -X#define SBSIZE 64 -X#endif -X#define SBMASK (SBSIZE - 1) -X#if (SBSIZE ^ SBMASK) != ((SBSIZE * 2) - 1) -X << error, SBSIZE must be a power of 2 >> -X#endif -X -Xstatic DEFBUF *symtab[SBSIZE]; /* Symbol table queue headers */ -X -XDEFBUF * -Xlookid(c) -Xint c; /* First character of token */ -X/* -X * Look for the next token in the symbol table. Returns token in "token". -X * If found, returns the table pointer; Else returns NULL. -X */ -X{ -X register int nhash; -X register DEFBUF *dp; -X register char *np; -X int temp; -X int isrecurse; /* For #define foo foo */ -X -X np = token; -X nhash = 0; -X if ((isrecurse = (c == DEF_MAGIC))) /* If recursive macro */ -X c = get(); /* hack, skip DEF_MAGIC */ -X do { -X if (np < &token[IDMAX]) { /* token dim is IDMAX+1 */ -X *np++ = c; /* Store token byte */ -X nhash += c; /* Update hash value */ -X } -X c = get(); /* And get another byte */ -X } while (type[c] == LET || type[c] == DIG); -X unget(); /* Rescan terminator */ -X *np = EOS; /* Terminate token */ -X if (isrecurse) /* Recursive definition */ -X return (NULL); /* undefined just now */ -X nhash += (np - token); /* Fix hash value */ -X dp = symtab[nhash & SBMASK]; /* Starting bucket */ -X while (dp != (DEFBUF *) NULL) { /* Search symbol table */ -X if (dp->hash == nhash /* Fast precheck */ -X && (temp = strcmp(dp->name, token)) >= 0) -X break; -X dp = dp->link; /* Nope, try next one */ -X } -X return ((temp == 0) ? dp : NULL); -X} -X -XDEFBUF * -Xdefendel(name, delete) -Xchar *name; -Xint delete; /* TRUE to delete a symbol */ -X/* -X * Enter this name in the lookup table (delete = FALSE) -X * or delete this name (delete = TRUE). -X * Returns a pointer to the define block (delete = FALSE) -X * Returns NULL if the symbol wasn't defined (delete = TRUE). -X */ -X{ -X register DEFBUF *dp; -X register DEFBUF **prevp; -X register char *np; -X int nhash; -X int temp; -X int size; -X -X for (nhash = 0, np = name; *np != EOS;) -X nhash += *np++; -X size = (np - name); -X nhash += size; -X prevp = &symtab[nhash & SBMASK]; -X while ((dp = *prevp) != (DEFBUF *) NULL) { -X if (dp->hash == nhash -X && (temp = strcmp(dp->name, name)) >= 0) { -X if (temp > 0) -X dp = NULL; /* Not found */ -X else { -X *prevp = dp->link; /* Found, unlink and */ -X if (dp->repl != NULL) /* Free the replacement */ -X free(dp->repl); /* if any, and then */ -X free((char *) dp); /* Free the symbol */ -X } -X break; -X } -X prevp = &dp->link; -X } -X if (!delete) { -X dp = (DEFBUF *) getmem(sizeof (DEFBUF) + size); -X dp->link = *prevp; -X *prevp = dp; -X dp->hash = nhash; -X dp->repl = NULL; -X dp->nargs = 0; -X strcpy(dp->name, name); -X } -X return (dp); -X} -X -X#if DEBUG -X -Xdumpdef(why) -Xchar *why; -X{ -X register DEFBUF *dp; -X register DEFBUF **syp; -X -X printf("CPP symbol table dump %s\n", why); -X for (syp = symtab; syp < &symtab[SBSIZE]; syp++) { -X if ((dp = *syp) != (DEFBUF *) NULL) { -X printf("symtab[%d]\n", (syp - symtab)); -X do { -X dumpadef((char *) NULL, dp); -X } while ((dp = dp->link) != (DEFBUF *) NULL); -X } -X } -X} -X -Xdumpadef(why, dp) -Xchar *why; /* Notation */ -Xregister DEFBUF *dp; -X{ -X register char *cp; -X register int c; -X -X printf(" \"%s\" [%d]", dp->name, dp->nargs); -X if (why != NULL) -X printf(" (%s)", why); -X if (dp->repl != NULL) { -X printf(" => "); -X for (cp = dp->repl; (c = *cp++ & 0xFF) != EOS;) { -X if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC)) -X printf("<%d>", c - MAC_PARM); -X else if (isprint(c) || c == '\n' || c == '\t') -X putchar(c); -X else if (c < ' ') -X printf("<^%c>", c + '@'); -X else -X printf("<\\0%o>", c); -X } -X } -X else { -X printf(", no replacement."); -X } -X putchar('\n'); -X} -X#endif -X -X/* -X * G E T -X */ -X -Xint -Xget() -X/* -X * Return the next character from a macro or the current file. -X * Handle end of file from #include files. -X */ -X{ -X register int c; -X register FILEINFO *file; -X register int popped; /* Recursion fixup */ -X -X popped = 0; -Xget_from_file: -X if ((file = infile) == NULL) -X return (EOF_CHAR); -Xnewline: -X#if 0 -X printf("get(%s), recursion %d, line %d, bptr = %d, buffer \"%s\"\n", -X file->filename, recursion, line, -X file->bptr - file->buffer, file->buffer); -X#endif -X /* -X * Read a character from the current input line or macro. -X * At EOS, either finish the current macro (freeing temp. -X * storage) or read another line from the current input file. -X * At EOF, exit the current file (#include) or, at EOF from -X * the cpp input file, return EOF_CHAR to finish processing. -X */ -X if ((c = *file->bptr++ & 0xFF) == EOS) { -X /* -X * Nothing in current line or macro. Get next line (if -X * input from a file), or do end of file/macro processing. -X * In the latter case, jump back to restart from the top. -X */ -X if (file->fp == NULL) { /* NULL if macro */ -X popped++; -X recursion -= file->unrecur; -X if (recursion < 0) -X recursion = 0; -X infile = file->parent; /* Unwind file chain */ -X } -X else { /* Else get from a file */ -X if ((file->bptr = fgets(file->buffer, NBUFF, file->fp)) -X != NULL) { -X#if DEBUG -X if (debug > 1) { /* Dump it to stdout */ -X printf("\n#line %d (%s), %s", -X line, file->filename, file->buffer); -X } -X#endif -X goto newline; /* process the line */ -X } -X else { -X fclose(file->fp); /* Close finished file */ -X if ((infile = file->parent) != NULL) { -X /* -X * There is an "ungotten" newline in the current -X * infile buffer (set there by doinclude() in -X * cpp1.c). Thus, we know that the mainline code -X * is skipping over blank lines and will do a -X * #line at its convenience. -X */ -X wrongline = TRUE; /* Need a #line now */ -X } -X } -X } -X /* -X * Free up space used by the (finished) file or macro and -X * restart input from the parent file/macro, if any. -X */ -X free(file->filename); /* Free name and */ -X if (file->progname != NULL) /* if a #line was seen, */ -X free(file->progname); /* free it, too. */ -X free((char *) file); /* Free file space */ -X if (infile == NULL) /* If at end of file */ -X return (EOF_CHAR); /* Return end of file */ -X line = infile->line; /* Reset line number */ -X goto get_from_file; /* Get from the top. */ -X } -X /* -X * Common processing for the new character. -X */ -X if (c == DEF_MAGIC && file->fp != NULL) /* Don't allow delete */ -X goto newline; /* from a file */ -X if (file->parent != NULL) { /* Macro or #include */ -X if (popped != 0) -X file->parent->unrecur += popped; -X else { -X recursion -= file->parent->unrecur; -X if (recursion < 0) -X recursion = 0; -X file->parent->unrecur = 0; -X } -X } -X if (c == '\n') /* Maintain current */ -X ++line; /* line counter */ -X if (instring) /* Strings just return */ -X return (c); /* the character. */ -X else if (c == '/') { /* Comment? */ -X instring = TRUE; /* So get() won't loop */ -X if ((c = get()) != '*') { /* Next byte '*'? */ -X instring = FALSE; /* Nope, no comment */ -X unget(); /* Push the char. back */ -X return ('/'); /* Return the slash */ -X } -X if (keepcomments) { /* If writing comments */ -X putchar('/'); /* Write out the */ -X putchar('*'); /* initializer */ -X } -X for (;;) { /* Eat a comment */ -X c = get(); -Xtest: if (keepcomments && c != EOF_CHAR) -X cput(c); -X switch (c) { -X case EOF_CHAR: -X cerror("EOF in comment", NULLST); -X return (EOF_CHAR); -X -X case '/': -X if ((c = get()) != '*') /* Don't let comments */ -X goto test; /* Nest. */ -X#ifdef VERBOSE -X cwarn("Nested comments", NULLST); -X#endif -X /* Fall into * stuff */ -X case '*': -X if ((c = get()) != '/') /* If comment doesn't */ -X goto test; /* end, look at next */ -X instring = FALSE; /* End of comment, */ -X if (keepcomments) { /* Put out the comment */ -X cput(c); /* terminator, too */ -X } -X /* -X * A comment is syntactically "whitespace" -- -X * however, there are certain strange sequences -X * such as -X * #define foo(x) (something) -X * foo|* comment *|(123) -X * these are '/' ^ ^ -X * where just returning space (or COM_SEP) will cause -X * problems. This can be "fixed" by overwriting the -X * '/' in the input line buffer with ' ' (or COM_SEP) -X * but that may mess up an error message. -X * So, we peek ahead -- if the next character is -X * "whitespace" we just get another character, if not, -X * we modify the buffer. All in the name of purity. -X */ -X if (*file->bptr == '\n' -X || type[*file->bptr & 0xFF] == SPA) -X goto newline; -X#if COMMENT_INVISIBLE -X /* -X * Return magic (old-fashioned) syntactic space. -X */ -X return ((file->bptr[-1] = COM_SEP)); -X#else -X return ((file->bptr[-1] = ' ')); -X#endif -X -X case '\n': /* we'll need a #line */ -X if (!keepcomments) -X wrongline = TRUE; /* later... */ -X default: /* Anything else is */ -X break; /* Just a character */ -X } /* End switch */ -X } /* End comment loop */ -X } /* End if in comment */ -X else if (!inmacro && c == '\\') { /* If backslash, peek */ -X if ((c = get()) == '\n') { /* for a . If so, */ -X wrongline = TRUE; -X goto newline; -X } -X else { /* Backslash anything */ -X unget(); /* Get it later */ -X return ('\\'); /* Return the backslash */ -X } -X } -X else if (c == '\f' || c == VT) /* Form Feed, Vertical */ -X c = ' '; /* Tab are whitespace */ -X return (c); /* Just return the char */ -X} -X -Xunget() -X/* -X * Backup the pointer to reread the last character. Fatal error -X * (code bug) if we backup too far. unget() may be called, -X * without problems, at end of file. Only one character may -X * be ungotten. If you need to unget more, call ungetstring(). -X */ -X{ -X register FILEINFO *file; -X -X if ((file = infile) == NULL) -X return; /* Unget after EOF */ -X if (--file->bptr < file->buffer) -X cfatal("Too much pushback", NULLST); -X if (*file->bptr == '\n') /* Ungetting a newline? */ -X --line; /* Unget the line number, too */ -X} -X -Xungetstring(text) -Xchar *text; -X/* -X * Push a string back on the input stream. This is done by treating -X * the text as if it were a macro. -X */ -X{ -X register FILEINFO *file; -X extern FILEINFO *getfile(); -X -X file = getfile(strlen(text) + 1, ""); -X strcpy(file->buffer, text); -X} -X -Xint -Xcget() -X/* -X * Get one character, absorb "funny space" after comments or -X * token concatenation -X */ -X{ -X register int c; -X -X do { -X c = get(); -X#if COMMENT_INVISIBLE -X } while (c == TOK_SEP || c == COM_SEP); -X#else -X } while (c == TOK_SEP); -X#endif -X return (c); -X} -X -X/* -X * Error messages and other hacks. The first byte of severity -X * is 'S' for string arguments and 'I' for int arguments. This -X * is needed for portability with machines that have int's that -X * are shorter than char *'s. -X */ -X -Xstatic -Xdomsg(severity, format, arg) -Xchar *severity; /* "Error", "Warning", "Fatal" */ -Xchar *format; /* Format for the error message */ -Xchar *arg; /* Something for the message */ -X/* -X * Print filenames, macro names, and line numbers for error messages. -X */ -X{ -X register char *tp; -X register FILEINFO *file; -X -X fprintf(stderr, "%sline %d, %s: ", MSG_PREFIX, line, &severity[1]); -X if (*severity == 'S') -X fprintf(stderr, format, arg); -X else -X fprintf(stderr, format, (int) arg); -X putc('\n', stderr); -X if ((file = infile) == NULL) -X return; /* At end of file */ -X if (file->fp != NULL) { -X tp = file->buffer; /* Print current file */ -X fprintf(stderr, "%s", tp); /* name, making sure */ -X if (tp[strlen(tp) - 1] != '\n') /* there's a newline */ -X putc('\n', stderr); -X } -X while ((file = file->parent) != NULL) { /* Print #includes, too */ -X if (file->fp == NULL) -X fprintf(stderr, "from macro %s\n", file->filename); -X else { -X tp = file->buffer; -X fprintf(stderr, "from file %s, line %d:\n%s", -X (file->progname != NULL) -X ? file->progname : file->filename, -X file->line, tp); -X if (tp[strlen(tp) - 1] != '\n') -X putc('\n', stderr); -X } -X } -X} -X -Xcerror(format, sarg) -Xchar *format; -Xchar *sarg; /* Single string argument */ -X/* -X * Print a normal error message, string argument. -X */ -X{ -X domsg("SError", format, sarg); -X errors++; -X} -X -Xcierror(format, narg) -Xchar *format; -Xint narg; /* Single numeric argument */ -X/* -X * Print a normal error message, numeric argument. -X */ -X{ -X domsg("IError", format, (char *) narg); -X errors++; -X} -X -Xcfatal(format, sarg) -Xchar *format; -Xchar *sarg; /* Single string argument */ -X/* -X * A real disaster -X */ -X{ -X domsg("SFatal error", format, sarg); -X exit(IO_ERROR); -X} -X -Xcwarn(format, sarg) -Xchar *format; -Xchar *sarg; /* Single string argument */ -X/* -X * A non-fatal error, string argument. -X */ -X{ -X domsg("SWarning", format, sarg); -X} -X -Xciwarn(format, narg) -Xchar *format; -Xint narg; /* Single numeric argument */ -X/* -X * A non-fatal error, numeric argument. -X */ -X{ -X domsg("IWarning", format, (char *) narg); -X} -X -X -X -END-of-cpp6.c -exit