]> granicus.if.org Git - nethack/commitdiff
*** empty log message ***
authorjwalz <jwalz>
Sat, 5 Jan 2002 21:05:59 +0000 (21:05 +0000)
committerjwalz <jwalz>
Sat, 5 Jan 2002 21:05:59 +0000 (21:05 +0000)
sys/unix/cpp1.shr [new file with mode: 0644]

diff --git a/sys/unix/cpp1.shr b/sys/unix/cpp1.shr
new file mode 100644 (file)
index 0000000..f2b133d
--- /dev/null
@@ -0,0 +1,1783 @@
+# 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 <expr> 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\f                                                                          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\f                                                                          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\f                                                                          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\f                                                                          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\f
+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              <ssdef.h>
+X#include              <stsdef.h>
+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\f
+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\f
+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      <stdio.h>
+X#include      <ctype.h>
+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      <nam.h>
+X#include      <fab.h>
+X#include      <rab.h>
+X#include      <rmsdef.h>
+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 <line-number> and <name>
+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\f
+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\f
+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 <file>.
+X *    #include <file>         Search in an implementation-dependent
+X *                            list of places.
+X *    #include token          Expand the token, it must be one of
+X *                            "file" or <file>, process as such.
+X *
+X * Note: the November 12 draft forbids '>' in the #include <file> 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\f
+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\f
+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\f
+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