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)
+
+++ /dev/null
-# 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
+++ /dev/null
-# 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 <number> <optional name>
-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 <foo> 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\f
-X#include <stdio.h>
-X#include <ctype.h>
-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 <DEF_MAGIC>). Note especially that
-X * comments and \<newline> 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 \<newline>
-X * to the caller. Strictly speaking, this is a bug as \<newline>
-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\f
-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 <file */
-X#endif
-X initdefines(); /* O.S. specific def's */
-X i = dooptions(argc, argv); /* Command line -flags */
-X switch (i) {
-X case 3:
-X /*
-X * Get output file, "-" means use stdout.
-X */
-X if (!streq(argv[2], "-")) {
-X#if HOST == SYS_VMS
-X /*
-X * On vms, reopen stdout with "vanilla rms" attributes.
-X */
-X if ((i = creat(argv[2], 0, "rat=cr", "rfm=var")) == -1
-X || dup2(i, fileno(stdout)) == -1) {
-X#else
-X if (freopen(argv[2], "w", stdout) == NULL) {
-X#endif
-X perror(argv[2]);
-X cerror("Can't open output file \"%s\"", argv[2]);
-X exit(IO_ERROR);
-X }
-X } /* Continue by opening input */
-X case 2: /* One file -> 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\f
-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\f
-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 <stdio.h>
-X#include <ctype.h>
-X#include "cppdef.h"
-X#include "cpp.h"
-X#if DEBUG && (HOST == SYS_VMS || HOST == SYS_UNIX)
-X#include <signal.h>
-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\f
-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\f
-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\f
-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\f
-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 */
-X if (freopen(++ap, "r", stdin) == NULL) {
-X perror(ap); /* Can't find file */
-X exit(errno); /* Is a fatal error */
-X }
-X break;
-X
-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 <stdio.h>
-X#include <ctype.h>
-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 \<newline> 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 <newline> hack */
-X}
-X\f
-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\f
-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\f
-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\f
-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\f
-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\f
-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\f
-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
+++ /dev/null
-# 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 <stdio.h>
-X#include <ctype.h>
-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\f
-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\f
-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\f
-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\f
-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\f
-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\f
-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\f
-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\f
-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\f
-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 \<nl> is everywhere invisible.
-X */
-X
-X#include <stdio.h>
-X#include <ctype.h>
-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\f
-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\f
-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\f
-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\f
-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\f
-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\f
-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\f
-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\f
-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\f
-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\f
-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\f
-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 <nl>. 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\f
-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\f
-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