summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorzack <zack@138bc75d-0d04-0410-961f-82ee72b054a4>2000-07-06 22:59:34 +0000
committerzack <zack@138bc75d-0d04-0410-961f-82ee72b054a4>2000-07-06 22:59:34 +0000
commitcdc562c33e39c641bb0552ecfca52a5df1740c3d (patch)
tree392d92123d45decf22762f36d765d06a91d05893 /gcc
parent472679ed118ab49b4b1677d9de6bdb874e054927 (diff)
downloadgcc-cdc562c33e39c641bb0552ecfca52a5df1740c3d.tar.gz
* tradcpp.c: New file.
* tradcif.y: New file. * tradcif.c: New generated file. * Makefile.in: Add rules to build tradcpp.o, tradcif.o, $(srcdir)/tradcif.c. Add tradcpp to STAGESTUFF and dependencies of C. Install tradcpp from install-common, in $(libsubdir). git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@34893 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/Makefile.in18
-rw-r--r--gcc/tradcif.c1543
-rw-r--r--gcc/tradcif.y584
-rw-r--r--gcc/tradcpp.c4831
5 files changed, 6985 insertions, 2 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d7e95ee04fa..3f32a1dd858 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,16 @@
2000-07-06 Zack Weinberg <zack@wolery.cumb.org>
+ * tradcpp.c: New file.
+ * tradcif.y: New file.
+ * tradcif.c: New generated file.
+
+ * Makefile.in: Add rules to build tradcpp.o, tradcif.o,
+ $(srcdir)/tradcif.c. Add tradcpp to STAGESTUFF and
+ dependencies of C. Install tradcpp from install-common, in
+ $(libsubdir).
+
+2000-07-06 Zack Weinberg <zack@wolery.cumb.org>
+
* cppinit.c: Include cppdefault.h. Refer to
cpp_GCC_INCLUDE_DIR and cpp_GCC_INCLUDE_DIR_len, not directly
to GCC_INCLUDE_DIR and its length.
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 33911321696..4412afd64c6 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -716,7 +716,7 @@ STAGESTUFF = *$(objext) insn-flags.h insn-config.h insn-codes.h \
xgcc$(exeext) xcpp$(exeext) cc1$(exeext) cpp$(exeext) $(EXTRA_PASSES) \
$(EXTRA_PARTS) $(EXTRA_PROGRAMS) gcc-cross$(exeext) cc1obj$(exeext) \
enquire$(exeext) protoize$(exeext) unprotoize$(exeext) \
- specs collect2$(exeext) $(USE_COLLECT2) underscore.c \
+ specs collect2$(exeext) $(USE_COLLECT2) underscore.c tradcpp$(exeext) \
gcov$(exeext) *.[0-9][0-9].* *.[si] libcpp.a libgcc libgcc.mk \
$(LANG_STAGESTUFF)
@@ -869,7 +869,7 @@ native: config.status auto-host.h cpp$(exeext) intl.all $(LANGUAGES) \
$(EXTRA_PASSES) $(EXTRA_PROGRAMS) $(USE_COLLECT2)
# Define the names for selecting languages in LANGUAGES.
-C c: cc1$(exeext)
+C c: cc1$(exeext) tradcpp$(exeext)
PROTO: proto
# Tell GNU make these are phony targets.
@@ -1814,6 +1814,18 @@ cppdefault.o: cppdefault.c $(CONFIG_H) system.h cppdefault.h Makefile
mkdeps.o: mkdeps.c $(CONFIG_H) system.h mkdeps.h
+# The traditional mode preprocessor, a separate program for ease of
+# maintenance. Some code is shared with the ISO-C cpp.
+tradcpp$(exeext): tradcpp.o tradcif.o cppdefault.o $(LIBDEPS)
+ $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o tradcpp$(exeext) \
+ tradcpp.o tradcif.o cppdefault.o version.o intl.o $(LIBS)
+
+tradcpp.o: tradcpp.c $(CONFIG_H) system.h version.h cppdefault.h
+tradcif.o: tradcif.c $(CONFIG_H) system.h
+
+$(srcdir)/tradcif.c: $(srcdir)/tradcif.y
+ cd $(srcdir); $(BISON) $(BISONFLAGS) -o tradcif.c tradcif.y
+
# Note for the stamp targets, we run the program `true' instead of
# having an empty command (nothing following the semicolon).
@@ -2339,6 +2351,8 @@ install-common: native installdirs $(EXTRA_PARTS) lang.install-common
fi
-rm -f $(libsubdir)/cpp$(exeext)
$(INSTALL_PROGRAM) cpp$(exeext) $(libsubdir)/cpp$(exeext)
+ -rm -f $(libsubdir)/tradcpp$(exeext)
+ $(INSTALL_PROGRAM) tradcpp$(exeext) $(libsubdir)/tradcpp$(exeext)
# Install gcov if it was compiled.
-if [ -f gcov$(exeext) ]; \
then \
diff --git a/gcc/tradcif.c b/gcc/tradcif.c
new file mode 100644
index 00000000000..36d2fce4422
--- /dev/null
+++ b/gcc/tradcif.c
@@ -0,0 +1,1543 @@
+
+/* A Bison parser, made from tradcif.y
+ by GNU Bison version 1.28 */
+
+#define YYBISON 1 /* Identify Bison output. */
+
+#define INT 257
+#define CHAR 258
+#define NAME 259
+#define ERROR 260
+#define OR 261
+#define AND 262
+#define EQUAL 263
+#define NOTEQUAL 264
+#define LEQ 265
+#define GEQ 266
+#define LSH 267
+#define RSH 268
+#define UNARY 269
+
+#line 26 "tradcif.y"
+
+#include "config.h"
+#include "system.h"
+#include <setjmp.h>
+
+ int yylex PARAMS ((void));
+ void yyerror PARAMS ((const char *msgid));
+ extern void error PARAMS ((const char *msgid, ...));
+ extern void warning PARAMS ((const char *msgid, ...));
+ extern struct hashnode *lookup PARAMS ((const unsigned char *, int, int));
+
+ int parse_number PARAMS ((int));
+ int parse_escape PARAMS ((char **));
+ int parse_c_expression PARAMS ((char *));
+
+ int expression_value;
+ static jmp_buf parse_return_error;
+
+ /* some external tables of character types */
+ extern unsigned char is_idstart[], is_idchar[];
+
+#ifndef CHAR_TYPE_SIZE
+#define CHAR_TYPE_SIZE BITS_PER_UNIT
+#endif
+
+#line 52 "tradcif.y"
+typedef union {
+ struct constant {long value; int unsignedp;} integer;
+ int voidval;
+ char *sval;
+} YYSTYPE;
+#include <stdio.h>
+
+#ifndef __cplusplus
+#ifndef __STDC__
+#define const
+#endif
+#endif
+
+
+
+#define YYFINAL 61
+#define YYFLAG -32768
+#define YYNTBASE 33
+
+#define YYTRANSLATE(x) ((unsigned)(x) <= 269 ? yytranslate[x] : 36)
+
+static const char yytranslate[] = { 0,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 29, 2, 2, 2, 27, 14, 2, 31,
+ 32, 25, 23, 9, 24, 2, 26, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 8, 2, 17,
+ 2, 18, 7, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 13, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 12, 2, 30, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 1, 3, 4, 5, 6,
+ 10, 11, 15, 16, 19, 20, 21, 22, 28
+};
+
+#if YYDEBUG != 0
+static const short yyprhs[] = { 0,
+ 0, 2, 4, 8, 11, 14, 17, 20, 24, 28,
+ 32, 36, 40, 44, 48, 52, 56, 60, 64, 68,
+ 72, 76, 80, 84, 88, 92, 96, 102, 104, 106
+};
+
+static const short yyrhs[] = { 34,
+ 0, 35, 0, 34, 9, 35, 0, 24, 35, 0,
+ 29, 35, 0, 23, 35, 0, 30, 35, 0, 31,
+ 34, 32, 0, 35, 25, 35, 0, 35, 26, 35,
+ 0, 35, 27, 35, 0, 35, 23, 35, 0, 35,
+ 24, 35, 0, 35, 21, 35, 0, 35, 22, 35,
+ 0, 35, 15, 35, 0, 35, 16, 35, 0, 35,
+ 19, 35, 0, 35, 20, 35, 0, 35, 17, 35,
+ 0, 35, 18, 35, 0, 35, 14, 35, 0, 35,
+ 13, 35, 0, 35, 12, 35, 0, 35, 11, 35,
+ 0, 35, 10, 35, 0, 35, 7, 35, 8, 35,
+ 0, 3, 0, 4, 0, 5, 0
+};
+
+#endif
+
+#if YYDEBUG != 0
+static const short yyrline[] = { 0,
+ 81, 86, 87, 92, 95, 98, 100, 103, 108, 114,
+ 125, 136, 139, 142, 148, 154, 157, 160, 167, 174,
+ 181, 188, 191, 194, 197, 200, 203, 206, 208, 210
+};
+#endif
+
+
+#if YYDEBUG != 0 || defined (YYERROR_VERBOSE)
+
+static const char * const yytname[] = { "$","error","$undefined.","INT","CHAR",
+"NAME","ERROR","'?'","':'","','","OR","AND","'|'","'^'","'&'","EQUAL","NOTEQUAL",
+"'<'","'>'","LEQ","GEQ","LSH","RSH","'+'","'-'","'*'","'/'","'%'","UNARY","'!'",
+"'~'","'('","')'","start","exp1","exp", NULL
+};
+#endif
+
+static const short yyr1[] = { 0,
+ 33, 34, 34, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35
+};
+
+static const short yyr2[] = { 0,
+ 1, 1, 3, 2, 2, 2, 2, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 5, 1, 1, 1
+};
+
+static const short yydefact[] = { 0,
+ 28, 29, 30, 0, 0, 0, 0, 0, 1, 2,
+ 6, 4, 5, 7, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 8, 3, 0, 26, 25,
+ 24, 23, 22, 16, 17, 20, 21, 18, 19, 14,
+ 15, 12, 13, 9, 10, 11, 0, 27, 0, 0,
+ 0
+};
+
+static const short yydefgoto[] = { 59,
+ 9, 10
+};
+
+static const short yypact[] = { 31,
+-32768,-32768,-32768, 31, 31, 31, 31, 31, 1, 77,
+-32768,-32768,-32768,-32768, 0, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31,-32768, 77, 56, 94, 25,
+ 109, 123, 136, 147, 147, 154, 154, 154, 154, -19,
+ -19, 32, 32,-32768,-32768,-32768, 31, 77, 11, 33,
+-32768
+};
+
+static const short yypgoto[] = {-32768,
+ 48, -4
+};
+
+
+#define YYLAST 181
+
+
+static const short yytable[] = { 11,
+ 12, 13, 14, 31, 32, 33, 34, 35, 16, 16,
+ 60, 37, 38, 39, 40, 41, 42, 43, 44, 45,
+ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 36, 61, 1, 2, 3, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 58, 4, 5, 15, 33, 34, 35, 6,
+ 7, 8, 17, 57, 0, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 17, 0, 0, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 29, 30, 31, 32, 33, 34,
+ 35
+};
+
+static const short yycheck[] = { 4,
+ 5, 6, 7, 23, 24, 25, 26, 27, 9, 9,
+ 0, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 32, 0, 3, 4, 5, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 26, 27, 57, 23, 24, 8, 25, 26, 27, 29,
+ 30, 31, 7, 8, -1, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 7, -1, -1, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 27, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 21, 22, 23, 24, 25, 26,
+ 27
+};
+/* -*-C-*- Note some compilers choke on comments on `#line' lines. */
+#line 3 "/usr/share/misc/bison.simple"
+/* This file comes from bison-1.28. */
+
+/* Skeleton output parser for bison,
+ Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* This is the parser code that is written into each bison parser
+ when the %semantic_parser declaration is not specified in the grammar.
+ It was written by Richard Stallman by simplifying the hairy parser
+ used when %semantic_parser is specified. */
+
+#ifndef YYSTACK_USE_ALLOCA
+#ifdef alloca
+#define YYSTACK_USE_ALLOCA
+#else /* alloca not defined */
+#ifdef __GNUC__
+#define YYSTACK_USE_ALLOCA
+#define alloca __builtin_alloca
+#else /* not GNU C. */
+#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386))
+#define YYSTACK_USE_ALLOCA
+#include <alloca.h>
+#else /* not sparc */
+/* We think this test detects Watcom and Microsoft C. */
+/* This used to test MSDOS, but that is a bad idea
+ since that symbol is in the user namespace. */
+#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__)
+#if 0 /* No need for malloc.h, which pollutes the namespace;
+ instead, just don't use alloca. */
+#include <malloc.h>
+#endif
+#else /* not MSDOS, or __TURBOC__ */
+#if defined(_AIX)
+/* I don't know what this was needed for, but it pollutes the namespace.
+ So I turned it off. rms, 2 May 1997. */
+/* #include <malloc.h> */
+ #pragma alloca
+#define YYSTACK_USE_ALLOCA
+#else /* not MSDOS, or __TURBOC__, or _AIX */
+#if 0
+#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up,
+ and on HPUX 10. Eventually we can turn this on. */
+#define YYSTACK_USE_ALLOCA
+#define alloca __builtin_alloca
+#endif /* __hpux */
+#endif
+#endif /* not _AIX */
+#endif /* not MSDOS, or __TURBOC__ */
+#endif /* not sparc */
+#endif /* not GNU C */
+#endif /* alloca not defined */
+#endif /* YYSTACK_USE_ALLOCA not defined */
+
+#ifdef YYSTACK_USE_ALLOCA
+#define YYSTACK_ALLOC alloca
+#else
+#define YYSTACK_ALLOC malloc
+#endif
+
+/* Note: there must be only one dollar sign in this file.
+ It is replaced by the list of actions, each action
+ as one case of the switch. */
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY -2
+#define YYEOF 0
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrlab1
+/* Like YYERROR except do call yyerror.
+ This remains here temporarily to ease the
+ transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+#define YYFAIL goto yyerrlab
+#define YYRECOVERING() (!!yyerrstatus)
+#define YYBACKUP(token, value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { yychar = (token), yylval = (value); \
+ yychar1 = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { yyerror ("syntax error: cannot back up"); YYERROR; } \
+while (0)
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+#ifndef YYPURE
+#define YYLEX yylex()
+#endif
+
+#ifdef YYPURE
+#ifdef YYLSP_NEEDED
+#ifdef YYLEX_PARAM
+#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM)
+#else
+#define YYLEX yylex(&yylval, &yylloc)
+#endif
+#else /* not YYLSP_NEEDED */
+#ifdef YYLEX_PARAM
+#define YYLEX yylex(&yylval, YYLEX_PARAM)
+#else
+#define YYLEX yylex(&yylval)
+#endif
+#endif /* not YYLSP_NEEDED */
+#endif
+
+/* If nonreentrant, generate the variables here */
+
+#ifndef YYPURE
+
+int yychar; /* the lookahead symbol */
+YYSTYPE yylval; /* the semantic value of the */
+ /* lookahead symbol */
+
+#ifdef YYLSP_NEEDED
+YYLTYPE yylloc; /* location data for the lookahead */
+ /* symbol */
+#endif
+
+int yynerrs; /* number of parse errors so far */
+#endif /* not YYPURE */
+
+#if YYDEBUG != 0
+int yydebug; /* nonzero means print parse trace */
+/* Since this is uninitialized, it does not stop multiple parsers
+ from coexisting. */
+#endif
+
+/* YYINITDEPTH indicates the initial size of the parser's stacks */
+
+#ifndef YYINITDEPTH
+#define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH is the maximum size the stacks can grow to
+ (effective only if the built-in stack extension method is used). */
+
+#if YYMAXDEPTH == 0
+#undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH 10000
+#endif
+
+/* Define __yy_memcpy. Note that the size argument
+ should be passed with type unsigned int, because that is what the non-GCC
+ definitions require. With GCC, __builtin_memcpy takes an arg
+ of type size_t, but it can handle unsigned int. */
+
+#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */
+#define __yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT)
+#else /* not GNU C or C++ */
+#ifndef __cplusplus
+
+/* This is the most reliable way to avoid incompatibilities
+ in available built-in functions on various systems. */
+static void
+__yy_memcpy (to, from, count)
+ char *to;
+ char *from;
+ unsigned int count;
+{
+ register char *f = from;
+ register char *t = to;
+ register int i = count;
+
+ while (i-- > 0)
+ *t++ = *f++;
+}
+
+#else /* __cplusplus */
+
+/* This is the most reliable way to avoid incompatibilities
+ in available built-in functions on various systems. */
+static void
+__yy_memcpy (char *to, char *from, unsigned int count)
+{
+ register char *t = to;
+ register char *f = from;
+ register int i = count;
+
+ while (i-- > 0)
+ *t++ = *f++;
+}
+
+#endif
+#endif
+
+#line 217 "/usr/share/misc/bison.simple"
+
+/* The user can define YYPARSE_PARAM as the name of an argument to be passed
+ into yyparse. The argument should have type void *.
+ It should actually point to an object.
+ Grammar actions can access the variable by casting it
+ to the proper pointer type. */
+
+#ifdef YYPARSE_PARAM
+#ifdef __cplusplus
+#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL
+#else /* not __cplusplus */
+#define YYPARSE_PARAM_ARG YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
+#endif /* not __cplusplus */
+#else /* not YYPARSE_PARAM */
+#define YYPARSE_PARAM_ARG
+#define YYPARSE_PARAM_DECL
+#endif /* not YYPARSE_PARAM */
+
+/* Prevent warning if -Wstrict-prototypes. */
+#ifdef __GNUC__
+#ifdef YYPARSE_PARAM
+int yyparse (void *);
+#else
+int yyparse (void);
+#endif
+#endif
+
+int
+yyparse(YYPARSE_PARAM_ARG)
+ YYPARSE_PARAM_DECL
+{
+ register int yystate;
+ register int yyn;
+ register short *yyssp;
+ register YYSTYPE *yyvsp;
+ int yyerrstatus; /* number of tokens to shift before error messages enabled */
+ int yychar1 = 0; /* lookahead token as an internal (translated) token number */
+
+ short yyssa[YYINITDEPTH]; /* the state stack */
+ YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */
+
+ short *yyss = yyssa; /* refer to the stacks thru separate pointers */
+ YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */
+
+#ifdef YYLSP_NEEDED
+ YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */
+ YYLTYPE *yyls = yylsa;
+ YYLTYPE *yylsp;
+
+#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--)
+#else
+#define YYPOPSTACK (yyvsp--, yyssp--)
+#endif
+
+ int yystacksize = YYINITDEPTH;
+ int yyfree_stacks = 0;
+
+#ifdef YYPURE
+ int yychar;
+ YYSTYPE yylval;
+ int yynerrs;
+#ifdef YYLSP_NEEDED
+ YYLTYPE yylloc;
+#endif
+#endif
+
+ YYSTYPE yyval; /* the variable used to return */
+ /* semantic values from the action */
+ /* routines */
+
+ int yylen;
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Starting parse\n");
+#endif
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss - 1;
+ yyvsp = yyvs;
+#ifdef YYLSP_NEEDED
+ yylsp = yyls;
+#endif
+
+/* Push a new state, which is found in yystate . */
+/* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks. */
+yynewstate:
+
+ *++yyssp = yystate;
+
+ if (yyssp >= yyss + yystacksize - 1)
+ {
+ /* Give user a chance to reallocate the stack */
+ /* Use copies of these so that the &'s don't force the real ones into memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short *yyss1 = yyss;
+#ifdef YYLSP_NEEDED
+ YYLTYPE *yyls1 = yyls;
+#endif
+
+ /* Get the current used size of the three stacks, in elements. */
+ int size = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ /* Each stack pointer address is followed by the size of
+ the data in use in that stack, in bytes. */
+#ifdef YYLSP_NEEDED
+ /* This used to be a conditional around just the two extra args,
+ but that might be undefined if yyoverflow is a macro. */
+ yyoverflow("parser stack overflow",
+ &yyss1, size * sizeof (*yyssp),
+ &yyvs1, size * sizeof (*yyvsp),
+ &yyls1, size * sizeof (*yylsp),
+ &yystacksize);
+#else
+ yyoverflow("parser stack overflow",
+ &yyss1, size * sizeof (*yyssp),
+ &yyvs1, size * sizeof (*yyvsp),
+ &yystacksize);
+#endif
+
+ yyss = yyss1; yyvs = yyvs1;
+#ifdef YYLSP_NEEDED
+ yyls = yyls1;
+#endif
+#else /* no yyoverflow */
+ /* Extend the stack our own way. */
+ if (yystacksize >= YYMAXDEPTH)
+ {
+ yyerror("parser stack overflow");
+ if (yyfree_stacks)
+ {
+ free (yyss);
+ free (yyvs);
+#ifdef YYLSP_NEEDED
+ free (yyls);
+#endif
+ }
+ return 2;
+ }
+ yystacksize *= 2;
+ if (yystacksize > YYMAXDEPTH)
+ yystacksize = YYMAXDEPTH;
+#ifndef YYSTACK_USE_ALLOCA
+ yyfree_stacks = 1;
+#endif
+ yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp));
+ __yy_memcpy ((char *)yyss, (char *)yyss1,
+ size * (unsigned int) sizeof (*yyssp));
+ yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp));
+ __yy_memcpy ((char *)yyvs, (char *)yyvs1,
+ size * (unsigned int) sizeof (*yyvsp));
+#ifdef YYLSP_NEEDED
+ yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp));
+ __yy_memcpy ((char *)yyls, (char *)yyls1,
+ size * (unsigned int) sizeof (*yylsp));
+#endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + size - 1;
+ yyvsp = yyvs + size - 1;
+#ifdef YYLSP_NEEDED
+ yylsp = yyls + size - 1;
+#endif
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Stack size increased to %d\n", yystacksize);
+#endif
+
+ if (yyssp >= yyss + yystacksize - 1)
+ YYABORT;
+ }
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Entering state %d\n", yystate);
+#endif
+
+ goto yybackup;
+ yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYFLAG)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* yychar is either YYEMPTY or YYEOF
+ or a valid token in external form. */
+
+ if (yychar == YYEMPTY)
+ {
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Reading a token: ");
+#endif
+ yychar = YYLEX;
+ }
+
+ /* Convert token to internal form (in yychar1) for indexing tables with */
+
+ if (yychar <= 0) /* This means end of input. */
+ {
+ yychar1 = 0;
+ yychar = YYEOF; /* Don't call YYLEX any more */
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Now at end of input.\n");
+#endif
+ }
+ else
+ {
+ yychar1 = YYTRANSLATE(yychar);
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
+ /* Give the individual parser a way to print the precise meaning
+ of a token, for further debugging info. */
+#ifdef YYPRINT
+ YYPRINT (stderr, yychar, yylval);
+#endif
+ fprintf (stderr, ")\n");
+ }
+#endif
+ }
+
+ yyn += yychar1;
+ if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
+ goto yydefault;
+
+ yyn = yytable[yyn];
+
+ /* yyn is what to do for this token type in this state.
+ Negative => reduce, -yyn is rule number.
+ Positive => shift, yyn is new state.
+ New state is final state => don't bother to shift,
+ just return success.
+ 0, or most negative number => error. */
+
+ if (yyn < 0)
+ {
+ if (yyn == YYFLAG)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+ else if (yyn == 0)
+ goto yyerrlab;
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the lookahead token. */
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
+#endif
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+ *++yylsp = yylloc;
+#endif
+
+ /* count tokens shifted since error; after three, turn off error status. */
+ if (yyerrstatus) yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+/* Do the default action for the current state. */
+yydefault:
+
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+
+/* Do a reduction. yyn is the number of a rule to reduce with. */
+yyreduce:
+ yylen = yyr2[yyn];
+ if (yylen > 0)
+ yyval = yyvsp[1-yylen]; /* implement default value of the action */
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ int i;
+
+ fprintf (stderr, "Reducing via rule %d (line %d), ",
+ yyn, yyrline[yyn]);
+
+ /* Print the symbols being reduced, and their result. */
+ for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
+ fprintf (stderr, "%s ", yytname[yyrhs[i]]);
+ fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
+ }
+#endif
+
+
+ switch (yyn) {
+
+case 1:
+#line 82 "tradcif.y"
+{ expression_value = yyvsp[0].integer.value; ;
+ break;}
+case 3:
+#line 88 "tradcif.y"
+{ yyval.integer = yyvsp[0].integer; ;
+ break;}
+case 4:
+#line 93 "tradcif.y"
+{ yyval.integer.value = - yyvsp[0].integer.value;
+ yyval.integer.unsignedp = yyvsp[0].integer.unsignedp; ;
+ break;}
+case 5:
+#line 96 "tradcif.y"
+{ yyval.integer.value = ! yyvsp[0].integer.value;
+ yyval.integer.unsignedp = 0; ;
+ break;}
+case 6:
+#line 99 "tradcif.y"
+{ yyval.integer = yyvsp[0].integer; ;
+ break;}
+case 7:
+#line 101 "tradcif.y"
+{ yyval.integer.value = ~ yyvsp[0].integer.value;
+ yyval.integer.unsignedp = yyvsp[0].integer.unsignedp; ;
+ break;}
+case 8:
+#line 104 "tradcif.y"
+{ yyval.integer = yyvsp[-1].integer; ;
+ break;}
+case 9:
+#line 109 "tradcif.y"
+{ yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp;
+ if (yyval.integer.unsignedp)
+ yyval.integer.value = (unsigned) yyvsp[-2].integer.value * yyvsp[0].integer.value;
+ else
+ yyval.integer.value = yyvsp[-2].integer.value * yyvsp[0].integer.value; ;
+ break;}
+case 10:
+#line 115 "tradcif.y"
+{ if (yyvsp[0].integer.value == 0)
+ {
+ error ("division by zero in #if");
+ yyvsp[0].integer.value = 1;
+ }
+ yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp;
+ if (yyval.integer.unsignedp)
+ yyval.integer.value = (unsigned) yyvsp[-2].integer.value / yyvsp[0].integer.value;
+ else
+ yyval.integer.value = yyvsp[-2].integer.value / yyvsp[0].integer.value; ;
+ break;}
+case 11:
+#line 126 "tradcif.y"
+{ if (yyvsp[0].integer.value == 0)
+ {
+ error ("division by zero in #if");
+ yyvsp[0].integer.value = 1;
+ }
+ yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp;
+ if (yyval.integer.unsignedp)
+ yyval.integer.value = (unsigned) yyvsp[-2].integer.value % yyvsp[0].integer.value;
+ else
+ yyval.integer.value = yyvsp[-2].integer.value % yyvsp[0].integer.value; ;
+ break;}
+case 12:
+#line 137 "tradcif.y"
+{ yyval.integer.value = yyvsp[-2].integer.value + yyvsp[0].integer.value;
+ yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp; ;
+ break;}
+case 13:
+#line 140 "tradcif.y"
+{ yyval.integer.value = yyvsp[-2].integer.value - yyvsp[0].integer.value;
+ yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp; ;
+ break;}
+case 14:
+#line 143 "tradcif.y"
+{ yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp;
+ if (yyval.integer.unsignedp)
+ yyval.integer.value = (unsigned) yyvsp[-2].integer.value << yyvsp[0].integer.value;
+ else
+ yyval.integer.value = yyvsp[-2].integer.value << yyvsp[0].integer.value; ;
+ break;}
+case 15:
+#line 149 "tradcif.y"
+{ yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp;
+ if (yyval.integer.unsignedp)
+ yyval.integer.value = (unsigned) yyvsp[-2].integer.value >> yyvsp[0].integer.value;
+ else
+ yyval.integer.value = yyvsp[-2].integer.value >> yyvsp[0].integer.value; ;
+ break;}
+case 16:
+#line 155 "tradcif.y"
+{ yyval.integer.value = (yyvsp[-2].integer.value == yyvsp[0].integer.value);
+ yyval.integer.unsignedp = 0; ;
+ break;}
+case 17:
+#line 158 "tradcif.y"
+{ yyval.integer.value = (yyvsp[-2].integer.value != yyvsp[0].integer.value);
+ yyval.integer.unsignedp = 0; ;
+ break;}
+case 18:
+#line 161 "tradcif.y"
+{ yyval.integer.unsignedp = 0;
+ if (yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp)
+ yyval.integer.value =
+ (unsigned) yyvsp[-2].integer.value <= (unsigned) yyvsp[0].integer.value;
+ else
+ yyval.integer.value = yyvsp[-2].integer.value <= yyvsp[0].integer.value; ;
+ break;}
+case 19:
+#line 168 "tradcif.y"
+{ yyval.integer.unsignedp = 0;
+ if (yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp)
+ yyval.integer.value =
+ (unsigned) yyvsp[-2].integer.value >= (unsigned) yyvsp[0].integer.value;
+ else
+ yyval.integer.value = yyvsp[-2].integer.value >= yyvsp[0].integer.value; ;
+ break;}
+case 20:
+#line 175 "tradcif.y"
+{ yyval.integer.unsignedp = 0;
+ if (yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp)
+ yyval.integer.value =
+ (unsigned) yyvsp[-2].integer.value < (unsigned) yyvsp[0].integer.value;
+ else
+ yyval.integer.value = yyvsp[-2].integer.value < yyvsp[0].integer.value; ;
+ break;}
+case 21:
+#line 182 "tradcif.y"
+{ yyval.integer.unsignedp = 0;
+ if (yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp)
+ yyval.integer.value =
+ (unsigned) yyvsp[-2].integer.value > (unsigned) yyvsp[0].integer.value;
+ else
+ yyval.integer.value = yyvsp[-2].integer.value > yyvsp[0].integer.value; ;
+ break;}
+case 22:
+#line 189 "tradcif.y"
+{ yyval.integer.value = yyvsp[-2].integer.value & yyvsp[0].integer.value;
+ yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp; ;
+ break;}
+case 23:
+#line 192 "tradcif.y"
+{ yyval.integer.value = yyvsp[-2].integer.value ^ yyvsp[0].integer.value;
+ yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp; ;
+ break;}
+case 24:
+#line 195 "tradcif.y"
+{ yyval.integer.value = yyvsp[-2].integer.value | yyvsp[0].integer.value;
+ yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp; ;
+ break;}
+case 25:
+#line 198 "tradcif.y"
+{ yyval.integer.value = (yyvsp[-2].integer.value && yyvsp[0].integer.value);
+ yyval.integer.unsignedp = 0; ;
+ break;}
+case 26:
+#line 201 "tradcif.y"
+{ yyval.integer.value = (yyvsp[-2].integer.value || yyvsp[0].integer.value);
+ yyval.integer.unsignedp = 0; ;
+ break;}
+case 27:
+#line 204 "tradcif.y"
+{ yyval.integer.value = yyvsp[-4].integer.value ? yyvsp[-2].integer.value : yyvsp[0].integer.value;
+ yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp; ;
+ break;}
+case 28:
+#line 207 "tradcif.y"
+{ yyval.integer = yylval.integer; ;
+ break;}
+case 29:
+#line 209 "tradcif.y"
+{ yyval.integer = yylval.integer; ;
+ break;}
+case 30:
+#line 211 "tradcif.y"
+{ yyval.integer.value = 0;
+ yyval.integer.unsignedp = 0; ;
+ break;}
+}
+ /* the action file gets copied in in place of this dollarsign */
+#line 543 "/usr/share/misc/bison.simple"
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+#ifdef YYLSP_NEEDED
+ yylsp -= yylen;
+#endif
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ short *ssp1 = yyss - 1;
+ fprintf (stderr, "state stack now");
+ while (ssp1 != yyssp)
+ fprintf (stderr, " %d", *++ssp1);
+ fprintf (stderr, "\n");
+ }
+#endif
+
+ *++yyvsp = yyval;
+
+#ifdef YYLSP_NEEDED
+ yylsp++;
+ if (yylen == 0)
+ {
+ yylsp->first_line = yylloc.first_line;
+ yylsp->first_column = yylloc.first_column;
+ yylsp->last_line = (yylsp-1)->last_line;
+ yylsp->last_column = (yylsp-1)->last_column;
+ yylsp->text = 0;
+ }
+ else
+ {
+ yylsp->last_line = (yylsp+yylen-1)->last_line;
+ yylsp->last_column = (yylsp+yylen-1)->last_column;
+ }
+#endif
+
+ /* Now "shift" the result of the reduction.
+ Determine what state that goes to,
+ based on the state we popped back to
+ and the rule number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
+ if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTBASE];
+
+ goto yynewstate;
+
+yyerrlab: /* here on detecting error */
+
+ if (! yyerrstatus)
+ /* If not already recovering from an error, report this error. */
+ {
+ ++yynerrs;
+
+#ifdef YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (yyn > YYFLAG && yyn < YYLAST)
+ {
+ int size = 0;
+ char *msg;
+ int x, count;
+
+ count = 0;
+ /* Start X at -yyn if nec to avoid negative indexes in yycheck. */
+ for (x = (yyn < 0 ? -yyn : 0);
+ x < (sizeof(yytname) / sizeof(char *)); x++)
+ if (yycheck[x + yyn] == x)
+ size += strlen(yytname[x]) + 15, count++;
+ msg = (char *) malloc(size + 15);
+ if (msg != 0)
+ {
+ strcpy(msg, "parse error");
+
+ if (count < 5)
+ {
+ count = 0;
+ for (x = (yyn < 0 ? -yyn : 0);
+ x < (sizeof(yytname) / sizeof(char *)); x++)
+ if (yycheck[x + yyn] == x)
+ {
+ strcat(msg, count == 0 ? ", expecting `" : " or `");
+ strcat(msg, yytname[x]);
+ strcat(msg, "'");
+ count++;
+ }
+ }
+ yyerror(msg);
+ free(msg);
+ }
+ else
+ yyerror ("parse error; also virtual memory exceeded");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror("parse error");
+ }
+
+ goto yyerrlab1;
+yyerrlab1: /* here on error raised explicitly by an action */
+
+ if (yyerrstatus == 3)
+ {
+ /* if just tried and failed to reuse lookahead token after an error, discard it. */
+
+ /* return failure if at end of input */
+ if (yychar == YYEOF)
+ YYABORT;
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
+#endif
+
+ yychar = YYEMPTY;
+ }
+
+ /* Else will try to reuse lookahead token
+ after shifting the error token. */
+
+ yyerrstatus = 3; /* Each real token shifted decrements this */
+
+ goto yyerrhandle;
+
+yyerrdefault: /* current state does not do anything special for the error token. */
+
+#if 0
+ /* This is wrong; only states that explicitly want error tokens
+ should shift them. */
+ yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/
+ if (yyn) goto yydefault;
+#endif
+
+yyerrpop: /* pop the current state because it cannot handle the error token */
+
+ if (yyssp == yyss) YYABORT;
+ yyvsp--;
+ yystate = *--yyssp;
+#ifdef YYLSP_NEEDED
+ yylsp--;
+#endif
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ short *ssp1 = yyss - 1;
+ fprintf (stderr, "Error: state stack now");
+ while (ssp1 != yyssp)
+ fprintf (stderr, " %d", *++ssp1);
+ fprintf (stderr, "\n");
+ }
+#endif
+
+yyerrhandle:
+
+ yyn = yypact[yystate];
+ if (yyn == YYFLAG)
+ goto yyerrdefault;
+
+ yyn += YYTERROR;
+ if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
+ goto yyerrdefault;
+
+ yyn = yytable[yyn];
+ if (yyn < 0)
+ {
+ if (yyn == YYFLAG)
+ goto yyerrpop;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+ else if (yyn == 0)
+ goto yyerrpop;
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Shifting error token, ");
+#endif
+
+ *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+ *++yylsp = yylloc;
+#endif
+
+ yystate = yyn;
+ goto yynewstate;
+
+ yyacceptlab:
+ /* YYACCEPT comes here. */
+ if (yyfree_stacks)
+ {
+ free (yyss);
+ free (yyvs);
+#ifdef YYLSP_NEEDED
+ free (yyls);
+#endif
+ }
+ return 0;
+
+ yyabortlab:
+ /* YYABORT comes here. */
+ if (yyfree_stacks)
+ {
+ free (yyss);
+ free (yyvs);
+#ifdef YYLSP_NEEDED
+ free (yyls);
+#endif
+ }
+ return 1;
+}
+#line 214 "tradcif.y"
+
+
+/* During parsing of a C expression, the pointer to the next character
+ is in this variable. */
+
+static char *lexptr;
+
+/* Take care of parsing a number (anything that starts with a digit).
+ Set yylval and return the token type; update lexptr.
+ LEN is the number of characters in it. */
+
+/* maybe needs to actually deal with floating point numbers */
+
+int
+parse_number (olen)
+ int olen;
+{
+ register char *p = lexptr;
+ register long n = 0;
+ register int c;
+ register int base = 10;
+ register int len = olen;
+
+ for (c = 0; c < len; c++)
+ if (p[c] == '.') {
+ /* It's a float since it contains a point. */
+ yyerror ("floating point numbers not allowed in #if expressions");
+ return ERROR;
+ }
+
+ yylval.integer.unsignedp = 0;
+
+ if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) {
+ p += 2;
+ base = 16;
+ len -= 2;
+ }
+ else if (*p == '0')
+ base = 8;
+
+ while (len > 0) {
+ c = *p++;
+ len--;
+ if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
+
+ if (c >= '0' && c <= '9') {
+ n *= base;
+ n += c - '0';
+ } else if (base == 16 && c >= 'a' && c <= 'f') {
+ n *= base;
+ n += c - 'a' + 10;
+ } else {
+ /* `l' means long, and `u' means unsigned. */
+ while (1) {
+ if (c == 'l' || c == 'L')
+ ;
+ else if (c == 'u' || c == 'U')
+ yylval.integer.unsignedp = 1;
+ else
+ break;
+
+ if (len == 0)
+ break;
+ c = *p++;
+ len--;
+ }
+ /* Don't look for any more digits after the suffixes. */
+ break;
+ }
+ }
+
+ if (len != 0) {
+ yyerror ("Invalid number in #if expression");
+ return ERROR;
+ }
+
+ /* If too big to be signed, consider it unsigned. */
+ if (n < 0)
+ yylval.integer.unsignedp = 1;
+
+ lexptr = p;
+ yylval.integer.value = n;
+ return INT;
+}
+
+struct token {
+ const char *operator;
+ int token;
+};
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+static struct token tokentab2[] = {
+ {"&&", AND},
+ {"||", OR},
+ {"<<", LSH},
+ {">>", RSH},
+ {"==", EQUAL},
+ {"!=", NOTEQUAL},
+ {"<=", LEQ},
+ {">=", GEQ},
+ {NULL, ERROR}
+};
+
+/* Read one token, getting characters through lexptr. */
+
+int
+yylex ()
+{
+ register int c;
+ register int namelen;
+ register char *tokstart;
+ register struct token *toktab;
+
+ retry:
+
+ tokstart = lexptr;
+ c = *tokstart;
+ /* See if it is a special token of length 2. */
+ for (toktab = tokentab2; toktab->operator != NULL; toktab++)
+ if (c == *toktab->operator && tokstart[1] == toktab->operator[1]) {
+ lexptr += 2;
+ return toktab->token;
+ }
+
+ switch (c) {
+ case 0:
+ return 0;
+
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ lexptr++;
+ goto retry;
+
+ case '\'':
+ lexptr++;
+ c = *lexptr++;
+ if (c == '\\')
+ c = parse_escape (&lexptr);
+
+ /* Sign-extend the constant if chars are signed on target machine. */
+ {
+ if (lookup ((const unsigned char *)"__CHAR_UNSIGNED__",
+ sizeof ("__CHAR_UNSIGNED__")-1, -1)
+ || ((c >> (CHAR_TYPE_SIZE - 1)) & 1) == 0)
+ yylval.integer.value = c & ((1 << CHAR_TYPE_SIZE) - 1);
+ else
+ yylval.integer.value = c | ~((1 << CHAR_TYPE_SIZE) - 1);
+ }
+
+ yylval.integer.unsignedp = 0;
+ c = *lexptr++;
+ if (c != '\'') {
+ yyerror ("Invalid character constant in #if");
+ return ERROR;
+ }
+
+ return CHAR;
+
+ /* some of these chars are invalid in constant expressions;
+ maybe do something about them later */
+ case '/':
+ case '+':
+ case '-':
+ case '*':
+ case '%':
+ case '|':
+ case '&':
+ case '^':
+ case '~':
+ case '!':
+ case '@':
+ case '<':
+ case '>':
+ case '(':
+ case ')':
+ case '[':
+ case ']':
+ case '.':
+ case '?':
+ case ':':
+ case '=':
+ case '{':
+ case '}':
+ case ',':
+ lexptr++;
+ return c;
+
+ case '"':
+ yyerror ("double quoted strings not allowed in #if expressions");
+ return ERROR;
+ }
+ if (c >= '0' && c <= '9') {
+ /* It's a number */
+ for (namelen = 0;
+ c = tokstart[namelen], is_idchar[c] || c == '.';
+ namelen++)
+ ;
+ return parse_number (namelen);
+ }
+
+ if (!is_idstart[c]) {
+ yyerror ("Invalid token in expression");
+ return ERROR;
+ }
+
+ /* It is a name. See how long it is. */
+
+ for (namelen = 0;
+ is_idchar[(int)(unsigned char)tokstart[namelen]];
+ namelen++)
+ ;
+
+ lexptr += namelen;
+ return NAME;
+}
+
+
+/* Parse a C escape sequence. STRING_PTR points to a variable
+ containing a pointer to the string to parse. That pointer
+ is updated past the characters we use. The value of the
+ escape sequence is returned.
+
+ A negative value means the sequence \ newline was seen,
+ which is supposed to be equivalent to nothing at all.
+
+ If \ is followed by a null character, we return a negative
+ value and leave the string pointer pointing at the null character.
+
+ If \ is followed by 000, we return 0 and leave the string pointer
+ after the zeros. A value of 0 does not mean end of string. */
+
+int
+parse_escape (string_ptr)
+ char **string_ptr;
+{
+ register int c = *(*string_ptr)++;
+ switch (c)
+ {
+ case 'a':
+ return TARGET_BELL;
+ case 'b':
+ return TARGET_BS;
+ case 'e':
+ return 033;
+ case 'f':
+ return TARGET_FF;
+ case 'n':
+ return TARGET_NEWLINE;
+ case 'r':
+ return TARGET_CR;
+ case 't':
+ return TARGET_TAB;
+ case 'v':
+ return TARGET_VT;
+ case '\n':
+ return -2;
+ case 0:
+ (*string_ptr)--;
+ return 0;
+ case '^':
+ c = *(*string_ptr)++;
+ if (c == '\\')
+ c = parse_escape (string_ptr);
+ if (c == '?')
+ return 0177;
+ return (c & 0200) | (c & 037);
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ register int i = c - '0';
+ register int count = 0;
+ while (++count < 3)
+ {
+ c = *(*string_ptr)++;
+ if (c >= '0' && c <= '7')
+ i = (i << 3) + c - '0';
+ else
+ {
+ (*string_ptr)--;
+ break;
+ }
+ }
+ if ((i & ~((1 << CHAR_TYPE_SIZE) - 1)) != 0)
+ {
+ i &= (1 << CHAR_TYPE_SIZE) - 1;
+ warning ("octal character constant does not fit in a byte");
+ }
+ return i;
+ }
+ case 'x':
+ {
+ register int i = 0;
+ for (;;)
+ {
+ c = *(*string_ptr)++;
+ if (c >= '0' && c <= '9')
+ i = (i << 4) + c - '0';
+ else if (c >= 'a' && c <= 'f')
+ i = (i << 4) + c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ i = (i << 4) + c - 'A' + 10;
+ else
+ {
+ (*string_ptr)--;
+ break;
+ }
+ }
+ if ((i & ~((1 << BITS_PER_UNIT) - 1)) != 0)
+ {
+ i &= (1 << BITS_PER_UNIT) - 1;
+ warning ("hex character constant does not fit in a byte");
+ }
+ return i;
+ }
+ default:
+ return c;
+ }
+}
+
+void
+yyerror (s)
+ const char *s;
+{
+ error (s);
+ longjmp (parse_return_error, 1);
+}
+
+/* This page contains the entry point to this file. */
+
+/* Parse STRING as an expression, and complain if this fails
+ to use up all of the contents of STRING. */
+/* We do not support C comments. They should be removed before
+ this function is called. */
+
+int
+parse_c_expression (string)
+ char *string;
+{
+ lexptr = string;
+
+ if (lexptr == 0 || *lexptr == 0) {
+ error ("empty #if expression");
+ return 0; /* don't include the #if group */
+ }
+
+ /* if there is some sort of scanning error, just return 0 and assume
+ the parsing routine has printed an error message somewhere.
+ there is surely a better thing to do than this. */
+ if (setjmp (parse_return_error))
+ return 0;
+
+ if (yyparse ())
+ return 0; /* actually this is never reached
+ the way things stand. */
+ if (*lexptr)
+ error ("Junk after end of expression.");
+
+ return expression_value; /* set by yyparse () */
+}
diff --git a/gcc/tradcif.y b/gcc/tradcif.y
new file mode 100644
index 00000000000..4a70bed89a3
--- /dev/null
+++ b/gcc/tradcif.y
@@ -0,0 +1,584 @@
+/* Parse C expressions for CCCP.
+ Copyright (C) 1987 Free Software Foundation.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 1, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them. Help stamp out software-hoarding!
+
+ Adapted from expread.y of GDB by Paul Rubin, July 1986.
+
+/* Parse a C expression from text in a string */
+
+%{
+#include "config.h"
+#include "system.h"
+#include <setjmp.h>
+
+ int yylex PARAMS ((void));
+ void yyerror PARAMS ((const char *msgid));
+ extern void error PARAMS ((const char *msgid, ...));
+ extern void warning PARAMS ((const char *msgid, ...));
+ extern struct hashnode *lookup PARAMS ((const unsigned char *, int, int));
+
+ int parse_number PARAMS ((int));
+ int parse_escape PARAMS ((char **));
+ int parse_c_expression PARAMS ((char *));
+
+ int expression_value;
+ static jmp_buf parse_return_error;
+
+ /* some external tables of character types */
+ extern unsigned char is_idstart[], is_idchar[];
+
+#ifndef CHAR_TYPE_SIZE
+#define CHAR_TYPE_SIZE BITS_PER_UNIT
+#endif
+%}
+
+%union {
+ struct constant {long value; int unsignedp;} integer;
+ int voidval;
+ char *sval;
+}
+
+%type <integer> exp exp1 start
+%token <integer> INT CHAR
+%token <sval> NAME
+%token <integer> ERROR
+
+%right '?' ':'
+%left ','
+%left OR
+%left AND
+%left '|'
+%left '^'
+%left '&'
+%left EQUAL NOTEQUAL
+%left '<' '>' LEQ GEQ
+%left LSH RSH
+%left '+' '-'
+%left '*' '/' '%'
+%right UNARY
+
+/* %expect 40 */
+
+%%
+
+start : exp1
+ { expression_value = $1.value; }
+ ;
+
+/* Expressions, including the comma operator. */
+exp1 : exp
+ | exp1 ',' exp
+ { $$ = $3; }
+ ;
+
+/* Expressions, not including the comma operator. */
+exp : '-' exp %prec UNARY
+ { $$.value = - $2.value;
+ $$.unsignedp = $2.unsignedp; }
+ | '!' exp %prec UNARY
+ { $$.value = ! $2.value;
+ $$.unsignedp = 0; }
+ | '+' exp %prec UNARY
+ { $$ = $2; }
+ | '~' exp %prec UNARY
+ { $$.value = ~ $2.value;
+ $$.unsignedp = $2.unsignedp; }
+ | '(' exp1 ')'
+ { $$ = $2; }
+ ;
+
+/* Binary operators in order of decreasing precedence. */
+exp : exp '*' exp
+ { $$.unsignedp = $1.unsignedp || $3.unsignedp;
+ if ($$.unsignedp)
+ $$.value = (unsigned) $1.value * $3.value;
+ else
+ $$.value = $1.value * $3.value; }
+ | exp '/' exp
+ { if ($3.value == 0)
+ {
+ error ("division by zero in #if");
+ $3.value = 1;
+ }
+ $$.unsignedp = $1.unsignedp || $3.unsignedp;
+ if ($$.unsignedp)
+ $$.value = (unsigned) $1.value / $3.value;
+ else
+ $$.value = $1.value / $3.value; }
+ | exp '%' exp
+ { if ($3.value == 0)
+ {
+ error ("division by zero in #if");
+ $3.value = 1;
+ }
+ $$.unsignedp = $1.unsignedp || $3.unsignedp;
+ if ($$.unsignedp)
+ $$.value = (unsigned) $1.value % $3.value;
+ else
+ $$.value = $1.value % $3.value; }
+ | exp '+' exp
+ { $$.value = $1.value + $3.value;
+ $$.unsignedp = $1.unsignedp || $3.unsignedp; }
+ | exp '-' exp
+ { $$.value = $1.value - $3.value;
+ $$.unsignedp = $1.unsignedp || $3.unsignedp; }
+ | exp LSH exp
+ { $$.unsignedp = $1.unsignedp;
+ if ($$.unsignedp)
+ $$.value = (unsigned) $1.value << $3.value;
+ else
+ $$.value = $1.value << $3.value; }
+ | exp RSH exp
+ { $$.unsignedp = $1.unsignedp;
+ if ($$.unsignedp)
+ $$.value = (unsigned) $1.value >> $3.value;
+ else
+ $$.value = $1.value >> $3.value; }
+ | exp EQUAL exp
+ { $$.value = ($1.value == $3.value);
+ $$.unsignedp = 0; }
+ | exp NOTEQUAL exp
+ { $$.value = ($1.value != $3.value);
+ $$.unsignedp = 0; }
+ | exp LEQ exp
+ { $$.unsignedp = 0;
+ if ($1.unsignedp || $3.unsignedp)
+ $$.value =
+ (unsigned) $1.value <= (unsigned) $3.value;
+ else
+ $$.value = $1.value <= $3.value; }
+ | exp GEQ exp
+ { $$.unsignedp = 0;
+ if ($1.unsignedp || $3.unsignedp)
+ $$.value =
+ (unsigned) $1.value >= (unsigned) $3.value;
+ else
+ $$.value = $1.value >= $3.value; }
+ | exp '<' exp
+ { $$.unsignedp = 0;
+ if ($1.unsignedp || $3.unsignedp)
+ $$.value =
+ (unsigned) $1.value < (unsigned) $3.value;
+ else
+ $$.value = $1.value < $3.value; }
+ | exp '>' exp
+ { $$.unsignedp = 0;
+ if ($1.unsignedp || $3.unsignedp)
+ $$.value =
+ (unsigned) $1.value > (unsigned) $3.value;
+ else
+ $$.value = $1.value > $3.value; }
+ | exp '&' exp
+ { $$.value = $1.value & $3.value;
+ $$.unsignedp = $1.unsignedp || $3.unsignedp; }
+ | exp '^' exp
+ { $$.value = $1.value ^ $3.value;
+ $$.unsignedp = $1.unsignedp || $3.unsignedp; }
+ | exp '|' exp
+ { $$.value = $1.value | $3.value;
+ $$.unsignedp = $1.unsignedp || $3.unsignedp; }
+ | exp AND exp
+ { $$.value = ($1.value && $3.value);
+ $$.unsignedp = 0; }
+ | exp OR exp
+ { $$.value = ($1.value || $3.value);
+ $$.unsignedp = 0; }
+ | exp '?' exp ':' exp
+ { $$.value = $1.value ? $3.value : $5.value;
+ $$.unsignedp = $3.unsignedp || $5.unsignedp; }
+ | INT
+ { $$ = yylval.integer; }
+ | CHAR
+ { $$ = yylval.integer; }
+ | NAME
+ { $$.value = 0;
+ $$.unsignedp = 0; }
+ ;
+%%
+
+/* During parsing of a C expression, the pointer to the next character
+ is in this variable. */
+
+static char *lexptr;
+
+/* Take care of parsing a number (anything that starts with a digit).
+ Set yylval and return the token type; update lexptr.
+ LEN is the number of characters in it. */
+
+/* maybe needs to actually deal with floating point numbers */
+
+int
+parse_number (olen)
+ int olen;
+{
+ register char *p = lexptr;
+ register long n = 0;
+ register int c;
+ register int base = 10;
+ register int len = olen;
+
+ for (c = 0; c < len; c++)
+ if (p[c] == '.') {
+ /* It's a float since it contains a point. */
+ yyerror ("floating point numbers not allowed in #if expressions");
+ return ERROR;
+ }
+
+ yylval.integer.unsignedp = 0;
+
+ if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) {
+ p += 2;
+ base = 16;
+ len -= 2;
+ }
+ else if (*p == '0')
+ base = 8;
+
+ while (len > 0) {
+ c = *p++;
+ len--;
+ if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
+
+ if (c >= '0' && c <= '9') {
+ n *= base;
+ n += c - '0';
+ } else if (base == 16 && c >= 'a' && c <= 'f') {
+ n *= base;
+ n += c - 'a' + 10;
+ } else {
+ /* `l' means long, and `u' means unsigned. */
+ while (1) {
+ if (c == 'l' || c == 'L')
+ ;
+ else if (c == 'u' || c == 'U')
+ yylval.integer.unsignedp = 1;
+ else
+ break;
+
+ if (len == 0)
+ break;
+ c = *p++;
+ len--;
+ }
+ /* Don't look for any more digits after the suffixes. */
+ break;
+ }
+ }
+
+ if (len != 0) {
+ yyerror ("Invalid number in #if expression");
+ return ERROR;
+ }
+
+ /* If too big to be signed, consider it unsigned. */
+ if (n < 0)
+ yylval.integer.unsignedp = 1;
+
+ lexptr = p;
+ yylval.integer.value = n;
+ return INT;
+}
+
+struct token {
+ const char *operator;
+ int token;
+};
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+static struct token tokentab2[] = {
+ {"&&", AND},
+ {"||", OR},
+ {"<<", LSH},
+ {">>", RSH},
+ {"==", EQUAL},
+ {"!=", NOTEQUAL},
+ {"<=", LEQ},
+ {">=", GEQ},
+ {NULL, ERROR}
+};
+
+/* Read one token, getting characters through lexptr. */
+
+int
+yylex ()
+{
+ register int c;
+ register int namelen;
+ register char *tokstart;
+ register struct token *toktab;
+
+ retry:
+
+ tokstart = lexptr;
+ c = *tokstart;
+ /* See if it is a special token of length 2. */
+ for (toktab = tokentab2; toktab->operator != NULL; toktab++)
+ if (c == *toktab->operator && tokstart[1] == toktab->operator[1]) {
+ lexptr += 2;
+ return toktab->token;
+ }
+
+ switch (c) {
+ case 0:
+ return 0;
+
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ lexptr++;
+ goto retry;
+
+ case '\'':
+ lexptr++;
+ c = *lexptr++;
+ if (c == '\\')
+ c = parse_escape (&lexptr);
+
+ /* Sign-extend the constant if chars are signed on target machine. */
+ {
+ if (lookup ((const unsigned char *)"__CHAR_UNSIGNED__",
+ sizeof ("__CHAR_UNSIGNED__")-1, -1)
+ || ((c >> (CHAR_TYPE_SIZE - 1)) & 1) == 0)
+ yylval.integer.value = c & ((1 << CHAR_TYPE_SIZE) - 1);
+ else
+ yylval.integer.value = c | ~((1 << CHAR_TYPE_SIZE) - 1);
+ }
+
+ yylval.integer.unsignedp = 0;
+ c = *lexptr++;
+ if (c != '\'') {
+ yyerror ("Invalid character constant in #if");
+ return ERROR;
+ }
+
+ return CHAR;
+
+ /* some of these chars are invalid in constant expressions;
+ maybe do something about them later */
+ case '/':
+ case '+':
+ case '-':
+ case '*':
+ case '%':
+ case '|':
+ case '&':
+ case '^':
+ case '~':
+ case '!':
+ case '@':
+ case '<':
+ case '>':
+ case '(':
+ case ')':
+ case '[':
+ case ']':
+ case '.':
+ case '?':
+ case ':':
+ case '=':
+ case '{':
+ case '}':
+ case ',':
+ lexptr++;
+ return c;
+
+ case '"':
+ yyerror ("double quoted strings not allowed in #if expressions");
+ return ERROR;
+ }
+ if (c >= '0' && c <= '9') {
+ /* It's a number */
+ for (namelen = 0;
+ c = tokstart[namelen], is_idchar[c] || c == '.';
+ namelen++)
+ ;
+ return parse_number (namelen);
+ }
+
+ if (!is_idstart[c]) {
+ yyerror ("Invalid token in expression");
+ return ERROR;
+ }
+
+ /* It is a name. See how long it is. */
+
+ for (namelen = 0;
+ is_idchar[(int)(unsigned char)tokstart[namelen]];
+ namelen++)
+ ;
+
+ lexptr += namelen;
+ return NAME;
+}
+
+
+/* Parse a C escape sequence. STRING_PTR points to a variable
+ containing a pointer to the string to parse. That pointer
+ is updated past the characters we use. The value of the
+ escape sequence is returned.
+
+ A negative value means the sequence \ newline was seen,
+ which is supposed to be equivalent to nothing at all.
+
+ If \ is followed by a null character, we return a negative
+ value and leave the string pointer pointing at the null character.
+
+ If \ is followed by 000, we return 0 and leave the string pointer
+ after the zeros. A value of 0 does not mean end of string. */
+
+int
+parse_escape (string_ptr)
+ char **string_ptr;
+{
+ register int c = *(*string_ptr)++;
+ switch (c)
+ {
+ case 'a':
+ return TARGET_BELL;
+ case 'b':
+ return TARGET_BS;
+ case 'e':
+ return 033;
+ case 'f':
+ return TARGET_FF;
+ case 'n':
+ return TARGET_NEWLINE;
+ case 'r':
+ return TARGET_CR;
+ case 't':
+ return TARGET_TAB;
+ case 'v':
+ return TARGET_VT;
+ case '\n':
+ return -2;
+ case 0:
+ (*string_ptr)--;
+ return 0;
+ case '^':
+ c = *(*string_ptr)++;
+ if (c == '\\')
+ c = parse_escape (string_ptr);
+ if (c == '?')
+ return 0177;
+ return (c & 0200) | (c & 037);
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ register int i = c - '0';
+ register int count = 0;
+ while (++count < 3)
+ {
+ c = *(*string_ptr)++;
+ if (c >= '0' && c <= '7')
+ i = (i << 3) + c - '0';
+ else
+ {
+ (*string_ptr)--;
+ break;
+ }
+ }
+ if ((i & ~((1 << CHAR_TYPE_SIZE) - 1)) != 0)
+ {
+ i &= (1 << CHAR_TYPE_SIZE) - 1;
+ warning ("octal character constant does not fit in a byte");
+ }
+ return i;
+ }
+ case 'x':
+ {
+ register int i = 0;
+ for (;;)
+ {
+ c = *(*string_ptr)++;
+ if (c >= '0' && c <= '9')
+ i = (i << 4) + c - '0';
+ else if (c >= 'a' && c <= 'f')
+ i = (i << 4) + c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ i = (i << 4) + c - 'A' + 10;
+ else
+ {
+ (*string_ptr)--;
+ break;
+ }
+ }
+ if ((i & ~((1 << BITS_PER_UNIT) - 1)) != 0)
+ {
+ i &= (1 << BITS_PER_UNIT) - 1;
+ warning ("hex character constant does not fit in a byte");
+ }
+ return i;
+ }
+ default:
+ return c;
+ }
+}
+
+void
+yyerror (s)
+ const char *s;
+{
+ error (s);
+ longjmp (parse_return_error, 1);
+}
+
+/* This page contains the entry point to this file. */
+
+/* Parse STRING as an expression, and complain if this fails
+ to use up all of the contents of STRING. */
+/* We do not support C comments. They should be removed before
+ this function is called. */
+
+int
+parse_c_expression (string)
+ char *string;
+{
+ lexptr = string;
+
+ if (lexptr == 0 || *lexptr == 0) {
+ error ("empty #if expression");
+ return 0; /* don't include the #if group */
+ }
+
+ /* if there is some sort of scanning error, just return 0 and assume
+ the parsing routine has printed an error message somewhere.
+ there is surely a better thing to do than this. */
+ if (setjmp (parse_return_error))
+ return 0;
+
+ if (yyparse ())
+ return 0; /* actually this is never reached
+ the way things stand. */
+ if (*lexptr)
+ error ("Junk after end of expression.");
+
+ return expression_value; /* set by yyparse () */
+}
diff --git a/gcc/tradcpp.c b/gcc/tradcpp.c
new file mode 100644
index 00000000000..ec42b63db99
--- /dev/null
+++ b/gcc/tradcpp.c
@@ -0,0 +1,4831 @@
+/* C Compatible Compiler Preprocessor (CCCP)
+Copyright (C) 1986, 1987, 1989, 2000 Free Software Foundation, Inc.
+ Written by Paul Rubin, June 1986
+ Adapted to ANSI C, Richard Stallman, Jan 1987
+ Dusted off, polished, and adapted for use as traditional
+ preprocessor only, Zack Weinberg, Jul 2000
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 1, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them. Help stamp out software-hoarding! */
+
+#include "config.h"
+#include "system.h"
+#include "version.h"
+#include "cppdefault.h"
+
+#include <signal.h>
+
+typedef unsigned char U_CHAR;
+
+/* Name under which this program was invoked. */
+
+char *progname;
+
+/* Current maximum length of directory names in the search path
+ for include files. (Altered as we get more of them.) */
+
+size_t max_include_len;
+
+/* Nonzero means copy comments into the output file. */
+
+int put_out_comments = 0;
+
+/* Nonzero means print the names of included files rather than
+ the preprocessed output. 1 means just the #include "...",
+ 2 means #include <...> as well. */
+
+int print_deps = 0;
+
+/* Nonzero means don't output line number information. */
+
+int no_line_commands;
+
+/* Nonzero means inhibit output of the preprocessed text
+ and instead output the definitions of all user-defined macros
+ in a form suitable for use as input to cccp. */
+
+int dump_macros;
+
+/* Nonzero means don't print warning messages. -w. */
+
+int inhibit_warnings = 0;
+
+/* Nonzero means warn if slash-star appears in a comment. */
+
+int warn_comments;
+
+/* Nonzero causes output not to be done,
+ but directives such as #define that have side effects
+ are still obeyed. */
+
+int no_output;
+
+/* Value of __USER_LABEL_PREFIX__. Target-dependent, also controlled
+ by -f(no-)leading-underscore. */
+const char *user_label_prefix;
+
+/* I/O buffer structure.
+ The `fname' field is nonzero for source files and #include files
+ and for the dummy text used for -D and -U.
+ It is zero for rescanning results of macro expansion
+ and for expanding macro arguments. */
+#define INPUT_STACK_MAX 200
+struct file_buf {
+ const char *fname;
+ int lineno;
+ int length;
+ U_CHAR *buf;
+ U_CHAR *bufp;
+ /* Macro that this level is the expansion of.
+ Included so that we can reenable the macro
+ at the end of this level. */
+ struct hashnode *macro;
+ /* Value of if_stack at start of this file.
+ Used to prohibit unmatched #endif (etc) in an include file. */
+ struct if_stack *if_stack;
+ /* Object to be freed at end of input at this level. */
+ U_CHAR *free_ptr;
+} instack[INPUT_STACK_MAX];
+
+typedef struct file_buf FILE_BUF;
+
+/* Current nesting level of input sources.
+ `instack[indepth]' is the level currently being read. */
+int indepth = -1;
+#define CHECK_DEPTH(code) \
+ if (indepth >= (INPUT_STACK_MAX - 1)) \
+ { \
+ error_with_line (line_for_error (instack[indepth].lineno), \
+ "macro or #include recursion too deep"); \
+ code; \
+ }
+
+/* Current depth in #include directives that use <...>. */
+int system_include_depth = 0;
+
+/* The output buffer. Its LENGTH field is the amount of room allocated
+ for the buffer, not the number of chars actually present. To get
+ that, subtract outbuf.buf from outbuf.bufp. */
+
+#define OUTBUF_SIZE 10 /* initial size of output buffer */
+FILE_BUF outbuf;
+
+/* Grow output buffer OBUF points at
+ so it can hold at least NEEDED more chars. */
+
+#define check_expand(OBUF, NEEDED) do { \
+ if ((OBUF)->length - ((OBUF)->bufp - (OBUF)->buf) <= (NEEDED)) \
+ grow_outbuf ((OBUF), (NEEDED)); \
+ } while (0)
+
+struct file_name_list
+ {
+ struct file_name_list *next;
+ const char *fname;
+ };
+
+struct file_name_list *include = 0; /* First dir to search */
+ /* First dir to search for <file> */
+struct file_name_list *first_bracket_include = 0;
+struct file_name_list *last_include = 0; /* Last in chain */
+
+/* List of included files that contained #once. */
+struct file_name_list *dont_repeat_files = 0;
+
+/* List of other included files. */
+struct file_name_list *all_include_files = 0;
+
+/* Structure allocated for every #define. For a simple replacement
+ such as
+ #define foo bar ,
+ nargs = -1, the `pattern' list is null, and the expansion is just
+ the replacement text. Nargs = 0 means a functionlike macro with no args,
+ e.g.,
+ #define getchar() getc (stdin) .
+ When there are args, the expansion is the replacement text with the
+ args squashed out, and the reflist is a list describing how to
+ build the output from the input: e.g., "3 chars, then the 1st arg,
+ then 9 chars, then the 3rd arg, then 0 chars, then the 2nd arg".
+ The chars here come from the expansion. Whatever is left of the
+ expansion after the last arg-occurrence is copied after that arg.
+ Note that the reflist can be arbitrarily long---
+ its length depends on the number of times the arguments appear in
+ the replacement text, not how many args there are. Example:
+ #define f(x) x+x+x+x+x+x+x would have replacement text "++++++" and
+ pattern list
+ { (0, 1), (1, 1), (1, 1), ..., (1, 1), NULL }
+ where (x, y) means (nchars, argno). */
+
+typedef struct definition DEFINITION;
+struct definition {
+ int nargs;
+ int length; /* length of expansion string */
+ U_CHAR *expansion;
+ struct reflist {
+ struct reflist *next;
+ char stringify; /* nonzero if this arg was preceded by a
+ # operator. */
+ char raw_before; /* Nonzero if a ## operator before arg. */
+ char raw_after; /* Nonzero if a ## operator after arg. */
+ int nchars; /* Number of literal chars to copy before
+ this arg occurrence. */
+ int argno; /* Number of arg to substitute (origin-0) */
+ } *pattern;
+ /* Names of macro args, concatenated in reverse order
+ with comma-space between them.
+ The only use of this is that we warn on redefinition
+ if this differs between the old and new definitions. */
+ U_CHAR *argnames;
+};
+
+/* different kinds of things that can appear in the value field
+ of a hash node. Actually, this may be useless now. */
+union hashval {
+ const char *cpval;
+ DEFINITION *defn;
+};
+
+
+/* The structure of a node in the hash table. The hash table
+ has entries for all tokens defined by #define commands (type T_MACRO),
+ plus some special tokens like __LINE__ (these each have their own
+ type, and the appropriate code is run when that type of node is seen.
+ It does not contain control words like "#define", which are recognized
+ by a separate piece of code. */
+
+/* different flavors of hash nodes --- also used in keyword table */
+enum node_type {
+ T_DEFINE = 1, /* `#define' */
+ T_INCLUDE, /* `#include' */
+ T_IFDEF, /* `#ifdef' */
+ T_IFNDEF, /* `#ifndef' */
+ T_IF, /* `#if' */
+ T_ELSE, /* `#else' */
+ T_ELIF, /* `#elif' */
+ T_UNDEF, /* `#undef' */
+ T_LINE, /* `#line' */
+ T_ENDIF, /* `#endif' */
+ T_SPECLINE, /* special symbol `__LINE__' */
+ T_DATE, /* `__DATE__' */
+ T_FILE, /* `__FILE__' */
+ T_BASE_FILE, /* `__BASE_FILE__' */
+ T_INCLUDE_LEVEL, /* `__INCLUDE_LEVEL__' */
+ T_VERSION, /* `__VERSION__' */
+ T_TIME, /* `__TIME__' */
+ T_CONST, /* Constant value, used by `__STDC__' */
+ T_MACRO, /* macro defined by `#define' */
+ T_SPEC_DEFINED, /* special `defined' macro for use in #if statements */
+ T_UNUSED /* Used for something not defined. */
+};
+
+struct hashnode {
+ struct hashnode *next; /* double links for easy deletion */
+ struct hashnode *prev;
+ struct hashnode **bucket_hdr; /* also, a back pointer to this node's hash
+ chain is kept, in case the node is the head
+ of the chain and gets deleted. */
+ enum node_type type; /* type of special token */
+ int length; /* length of token, for quick comparison */
+ U_CHAR *name; /* the actual name */
+ union hashval value; /* pointer to expansion, or whatever */
+};
+
+typedef struct hashnode HASHNODE;
+
+/* Some definitions for the hash table. The hash function MUST be
+ computed as shown in hashf () below. That is because the rescan
+ loop computes the hash value `on the fly' for most tokens,
+ in order to avoid the overhead of a lot of procedure calls to
+ the hashf () function. Hashf () only exists for the sake of
+ politeness, for use when speed isn't so important. */
+
+#define HASHSIZE 1403
+HASHNODE *hashtab[HASHSIZE];
+#define HASHSTEP(old, c) ((old << 2) + c)
+#define MAKE_POS(v) (v & 0x7fffffff) /* make number positive */
+
+/* `struct directive' defines one #-directive, including how to handle it. */
+
+struct directive {
+ int length; /* Length of name */
+ void (*func) PARAMS ((U_CHAR *, U_CHAR *, FILE_BUF *, struct directive *));
+ /* Function to handle directive */
+ const char *name; /* Name of directive */
+ enum node_type type; /* Code which describes which directive. */
+};
+
+/* Last arg to output_line_command. */
+enum file_change_code {same_file, enter_file, leave_file};
+
+/* This structure represents one parsed argument in a macro call.
+ `raw' points to the argument text as written (`raw_length' is its length).
+ `expanded' points to the argument's macro-expansion
+ (its length is `expand_length').
+ `stringified_length' is the length the argument would have
+ if stringified.
+ `free1' and `free2', if nonzero, point to blocks to be freed
+ when the macro argument data is no longer needed. */
+
+struct argdata {
+ U_CHAR *raw, *expanded;
+ int raw_length, expand_length;
+ int stringified_length;
+ U_CHAR *free1, *free2;
+ char newlines;
+ char comments;
+};
+
+/* The arglist structure is built by do_define to tell
+ collect_definition where the argument names begin. That
+ is, for a define like "#define f(x,y,z) foo+x-bar*y", the arglist
+ would contain pointers to the strings x, y, and z.
+ Collect_definition would then build a DEFINITION node,
+ with reflist nodes pointing to the places x, y, and z had
+ appeared. So the arglist is just convenience data passed
+ between these two routines. It is not kept around after
+ the current #define has been processed and entered into the
+ hash table. */
+
+struct arglist {
+ struct arglist *next;
+ U_CHAR *name;
+ int length;
+ int argno;
+};
+
+/* Function prototypes. */
+
+void do_define PARAMS ((U_CHAR *, U_CHAR *, FILE_BUF *, struct directive *));
+void do_line PARAMS ((U_CHAR *, U_CHAR *, FILE_BUF *, struct directive *));
+void do_include PARAMS ((U_CHAR *, U_CHAR *, FILE_BUF *, struct directive *));
+void do_undef PARAMS ((U_CHAR *, U_CHAR *, FILE_BUF *, struct directive *));
+void do_if PARAMS ((U_CHAR *, U_CHAR *, FILE_BUF *, struct directive *));
+void do_xifdef PARAMS ((U_CHAR *, U_CHAR *, FILE_BUF *, struct directive *));
+void do_else PARAMS ((U_CHAR *, U_CHAR *, FILE_BUF *, struct directive *));
+void do_elif PARAMS ((U_CHAR *, U_CHAR *, FILE_BUF *, struct directive *));
+void do_endif PARAMS ((U_CHAR *, U_CHAR *, FILE_BUF *, struct directive *));
+
+struct hashnode *install PARAMS ((const U_CHAR *, int, enum node_type, int));
+struct hashnode *lookup PARAMS ((const U_CHAR *, int, int));
+int hashf PARAMS ((const U_CHAR *, int, int));
+int compare_defs PARAMS ((DEFINITION *, DEFINITION *));
+int comp_def_part PARAMS ((int, U_CHAR *, int, U_CHAR *, int, int));
+void delete_macro PARAMS ((HASHNODE *));
+
+/* First arg to v_message. */
+enum msgtype { WARNING = 0, ERROR, FATAL };
+void v_message PARAMS ((enum msgtype mtype, int line,
+ const char *msgid, va_list ap));
+
+void warning PARAMS ((const char *msgid, ...));
+void error PARAMS ((const char *msgid, ...));
+void fatal PARAMS ((const char *msgid, ...)) ATTRIBUTE_NORETURN;
+void error_with_line PARAMS ((int, const char *msgid, ...));
+void error_from_errno PARAMS ((const char *msgid));
+
+void perror_with_name PARAMS ((const char *msgid));
+void pfatal_with_name PARAMS ((const char *msgid)) ATTRIBUTE_NORETURN;
+void fancy_abort PARAMS ((int, const char *)) ATTRIBUTE_NORETURN;
+
+int line_for_error PARAMS ((int));
+
+/* We know perfectly well which file this is, so we don't need to
+ use __FILE__. */
+#undef abort
+#if (GCC_VERSION >= 2007)
+#define abort() fancy_abort(__LINE__, __FUNCTION__)
+#else
+#define abort() fancy_abort(__LINE__, 0);
+#endif
+
+void macroexpand PARAMS ((HASHNODE *, FILE_BUF *));
+void special_symbol PARAMS ((HASHNODE *, FILE_BUF *));
+void dump_all_macros PARAMS ((void));
+void dump_defn_1 PARAMS ((U_CHAR *, int, int));
+void dump_arg_n PARAMS ((DEFINITION *, int));
+void conditional_skip PARAMS ((FILE_BUF *, int, enum node_type));
+void skip_if_group PARAMS ((FILE_BUF *, int));
+void output_line_command PARAMS ((FILE_BUF *, FILE_BUF *,
+ int, enum file_change_code));
+
+int eval_if_expression PARAMS ((U_CHAR *, int));
+int parse_c_expression PARAMS ((char *)); /* in tradcif.y */
+
+void initialize_char_syntax PARAMS ((void));
+void initialize_builtins PARAMS ((void));
+void make_definition PARAMS ((U_CHAR *));
+void make_undef PARAMS ((U_CHAR *));
+
+void grow_outbuf PARAMS ((FILE_BUF *, int));
+int handle_directive PARAMS ((FILE_BUF *, FILE_BUF *));
+void finclude PARAMS ((int, const char *, FILE_BUF *));
+void deps_output PARAMS ((const char *, int));
+void rescan PARAMS ((FILE_BUF *, int));
+void newline_fix PARAMS ((U_CHAR *));
+void name_newline_fix PARAMS ((U_CHAR *));
+U_CHAR *macarg1 PARAMS ((U_CHAR *, U_CHAR *, int *, int *, int *));
+const char *macarg PARAMS ((struct argdata *));
+int discard_comments PARAMS ((U_CHAR *, int, int));
+int file_size_and_mode PARAMS ((int, int *, long *));
+
+U_CHAR *skip_to_end_of_comment PARAMS ((FILE_BUF *, int *));
+U_CHAR *skip_quoted_string PARAMS ((U_CHAR *, U_CHAR *, int,
+ int *, int *, int *));
+
+void pipe_closed PARAMS ((int));
+int main PARAMS ((int, char **));
+
+/* Convenience. Write U"string" to get an unsigned string constant. */
+#define U (const unsigned char *)
+
+/* Here is the actual list of #-directives, most-often-used first. */
+
+struct directive directive_table[] = {
+ { 6, do_define, "define", T_DEFINE },
+ { 7, do_include, "include", T_INCLUDE },
+ { 5, do_endif, "endif", T_ENDIF },
+ { 5, do_xifdef, "ifdef", T_IFDEF },
+ { 2, do_if, "if", T_IF, },
+ { 4, do_else, "else", T_ELSE },
+ { 6, do_xifdef, "ifndef", T_IFNDEF },
+ { 5, do_undef, "undef", T_UNDEF },
+ { 4, do_line, "line", T_LINE },
+ { 4, do_elif, "elif", T_ELIF },
+ { -1, 0, "", T_UNUSED},
+};
+
+/* table to tell if char can be part of a C identifier. */
+U_CHAR is_idchar[256];
+/* table to tell if char can be first char of a c identifier. */
+U_CHAR is_idstart[256];
+/* table to tell if c is horizontal space. */
+U_CHAR is_hor_space[256];
+/* table to tell if c is horizontal or vertical space. */
+U_CHAR is_space[256];
+
+#define SKIP_WHITE_SPACE(p) do { while (is_hor_space[*p]) p++; } while (0)
+#define SKIP_ALL_WHITE_SPACE(p) do { while (is_space[*p]) p++; } while (0)
+
+int errors = 0; /* Error counter for exit code */
+
+FILE_BUF expand_to_temp_buffer PARAMS ((U_CHAR *, U_CHAR *, int));
+DEFINITION *collect_expansion PARAMS ((U_CHAR *, U_CHAR *, int,
+ struct arglist *));
+
+/* Stack of conditionals currently in progress
+ (including both successful and failing conditionals). */
+
+struct if_stack {
+ struct if_stack *next; /* for chaining to the next stack frame */
+ const char *fname; /* copied from input when frame is made */
+ int lineno; /* similarly */
+ int if_succeeded; /* true if a leg of this if-group
+ has been passed through rescan */
+ enum node_type type; /* type of last directive seen in this group */
+};
+typedef struct if_stack IF_STACK_FRAME;
+IF_STACK_FRAME *if_stack = NULL;
+
+/* Buffer of -M output. */
+
+char *deps_buffer;
+
+/* Number of bytes allocated in above. */
+int deps_allocated_size;
+
+/* Number of bytes used. */
+int deps_size;
+
+/* Number of bytes since the last newline. */
+int deps_column;
+
+/* Nonzero means -I- has been seen,
+ so don't look for #include "foo" the source-file directory. */
+int ignore_srcdir;
+
+/* Handler for SIGPIPE. */
+
+void
+pipe_closed (dummy)
+ int dummy ATTRIBUTE_UNUSED;
+{
+ exit (FATAL_EXIT_CODE);
+}
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int st_mode;
+ long st_size;
+ const char *in_fname, *out_fname;
+ int f, i;
+ FILE_BUF *fp;
+ const char **pend_files = (const char **) xmalloc (argc * sizeof (char *));
+ const char **pend_defs = (const char **) xmalloc (argc * sizeof (char *));
+ const char **pend_undefs = (const char **) xmalloc (argc * sizeof (char *));
+ int no_standard_includes = 0;
+
+ /* Non-0 means don't output the preprocessed program. */
+ int inhibit_output = 0;
+
+ /* Stream on which to print the dependency information. */
+ FILE *deps_stream = 0;
+ /* Target-name to write with the dependency information. */
+ char *deps_target = 0;
+
+#ifdef RLIMIT_STACK
+ /* Get rid of any avoidable limit on stack size. */
+ {
+ struct rlimit rlim;
+
+ /* Set the stack limit huge so that alloca (particularly stringtab
+ * in dbxread.c) does not fail. */
+ getrlimit (RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max;
+ setrlimit (RLIMIT_STACK, &rlim);
+ }
+#endif /* RLIMIT_STACK defined */
+
+ progname = argv[0];
+
+ in_fname = NULL;
+ out_fname = NULL;
+
+ /* Initialize is_idchar to allow $. */
+ initialize_char_syntax ();
+
+ no_line_commands = 0;
+ dump_macros = 0;
+ no_output = 0;
+
+ signal (SIGPIPE, pipe_closed);
+
+ max_include_len = cpp_GCC_INCLUDE_DIR_len + 7; /* ??? */
+
+ memset (pend_files, 0, argc * sizeof (char *));
+ memset (pend_defs, 0, argc * sizeof (char *));
+ memset (pend_undefs, 0, argc * sizeof (char *));
+
+ /* Process switches and find input file name. */
+
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] != '-') {
+ if (out_fname != NULL)
+ fatal ("Usage: %s [switches] input output", argv[0]);
+ else if (in_fname != NULL)
+ out_fname = argv[i];
+ else
+ in_fname = argv[i];
+ } else {
+ switch (argv[i][1]) {
+ case 'A':
+ case 'E':
+ case '$':
+ case 'g':
+ break; /* Ignore for compatibility with ISO/extended cpp. */
+
+ case 'l':
+ if (!strcmp (argv[i], "-lang-c++")
+ || !strcmp (argv[i], "-lang-objc++"))
+ fatal ("-traditional is not supported in C++");
+ else if (!strcmp (argv[i], "-lang-c89"))
+ fatal ("-traditional and -ansi are mutually exclusive");
+ else if (!strcmp (argv[i], "-lang-objc"))
+ pend_defs[i] = "__OBJC__";
+ else if (!strcmp (argv[i], "-lang-asm"))
+ pend_defs[i] = "__ASSEMBLER__";
+ else if (!strcmp (argv[i], "-lang-fortran"))
+ pend_defs[i] = "_LANGUAGE_FORTRAN";
+ /* All other possibilities ignored. */
+ break;
+
+ case 'i':
+ if (!strcmp (argv[i], "-include"))
+ {
+ if (i + 1 == argc)
+ fatal ("Filename missing after -i option");
+ else
+ pend_files[i] = argv[i+1], i++;
+ }
+ else if (!strcmp (argv[i], "-iprefix"))
+ i++; /* Ignore for compatibility */
+ else if (!strcmp (argv[i], "-isystem")
+ || !strcmp (argv[i], "-iwithprefix")
+ || !strcmp (argv[i], "-iwithprefixbefore")
+ || !strcmp (argv[i], "-idirafter"))
+ goto include; /* best we can do */
+
+ break;
+
+ case 'o':
+ if (out_fname != NULL)
+ fatal ("Output filename specified twice");
+ if (i + 1 == argc)
+ fatal ("Filename missing after -o option");
+ out_fname = argv[++i];
+ if (!strcmp (out_fname, "-"))
+ out_fname = "";
+ break;
+
+ case 'w':
+ inhibit_warnings = 1;
+ break;
+
+ case 'W':
+ if (!strcmp (argv[i], "-Wcomments"))
+ warn_comments = 1;
+ else if (!strcmp (argv[i], "-Wcomment"))
+ warn_comments = 1;
+ else if (!strcmp (argv[i], "-Wall")) {
+ warn_comments = 1;
+ }
+ break;
+
+ case 'f':
+ if (!strcmp (argv[i], "-fleading-underscore"))
+ user_label_prefix = "_";
+ else if (!strcmp (argv[i], "-fno-leading-underscore"))
+ user_label_prefix = "";
+ break;
+
+ case 'M':
+ if (!strcmp (argv[i], "-M"))
+ print_deps = 2;
+ else if (!strcmp (argv[i], "-MM"))
+ print_deps = 1;
+ inhibit_output = 1;
+ break;
+
+ case 'd':
+ dump_macros = 1;
+ no_output = 1;
+ break;
+
+ case 'v':
+ fprintf (stderr, "GNU traditional CPP version %s\n", version_string);
+ break;
+
+ case 'D':
+ {
+ char *p, *p1;
+
+ if (argv[i][2] != 0)
+ p = argv[i] + 2;
+ else if (i + 1 == argc)
+ fatal ("Macro name missing after -D option");
+ else
+ p = argv[++i];
+
+ if ((p1 = (char *) strchr (p, '=')) != NULL)
+ *p1 = ' ';
+ pend_defs[i] = p;
+ }
+ break;
+
+ case 'U': /* JF #undef something */
+ if (argv[i][2] != 0)
+ pend_undefs[i] = argv[i] + 2;
+ else if (i + 1 == argc)
+ fatal ("Macro name missing after -U option");
+ else
+ pend_undefs[i] = argv[i+1], i++;
+ break;
+
+ case 'C':
+ put_out_comments = 1;
+ break;
+
+ case 'p':
+ if (!strcmp (argv[i], "-pedantic"))
+ fatal ("-pedantic and -traditional are mutually exclusive");
+ break;
+
+ case 't':
+ if (!strcmp (argv[i], "-trigraphs"))
+ fatal ("-trigraphs and -traditional are mutually exclusive");
+ break;
+
+ case 'P':
+ no_line_commands = 1;
+ break;
+
+ case 'I': /* Add directory to path for includes. */
+ include:
+ {
+ struct file_name_list *dirtmp;
+
+ if (! ignore_srcdir && !strcmp (argv[i] + 2, "-"))
+ ignore_srcdir = 1;
+ else {
+ dirtmp = (struct file_name_list *)
+ xmalloc (sizeof (struct file_name_list));
+ dirtmp->next = 0; /* New one goes on the end */
+ if (include == 0)
+ include = dirtmp;
+ else
+ last_include->next = dirtmp;
+ last_include = dirtmp; /* Tail follows the last one */
+ if (argv[i][1] == 'I' && argv[i][2] != 0)
+ dirtmp->fname = argv[i] + 2;
+ else if (i + 1 == argc)
+ fatal ("Directory name missing after -I option");
+ else
+ dirtmp->fname = argv[++i];
+ if (strlen (dirtmp->fname) > max_include_len)
+ max_include_len = strlen (dirtmp->fname);
+ if (ignore_srcdir && first_bracket_include == 0)
+ first_bracket_include = dirtmp;
+ }
+ }
+ break;
+
+ case 'n':
+ /* -nostdinc causes no default include directories.
+ You must specify all include-file directories with -I. */
+ no_standard_includes = 1;
+ break;
+
+ case '\0': /* JF handle '-' as file name meaning stdin or stdout */
+ if (in_fname == NULL) {
+ in_fname = "";
+ break;
+ } else if (out_fname == NULL) {
+ out_fname = "";
+ break;
+ } /* else fall through into error */
+
+ default:
+ fatal ("Invalid option `%s'", argv[i]);
+ }
+ }
+ }
+
+ if (user_label_prefix == 0)
+ user_label_prefix = USER_LABEL_PREFIX;
+
+ /* Initialize is_idchar. */
+ initialize_char_syntax ();
+
+ /* Install __LINE__, etc. Must follow initialize_char_syntax
+ and option processing. */
+ initialize_builtins ();
+
+ /* Do defines specified with -D. */
+ for (i = 1; i < argc; i++)
+ if (pend_defs[i])
+ make_definition ((U_CHAR *)pend_defs[i]);
+
+ /* Do undefines specified with -U. */
+ for (i = 1; i < argc; i++)
+ if (pend_undefs[i])
+ make_undef ((U_CHAR *)pend_undefs[i]);
+
+ /* Unless -fnostdinc,
+ tack on the standard include file dirs to the specified list */
+ if (!no_standard_includes) {
+ const struct default_include *di;
+ struct file_name_list *old_last_include = last_include;
+ struct file_name_list *dirtmp;
+ for (di = cpp_include_defaults; di->fname; di++) {
+ if (di->cplusplus)
+ continue;
+ dirtmp = (struct file_name_list *)
+ xmalloc (sizeof (struct file_name_list));
+ dirtmp->next = 0; /* New one goes on the end */
+ if (include == 0)
+ include = dirtmp;
+ else
+ last_include->next = dirtmp;
+ last_include = dirtmp; /* Tail follows the last one */
+ dirtmp->fname = di->fname;
+ }
+
+ if (ignore_srcdir && first_bracket_include == 0)
+ first_bracket_include = old_last_include->next;
+ }
+
+ /* Initialize output buffer */
+
+ outbuf.buf = (U_CHAR *) xmalloc (OUTBUF_SIZE);
+ outbuf.bufp = outbuf.buf;
+ outbuf.length = OUTBUF_SIZE;
+
+ /* Scan the -i files before the main input.
+ Much like #including them, but with no_output set
+ so that only their macro definitions matter. */
+
+ no_output++;
+ for (i = 1; i < argc; i++)
+ if (pend_files[i]) {
+ int fd = open (pend_files[i], O_RDONLY, 0666);
+ if (fd < 0) {
+ perror_with_name (pend_files[i]);
+ return FATAL_EXIT_CODE;
+ }
+ finclude (fd, pend_files[i], &outbuf);
+ }
+ no_output--;
+
+ /* Create an input stack level for the main input file
+ and copy the entire contents of the file into it. */
+
+ fp = &instack[++indepth];
+
+ /* JF check for stdin */
+ if (in_fname == NULL || *in_fname == 0) {
+ in_fname = "";
+ f = 0;
+ } else if ((f = open (in_fname, O_RDONLY, 0666)) < 0)
+ goto perror;
+
+ /* Either of two environment variables can specify output of deps.
+ Its value is either "OUTPUT_FILE" or "OUTPUT_FILE DEPS_TARGET",
+ where OUTPUT_FILE is the file to write deps info to
+ and DEPS_TARGET is the target to mention in the deps. */
+
+ if (print_deps == 0
+ && (getenv ("SUNPRO_DEPENDENCIES") != 0
+ || getenv ("DEPENDENCIES_OUTPUT") != 0))
+ {
+ char *spec = getenv ("DEPENDENCIES_OUTPUT");
+ char *s;
+ char *output_file;
+
+ if (spec == 0)
+ {
+ spec = getenv ("SUNPRO_DEPENDENCIES");
+ print_deps = 2;
+ }
+ else
+ print_deps = 1;
+
+ /* Find the space before the DEPS_TARGET, if there is one. */
+ s = strchr (spec, ' ');
+ if (s)
+ {
+ deps_target = s + 1;
+ output_file = (char *) xmalloc (s - spec + 1);
+ memcpy (output_file, spec, s - spec);
+ output_file[s - spec] = 0;
+ }
+ else
+ {
+ deps_target = 0;
+ output_file = spec;
+ }
+
+ deps_stream = fopen (output_file, "a");
+ if (deps_stream == 0)
+ pfatal_with_name (output_file);
+ }
+ /* If the -M option was used, output the deps to standard output. */
+ else if (print_deps)
+ deps_stream = stdout;
+
+ /* For -M, print the expected object file name
+ as the target of this Make-rule. */
+ if (print_deps) {
+ deps_allocated_size = 200;
+ deps_buffer = (char *) xmalloc (deps_allocated_size);
+ deps_buffer[0] = 0;
+ deps_size = 0;
+ deps_column = 0;
+
+ if (deps_target) {
+ deps_output (deps_target, 0);
+ deps_output (":", 0);
+ } else if (*in_fname == 0)
+ deps_output ("-: ", 0);
+ else {
+ int len;
+ const char *p = in_fname;
+ const char *p1 = p;
+ /* Discard all directory prefixes from P. */
+ while (*p1) {
+ if (*p1 == '/')
+ p = p1 + 1;
+ p1++;
+ }
+ /* Output P, but remove known suffixes. */
+ len = strlen (p);
+ if (p[len - 2] == '.'
+ && (p[len - 1] == 'c' || p[len - 1] == 'C' || p[len - 1] == 'S'))
+ deps_output (p, len - 2);
+ else if (p[len - 3] == '.'
+ && p[len - 2] == 'c'
+ && p[len - 1] == 'c')
+ deps_output (p, len - 3);
+ else
+ deps_output (p, 0);
+ /* Supply our own suffix. */
+ deps_output (".o : ", 0);
+ deps_output (in_fname, 0);
+ deps_output (" ", 0);
+ }
+ }
+
+ if (file_size_and_mode (f, &st_mode, &st_size))
+ goto perror;
+ fp->fname = in_fname;
+ fp->lineno = 1;
+ /* JF all this is mine about reading pipes and ttys */
+ if (!S_ISREG (st_mode)) {
+ /* Read input from a file that is not a normal disk file.
+ We cannot preallocate a buffer with the correct size,
+ so we must read in the file a piece at the time and make it bigger. */
+ int size;
+ int bsize;
+ int cnt;
+ U_CHAR *bufp;
+
+ bsize = 2000;
+ size = 0;
+ fp->buf = (U_CHAR *) xmalloc (bsize + 2);
+ bufp = fp->buf;
+ for (;;) {
+ cnt = read (f, bufp, bsize - size);
+ if (cnt < 0) goto perror; /* error! */
+ if (cnt == 0) break; /* End of file */
+ size += cnt;
+ bufp += cnt;
+ if (bsize == size) { /* Buffer is full! */
+ bsize *= 2;
+ fp->buf = (U_CHAR *) xrealloc (fp->buf, bsize + 2);
+ bufp = fp->buf + size; /* May have moved */
+ }
+ }
+ fp->length = size;
+ } else {
+ /* Read a file whose size we can determine in advance.
+ For the sake of VMS, st_size is just an upper bound. */
+ long i;
+ fp->length = 0;
+ fp->buf = (U_CHAR *) xmalloc (st_size + 2);
+
+ while (st_size > 0) {
+ i = read (f, fp->buf + fp->length, st_size);
+ if (i <= 0) {
+ if (i == 0) break;
+ goto perror;
+ }
+ fp->length += i;
+ st_size -= i;
+ }
+ }
+ fp->bufp = fp->buf;
+ fp->if_stack = if_stack;
+
+ /* Make sure data ends with a newline. And put a null after it. */
+
+ if (fp->length > 0 && fp->buf[fp->length-1] != '\n')
+ fp->buf[fp->length++] = '\n';
+ fp->buf[fp->length] = '\0';
+
+ /* Now that we know the input file is valid, open the output. */
+
+ if (!out_fname || !strcmp (out_fname, ""))
+ out_fname = "stdout";
+ else if (! freopen (out_fname, "w", stdout))
+ pfatal_with_name (out_fname);
+
+ output_line_command (fp, &outbuf, 0, same_file);
+
+ /* Scan the input, processing macros and directives. */
+
+ rescan (&outbuf, 0);
+
+ /* Now we have processed the entire input
+ Write whichever kind of output has been requested. */
+
+
+ if (dump_macros)
+ dump_all_macros ();
+ else if (! inhibit_output && deps_stream != stdout) {
+ if (write (fileno (stdout), outbuf.buf, outbuf.bufp - outbuf.buf) < 0)
+ fatal ("I/O error on output");
+ }
+
+ if (print_deps) {
+ fputs (deps_buffer, deps_stream);
+ putc ('\n', deps_stream);
+ if (deps_stream != stdout) {
+ fclose (deps_stream);
+ if (ferror (deps_stream))
+ fatal ("I/O error on output");
+ }
+ }
+
+ if (ferror (stdout))
+ fatal ("I/O error on output");
+
+ if (errors)
+ exit (FATAL_EXIT_CODE);
+ exit (SUCCESS_EXIT_CODE);
+
+ perror:
+ pfatal_with_name (in_fname);
+}
+
+/* Move all backslash-newline pairs out of embarrassing places.
+ Exchange all such pairs following BP
+ with any potentially-embarrasing characters that follow them.
+ Potentially-embarrassing characters are / and *
+ (because a backslash-newline inside a comment delimiter
+ would cause it not to be recognized). */
+void
+newline_fix (bp)
+ U_CHAR *bp;
+{
+ register U_CHAR *p = bp;
+ register int count = 0;
+
+ /* First count the backslash-newline pairs here. */
+
+ while (*p++ == '\\' && *p++ == '\n')
+ count++;
+
+ p = bp + count * 2;
+
+ /* Exit if what follows the backslash-newlines is not embarrassing. */
+
+ if (count == 0 || (*p != '/' && *p != '*'))
+ return;
+
+ /* Copy all potentially embarrassing characters
+ that follow the backslash-newline pairs
+ down to where the pairs originally started. */
+
+ while (*p == '*' || *p == '/')
+ *bp++ = *p++;
+
+ /* Now write the same number of pairs after the embarrassing chars. */
+ while (count-- > 0) {
+ *bp++ = '\\';
+ *bp++ = '\n';
+ }
+}
+
+/* Like newline_fix but for use within a directive-name.
+ Move any backslash-newlines up past any following symbol constituents. */
+void
+name_newline_fix (bp)
+ U_CHAR *bp;
+{
+ register U_CHAR *p = bp;
+ register int count = 0;
+
+ /* First count the backslash-newline pairs here. */
+
+ while (*p++ == '\\' && *p++ == '\n')
+ count++;
+
+ p = bp + count * 2;
+
+ /* What follows the backslash-newlines is not embarrassing. */
+
+ if (count == 0 || !is_idchar[*p])
+ return;
+
+ /* Copy all potentially embarrassing characters
+ that follow the backslash-newline pairs
+ down to where the pairs originally started. */
+
+ while (is_idchar[*p])
+ *bp++ = *p++;
+
+ /* Now write the same number of pairs after the embarrassing chars. */
+ while (count-- > 0) {
+ *bp++ = '\\';
+ *bp++ = '\n';
+ }
+}
+
+/*
+ * The main loop of the program.
+ *
+ * Read characters from the input stack, transferring them to the
+ * output buffer OP.
+ *
+ * Macros are expanded and push levels on the input stack.
+ * At the end of such a level it is popped off and we keep reading.
+ * At the end of any other kind of level, we return.
+ * #-directives are handled, except within macros.
+ *
+ * If OUTPUT_MARKS is nonzero, keep Newline markers found in the input
+ * and insert them when appropriate. This is set while scanning macro
+ * arguments before substitution. It is zero when scanning for final output.
+ * There are three types of Newline markers:
+ * * Newline - follows a macro name that was not expanded
+ * because it appeared inside an expansion of the same macro.
+ * This marker prevents future expansion of that identifier.
+ * When the input is rescanned into the final output, these are deleted.
+ * These are also deleted by ## concatenation.
+ * * Newline Space (or Newline and any other whitespace character)
+ * stands for a place that tokens must be separated or whitespace
+ * is otherwise desirable, but where the ANSI standard specifies there
+ * is no whitespace. This marker turns into a Space (or whichever other
+ * whitespace char appears in the marker) in the final output,
+ * but it turns into nothing in an argument that is stringified with #.
+ * Such stringified arguments are the only place where the ANSI standard
+ * specifies with precision that whitespace may not appear.
+ *
+ * During this function, IP->bufp is kept cached in IBP for speed of access.
+ * Likewise, OP->bufp is kept in OBP. Before calling a subroutine
+ * IBP, IP and OBP must be copied back to memory. IP and IBP are
+ * copied back with the RECACHE macro. OBP must be copied back from OP->bufp
+ * explicitly, and before RECACHE, since RECACHE uses OBP.
+ */
+
+void
+rescan (op, output_marks)
+ FILE_BUF *op;
+ int output_marks;
+{
+ /* Character being scanned in main loop. */
+ register U_CHAR c;
+
+ /* Length of pending accumulated identifier. */
+ register int ident_length = 0;
+
+ /* Hash code of pending accumulated identifier. */
+ register int hash = 0;
+
+ /* Current input level (&instack[indepth]). */
+ FILE_BUF *ip;
+
+ /* Pointer for scanning input. */
+ register U_CHAR *ibp;
+
+ /* Pointer to end of input. End of scan is controlled by LIMIT. */
+ register U_CHAR *limit;
+
+ /* Pointer for storing output. */
+ register U_CHAR *obp;
+
+ /* REDO_CHAR is nonzero if we are processing an identifier
+ after backing up over the terminating character.
+ Sometimes we process an identifier without backing up over
+ the terminating character, if the terminating character
+ is not special. Backing up is done so that the terminating character
+ will be dispatched on again once the identifier is dealt with. */
+ int redo_char = 0;
+
+ /* 1 if within an identifier inside of which a concatenation
+ marker (Newline -) has been seen. */
+ int concatenated = 0;
+
+ /* While scanning a comment or a string constant,
+ this records the line it started on, for error messages. */
+ int start_line;
+
+ /* Record position of last `real' newline. */
+ U_CHAR *beg_of_line;
+
+/* Pop the innermost input stack level, assuming it is a macro expansion. */
+
+#define POPMACRO \
+do { ip->macro->type = T_MACRO; \
+ if (ip->free_ptr) free (ip->free_ptr); \
+ --indepth; } while (0)
+
+/* Reload `rescan's local variables that describe the current
+ level of the input stack. */
+
+#define RECACHE \
+do { ip = &instack[indepth]; \
+ ibp = ip->bufp; \
+ limit = ip->buf + ip->length; \
+ op->bufp = obp; \
+ check_expand (op, limit - ibp); \
+ beg_of_line = 0; \
+ obp = op->bufp; } while (0)
+
+ if (no_output && instack[indepth].fname != 0)
+ skip_if_group (&instack[indepth], 1);
+
+ obp = op->bufp;
+ RECACHE;
+ beg_of_line = ibp;
+
+ /* Our caller must always put a null after the end of
+ the input at each input stack level. */
+ if (*limit != 0)
+ abort ();
+
+ while (1) {
+ c = *ibp++;
+ *obp++ = c;
+
+ switch (c) {
+ case '\\':
+ if (ibp >= limit)
+ break;
+ if (*ibp == '\n') {
+ /* Always merge lines ending with backslash-newline,
+ even in middle of identifier. */
+ ++ibp;
+ ++ip->lineno;
+ --obp; /* remove backslash from obuf */
+ break;
+ }
+ /* Otherwise, backslash suppresses specialness of following char,
+ so copy it here to prevent the switch from seeing it.
+ But first get any pending identifier processed. */
+ if (ident_length > 0)
+ goto specialchar;
+ *obp++ = *ibp++;
+ break;
+
+ case '#':
+ /* If this is expanding a macro definition, don't recognize
+ preprocessor directives. */
+ if (ip->macro != 0)
+ goto randomchar;
+ if (ident_length)
+ goto specialchar;
+
+ /* # keyword: a # must be first nonblank char on the line */
+ if (beg_of_line == 0)
+ goto randomchar;
+ {
+ U_CHAR *bp;
+
+ /* Scan from start of line, skipping whitespace, comments
+ and backslash-newlines, and see if we reach this #.
+ If not, this # is not special. */
+ bp = beg_of_line;
+ while (1) {
+ if (is_hor_space[*bp])
+ bp++;
+ else if (*bp == '\\' && bp[1] == '\n')
+ bp += 2;
+ else if (*bp == '/' && (newline_fix (bp + 1), bp[1]) == '*') {
+ bp += 2;
+ while (!(*bp == '*' && (newline_fix (bp + 1), bp[1]) == '/'))
+ bp++;
+ bp += 1;
+ }
+ else break;
+ }
+ if (bp + 1 != ibp)
+ goto randomchar;
+ }
+
+ /* This # can start a directive. */
+
+ --obp; /* Don't copy the '#' */
+
+ ip->bufp = ibp;
+ op->bufp = obp;
+ if (! handle_directive (ip, op)) {
+#ifdef USE_C_ALLOCA
+ alloca (0);
+#endif
+ /* Not a known directive: treat it as ordinary text.
+ IP, OP, IBP, etc. have not been changed. */
+ if (no_output && instack[indepth].fname) {
+ /* If not generating expanded output,
+ what we do with ordinary text is skip it.
+ Discard everything until next # directive. */
+ skip_if_group (&instack[indepth], 1);
+ RECACHE;
+ beg_of_line = ibp;
+ break;
+ }
+ ++obp; /* Copy the '#' after all */
+ goto randomchar;
+ }
+#ifdef USE_C_ALLOCA
+ alloca (0);
+#endif
+ /* A # directive has been successfully processed. */
+ /* If not generating expanded output, ignore everything until
+ next # directive. */
+ if (no_output && instack[indepth].fname)
+ skip_if_group (&instack[indepth], 1);
+ obp = op->bufp;
+ RECACHE;
+ beg_of_line = ibp;
+ break;
+
+ case '\"': /* skip quoted string */
+ case '\'':
+ /* A single quoted string is treated like a double -- some
+ programs (e.g., troff) are perverse this way */
+
+ if (ident_length)
+ goto specialchar;
+
+ start_line = ip->lineno;
+
+ /* Skip ahead to a matching quote. */
+
+ while (1) {
+ if (ibp >= limit) {
+ if (ip->macro != 0) {
+ /* try harder: this string crosses a macro expansion boundary */
+ POPMACRO;
+ RECACHE;
+ continue;
+ }
+ break;
+ }
+ *obp++ = *ibp;
+ switch (*ibp++) {
+ case '\n':
+ ++ip->lineno;
+ ++op->lineno;
+ /* Traditionally, end of line ends a string constant with no error.
+ So exit the loop and record the new line. */
+ beg_of_line = ibp;
+ goto while2end;
+
+ case '\\':
+ if (ibp >= limit)
+ break;
+ if (*ibp == '\n') {
+ /* Backslash newline is replaced by nothing at all,
+ but keep the line counts correct. */
+ --obp;
+ ++ibp;
+ ++ip->lineno;
+ } else {
+ /* ANSI stupidly requires that in \\ the second \
+ is *not* prevented from combining with a newline. */
+ while (*ibp == '\\' && ibp[1] == '\n') {
+ ibp += 2;
+ ++ip->lineno;
+ }
+ *obp++ = *ibp++;
+ }
+ break;
+
+ case '\"':
+ case '\'':
+ if (ibp[-1] == c)
+ goto while2end;
+ break;
+ }
+ }
+ while2end:
+ break;
+
+ case '/':
+ if (*ibp == '\\' && ibp[1] == '\n')
+ newline_fix (ibp);
+ /* Don't look for comments inside a macro definition. */
+ if (ip->macro != 0)
+ goto randomchar;
+ /* A comment constitutes white space, so it can terminate an identifier.
+ Process the identifier, if any. */
+ if (ident_length)
+ goto specialchar;
+
+ if (*ibp != '*')
+ goto randomchar;
+
+ /* We have a comment. Skip it, optionally copying it to output. */
+
+ start_line = ip->lineno;
+
+ ++ibp; /* Skip the star. */
+
+ /* In K+R C, a comment is equivalent to nothing. Note that we
+ already output the slash; we might not want it. */
+ if (! put_out_comments)
+ obp--;
+ else
+ *obp++ = '*';
+
+ {
+ U_CHAR *before_bp = ibp;
+
+ while (ibp < limit) {
+ switch (*ibp++) {
+ case '/':
+ if (warn_comments && ibp < limit && *ibp == '*')
+ warning("`/*' within comment");
+ break;
+ case '*':
+ if (*ibp == '\\' && ibp[1] == '\n')
+ newline_fix (ibp);
+ if (ibp >= limit || *ibp == '/')
+ goto comment_end;
+ break;
+ case '\n':
+ ++ip->lineno;
+ /* Copy the newline into the output buffer, in order to
+ avoid the pain of a #line every time a multiline comment
+ is seen. */
+ if (!put_out_comments)
+ *obp++ = '\n';
+ ++op->lineno;
+ }
+ }
+ comment_end:
+
+ if (ibp >= limit)
+ error_with_line (line_for_error (start_line),
+ "unterminated comment");
+ else {
+ ibp++;
+ if (put_out_comments) {
+ memcpy (obp, before_bp, ibp - before_bp);
+ obp += ibp - before_bp;
+ }
+ }
+ }
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ /* If digit is not part of identifier, it starts a number,
+ which means that following letters are not an identifier.
+ "0x5" does not refer to an identifier "x5".
+ So copy all alphanumerics that follow without accumulating
+ as an identifier. Periods also, for sake of "3.e7". */
+
+ if (ident_length == 0) {
+ while (ibp < limit) {
+ while (ibp < limit && ibp[0] == '\\' && ibp[1] == '\n') {
+ ++ip->lineno;
+ ibp += 2;
+ }
+ c = *ibp++;
+ if (!isalnum (c) && c != '.' && c != '_') {
+ --ibp;
+ break;
+ }
+ *obp++ = c;
+ /* A sign can be part of a preprocessing number
+ if it follows an e. */
+ if (c == 'e' || c == 'E') {
+ while (ibp < limit && ibp[0] == '\\' && ibp[1] == '\n') {
+ ++ip->lineno;
+ ibp += 2;
+ }
+ if (ibp < limit && (*ibp == '+' || *ibp == '-')) {
+ *obp++ = *ibp++;
+ /* Traditional C does not let the token go past the sign. */
+ break;
+ }
+ }
+ }
+ break;
+ }
+ /* fall through */
+
+ case '_':
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
+ case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
+ case 's': case 't': case 'u': case 'v': case 'w': case 'x':
+ case 'y': case 'z':
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+ case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+ case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+ case 'Y': case 'Z':
+ ident_length++;
+ /* Compute step of hash function, to avoid a proc call on every token */
+ hash = HASHSTEP (hash, c);
+ break;
+
+ case '\n':
+ /* If reprocessing a macro expansion, newline is a special marker. */
+ if (ip->macro != 0) {
+ /* Newline White is a "funny space" to separate tokens that are
+ supposed to be separate but without space between.
+ Here White means any horizontal whitespace character.
+ Newline - marks a recursive macro use that is not
+ supposed to be expandable. */
+
+ if (*ibp == '-') {
+ /* Newline - inhibits expansion of preceding token.
+ If expanding a macro arg, we keep the newline -.
+ In final output, it is deleted. */
+ if (! concatenated) {
+ ident_length = 0;
+ hash = 0;
+ }
+ ibp++;
+ if (!output_marks) {
+ obp--;
+ } else {
+ /* If expanding a macro arg, keep the newline -. */
+ *obp++ = '-';
+ }
+ } else if (is_space[*ibp]) {
+ /* Newline Space does not prevent expansion of preceding token
+ so expand the preceding token and then come back. */
+ if (ident_length > 0)
+ goto specialchar;
+
+ /* If generating final output, newline space makes a space. */
+ if (!output_marks) {
+ obp[-1] = *ibp++;
+ /* And Newline Newline makes a newline, so count it. */
+ if (obp[-1] == '\n')
+ op->lineno++;
+ } else {
+ /* If expanding a macro arg, keep the newline space.
+ If the arg gets stringified, newline space makes nothing. */
+ *obp++ = *ibp++;
+ }
+ } else abort (); /* Newline followed by something random? */
+ break;
+ }
+
+ /* If there is a pending identifier, handle it and come back here. */
+ if (ident_length > 0)
+ goto specialchar;
+
+ beg_of_line = ibp;
+
+ /* Update the line counts and output a #line if necessary. */
+ ++ip->lineno;
+ ++op->lineno;
+ if (ip->lineno != op->lineno) {
+ op->bufp = obp;
+ output_line_command (ip, op, 1, same_file);
+ check_expand (op, ip->length - (ip->bufp - ip->buf));
+ obp = op->bufp;
+ }
+ break;
+
+ /* Come here either after (1) a null character that is part of the input
+ or (2) at the end of the input, because there is a null there. */
+ case 0:
+ if (ibp <= limit)
+ /* Our input really contains a null character. */
+ goto randomchar;
+
+ /* At end of a macro-expansion level, pop it and read next level. */
+ if (ip->macro != 0) {
+ obp--;
+ ibp--;
+ /* If we have an identifier that ends here, process it now, so
+ we get the right error for recursion. */
+ if (ident_length && ! is_idchar[*instack[indepth - 1].bufp]) {
+ redo_char = 1;
+ goto randomchar;
+ }
+ POPMACRO;
+ RECACHE;
+ break;
+ }
+
+ /* If we don't have a pending identifier,
+ return at end of input. */
+ if (ident_length == 0) {
+ obp--;
+ ibp--;
+ op->bufp = obp;
+ ip->bufp = ibp;
+ goto ending;
+ }
+
+ /* If we do have a pending identifier, just consider this null
+ a special character and arrange to dispatch on it again.
+ The second time, IDENT_LENGTH will be zero so we will return. */
+
+ /* Fall through */
+
+specialchar:
+
+ /* Handle the case of a character such as /, ', " or null
+ seen following an identifier. Back over it so that
+ after the identifier is processed the special char
+ will be dispatched on again. */
+
+ ibp--;
+ obp--;
+ redo_char = 1;
+
+ default:
+
+randomchar:
+
+ if (ident_length > 0) {
+ register HASHNODE *hp;
+
+ /* We have just seen an identifier end. If it's a macro, expand it.
+
+ IDENT_LENGTH is the length of the identifier
+ and HASH is its hash code.
+
+ The identifier has already been copied to the output,
+ so if it is a macro we must remove it.
+
+ If REDO_CHAR is 0, the char that terminated the identifier
+ has been skipped in the output and the input.
+ OBP-IDENT_LENGTH-1 points to the identifier.
+ If the identifier is a macro, we must back over the terminator.
+
+ If REDO_CHAR is 1, the terminating char has already been
+ backed over. OBP-IDENT_LENGTH points to the identifier. */
+
+ for (hp = hashtab[MAKE_POS (hash) % HASHSIZE]; hp != NULL;
+ hp = hp->next) {
+
+ if (hp->length == ident_length) {
+ U_CHAR *obufp_before_macroname;
+ int op_lineno_before_macroname;
+ register int i = ident_length;
+ register U_CHAR *p = hp->name;
+ register U_CHAR *q = obp - i;
+
+ if (! redo_char)
+ q--;
+
+ do { /* All this to avoid a strncmp () */
+ if (*p++ != *q++)
+ goto hashcollision;
+ } while (--i);
+
+ /* We found a use of a macro name.
+ see if the context shows it is a macro call. */
+
+ /* Back up over terminating character if not already done. */
+ if (! redo_char) {
+ ibp--;
+ obp--;
+ }
+
+ obufp_before_macroname = obp - ident_length;
+ op_lineno_before_macroname = op->lineno;
+
+ /* If macro wants an arglist, verify that a '(' follows.
+ first skip all whitespace, copying it to the output
+ after the macro name. Then, if there is no '(',
+ decide this is not a macro call and leave things that way. */
+ if (hp->type == T_MACRO && hp->value.defn->nargs >= 0)
+ {
+ while (1) {
+ /* Scan forward over whitespace, copying it to the output. */
+ if (ibp == limit && ip->macro != 0) {
+ POPMACRO;
+ RECACHE;
+ }
+ /* A comment: copy it unchanged or discard it. */
+ else if (*ibp == '/' && ibp+1 != limit && ibp[1] == '*') {
+ if (put_out_comments) {
+ *obp++ = '/';
+ *obp++ = '*';
+ }
+ ibp += 2;
+ while (ibp + 1 != limit
+ && !(ibp[0] == '*' && ibp[1] == '/')) {
+ /* We need not worry about newline-marks,
+ since they are never found in comments. */
+ if (*ibp == '\n') {
+ /* Newline in a file. Count it. */
+ ++ip->lineno;
+ ++op->lineno;
+ }
+ if (put_out_comments)
+ *obp++ = *ibp++;
+ else
+ ibp++;
+ }
+ ibp += 2;
+ if (put_out_comments) {
+ *obp++ = '*';
+ *obp++ = '/';
+ }
+ }
+ else if (is_space[*ibp]) {
+ *obp++ = *ibp++;
+ if (ibp[-1] == '\n') {
+ if (ip->macro == 0) {
+ /* Newline in a file. Count it. */
+ ++ip->lineno;
+ ++op->lineno;
+ } else if (!output_marks) {
+ /* A newline mark, and we don't want marks
+ in the output. If it is newline-hyphen,
+ discard it entirely. Otherwise, it is
+ newline-whitechar, so keep the whitechar. */
+ obp--;
+ if (*ibp == '-')
+ ibp++;
+ else {
+ if (*ibp == '\n')
+ ++op->lineno;
+ *obp++ = *ibp++;
+ }
+ } else {
+ /* A newline mark; copy both chars to the output. */
+ *obp++ = *ibp++;
+ }
+ }
+ }
+ else break;
+ }
+ if (*ibp != '(')
+ break;
+ }
+
+ /* This is now known to be a macro call.
+ Discard the macro name from the output,
+ along with any following whitespace just copied. */
+ obp = obufp_before_macroname;
+ op->lineno = op_lineno_before_macroname;
+
+ /* Expand the macro, reading arguments as needed,
+ and push the expansion on the input stack. */
+ ip->bufp = ibp;
+ op->bufp = obp;
+ macroexpand (hp, op);
+
+ /* Reexamine input stack, since macroexpand has pushed
+ a new level on it. */
+ obp = op->bufp;
+ RECACHE;
+ break;
+ }
+hashcollision:
+ ;
+ } /* End hash-table-search loop */
+ ident_length = hash = 0; /* Stop collecting identifier */
+ redo_char = 0;
+ concatenated = 0;
+ } /* End if (ident_length > 0) */
+ } /* End switch */
+ } /* End per-char loop */
+
+ /* Come here to return -- but first give an error message
+ if there was an unterminated successful conditional. */
+ ending:
+ if (if_stack != ip->if_stack) {
+ const char *str;
+ switch (if_stack->type) {
+ case T_IF:
+ str = "if";
+ break;
+ case T_IFDEF:
+ str = "ifdef";
+ break;
+ case T_IFNDEF:
+ str = "ifndef";
+ break;
+ case T_ELSE:
+ str = "else";
+ break;
+ case T_ELIF:
+ str = "elif";
+ break;
+ default:
+ abort ();
+ }
+ error_with_line (line_for_error (if_stack->lineno),
+ "unterminated #%s conditional", str);
+ }
+ if_stack = ip->if_stack;
+}
+
+/*
+ * Rescan a string into a temporary buffer and return the result
+ * as a FILE_BUF. Note this function returns a struct, not a pointer.
+ *
+ * OUTPUT_MARKS nonzero means keep Newline markers found in the input
+ * and insert such markers when appropriate. See `rescan' for details.
+ * OUTPUT_MARKS is 1 for macroexpanding a macro argument separately
+ * before substitution; it is 0 for other uses.
+ */
+FILE_BUF
+expand_to_temp_buffer (buf, limit, output_marks)
+ U_CHAR *buf, *limit;
+ int output_marks;
+{
+ register FILE_BUF *ip;
+ FILE_BUF obuf;
+ int length = limit - buf;
+ U_CHAR *buf1;
+ int odepth = indepth;
+
+ if (length < 0)
+ abort ();
+
+ /* Set up the input on the input stack. */
+
+ buf1 = (U_CHAR *) alloca (length + 1);
+ {
+ register U_CHAR *p1 = buf;
+ register U_CHAR *p2 = buf1;
+
+ while (p1 != limit)
+ *p2++ = *p1++;
+ }
+ buf1[length] = 0;
+
+ /* Set up to receive the output. */
+
+ obuf.length = length * 2 + 100; /* Usually enough. Why be stingy? */
+ obuf.bufp = obuf.buf = (U_CHAR *) xmalloc (obuf.length);
+ obuf.fname = 0;
+ obuf.macro = 0;
+ obuf.free_ptr = 0;
+
+ CHECK_DEPTH ({return obuf;});
+
+ ++indepth;
+
+ ip = &instack[indepth];
+ ip->fname = 0;
+ ip->macro = 0;
+ ip->free_ptr = 0;
+ ip->length = length;
+ ip->buf = ip->bufp = buf1;
+ ip->if_stack = if_stack;
+
+ ip->lineno = obuf.lineno = 1;
+
+ /* Scan the input, create the output. */
+
+ rescan (&obuf, output_marks);
+
+ /* Pop input stack to original state. */
+ --indepth;
+
+ if (indepth != odepth)
+ abort ();
+
+ /* Record the output. */
+ obuf.length = obuf.bufp - obuf.buf;
+
+ return obuf;
+}
+
+/*
+ * Process a # directive. Expects IP->bufp to point to the '#', as in
+ * `#define foo bar'. Passes to the command handler
+ * (do_define, do_include, etc.): the addresses of the 1st and
+ * last chars of the command (starting immediately after the #
+ * keyword), plus op and the keyword table pointer. If the command
+ * contains comments it is copied into a temporary buffer sans comments
+ * and the temporary buffer is passed to the command handler instead.
+ * Likewise for backslash-newlines.
+ *
+ * Returns nonzero if this was a known # directive.
+ * Otherwise, returns zero, without advancing the input pointer.
+ */
+
+int
+handle_directive (ip, op)
+ FILE_BUF *ip, *op;
+{
+ register U_CHAR *bp, *cp;
+ register struct directive *kt;
+ register int ident_length;
+ U_CHAR *resume_p;
+
+ /* Nonzero means we must copy the entire command
+ to get rid of comments or backslash-newlines. */
+ int copy_command = 0;
+
+ U_CHAR *ident, *after_ident;
+
+ bp = ip->bufp;
+ /* Skip whitespace and \-newline. */
+ while (1) {
+ if (is_hor_space[*bp])
+ bp++;
+ else if (*bp == '/' && (newline_fix (bp + 1), bp[1]) == '*') {
+ ip->bufp = bp;
+ skip_to_end_of_comment (ip, &ip->lineno);
+ bp = ip->bufp;
+ } else if (*bp == '\\' && bp[1] == '\n') {
+ bp += 2; ip->lineno++;
+ } else break;
+ }
+
+ /* Now find end of directive name.
+ If we encounter a backslash-newline, exchange it with any following
+ symbol-constituents so that we end up with a contiguous name. */
+
+ cp = bp;
+ while (1) {
+ if (is_idchar[*cp])
+ cp++;
+ else {
+ if (*cp == '\\' && cp[1] == '\n')
+ name_newline_fix (cp);
+ if (is_idchar[*cp])
+ cp++;
+ else break;
+ }
+ }
+ ident_length = cp - bp;
+ ident = bp;
+ after_ident = cp;
+
+ /* A line of just `#' becomes blank. */
+
+ if (ident_length == 0 && *after_ident == '\n') {
+ ip->bufp = after_ident;
+ return 1;
+ }
+
+ /*
+ * Decode the keyword and call the appropriate expansion
+ * routine, after moving the input pointer up to the next line.
+ */
+ for (kt = directive_table; kt->length > 0; kt++) {
+ if (kt->length == ident_length
+ && !strncmp (kt->name, (char *)ident, ident_length)) {
+ register U_CHAR *buf;
+ register U_CHAR *limit = ip->buf + ip->length;
+ int unterminated = 0;
+
+ /* Nonzero means do not delete comments within the directive.
+ #define needs this to detect traditional token paste. */
+ int keep_comments = kt->type == T_DEFINE;
+
+ /* Find the end of this command (first newline not backslashed
+ and not in a string or comment).
+ Set COPY_COMMAND if the command must be copied
+ (it contains a backslash-newline or a comment). */
+
+ buf = bp = after_ident;
+ while (bp < limit) {
+ register U_CHAR c = *bp++;
+ switch (c) {
+ case '\\':
+ if (bp < limit) {
+ if (*bp == '\n') {
+ ip->lineno++;
+ copy_command = 1;
+ }
+ bp++;
+ }
+ break;
+
+ case '\'':
+ case '\"':
+ bp = skip_quoted_string (bp - 1, limit, ip->lineno, &ip->lineno, &copy_command, &unterminated);
+ if (unterminated) {
+ /* Traditional preprocessing permits unterminated strings. */
+ ip->bufp = bp;
+ goto endloop1;
+ }
+ break;
+
+ /* <...> is special for #include. */
+ case '<':
+ if (kt->type != T_INCLUDE)
+ break;
+ while (*bp && *bp != '>') bp++;
+ break;
+
+ case '/':
+ if (*bp == '\\' && bp[1] == '\n')
+ newline_fix (bp);
+ if (*bp == '*') {
+ U_CHAR *obp = bp - 1;
+ ip->bufp = bp + 1;
+ skip_to_end_of_comment (ip, &ip->lineno);
+ bp = ip->bufp;
+ /* No need to copy the command because of a comment at the end;
+ just don't include the comment in the directive. */
+ if (bp == limit || *bp == '\n') {
+ bp = obp;
+ goto endloop1;
+ }
+ /* Don't remove the comments if this is #define. */
+ if (! keep_comments)
+ copy_command++;
+ }
+ break;
+
+ case '\n':
+ --bp; /* Point to the newline */
+ ip->bufp = bp;
+ goto endloop1;
+ }
+ }
+ ip->bufp = bp;
+
+ endloop1:
+ resume_p = ip->bufp;
+ /* BP is the end of the directive.
+ RESUME_P is the next interesting data after the directive.
+ A comment may come between. */
+
+ if (copy_command) {
+ register U_CHAR *xp = buf;
+ /* Need to copy entire command into temp buffer before dispatching */
+
+ cp = (U_CHAR *) alloca (bp - buf + 5); /* room for cmd plus
+ some slop */
+ buf = cp;
+
+ /* Copy to the new buffer, deleting comments
+ and backslash-newlines (and whitespace surrounding the latter). */
+
+ while (xp < bp) {
+ register U_CHAR c = *xp++;
+ *cp++ = c;
+
+ switch (c) {
+ case '\n':
+ break;
+
+ /* <...> is special for #include. */
+ case '<':
+ if (kt->type != T_INCLUDE)
+ break;
+ while (xp < bp && c != '>') {
+ c = *xp++;
+ if (c == '\\' && xp < bp && *xp == '\n')
+ xp++, ip->lineno++;
+ else
+ *cp++ = c;
+ }
+ break;
+
+ case '\\':
+ if (*xp == '\n') {
+ xp++;
+ cp--;
+ if (cp != buf && is_space[cp[-1]]) {
+ while (cp != buf && is_space[cp[-1]]) cp--;
+ cp++;
+ SKIP_WHITE_SPACE (xp);
+ } else if (is_space[*xp]) {
+ *cp++ = *xp++;
+ SKIP_WHITE_SPACE (xp);
+ }
+ } else {
+ *cp++ = *xp++;
+ }
+ break;
+
+ case '\'':
+ case '\"':
+ {
+ register U_CHAR *bp1
+ = skip_quoted_string (xp - 1, limit, ip->lineno, 0, 0, 0);
+ while (xp != bp1)
+ *cp++ = *xp++;
+ }
+ break;
+
+ case '/':
+ if (*xp == '*') {
+ ip->bufp = xp + 1;
+ skip_to_end_of_comment (ip, 0);
+ if (keep_comments)
+ while (xp != ip->bufp)
+ *cp++ = *xp++;
+ /* Delete the slash. */
+ else
+ cp--;
+ xp = ip->bufp;
+ }
+ }
+ }
+
+ /* Null-terminate the copy. */
+
+ *cp = 0;
+ }
+ else
+ cp = bp;
+
+ ip->bufp = resume_p;
+
+ /* Call the appropriate command handler. buf now points to
+ either the appropriate place in the input buffer, or to
+ the temp buffer if it was necessary to make one. cp
+ points to the first char after the contents of the (possibly
+ copied) command, in either case. */
+ (*kt->func) (buf, cp, op, kt);
+ check_expand (op, ip->length - (ip->bufp - ip->buf));
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static const char *const
+monthnames[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+/*
+ * expand things like __FILE__. Place the expansion into the output
+ * buffer *without* rescanning.
+ */
+void
+special_symbol (hp, op)
+ HASHNODE *hp;
+ FILE_BUF *op;
+{
+ char *buf = 0;
+ time_t t;
+ int i, len;
+ int true_indepth;
+ FILE_BUF *ip = NULL;
+ static struct tm *timebuf = NULL;
+
+ int paren = 0; /* For special `defined' keyword */
+
+ for (i = indepth; i >= 0; i--)
+ if (instack[i].fname != NULL) {
+ ip = &instack[i];
+ break;
+ }
+ if (ip == NULL)
+ fatal ("not in any file?!");
+
+ switch (hp->type) {
+ case T_FILE:
+ case T_BASE_FILE:
+ {
+ const char *string;
+ if (hp->type == T_FILE)
+ string = ip->fname;
+ else
+ string = instack[0].fname;
+
+ if (string)
+ {
+ buf = (char *) alloca (3 + strlen (string));
+ sprintf (buf, "\"%s\"", string);
+ }
+ else
+ strcpy (buf, "\"\"");
+
+ break;
+ }
+
+ case T_INCLUDE_LEVEL:
+ true_indepth = 0;
+ for (i = indepth; i >= 0; i--)
+ if (instack[i].fname != NULL)
+ true_indepth++;
+
+ buf = (char *) alloca (8); /* Eigth bytes ought to be more than enough */
+ sprintf (buf, "%d", true_indepth - 1);
+ break;
+
+ case T_VERSION:
+ buf = (char *) alloca (3 + strlen (version_string));
+ sprintf (buf, "\"%s\"", version_string);
+ break;
+
+ case T_CONST:
+ buf = (char *) hp->value.cpval;
+ break;
+
+ case T_SPECLINE:
+ buf = (char *) alloca (10);
+ sprintf (buf, "%d", ip->lineno);
+ break;
+
+ case T_DATE:
+ case T_TIME:
+ if (timebuf == NULL) {
+ t = time (0);
+ timebuf = localtime (&t);
+ }
+ buf = (char *) alloca (20);
+ if (hp->type == T_DATE)
+ sprintf (buf, "\"%s %2d %4d\"", monthnames[timebuf->tm_mon],
+ timebuf->tm_mday, timebuf->tm_year + 1900);
+ else
+ sprintf (buf, "\"%02d:%02d:%02d\"", timebuf->tm_hour, timebuf->tm_min,
+ timebuf->tm_sec);
+ break;
+
+ case T_SPEC_DEFINED:
+ buf = (char *) " 0 "; /* Assume symbol is not defined */
+ ip = &instack[indepth];
+ SKIP_WHITE_SPACE (ip->bufp);
+ if (*ip->bufp == '(') {
+ paren++;
+ ip->bufp++; /* Skip over the paren */
+ SKIP_WHITE_SPACE (ip->bufp);
+ }
+
+ if (!is_idstart[*ip->bufp])
+ goto oops;
+ if (lookup (ip->bufp, -1, -1))
+ buf = (char *) " 1 ";
+ while (is_idchar[*ip->bufp])
+ ++ip->bufp;
+ SKIP_WHITE_SPACE (ip->bufp);
+ if (paren) {
+ if (*ip->bufp != ')')
+ goto oops;
+ ++ip->bufp;
+ }
+ break;
+
+oops:
+
+ error ("`defined' must be followed by ident or (ident)");
+ break;
+
+ default:
+ error ("cccp error: invalid special hash type"); /* time for gdb */
+ abort ();
+ }
+ len = strlen (buf);
+ check_expand (op, len);
+ memcpy (op->bufp, buf, len);
+ op->bufp += len;
+}
+
+
+/* Routines to handle #directives */
+
+/*
+ * Process include file by reading it in and calling rescan.
+ * Expects to see "fname" or <fname> on the input.
+ */
+void
+do_include (buf, limit, op, keyword)
+ U_CHAR *buf, *limit;
+ FILE_BUF *op;
+ struct directive *keyword ATTRIBUTE_UNUSED;
+{
+ char *fname; /* Dynamically allocated fname buffer */
+ U_CHAR *fbeg, *fend; /* Beginning and end of fname */
+
+ struct file_name_list *stackp = include; /* Chain of dirs to search */
+ struct file_name_list dsp[1]; /* First in chain, if #include "..." */
+ int flen;
+
+ int f; /* file number */
+
+ int retried = 0; /* Have already tried macro
+ expanding the include line*/
+ FILE_BUF trybuf; /* It got expanded into here */
+ int system_header_p = 0; /* 0 for "...", 1 for <...> */
+
+ f= -1; /* JF we iz paranoid! */
+
+get_filename:
+
+ fbeg = buf;
+ SKIP_WHITE_SPACE (fbeg);
+ /* Discard trailing whitespace so we can easily see
+ if we have parsed all the significant chars we were given. */
+ while (limit != fbeg && is_hor_space[limit[-1]]) limit--;
+
+ switch (*fbeg++) {
+ case '\"':
+ fend = fbeg;
+ while (fend != limit && *fend != '\"')
+ fend++;
+ if (*fend == '\"' && fend + 1 == limit) {
+ FILE_BUF *fp;
+
+ /* We have "filename". Figure out directory this source
+ file is coming from and put it on the front of the list. */
+
+ /* If -I- was specified, don't search current dir, only spec'd ones. */
+ if (ignore_srcdir) break;
+
+ for (fp = &instack[indepth]; fp >= instack; fp--)
+ {
+ size_t n;
+ const char *ep, *nam;
+
+ if ((nam = fp->fname) != NULL) {
+ /* Found a named file. Figure out dir of the file,
+ and put it in front of the search list. */
+ dsp[0].next = stackp;
+ stackp = dsp;
+ ep = strrchr (nam, '/');
+ if (ep != NULL) {
+ char *f;
+ n = ep - nam;
+ f = (char *) alloca (n + 1);
+ strncpy (f, nam, n);
+ f[n] = '\0';
+ dsp[0].fname = f;
+ if (n > max_include_len) max_include_len = n;
+ } else {
+ dsp[0].fname = 0; /* Current directory */
+ }
+ break;
+ }
+ }
+ break;
+ }
+ goto fail;
+
+ case '<':
+ fend = fbeg;
+ while (fend != limit && *fend != '>') fend++;
+ if (*fend == '>' && fend + 1 == limit) {
+ system_header_p = 1;
+ /* If -I-, start with the first -I dir after the -I-. */
+ if (first_bracket_include)
+ stackp = first_bracket_include;
+ break;
+ }
+ goto fail;
+
+ default:
+ fail:
+ if (retried) {
+ error ("#include expects \"fname\" or <fname>");
+ return;
+ } else {
+ trybuf = expand_to_temp_buffer (buf, limit, 0);
+ buf = (U_CHAR *) alloca (trybuf.bufp - trybuf.buf + 1);
+ memcpy (buf, trybuf.buf, trybuf.bufp - trybuf.buf);
+ limit = buf + (trybuf.bufp - trybuf.buf);
+ free (trybuf.buf);
+ retried++;
+ goto get_filename;
+ }
+ }
+
+ flen = fend - fbeg;
+ fname = (char *) alloca (max_include_len + flen + 2);
+ /* + 2 above for slash and terminating null. */
+
+ /* If specified file name is absolute, just open it. */
+
+ if (*fbeg == '/') {
+ strncpy (fname, (char *)fbeg, flen);
+ fname[flen] = 0;
+ f = open (fname, O_RDONLY, 0666);
+ } else {
+ /* Search directory path, trying to open the file.
+ Copy each filename tried into FNAME. */
+
+ for (; stackp; stackp = stackp->next) {
+ if (stackp->fname) {
+ strcpy (fname, stackp->fname);
+ strcat (fname, "/");
+ fname[strlen (fname) + flen] = 0;
+ } else {
+ fname[0] = 0;
+ }
+ strncat (fname, (char *)fbeg, flen);
+ if ((f = open (fname, O_RDONLY, 0666)) >= 0)
+ break;
+ }
+ }
+
+ if (f < 0) {
+ strncpy (fname, (char *)fbeg, flen);
+ fname[flen] = 0;
+ error_from_errno (fname);
+
+ /* For -M, add this file to the dependencies. */
+ if (print_deps > (system_header_p || (system_include_depth > 0))) {
+ if (system_header_p)
+ warning ("nonexistent file <%.*s> omitted from dependency output",
+ fend - fbeg, fbeg);
+ else
+ {
+ deps_output ((const char *)fbeg, fend - fbeg);
+ deps_output (" ", 0);
+ }
+ }
+ } else {
+
+ /* Check to see if this include file is a once-only include file.
+ If so, give up. */
+
+ struct file_name_list* ptr;
+
+ for (ptr = dont_repeat_files; ptr; ptr = ptr->next) {
+ if (!strcmp (ptr->fname, fname)) {
+ close (f);
+ return; /* This file was once'd. */
+ }
+ }
+
+ for (ptr = all_include_files; ptr; ptr = ptr->next) {
+ if (!strcmp (ptr->fname, fname))
+ break; /* This file was included before. */
+ }
+
+ if (ptr == 0) {
+ /* This is the first time for this file. */
+ /* Add it to list of files included. */
+
+ ptr = (struct file_name_list *) xmalloc (sizeof (struct file_name_list));
+ ptr->next = all_include_files;
+ all_include_files = ptr;
+ ptr->fname = xstrdup (fname);
+
+ /* For -M, add this file to the dependencies. */
+ if (print_deps > (system_header_p || (system_include_depth > 0))) {
+ deps_output (fname, strlen (fname));
+ deps_output (" ", 0);
+ }
+ }
+
+ if (system_header_p)
+ system_include_depth++;
+
+ /* Actually process the file. */
+ finclude (f, fname, op);
+
+ if (system_header_p)
+ system_include_depth--;
+
+ close (f);
+ }
+}
+
+/* Process the contents of include file FNAME, already open on descriptor F,
+ with output to OP. */
+
+void
+finclude (f, fname, op)
+ int f;
+ const char *fname;
+ FILE_BUF *op;
+{
+ int st_mode;
+ long st_size;
+ long i;
+ FILE_BUF *fp; /* For input stack frame */
+
+ CHECK_DEPTH (return;);
+
+ if (file_size_and_mode (f, &st_mode, &st_size))
+ goto nope;
+
+ fp = &instack[indepth + 1];
+ memset (fp, 0, sizeof (FILE_BUF));
+ fp->fname = fname;
+ fp->length = 0;
+ fp->lineno = 1;
+ fp->if_stack = if_stack;
+
+ if (S_ISREG (st_mode)) {
+ fp->buf = (U_CHAR *) xmalloc (st_size + 2);
+ fp->bufp = fp->buf;
+
+ /* Read the file contents, knowing that st_size is an upper bound
+ on the number of bytes we can read. */
+ while (st_size > 0) {
+ i = read (f, fp->buf + fp->length, st_size);
+ if (i <= 0) {
+ if (i == 0) break;
+ goto nope;
+ }
+ fp->length += i;
+ st_size -= i;
+ }
+ }
+ else {
+ /* Cannot count its file size before reading. */
+
+ U_CHAR *bufp;
+ U_CHAR *basep;
+ int bsize = 2000;
+
+ st_size = 0;
+ basep = (U_CHAR *) xmalloc (bsize + 2);
+ bufp = basep;
+
+ for (;;) {
+ i = read (f, bufp, bsize - st_size);
+ if (i < 0)
+ goto nope; /* error! */
+ if (i == 0)
+ break; /* End of file */
+ st_size += i;
+ bufp += i;
+ if (bsize == st_size) { /* Buffer is full! */
+ bsize *= 2;
+ basep = (U_CHAR *) xrealloc (basep, bsize + 2);
+ bufp = basep + st_size; /* May have moved */
+ }
+ }
+ fp->buf = basep;
+ fp->bufp = fp->buf;
+ fp->length = st_size;
+ }
+ close (f);
+
+ /* Make sure data ends with a newline. And put a null after it. */
+
+ if (fp->length > 0 && fp->buf[fp->length-1] != '\n')
+ fp->buf[fp->length++] = '\n';
+ fp->buf[fp->length] = '\0';
+
+ indepth++;
+ output_line_command (fp, op, 0, enter_file);
+ rescan (op, 0);
+ indepth--;
+ output_line_command (&instack[indepth], op, 0, leave_file);
+ free (fp->buf);
+ return;
+
+nope:
+ perror_with_name (fname);
+ close (f);
+}
+
+
+/* Process a #define command.
+BUF points to the contents of the #define command, as a continguous string.
+LIMIT points to the first character past the end of the definition.
+KEYWORD is the keyword-table entry for #define. */
+
+void
+do_define (buf, limit, op, keyword)
+ U_CHAR *buf, *limit;
+ FILE_BUF *op ATTRIBUTE_UNUSED;
+ struct directive *keyword ATTRIBUTE_UNUSED;
+{
+ U_CHAR *bp; /* temp ptr into input buffer */
+ U_CHAR *symname; /* remember where symbol name starts */
+ int sym_length; /* and how long it is */
+
+ DEFINITION *defn;
+ int arglengths = 0; /* Accumulate lengths of arg names
+ plus number of args. */
+ int hashcode;
+
+ bp = buf;
+
+ while (is_hor_space[*bp])
+ bp++;
+
+ symname = bp; /* remember where it starts */
+ while (is_idchar[*bp] && bp < limit) {
+ bp++;
+ }
+ sym_length = bp - symname;
+ if (sym_length == 0)
+ error ("invalid macro name");
+ else if (!is_idstart[*symname]) {
+ U_CHAR *msg; /* what pain... */
+ msg = (U_CHAR *) alloca (sym_length + 1);
+ memcpy (msg, symname, sym_length);
+ msg[sym_length] = 0;
+ error ("invalid macro name `%s'", msg);
+ } else {
+ if (! strncmp ((char *)symname, "defined", 7) && sym_length == 7)
+ error ("defining `defined' as a macro");
+ }
+
+ /* lossage will occur if identifiers or control keywords are broken
+ across lines using backslash. This is not the right place to take
+ care of that. */
+
+ if (*bp == '(') {
+ struct arglist *arg_ptrs = NULL;
+ int argno = 0;
+
+ bp++; /* skip '(' */
+ SKIP_WHITE_SPACE (bp);
+
+ /* Loop over macro argument names. */
+ while (*bp != ')') {
+ struct arglist *temp;
+
+ temp = (struct arglist *) alloca (sizeof (struct arglist));
+ temp->name = bp;
+ temp->next = arg_ptrs;
+ temp->argno = argno++;
+ arg_ptrs = temp;
+
+ if (!is_idstart[*bp])
+ warning ("parameter name starts with a digit in #define");
+
+ /* Find the end of the arg name. */
+ while (is_idchar[*bp]) {
+ bp++;
+ }
+ temp->length = bp - temp->name;
+ arglengths += temp->length + 2;
+ SKIP_WHITE_SPACE (bp);
+ if (temp->length == 0 || (*bp != ',' && *bp != ')')) {
+ error ("badly punctuated parameter list in #define");
+ return;
+ }
+ if (*bp == ',') {
+ bp++;
+ SKIP_WHITE_SPACE (bp);
+ }
+ if (bp >= limit) {
+ error ("unterminated parameter list in #define");
+ return;
+ }
+ }
+
+ ++bp; /* skip paren */
+ /* Skip exactly one space or tab if any. */
+ if (bp < limit && (*bp == ' ' || *bp == '\t')) ++bp;
+ /* now everything from bp before limit is the definition. */
+ defn = collect_expansion (bp, limit, argno, arg_ptrs);
+
+ /* Now set defn->argnames to the result of concatenating
+ the argument names in reverse order
+ with comma-space between them. */
+ defn->argnames = (U_CHAR *) xmalloc (arglengths + 1);
+ {
+ struct arglist *temp;
+ int i = 0;
+ for (temp = arg_ptrs; temp; temp = temp->next) {
+ memcpy (&defn->argnames[i], temp->name, temp->length);
+ i += temp->length;
+ if (temp->next != 0) {
+ defn->argnames[i++] = ',';
+ defn->argnames[i++] = ' ';
+ }
+ }
+ defn->argnames[i] = 0;
+ }
+ } else {
+ /* simple expansion or empty definition; gobble it */
+ if (is_hor_space[*bp])
+ ++bp; /* skip exactly one blank/tab char */
+ /* now everything from bp before limit is the definition. */
+ defn = collect_expansion (bp, limit, -1, 0);
+ defn->argnames = (U_CHAR *) "";
+ }
+
+ hashcode = hashf (symname, sym_length, HASHSIZE);
+
+ {
+ HASHNODE *hp;
+ if ((hp = lookup (symname, sym_length, hashcode)) == NULL)
+ hp = install (symname, sym_length, T_MACRO, hashcode);
+ else {
+ if (hp->type != T_MACRO || compare_defs (defn, hp->value.defn))
+ warning ("\"%.*s\" redefined", sym_length, symname);
+
+ /* Replace the old definition. */
+ hp->type = T_MACRO;
+ }
+
+ hp->value.defn = defn;
+ }
+}
+
+/*
+ * return zero if two DEFINITIONs are isomorphic
+ */
+int
+compare_defs (d1, d2)
+ DEFINITION *d1, *d2;
+{
+ register struct reflist *a1, *a2;
+ register U_CHAR *p1 = d1->expansion;
+ register U_CHAR *p2 = d2->expansion;
+ int first = 1;
+
+ if (d1->nargs != d2->nargs)
+ return 1;
+ if (strcmp ((char *)d1->argnames, (char *)d2->argnames))
+ return 1;
+ for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2;
+ a1 = a1->next, a2 = a2->next) {
+ if (!((a1->nchars == a2->nchars
+ && ! strncmp ((char *)p1, (char *)p2, a1->nchars))
+ || ! comp_def_part (first, p1, a1->nchars, p2, a2->nchars, 0))
+ || a1->argno != a2->argno
+ || a1->stringify != a2->stringify
+ || a1->raw_before != a2->raw_before
+ || a1->raw_after != a2->raw_after)
+ return 1;
+ first = 0;
+ p1 += a1->nchars;
+ p2 += a2->nchars;
+ }
+ if (a1 != a2)
+ return 1;
+ if (comp_def_part (first, p1, d1->length - (p1 - d1->expansion),
+ p2, d2->length - (p2 - d2->expansion), 1))
+ return 1;
+ return 0;
+}
+
+/* Return 1 if two parts of two macro definitions are effectively different.
+ One of the parts starts at BEG1 and has LEN1 chars;
+ the other has LEN2 chars at BEG2.
+ Any sequence of whitespace matches any other sequence of whitespace.
+ FIRST means these parts are the first of a macro definition;
+ so ignore leading whitespace entirely.
+ LAST means these parts are the last of a macro definition;
+ so ignore trailing whitespace entirely. */
+int
+comp_def_part (first, beg1, len1, beg2, len2, last)
+ int first;
+ U_CHAR *beg1, *beg2;
+ int len1, len2;
+ int last;
+{
+ register U_CHAR *end1 = beg1 + len1;
+ register U_CHAR *end2 = beg2 + len2;
+ if (first) {
+ while (beg1 != end1 && is_space[*beg1]) beg1++;
+ while (beg2 != end2 && is_space[*beg2]) beg2++;
+ }
+ if (last) {
+ while (beg1 != end1 && is_space[end1[-1]]) end1--;
+ while (beg2 != end2 && is_space[end2[-1]]) end2--;
+ }
+ while (beg1 != end1 && beg2 != end2) {
+ if (is_space[*beg1] && is_space[*beg2]) {
+ while (beg1 != end1 && is_space[*beg1]) beg1++;
+ while (beg2 != end2 && is_space[*beg2]) beg2++;
+ } else if (*beg1 == *beg2) {
+ beg1++; beg2++;
+ } else break;
+ }
+ return (beg1 != end1) || (beg2 != end2);
+}
+
+/* Read a replacement list for a macro with parameters.
+ Build the DEFINITION structure.
+ Reads characters of text starting at BUF until LIMIT.
+ ARGLIST specifies the formal parameters to look for
+ in the text of the definition; NARGS is the number of args
+ in that list, or -1 for a macro name that wants no argument list.
+ MACRONAME is the macro name itself (so we can avoid recursive expansion)
+ and NAMELEN is its length in characters.
+
+Note that comments and backslash-newlines have already been deleted
+from the argument. */
+
+/* Leading and trailing Space, Tab, etc. are converted to markers
+ Newline Space, Newline Tab, etc.
+ Newline Space makes a space in the final output
+ but is discarded if stringified. (Newline Tab is similar but
+ makes a Tab instead.)
+
+ If there is no trailing whitespace, a Newline Space is added at the end
+ to prevent concatenation that would be contrary to the standard. */
+
+DEFINITION *
+collect_expansion (buf, end, nargs, arglist)
+ U_CHAR *buf, *end;
+ int nargs;
+ struct arglist *arglist;
+{
+ DEFINITION *defn;
+ register U_CHAR *p, *limit, *lastp, *exp_p;
+ struct reflist *endpat = NULL;
+ /* Pointer to first nonspace after last ## seen. */
+ U_CHAR *concat = 0;
+ /* Pointer to first nonspace after last single-# seen. */
+ U_CHAR *stringify = 0;
+ int maxsize;
+ int expected_delimiter = '\0';
+
+ /* Scan thru the replacement list, ignoring comments and quoted
+ strings, picking up on the macro calls. It does a linear search
+ thru the arg list on every potential symbol. Profiling might say
+ that something smarter should happen. */
+
+ if (end < buf)
+ abort ();
+
+ /* Find the beginning of the trailing whitespace. */
+ /* Find end of leading whitespace. */
+ limit = end;
+ p = buf;
+ while (p < limit && is_space[limit[-1]]) limit--;
+ while (p < limit && is_space[*p]) p++;
+
+ /* Allocate space for the text in the macro definition.
+ Leading and trailing whitespace chars need 2 bytes each.
+ Each other input char may or may not need 1 byte,
+ so this is an upper bound.
+ The extra 2 are for invented trailing newline-marker and final null. */
+ maxsize = (sizeof (DEFINITION)
+ + 2 * (end - limit) + 2 * (p - buf)
+ + (limit - p) + 3);
+ defn = (DEFINITION *) xcalloc (1, maxsize);
+
+ defn->nargs = nargs;
+ exp_p = defn->expansion = (U_CHAR *) defn + sizeof (DEFINITION);
+ lastp = exp_p;
+
+ p = buf;
+
+ /* Convert leading whitespace to Newline-markers. */
+ while (p < limit && is_space[*p]) {
+ *exp_p++ = '\n';
+ *exp_p++ = *p++;
+ }
+
+ /* Process the main body of the definition. */
+ while (p < limit) {
+ int skipped_arg = 0;
+ register U_CHAR c = *p++;
+
+ *exp_p++ = c;
+
+ /* In -traditional mode, recognize arguments inside strings and
+ and character constants, and ignore special properties of #.
+ Arguments inside strings are considered "stringified", but no
+ extra quote marks are supplied. */
+ switch (c) {
+ case '\'':
+ case '\"':
+ if (expected_delimiter != '\0') {
+ if (c == expected_delimiter)
+ expected_delimiter = '\0';
+ } else
+ expected_delimiter = c;
+ break;
+
+ case '\\':
+ /* Backslash quotes delimiters and itself, but not macro args. */
+ if (expected_delimiter != 0 && p < limit
+ && (*p == expected_delimiter || *p == '\\')) {
+ *exp_p++ = *p++;
+ continue;
+ }
+ break;
+
+ case '/':
+ if (expected_delimiter != '\0') /* No comments inside strings. */
+ break;
+ if (*p == '*') {
+ /* If we find a comment that wasn't removed by handle_directive,
+ this must be -traditional. So replace the comment with
+ nothing at all. */
+ exp_p--;
+ p += 1;
+ while (p < limit && !(p[-2] == '*' && p[-1] == '/'))
+ p++;
+ }
+ break;
+ }
+
+ if (is_idchar[c] && nargs > 0) {
+ U_CHAR *id_beg = p - 1;
+ int id_len;
+
+ --exp_p;
+ while (p != limit && is_idchar[*p]) p++;
+ id_len = p - id_beg;
+
+ if (is_idstart[c]) {
+ register struct arglist *arg;
+
+ for (arg = arglist; arg != NULL; arg = arg->next) {
+ struct reflist *tpat;
+
+ if (arg->name[0] == c
+ && arg->length == id_len
+ && strncmp ((char *)arg->name, (char *)id_beg, id_len) == 0) {
+ /* make a pat node for this arg and append it to the end of
+ the pat list */
+ tpat = (struct reflist *) xmalloc (sizeof (struct reflist));
+ tpat->next = NULL;
+ tpat->raw_before = concat == id_beg;
+ tpat->raw_after = 0;
+ tpat->stringify = expected_delimiter != '\0';
+
+ if (endpat == NULL)
+ defn->pattern = tpat;
+ else
+ endpat->next = tpat;
+ endpat = tpat;
+
+ tpat->argno = arg->argno;
+ tpat->nchars = exp_p - lastp;
+ {
+ register U_CHAR *p1 = p;
+ SKIP_WHITE_SPACE (p1);
+ if (p1 + 2 <= limit && p1[0] == '#' && p1[1] == '#')
+ tpat->raw_after = 1;
+ }
+ lastp = exp_p; /* place to start copying from next time */
+ skipped_arg = 1;
+ break;
+ }
+ }
+ }
+
+ /* If this was not a macro arg, copy it into the expansion. */
+ if (! skipped_arg) {
+ register U_CHAR *lim1 = p;
+ p = id_beg;
+ while (p != lim1)
+ *exp_p++ = *p++;
+ if (stringify == id_beg)
+ error ("# operator should be followed by a macro argument name");
+ }
+ }
+ }
+
+ if (limit < end) {
+ /* Convert trailing whitespace to Newline-markers. */
+ while (limit < end && is_space[*limit]) {
+ *exp_p++ = '\n';
+ *exp_p++ = *limit++;
+ }
+ }
+ *exp_p = '\0';
+
+ defn->length = exp_p - defn->expansion;
+
+ /* Crash now if we overrun the allocated size. */
+ if (defn->length + 1 > maxsize)
+ abort ();
+
+ return defn;
+}
+
+/*
+ * interpret #line command. Remembers previously seen fnames
+ * in its very own hash table.
+ */
+#define FNAME_HASHSIZE 37
+void
+do_line (buf, limit, op, keyword)
+ U_CHAR *buf, *limit;
+ FILE_BUF *op;
+ struct directive *keyword ATTRIBUTE_UNUSED;
+{
+ register U_CHAR *bp;
+ FILE_BUF *ip = &instack[indepth];
+ FILE_BUF tem;
+ int new_lineno;
+ enum file_change_code file_change = same_file;
+
+ /* Expand any macros. */
+ tem = expand_to_temp_buffer (buf, limit, 0);
+
+ /* Point to macroexpanded line, which is null-terminated now. */
+ bp = tem.buf;
+ SKIP_WHITE_SPACE (bp);
+
+ if (!isdigit (*bp)) {
+ error ("invalid format #line command");
+ return;
+ }
+
+ /* The Newline at the end of this line remains to be processed.
+ To put the next line at the specified line number,
+ we must store a line number now that is one less. */
+ new_lineno = atoi ((char *)bp) - 1;
+
+ /* skip over the line number. */
+ while (isdigit (*bp))
+ bp++;
+
+#if 0 /* #line 10"foo.c" is supposed to be allowed. */
+ if (*bp && !is_space[*bp]) {
+ error ("invalid format #line command");
+ return;
+ }
+#endif
+
+ SKIP_WHITE_SPACE (bp);
+
+ if (*bp == '\"') {
+ static HASHNODE *fname_table[FNAME_HASHSIZE];
+ HASHNODE *hp, **hash_bucket;
+ U_CHAR *fname;
+ int fname_length;
+
+ fname = ++bp;
+
+ while (*bp && *bp != '\"')
+ bp++;
+ if (*bp != '\"') {
+ error ("invalid format #line command");
+ return;
+ }
+
+ fname_length = bp - fname;
+
+ bp++;
+ SKIP_WHITE_SPACE (bp);
+ if (*bp) {
+ if (*bp == '1')
+ file_change = enter_file;
+ else if (*bp == '2')
+ file_change = leave_file;
+ else {
+ error ("invalid format #line command");
+ return;
+ }
+
+ bp++;
+ SKIP_WHITE_SPACE (bp);
+ if (*bp) {
+ error ("invalid format #line command");
+ return;
+ }
+ }
+
+ hash_bucket =
+ &fname_table[hashf (fname, fname_length, FNAME_HASHSIZE)];
+ for (hp = *hash_bucket; hp != NULL; hp = hp->next)
+ if (hp->length == fname_length &&
+ strncmp (hp->value.cpval, (char *)fname, fname_length) == 0) {
+ ip->fname = hp->value.cpval;
+ break;
+ }
+ if (hp == 0) {
+ char *q;
+ /* Didn't find it; cons up a new one. */
+ hp = (HASHNODE *) xcalloc (1, sizeof (HASHNODE) + fname_length + 1);
+ hp->next = *hash_bucket;
+ *hash_bucket = hp;
+
+ hp->length = fname_length;
+ ip->fname = hp->value.cpval = q = ((char *) hp) + sizeof (HASHNODE);
+ memcpy (q, fname, fname_length);
+ }
+ } else if (*bp) {
+ error ("invalid format #line command");
+ return;
+ }
+
+ ip->lineno = new_lineno;
+ output_line_command (ip, op, 0, file_change);
+ check_expand (op, ip->length - (ip->bufp - ip->buf));
+}
+
+/*
+ * remove all definitions of symbol from symbol table.
+ * according to un*x /lib/cpp, it is not an error to undef
+ * something that has no definitions, so it isn't one here either.
+ */
+void
+do_undef (buf, limit, op, keyword)
+ U_CHAR *buf;
+ U_CHAR *limit ATTRIBUTE_UNUSED;
+ FILE_BUF *op ATTRIBUTE_UNUSED;
+ struct directive *keyword ATTRIBUTE_UNUSED;
+{
+ HASHNODE *hp;
+
+ SKIP_WHITE_SPACE (buf);
+
+ if (! strncmp ((char *)buf, "defined", 7) && ! is_idchar[buf[7]])
+ warning ("undefining `defined'");
+
+ while ((hp = lookup (buf, -1, -1)) != NULL) {
+ if (hp->type != T_MACRO)
+ warning ("undefining `%s'", hp->name);
+ delete_macro (hp);
+ }
+}
+
+/*
+ * handle #if command by
+ * 1) inserting special `defined' keyword into the hash table
+ * that gets turned into 0 or 1 by special_symbol (thus,
+ * if the luser has a symbol called `defined' already, it won't
+ * work inside the #if command)
+ * 2) rescan the input into a temporary output buffer
+ * 3) pass the output buffer to the yacc parser and collect a value
+ * 4) clean up the mess left from steps 1 and 2.
+ * 5) call conditional_skip to skip til the next #endif (etc.),
+ * or not, depending on the value from step 3.
+ */
+void
+do_if (buf, limit, op, keyword)
+ U_CHAR *buf, *limit;
+ FILE_BUF *op ATTRIBUTE_UNUSED;
+ struct directive *keyword ATTRIBUTE_UNUSED;
+{
+ int value;
+ FILE_BUF *ip = &instack[indepth];
+
+ value = eval_if_expression (buf, limit - buf);
+ conditional_skip (ip, value == 0, T_IF);
+}
+
+/*
+ * handle a #elif directive by not changing if_stack either.
+ * see the comment above do_else.
+ */
+void
+do_elif (buf, limit, op, keyword)
+ U_CHAR *buf, *limit;
+ FILE_BUF *op;
+ struct directive *keyword ATTRIBUTE_UNUSED;
+{
+ int value;
+ FILE_BUF *ip = &instack[indepth];
+
+ if (if_stack == instack[indepth].if_stack) {
+ error ("#elif not within a conditional");
+ return;
+ } else {
+ if (if_stack->type != T_IF && if_stack->type != T_ELIF) {
+ error ("#elif after #else");
+ fprintf (stderr, " (matches line %d", if_stack->lineno);
+ if (if_stack->fname != NULL && ip->fname != NULL &&
+ strcmp (if_stack->fname, ip->fname) != 0)
+ fprintf (stderr, ", file %s", if_stack->fname);
+ fprintf (stderr, ")\n");
+ }
+ if_stack->type = T_ELIF;
+ }
+
+ if (if_stack->if_succeeded)
+ skip_if_group (ip, 0);
+ else {
+ value = eval_if_expression (buf, limit - buf);
+ if (value == 0)
+ skip_if_group (ip, 0);
+ else {
+ ++if_stack->if_succeeded; /* continue processing input */
+ output_line_command (ip, op, 1, same_file);
+ }
+ }
+}
+
+/*
+ * evaluate a #if expression in BUF, of length LENGTH,
+ * then parse the result as a C expression and return the value as an int.
+ */
+int
+eval_if_expression (buf, length)
+ U_CHAR *buf;
+ int length;
+{
+ FILE_BUF temp_obuf;
+ HASHNODE *save_defined;
+ int value;
+
+ save_defined = install (U"defined", -1, T_SPEC_DEFINED, -1);
+ temp_obuf = expand_to_temp_buffer (buf, buf + length, 0);
+ delete_macro (save_defined); /* clean up special symbol */
+
+ value = parse_c_expression ((char *)temp_obuf.buf);
+
+ free (temp_obuf.buf);
+
+ return value;
+}
+
+/*
+ * routine to handle ifdef/ifndef. Try to look up the symbol,
+ * then do or don't skip to the #endif/#else/#elif depending
+ * on what directive is actually being processed.
+ */
+void
+do_xifdef (buf, limit, op, keyword)
+ U_CHAR *buf, *limit;
+ FILE_BUF *op ATTRIBUTE_UNUSED;
+ struct directive *keyword;
+{
+ int skip;
+ FILE_BUF *ip = &instack[indepth];
+ U_CHAR *end;
+
+ /* Discard leading and trailing whitespace. */
+ SKIP_WHITE_SPACE (buf);
+ while (limit != buf && is_hor_space[limit[-1]]) limit--;
+
+ /* Find the end of the identifier at the beginning. */
+ for (end = buf; is_idchar[*end]; end++);
+
+ if (end == buf) {
+ skip = (keyword->type == T_IFDEF);
+ } else {
+ skip = (lookup (buf, end-buf, -1) == NULL) ^ (keyword->type == T_IFNDEF);
+ }
+
+ conditional_skip (ip, skip, T_IF);
+}
+
+/*
+ * push TYPE on stack; then, if SKIP is nonzero, skip ahead.
+ */
+void
+conditional_skip (ip, skip, type)
+ FILE_BUF *ip;
+ int skip;
+ enum node_type type;
+{
+ IF_STACK_FRAME *temp;
+
+ temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME));
+ temp->fname = ip->fname;
+ temp->lineno = ip->lineno;
+ temp->next = if_stack;
+ if_stack = temp;
+
+ if_stack->type = type;
+
+ if (skip != 0) {
+ skip_if_group (ip, 0);
+ return;
+ } else {
+ ++if_stack->if_succeeded;
+ output_line_command (ip, &outbuf, 1, same_file);
+ }
+}
+
+/*
+ * skip to #endif, #else, or #elif. adjust line numbers, etc.
+ * leaves input ptr at the sharp sign found.
+ * If ANY is nonzero, return at next directive of any sort.
+ */
+void
+skip_if_group (ip, any)
+ FILE_BUF *ip;
+ int any;
+{
+ register U_CHAR *bp = ip->bufp, *cp;
+ register U_CHAR *endb = ip->buf + ip->length;
+ struct directive *kt;
+ IF_STACK_FRAME *save_if_stack = if_stack; /* don't pop past here */
+ U_CHAR *beg_of_line = bp;
+
+ while (bp < endb) {
+ switch (*bp++) {
+ case '/': /* possible comment */
+ if (*bp == '\\' && bp[1] == '\n')
+ newline_fix (bp);
+ if (*bp == '*') {
+ ip->bufp = ++bp;
+ bp = skip_to_end_of_comment (ip, &ip->lineno);
+ }
+ break;
+ case '\"':
+ case '\'':
+ bp = skip_quoted_string (bp - 1, endb, ip->lineno, &ip->lineno, 0, 0);
+ break;
+ case '\\':
+ /* Char after backslash loses its special meaning. */
+ if (bp < endb) {
+ if (*bp == '\n')
+ ++ip->lineno; /* But do update the line-count. */
+ bp++;
+ }
+ break;
+ case '\n':
+ ++ip->lineno;
+ beg_of_line = bp;
+ break;
+ case '#':
+ ip->bufp = bp - 1;
+
+ /* # keyword: a # must be first nonblank char on the line */
+ if (beg_of_line == 0)
+ break;
+ /* Scan from start of line, skipping whitespace, comments
+ and backslash-newlines, and see if we reach this #.
+ If not, this # is not special. */
+ bp = beg_of_line;
+ while (1) {
+ if (is_hor_space[*bp])
+ bp++;
+ else if (*bp == '\\' && bp[1] == '\n')
+ bp += 2;
+ else if (*bp == '/' && bp[1] == '*') {
+ bp += 2;
+ while (!(*bp == '*' && bp[1] == '/')) {
+ if (*bp == '\n')
+ ip->lineno++;
+ bp++;
+ }
+ bp += 2;
+ }
+ else break;
+ }
+ if (bp != ip->bufp) {
+ bp = ip->bufp + 1; /* Reset bp to after the #. */
+ break;
+ }
+
+ bp = ip->bufp + 1; /* Point after '#'. */
+
+ /* Skip whitespace and \-newline. */
+ while (1) {
+ if (is_hor_space[*bp])
+ bp++;
+ else if (*bp == '\\' && bp[1] == '\n')
+ bp += 2;
+ else if (*bp == '/' && bp[1] == '*') {
+ bp += 2;
+ while (!(*bp == '*' && bp[1] == '/'))
+ bp++;
+ bp += 2;
+ }
+ else break;
+ }
+
+ cp = bp;
+
+ /* Now find end of directive name.
+ If we encounter a backslash-newline, exchange it with any following
+ symbol-constituents so that we end up with a contiguous name. */
+
+ while (1) {
+ if (is_idchar[*bp])
+ bp++;
+ else {
+ if (*bp == '\\' && bp[1] == '\n')
+ name_newline_fix (bp);
+ if (is_idchar[*bp])
+ bp++;
+ else break;
+ }
+ }
+
+ for (kt = directive_table; kt->length >= 0; kt++) {
+ IF_STACK_FRAME *temp;
+ if (strncmp ((char *)cp, kt->name, kt->length) == 0
+ && !is_idchar[cp[kt->length]]) {
+
+ /* If we are asked to return on next directive,
+ do so now. */
+ if (any)
+ return;
+
+ switch (kt->type) {
+ case T_IF:
+ case T_IFDEF:
+ case T_IFNDEF:
+ temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME));
+ temp->next = if_stack;
+ if_stack = temp;
+ temp->lineno = ip->lineno;
+ temp->fname = ip->fname;
+ temp->type = kt->type;
+ break;
+ case T_ELSE:
+ case T_ENDIF:
+ case T_ELIF:
+ if (if_stack == instack[indepth].if_stack) {
+ error ("#%s not within a conditional", kt->name);
+ break;
+ }
+ else if (if_stack == save_if_stack)
+ return; /* found what we came for */
+
+ if (kt->type != T_ENDIF) {
+ if (if_stack->type == T_ELSE)
+ error ("#else or #elif after #else");
+ if_stack->type = kt->type;
+ break;
+ }
+
+ temp = if_stack;
+ if_stack = if_stack->next;
+ free (temp);
+ break;
+
+ default:
+ /* Anything else is ignored. */
+ break;
+ }
+ break;
+ }
+ }
+ }
+ }
+ ip->bufp = bp;
+ /* after this returns, rescan will exit because ip->bufp
+ now points to the end of the buffer.
+ rescan is responsible for the error message also. */
+}
+
+/*
+ * handle a #else directive. Do this by just continuing processing
+ * without changing if_stack ; this is so that the error message
+ * for missing #endif's etc. will point to the original #if. It
+ * is possible that something different would be better.
+ */
+void
+do_else (buf, limit, op, keyword)
+ U_CHAR *buf ATTRIBUTE_UNUSED;
+ U_CHAR *limit ATTRIBUTE_UNUSED;
+ FILE_BUF *op;
+ struct directive *keyword ATTRIBUTE_UNUSED;
+{
+ FILE_BUF *ip = &instack[indepth];
+
+ if (if_stack == instack[indepth].if_stack) {
+ error ("#else not within a conditional");
+ return;
+ } else {
+ if (if_stack->type != T_IF && if_stack->type != T_ELIF) {
+ error ("#else after #else");
+ fprintf (stderr, " (matches line %d", if_stack->lineno);
+ if (strcmp (if_stack->fname, ip->fname) != 0)
+ fprintf (stderr, ", file %s", if_stack->fname);
+ fprintf (stderr, ")\n");
+ }
+ if_stack->type = T_ELSE;
+ }
+
+ if (if_stack->if_succeeded)
+ skip_if_group (ip, 0);
+ else {
+ ++if_stack->if_succeeded; /* continue processing input */
+ output_line_command (ip, op, 1, same_file);
+ }
+}
+
+/*
+ * unstack after #endif command
+ */
+void
+do_endif (buf, limit, op, keyword)
+ U_CHAR *buf ATTRIBUTE_UNUSED;
+ U_CHAR *limit ATTRIBUTE_UNUSED;
+ FILE_BUF *op;
+ struct directive *keyword ATTRIBUTE_UNUSED;
+{
+ if (if_stack == instack[indepth].if_stack)
+ error ("unbalanced #endif");
+ else {
+ IF_STACK_FRAME *temp = if_stack;
+ if_stack = if_stack->next;
+ free (temp);
+ output_line_command (&instack[indepth], op, 1, same_file);
+ }
+}
+
+/*
+ * Skip a comment, assuming the input ptr immediately follows the
+ * initial slash-star. Bump line counter as necessary.
+ * (The canonical line counter is &ip->lineno).
+ * Don't use this routine (or the next one) if bumping the line
+ * counter is not sufficient to deal with newlines in the string.
+ */
+U_CHAR *
+skip_to_end_of_comment (ip, line_counter)
+ register FILE_BUF *ip;
+ int *line_counter; /* place to remember newlines, or NULL */
+{
+ register U_CHAR *limit = ip->buf + ip->length;
+ register U_CHAR *bp = ip->bufp;
+ FILE_BUF *op = &outbuf; /* JF */
+ int output = put_out_comments && !line_counter;
+
+ /* JF this line_counter stuff is a crock to make sure the
+ comment is only put out once, no matter how many times
+ the comment is skipped. It almost works */
+ if (output) {
+ *op->bufp++ = '/';
+ *op->bufp++ = '*';
+ }
+ while (bp < limit) {
+ if (output)
+ *op->bufp++ = *bp;
+ switch (*bp++) {
+ case '/':
+ if (warn_comments && bp < limit && *bp == '*')
+ warning("`/*' within comment");
+ break;
+ case '\n':
+ if (line_counter != NULL)
+ ++*line_counter;
+ if (output)
+ ++op->lineno;
+ break;
+ case '*':
+ if (*bp == '\\' && bp[1] == '\n')
+ newline_fix (bp);
+ if (*bp == '/') {
+ if (output)
+ *op->bufp++ = '/';
+ ip->bufp = ++bp;
+ return bp;
+ }
+ break;
+ }
+ }
+ ip->bufp = bp;
+ return bp;
+}
+
+/*
+ * Skip over a quoted string. BP points to the opening quote.
+ * Returns a pointer after the closing quote. Don't go past LIMIT.
+ * START_LINE is the line number of the starting point (but it need
+ * not be valid if the starting point is inside a macro expansion).
+ *
+ * The input stack state is not changed.
+ *
+ * If COUNT_NEWLINES is nonzero, it points to an int to increment
+ * for each newline passed.
+ *
+ * If BACKSLASH_NEWLINES_P is nonzero, store 1 thru it
+ * if we pass a backslash-newline.
+ *
+ * If EOFP is nonzero, set *EOFP to 1 if the string is unterminated.
+ */
+U_CHAR *
+skip_quoted_string (bp, limit, start_line, count_newlines, backslash_newlines_p, eofp)
+ register U_CHAR *bp;
+ register U_CHAR *limit;
+ int start_line;
+ int *count_newlines;
+ int *backslash_newlines_p;
+ int *eofp;
+{
+ register U_CHAR c, match;
+
+ match = *bp++;
+ while (1) {
+ if (bp >= limit) {
+ error_with_line (line_for_error (start_line),
+ "unterminated string or character constant");
+ if (eofp)
+ *eofp = 1;
+ break;
+ }
+ c = *bp++;
+ if (c == '\\') {
+ while (*bp == '\\' && bp[1] == '\n') {
+ if (backslash_newlines_p)
+ *backslash_newlines_p = 1;
+ if (count_newlines)
+ ++*count_newlines;
+ bp += 2;
+ }
+ if (*bp == '\n' && count_newlines) {
+ if (backslash_newlines_p)
+ *backslash_newlines_p = 1;
+ ++*count_newlines;
+ }
+ bp++;
+ } else if (c == '\n') {
+ /* Unterminated strings and character constants are 'legal'. */
+ bp--; /* Don't consume the newline. */
+ if (eofp)
+ *eofp = 1;
+ break;
+ } else if (c == match)
+ break;
+ }
+ return bp;
+}
+
+/*
+ * write out a #line command, for instance, after an #include file.
+ * If CONDITIONAL is nonzero, we can omit the #line if it would
+ * appear to be a no-op, and we can output a few newlines instead
+ * if we want to increase the line number by a small amount.
+ * FILE_CHANGE says whether we are entering a file, leaving, or neither.
+ */
+
+void
+output_line_command (ip, op, conditional, file_change)
+ FILE_BUF *ip, *op;
+ int conditional;
+ enum file_change_code file_change;
+{
+ int len;
+ char line_cmd_buf[500];
+
+ if (no_line_commands
+ || ip->fname == NULL
+ || no_output) {
+ op->lineno = ip->lineno;
+ return;
+ }
+
+ if (conditional) {
+ if (ip->lineno == op->lineno)
+ return;
+
+ /* If the inherited line number is a little too small,
+ output some newlines instead of a #line command. */
+ if (ip->lineno > op->lineno && ip->lineno < op->lineno + 8) {
+ check_expand (op, 10);
+ while (ip->lineno > op->lineno) {
+ *op->bufp++ = '\n';
+ op->lineno++;
+ }
+ return;
+ }
+ }
+
+ sprintf (line_cmd_buf, "# %d \"%s\"", ip->lineno, ip->fname);
+ if (file_change != same_file)
+ strcat (line_cmd_buf, file_change == enter_file ? " 1" : " 2");
+ len = strlen (line_cmd_buf);
+ line_cmd_buf[len++] = '\n';
+ check_expand (op, len + 1);
+ if (op->bufp > op->buf && op->bufp[-1] != '\n')
+ *op->bufp++ = '\n';
+ memcpy (op->bufp, line_cmd_buf, len);
+ op->bufp += len;
+ op->lineno = ip->lineno;
+}
+
+
+/* Expand a macro call.
+ HP points to the symbol that is the macro being called.
+ Put the result of expansion onto the input stack
+ so that subsequent input by our caller will use it.
+
+ If macro wants arguments, caller has already verified that
+ an argument list follows; arguments come from the input stack. */
+
+void
+macroexpand (hp, op)
+ HASHNODE *hp;
+ FILE_BUF *op;
+{
+ int nargs;
+ DEFINITION *defn = hp->value.defn;
+ register U_CHAR *xbuf;
+ int xbuf_len;
+ int start_line = instack[indepth].lineno;
+
+ CHECK_DEPTH (return;);
+
+ /* it might not actually be a macro. */
+ if (hp->type != T_MACRO) {
+ special_symbol (hp, op);
+ return;
+ }
+
+ nargs = defn->nargs;
+
+ if (nargs >= 0) {
+ register int i;
+ struct argdata *args;
+ const char *parse_error = 0;
+
+ args = (struct argdata *) alloca ((nargs + 1) * sizeof (struct argdata));
+
+ for (i = 0; i < nargs; i++) {
+ args[i].raw = args[i].expanded = (U_CHAR *) "";
+ args[i].raw_length = args[i].expand_length
+ = args[i].stringified_length = 0;
+ args[i].free1 = args[i].free2 = 0;
+ }
+
+ /* Parse all the macro args that are supplied. I counts them.
+ The first NARGS args are stored in ARGS.
+ The rest are discarded. */
+ i = 0;
+ do {
+ /* Discard the open-parenthesis or comma before the next arg. */
+ ++instack[indepth].bufp;
+ parse_error
+ = macarg ((i < nargs || (nargs == 0 && i == 0)) ? &args[i] : 0);
+ if (parse_error)
+ {
+ error_with_line (line_for_error (start_line), parse_error);
+ break;
+ }
+ i++;
+ } while (*instack[indepth].bufp != ')');
+
+ /* If we got one arg but it was just whitespace, call that 0 args. */
+ if (i == 1) {
+ register U_CHAR *bp = args[0].raw;
+ register U_CHAR *lim = bp + args[0].raw_length;
+ while (bp != lim && is_space[*bp]) bp++;
+ if (bp == lim)
+ i = 0;
+ }
+
+ if (nargs == 0 && i > 0)
+ error ("arguments given to macro `%s'", hp->name);
+ else if (i < nargs) {
+ /* traditional C allows foo() if foo wants one argument. */
+ if (nargs == 1 && i == 0)
+ ;
+ else if (i == 0)
+ error ("no args to macro `%s'", hp->name);
+ else if (i == 1)
+ error ("only 1 arg to macro `%s'", hp->name);
+ else
+ error ("only %d args to macro `%s'", i, hp->name);
+ } else if (i > nargs)
+ error ("too many (%d) args to macro `%s'", i, hp->name);
+
+ /* Swallow the closeparen. */
+ ++instack[indepth].bufp;
+
+ /* If macro wants zero args, we parsed the arglist for checking only.
+ Read directly from the macro definition. */
+ if (nargs == 0) {
+ xbuf = defn->expansion;
+ xbuf_len = defn->length;
+ } else {
+ register U_CHAR *exp = defn->expansion;
+ register int offset; /* offset in expansion,
+ copied a piece at a time */
+ register int totlen; /* total amount of exp buffer filled so far */
+
+ register struct reflist *ap;
+
+ /* Macro really takes args. Compute the expansion of this call. */
+
+ /* Compute length in characters of the macro's expansion. */
+ xbuf_len = defn->length;
+ for (ap = defn->pattern; ap != NULL; ap = ap->next) {
+ if (ap->stringify)
+ xbuf_len += args[ap->argno].stringified_length;
+ else
+ xbuf_len += args[ap->argno].raw_length;
+ }
+
+ xbuf = (U_CHAR *) xmalloc (xbuf_len + 1);
+
+ /* Generate in XBUF the complete expansion
+ with arguments substituted in.
+ TOTLEN is the total size generated so far.
+ OFFSET is the index in the definition
+ of where we are copying from. */
+ offset = totlen = 0;
+ for (ap = defn->pattern; ap != NULL; ap = ap->next) {
+ register struct argdata *arg = &args[ap->argno];
+
+ for (i = 0; i < ap->nchars; i++)
+ xbuf[totlen++] = exp[offset++];
+
+ if (ap->stringify != 0) {
+ int arglen = arg->raw_length;
+ int escaped = 0;
+ int in_string = 0;
+ int c;
+ i = 0;
+ while (i < arglen
+ && (c = arg->raw[i], is_space[c]))
+ i++;
+ while (i < arglen
+ && (c = arg->raw[arglen - 1], is_space[c]))
+ arglen--;
+ for (; i < arglen; i++) {
+ c = arg->raw[i];
+
+ /* Special markers Newline Space
+ generate nothing for a stringified argument. */
+ if (c == '\n' && arg->raw[i+1] != '\n') {
+ i++;
+ continue;
+ }
+
+ /* Internal sequences of whitespace are replaced by one space
+ except within an string or char token. */
+ if (! in_string
+ && (c == '\n' ? arg->raw[i+1] == '\n' : is_space[c])) {
+ while (1) {
+ /* Note that Newline Space does occur within whitespace
+ sequences; consider it part of the sequence. */
+ if (c == '\n' && is_space[arg->raw[i+1]])
+ i += 2;
+ else if (c != '\n' && is_space[c])
+ i++;
+ else break;
+ c = arg->raw[i];
+ }
+ i--;
+ c = ' ';
+ }
+
+ if (escaped)
+ escaped = 0;
+ else {
+ if (c == '\\')
+ escaped = 1;
+ if (in_string) {
+ if (c == in_string)
+ in_string = 0;
+ } else if (c == '\"' || c == '\'')
+ in_string = c;
+ }
+
+ /* Escape these chars */
+ if (c == '\"' || (in_string && c == '\\'))
+ xbuf[totlen++] = '\\';
+ if (isprint (c))
+ xbuf[totlen++] = c;
+ else {
+ sprintf ((char *) &xbuf[totlen], "\\%03o", (unsigned int) c);
+ totlen += 4;
+ }
+ }
+ } else {
+ U_CHAR *p1 = arg->raw;
+ U_CHAR *l1 = p1 + arg->raw_length;
+
+ if (ap->raw_before) {
+ while (p1 != l1 && is_space[*p1]) p1++;
+ while (p1 != l1 && is_idchar[*p1])
+ xbuf[totlen++] = *p1++;
+ /* Delete any no-reexpansion marker that follows
+ an identifier at the beginning of the argument
+ if the argument is concatenated with what precedes it. */
+ if (p1[0] == '\n' && p1[1] == '-')
+ p1 += 2;
+ }
+ if (ap->raw_after) {
+ /* Arg is concatenated after: delete trailing whitespace,
+ whitespace markers, and no-reexpansion markers. */
+ while (p1 != l1) {
+ if (is_space[l1[-1]]) l1--;
+ else if (l1[-1] == '-') {
+ U_CHAR *p2 = l1 - 1;
+ /* If a `-' is preceded by an odd number of newlines then it
+ and the last newline are a no-reexpansion marker. */
+ while (p2 != p1 && p2[-1] == '\n') p2--;
+ if ((l1 - 1 - p2) & 1) {
+ l1 -= 2;
+ }
+ else break;
+ }
+ else break;
+ }
+ }
+ memmove (xbuf + totlen, p1, l1 - p1);
+ totlen += l1 - p1;
+ }
+
+ if (totlen > xbuf_len)
+ abort ();
+ }
+
+ /* if there is anything left of the definition
+ after handling the arg list, copy that in too. */
+
+ for (i = offset; i < defn->length; i++)
+ xbuf[totlen++] = exp[i];
+
+ xbuf[totlen] = 0;
+ xbuf_len = totlen;
+
+ for (i = 0; i < nargs; i++) {
+ if (args[i].free1 != 0)
+ free (args[i].free1);
+ if (args[i].free2 != 0)
+ free (args[i].free2);
+ }
+ }
+ } else {
+ xbuf = defn->expansion;
+ xbuf_len = defn->length;
+ }
+
+ /* Now put the expansion on the input stack
+ so our caller will commence reading from it. */
+ {
+ register FILE_BUF *ip2;
+
+ ip2 = &instack[++indepth];
+
+ ip2->fname = 0;
+ ip2->lineno = 0;
+ ip2->buf = xbuf;
+ ip2->length = xbuf_len;
+ ip2->bufp = xbuf;
+ ip2->free_ptr = (nargs > 0) ? xbuf : 0;
+ ip2->macro = hp;
+ ip2->if_stack = if_stack;
+ }
+}
+
+/*
+ * Parse a macro argument and store the info on it into *ARGPTR.
+ * Return nonzero to indicate a syntax error.
+ */
+
+const char *
+macarg (argptr)
+ register struct argdata *argptr;
+{
+ FILE_BUF *ip = &instack[indepth];
+ int paren = 0;
+ int newlines = 0;
+ int comments = 0;
+
+ /* Try to parse as much of the argument as exists at this
+ input stack level. */
+ U_CHAR *bp = macarg1 (ip->bufp, ip->buf + ip->length,
+ &paren, &newlines, &comments);
+
+ /* If we find the end of the argument at this level,
+ set up *ARGPTR to point at it in the input stack. */
+ if (!(ip->fname != 0 && (newlines != 0 || comments != 0))
+ && bp != ip->buf + ip->length) {
+ if (argptr != 0) {
+ argptr->raw = ip->bufp;
+ argptr->raw_length = bp - ip->bufp;
+ }
+ ip->bufp = bp;
+ } else {
+ /* This input stack level ends before the macro argument does.
+ We must pop levels and keep parsing.
+ Therefore, we must allocate a temporary buffer and copy
+ the macro argument into it. */
+ int bufsize = bp - ip->bufp;
+ int extra = newlines;
+ U_CHAR *buffer = (U_CHAR *) xmalloc (bufsize + extra + 1);
+ int final_start = 0;
+
+ memcpy (buffer, ip->bufp, bufsize);
+ ip->bufp = bp;
+ ip->lineno += newlines;
+
+ while (bp == ip->buf + ip->length) {
+ if (instack[indepth].macro == 0) {
+ free (buffer);
+ return "unterminated macro call";
+ }
+ ip->macro->type = T_MACRO;
+ if (ip->free_ptr)
+ free (ip->free_ptr);
+ ip = &instack[--indepth];
+ newlines = 0;
+ comments = 0;
+ bp = macarg1 (ip->bufp, ip->buf + ip->length, &paren,
+ &newlines, &comments);
+ final_start = bufsize;
+ bufsize += bp - ip->bufp;
+ extra += newlines;
+ buffer = (U_CHAR *) xrealloc (buffer, bufsize + extra + 1);
+ memcpy (buffer + bufsize - (bp - ip->bufp), ip->bufp, bp - ip->bufp);
+ ip->bufp = bp;
+ ip->lineno += newlines;
+ }
+
+ /* Now, if arg is actually wanted, record its raw form,
+ discarding comments and duplicating newlines in whatever
+ part of it did not come from a macro expansion.
+ EXTRA space has been preallocated for duplicating the newlines.
+ FINAL_START is the index of the start of that part. */
+ if (argptr != 0) {
+ argptr->raw = buffer;
+ argptr->raw_length = bufsize;
+ argptr->free1 = buffer;
+ argptr->newlines = newlines;
+ argptr->comments = comments;
+ if ((newlines || comments) && ip->fname != 0)
+ argptr->raw_length
+ = final_start +
+ discard_comments (argptr->raw + final_start,
+ argptr->raw_length - final_start,
+ newlines);
+ argptr->raw[argptr->raw_length] = 0;
+ if (argptr->raw_length > bufsize + extra)
+ abort ();
+ }
+ }
+
+ /* If we are not discarding this argument,
+ macroexpand it and compute its length as stringified.
+ All this info goes into *ARGPTR. */
+
+ if (argptr != 0) {
+ FILE_BUF obuf;
+ register U_CHAR *buf, *lim;
+ register int totlen;
+
+ obuf = expand_to_temp_buffer (argptr->raw,
+ argptr->raw + argptr->raw_length,
+ 1);
+
+ argptr->expanded = obuf.buf;
+ argptr->expand_length = obuf.length;
+ argptr->free2 = obuf.buf;
+
+ buf = argptr->raw;
+ lim = buf + argptr->raw_length;
+
+ totlen = 0;
+ while (buf != lim) {
+ register U_CHAR c = *buf++;
+ totlen++;
+ /* Internal sequences of whitespace are replaced by one space
+ in most cases, but not always. So count all the whitespace
+ in case we need to keep it all. */
+ if (c == '\"' || c == '\\') /* escape these chars */
+ totlen++;
+ else if (!isprint (c))
+ totlen += 3;
+ }
+ argptr->stringified_length = totlen;
+ }
+ return 0;
+}
+
+/* Scan text from START (inclusive) up to LIMIT (exclusive),
+ counting parens in *DEPTHPTR,
+ and return if reach LIMIT
+ or before a `)' that would make *DEPTHPTR negative
+ or before a comma when *DEPTHPTR is zero.
+ Single and double quotes are matched and termination
+ is inhibited within them. Comments also inhibit it.
+ Value returned is pointer to stopping place.
+
+ Increment *NEWLINES each time a newline is passed.
+ Set *COMMENTS to 1 if a comment is seen. */
+
+U_CHAR *
+macarg1 (start, limit, depthptr, newlines, comments)
+ U_CHAR *start;
+ register U_CHAR *limit;
+ int *depthptr, *newlines, *comments;
+{
+ register U_CHAR *bp = start;
+
+ while (bp < limit) {
+ switch (*bp) {
+ case '(':
+ (*depthptr)++;
+ break;
+ case ')':
+ if (--(*depthptr) < 0)
+ return bp;
+ break;
+ case '\\':
+ /* Traditionally, backslash makes following char not special. */
+ if (bp + 1 < limit)
+ {
+ bp++;
+ /* But count source lines anyway. */
+ if (*bp == '\n')
+ ++*newlines;
+ }
+ break;
+ case '\n':
+ ++*newlines;
+ break;
+ case '/':
+ if (bp[1] == '\\' && bp[2] == '\n')
+ newline_fix (bp + 1);
+ if (bp[1] != '*' || bp + 1 >= limit)
+ break;
+ *comments = 1;
+ bp += 2;
+ while (bp + 1 < limit) {
+ if (bp[0] == '*'
+ && bp[1] == '\\' && bp[2] == '\n')
+ newline_fix (bp + 1);
+ if (bp[0] == '*' && bp[1] == '/')
+ break;
+ if (*bp == '\n') ++*newlines;
+ bp++;
+ }
+ bp += 1;
+ break;
+ case '\'':
+ case '\"':
+ {
+ int quotec;
+ for (quotec = *bp++; bp + 1 < limit && *bp != quotec; bp++) {
+ if (*bp == '\\') {
+ bp++;
+ if (*bp == '\n')
+ ++*newlines;
+ while (*bp == '\\' && bp[1] == '\n') {
+ bp += 2;
+ }
+ } else if (*bp == '\n') {
+ ++*newlines;
+ if (quotec == '\'')
+ break;
+ }
+ }
+ }
+ break;
+ case ',':
+ if ((*depthptr) == 0)
+ return bp;
+ break;
+ }
+ bp++;
+ }
+
+ return bp;
+}
+
+/* Discard comments and duplicate newlines
+ in the string of length LENGTH at START,
+ except inside of string constants.
+ The string is copied into itself with its beginning staying fixed.
+
+ NEWLINES is the number of newlines that must be duplicated.
+ We assume that that much extra space is available past the end
+ of the string. */
+
+int
+discard_comments (start, length, newlines)
+ U_CHAR *start;
+ int length;
+ int newlines;
+{
+ register U_CHAR *ibp;
+ register U_CHAR *obp;
+ register U_CHAR *limit;
+ register int c;
+
+ /* If we have newlines to duplicate, copy everything
+ that many characters up. Then, in the second part,
+ we will have room to insert the newlines
+ while copying down.
+ NEWLINES may actually be too large, because it counts
+ newlines in string constants, and we don't duplicate those.
+ But that does no harm. */
+ if (newlines > 0) {
+ ibp = start + length;
+ obp = ibp + newlines;
+ limit = start;
+ while (limit != ibp)
+ *--obp = *--ibp;
+ }
+
+ ibp = start + newlines;
+ limit = start + length + newlines;
+ obp = start;
+
+ while (ibp < limit) {
+ *obp++ = c = *ibp++;
+ switch (c) {
+ case '\n':
+ /* Duplicate the newline. */
+ *obp++ = '\n';
+ break;
+
+ case '\\':
+ if (*ibp == '\n') {
+ obp--;
+ ibp++;
+ }
+ break;
+
+ case '/':
+ if (*ibp == '\\' && ibp[1] == '\n')
+ newline_fix (ibp);
+ /* Delete any comment. */
+ if (ibp[0] != '*' || ibp + 1 >= limit)
+ break;
+ obp--;
+ ibp++;
+ while (ibp + 1 < limit) {
+ if (ibp[0] == '*'
+ && ibp[1] == '\\' && ibp[2] == '\n')
+ newline_fix (ibp + 1);
+ if (ibp[0] == '*' && ibp[1] == '/')
+ break;
+ ibp++;
+ }
+ ibp += 2;
+ break;
+
+ case '\'':
+ case '\"':
+ /* Notice and skip strings, so that we don't
+ think that comments start inside them,
+ and so we don't duplicate newlines in them. */
+ {
+ int quotec = c;
+ while (ibp < limit) {
+ *obp++ = c = *ibp++;
+ if (c == quotec)
+ break;
+ if (c == '\n' && quotec == '\'')
+ break;
+ if (c == '\\' && ibp < limit) {
+ while (*ibp == '\\' && ibp[1] == '\n')
+ ibp += 2;
+ *obp++ = *ibp++;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ return obp - start;
+}
+
+
+/* Core error handling routine. */
+void
+v_message (mtype, line, msgid, ap)
+ enum msgtype mtype;
+ int line;
+ const char *msgid;
+ va_list ap;
+{
+ const char *fname = 0;
+ int i;
+
+ if (mtype == WARNING && inhibit_warnings)
+ return;
+
+ for (i = indepth; i >= 0; i--)
+ if (instack[i].fname != NULL) {
+ if (line == 0)
+ line = instack[i].lineno;
+ fname = instack[i].fname;
+ break;
+ }
+
+ if (fname)
+ fprintf (stderr, "%s:%d: ", fname, line);
+ else
+ fprintf (stderr, "%s: ", progname);
+
+ if (mtype == WARNING)
+ fputs ("warning: ", stderr);
+
+ vfprintf (stderr, msgid, ap);
+ putc ('\n', stderr);
+
+ if (mtype == ERROR)
+ errors++;
+}
+
+/*
+ * error - print error message and increment count of errors.
+ */
+void
+error VPARAMS ((const char *msgid, ...))
+{
+#ifndef ANSI_PROTOTYPES
+ const char *msgid;
+#endif
+ va_list ap;
+
+ VA_START(ap, msgid);
+
+#ifndef ANSI_PROTOTYPES
+ msgid = va_arg (ap, const char *);
+#endif
+
+ v_message (ERROR, 0, msgid, ap);
+}
+
+void
+error_with_line VPARAMS ((int line, const char *msgid, ...))
+{
+#ifndef ANSI_PROTOTYPES
+ int line;
+ const char *msgid;
+#endif
+ va_list ap;
+
+ VA_START(ap, msgid);
+
+#ifndef ANSI_PROTOTYPES
+ line = va_arg (ap, int);
+ msgid = va_arg (ap, const char *);
+#endif
+
+ v_message (ERROR, line, msgid, ap);
+}
+
+/* Error including a message from `errno'. */
+void
+error_from_errno (name)
+ const char *name;
+{
+ error ("%s: %s", name, strerror (errno));
+}
+
+/* Print error message but don't count it. */
+void
+warning VPARAMS ((const char *msgid, ...))
+{
+#ifndef ANSI_PROTOTYPES
+ const char *msgid;
+#endif
+ va_list ap;
+
+ VA_START(ap, msgid);
+
+#ifndef ANSI_PROTOTYPES
+ msgid = va_arg (ap, const char *);
+#endif
+
+ v_message (WARNING, 0, msgid, ap);
+}
+
+void
+fatal VPARAMS ((const char *msgid, ...))
+{
+#ifndef ANSI_PROTOTYPES
+ const char *msgid;
+#endif
+ va_list ap;
+
+ VA_START(ap, msgid);
+
+#ifndef ANSI_PROTOTYPES
+ msgid = va_arg (ap, const char *);
+#endif
+
+ v_message (FATAL, 0, msgid, ap);
+ exit (FATAL_EXIT_CODE);
+}
+
+/* More 'friendly' abort that prints the location at which we died. */
+void
+fancy_abort (line, func)
+ int line;
+ const char *func;
+{
+ if (!func)
+ func = "?";
+
+ fatal ("Internal error in \"%s\", at tradcpp.c:%d\n\
+Please submit a full bug report.\n\
+See %s for instructions.", func, line, GCCBUGURL);
+}
+
+void
+perror_with_name (name)
+ const char *name;
+{
+ fprintf (stderr, "%s: %s: %s\n", progname, name, strerror (errno));
+ errors++;
+}
+
+void
+pfatal_with_name (name)
+ const char *name;
+{
+ perror_with_name (name);
+ exit (FATAL_EXIT_CODE);
+}
+
+/* Return the line at which an error occurred.
+ The error is not necessarily associated with the current spot
+ in the input stack, so LINE says where. LINE will have been
+ copied from ip->lineno for the current input level.
+ If the current level is for a file, we return LINE.
+ But if the current level is not for a file, LINE is meaningless.
+ In that case, we return the lineno of the innermost file. */
+int
+line_for_error (line)
+ int line;
+{
+ int i;
+ int line1 = line;
+
+ for (i = indepth; i >= 0; ) {
+ if (instack[i].fname != 0)
+ return line1;
+ i--;
+ if (i < 0)
+ return 0;
+ line1 = instack[i].lineno;
+ }
+ return 0;
+}
+
+/*
+ * If OBUF doesn't have NEEDED bytes after OPTR, make it bigger.
+ *
+ * As things stand, nothing is ever placed in the output buffer to be
+ * removed again except when it's KNOWN to be part of an identifier,
+ * so flushing and moving down everything left, instead of expanding,
+ * should work ok.
+ */
+
+void
+grow_outbuf (obuf, needed)
+ register FILE_BUF *obuf;
+ register int needed;
+{
+ register U_CHAR *p;
+ int minsize;
+
+ if (obuf->length - (obuf->bufp - obuf->buf) > needed)
+ return;
+
+ /* Make it at least twice as big as it is now. */
+ obuf->length *= 2;
+ /* Make it have at least 150% of the free space we will need. */
+ minsize = (3 * needed) / 2 + (obuf->bufp - obuf->buf);
+ if (minsize > obuf->length)
+ obuf->length = minsize;
+
+ p = (U_CHAR *) xrealloc (obuf->buf, obuf->length);
+ obuf->bufp = p + (obuf->bufp - obuf->buf);
+ obuf->buf = p;
+}
+
+/* Symbol table for macro names and special symbols */
+
+/*
+ * install a name in the main hash table, even if it is already there.
+ * name stops with first non alphanumeric, except leading '#'.
+ * caller must check against redefinition if that is desired.
+ * delete_macro () removes things installed by install () in fifo order.
+ * this is important because of the `defined' special symbol used
+ * in #if, and also if pushdef/popdef directives are ever implemented.
+ *
+ * If LEN is >= 0, it is the length of the name.
+ * Otherwise, compute the length by scanning the entire name.
+ *
+ * If HASH is >= 0, it is the precomputed hash code.
+ * Otherwise, compute the hash code.
+ *
+ * caller must set the value, if any is desired.
+ */
+HASHNODE *
+install (name, len, type, hash)
+ const U_CHAR *name;
+ int len;
+ enum node_type type;
+ int hash;
+ /* watch out here if sizeof (U_CHAR *) != sizeof (int) */
+{
+ register HASHNODE *hp;
+ register int bucket;
+ register const U_CHAR *p;
+ U_CHAR *q;
+
+ if (len < 0) {
+ p = name;
+ while (is_idchar[*p])
+ p++;
+ len = p - name;
+ }
+
+ if (hash < 0)
+ hash = hashf (name, len, HASHSIZE);
+
+ hp = (HASHNODE *) xmalloc (sizeof (HASHNODE) + len + 1);
+ bucket = hash;
+ hp->bucket_hdr = &hashtab[bucket];
+ hp->next = hashtab[bucket];
+ hashtab[bucket] = hp;
+ hp->prev = NULL;
+ if (hp->next != NULL)
+ hp->next->prev = hp;
+ hp->type = type;
+ hp->length = len;
+ hp->name = q = ((U_CHAR *) hp) + sizeof (HASHNODE);
+ memcpy (q, name, len);
+ q[len] = 0;
+ return hp;
+}
+
+/*
+ * find the most recent hash node for name name (ending with first
+ * non-identifier char) installed by install
+ *
+ * If LEN is >= 0, it is the length of the name.
+ * Otherwise, compute the length by scanning the entire name.
+ *
+ * If HASH is >= 0, it is the precomputed hash code.
+ * Otherwise, compute the hash code.
+ */
+HASHNODE *
+lookup (name, len, hash)
+ const U_CHAR *name;
+ int len;
+ int hash;
+{
+ register const U_CHAR *bp;
+ register HASHNODE *bucket;
+
+ if (len < 0) {
+ for (bp = name; is_idchar[*bp]; bp++) ;
+ len = bp - name;
+ }
+
+ if (hash < 0)
+ hash = hashf (name, len, HASHSIZE);
+
+ bucket = hashtab[hash];
+ while (bucket) {
+ if (bucket->length == len
+ && strncmp ((char *)bucket->name, (char *)name, len) == 0)
+ return bucket;
+ bucket = bucket->next;
+ }
+ return NULL;
+}
+
+/*
+ * Delete a hash node. Some weirdness to free junk from macros.
+ * More such weirdness will have to be added if you define more hash
+ * types that need it.
+ */
+
+/* Note that the DEFINITION of a macro is removed from the hash table
+ but its storage is not freed. This would be a storage leak
+ except that it is not reasonable to keep undefining and redefining
+ large numbers of macros many times.
+ In any case, this is necessary, because a macro can be #undef'd
+ in the middle of reading the arguments to a call to it.
+ If #undef freed the DEFINITION, that would crash. */
+void
+delete_macro (hp)
+ HASHNODE *hp;
+{
+
+ if (hp->prev != NULL)
+ hp->prev->next = hp->next;
+ if (hp->next != NULL)
+ hp->next->prev = hp->prev;
+
+ /* make sure that the bucket chain header that
+ the deleted guy was on points to the right thing afterwards. */
+ if (hp == *hp->bucket_hdr)
+ *hp->bucket_hdr = hp->next;
+
+ free (hp);
+}
+
+/*
+ * return hash function on name. must be compatible with the one
+ * computed a step at a time, elsewhere
+ */
+int
+hashf (name, len, hashsize)
+ register const U_CHAR *name;
+ register int len;
+ int hashsize;
+{
+ register int r = 0;
+
+ while (len--)
+ r = HASHSTEP (r, *name++);
+
+ return MAKE_POS (r) % hashsize;
+}
+
+/* Dump all macro definitions as #defines to stdout. */
+
+void
+dump_all_macros ()
+{
+ int bucket;
+
+ for (bucket = 0; bucket < HASHSIZE; bucket++) {
+ register HASHNODE *hp;
+
+ for (hp = hashtab[bucket]; hp; hp= hp->next) {
+ if (hp->type == T_MACRO) {
+ register DEFINITION *defn = hp->value.defn;
+ struct reflist *ap;
+ int offset;
+ int concat;
+
+
+ /* Print the definition of the macro HP. */
+
+ printf ("#define %s", hp->name);
+ if (defn->nargs >= 0) {
+ int i;
+
+ printf ("(");
+ for (i = 0; i < defn->nargs; i++) {
+ dump_arg_n (defn, i);
+ if (i + 1 < defn->nargs)
+ printf (", ");
+ }
+ printf (")");
+ }
+
+ printf (" ");
+
+ offset = 0;
+ concat = 0;
+ for (ap = defn->pattern; ap != NULL; ap = ap->next) {
+ dump_defn_1 (defn->expansion, offset, ap->nchars);
+ if (ap->nchars != 0)
+ concat = 0;
+ offset += ap->nchars;
+ if (ap->stringify)
+ printf (" #");
+ if (ap->raw_before && !concat)
+ printf (" ## ");
+ concat = 0;
+ dump_arg_n (defn, ap->argno);
+ if (ap->raw_after) {
+ printf (" ## ");
+ concat = 1;
+ }
+ }
+ dump_defn_1 (defn->expansion, offset, defn->length - offset);
+ printf ("\n");
+ }
+ }
+ }
+}
+
+/* Output to stdout a substring of a macro definition.
+ BASE is the beginning of the definition.
+ Output characters START thru LENGTH.
+ Discard newlines outside of strings, thus
+ converting funny-space markers to ordinary spaces. */
+void
+dump_defn_1 (base, start, length)
+ U_CHAR *base;
+ int start;
+ int length;
+{
+ U_CHAR *p = base + start;
+ U_CHAR *limit = base + start + length;
+
+ while (p < limit) {
+ if (*p != '\n')
+ putchar (*p);
+ else if (*p == '\"' || *p =='\'') {
+ U_CHAR *p1 = skip_quoted_string (p, limit, 0, 0, 0, 0);
+ fwrite (p, p1 - p, 1, stdout);
+ p = p1 - 1;
+ }
+ p++;
+ }
+}
+
+/* Print the name of argument number ARGNUM of macro definition DEFN.
+ Recall that DEFN->argnames contains all the arg names
+ concatenated in reverse order with comma-space in between. */
+void
+dump_arg_n (defn, argnum)
+ DEFINITION *defn;
+ int argnum;
+{
+ register U_CHAR *p = defn->argnames;
+ while (argnum + 1 < defn->nargs) {
+ p = (U_CHAR *) strchr ((char *)p, ' ') + 1;
+ argnum++;
+ }
+
+ while (*p && *p != ',') {
+ putchar (*p);
+ p++;
+ }
+}
+
+/* Initialize syntactic classifications of characters. */
+void
+initialize_char_syntax ()
+{
+ register int i;
+
+ /*
+ * Set up is_idchar and is_idstart tables. These should be
+ * faster than saying (is_alpha (c) || c == '_'), etc.
+ * Must do set up these things before calling any routines tthat
+ * refer to them.
+ */
+ for (i = 'a'; i <= 'z'; i++) {
+ is_idchar[i - 'a' + 'A'] = 1;
+ is_idchar[i] = 1;
+ is_idstart[i - 'a' + 'A'] = 1;
+ is_idstart[i] = 1;
+ }
+ for (i = '0'; i <= '9'; i++)
+ is_idchar[i] = 1;
+ is_idchar['_'] = 1;
+ is_idstart['_'] = 1;
+
+ /* horizontal space table */
+ is_hor_space[' '] = 1;
+ is_hor_space['\t'] = 1;
+ is_hor_space['\v'] = 1;
+ is_hor_space['\f'] = 1;
+ is_hor_space['\r'] = 1;
+
+ is_space[' '] = 1;
+ is_space['\t'] = 1;
+ is_space['\v'] = 1;
+ is_space['\f'] = 1;
+ is_space['\n'] = 1;
+ is_space['\r'] = 1;
+}
+
+/* Initialize the built-in macros. */
+#define DSC(x) U x, sizeof x - 1
+#define install_spec(name, type) \
+ install(DSC(name), type, -1);
+#define install_value(name, val) \
+ hp = install(DSC(name), T_CONST, -1); hp->value.cpval = val;
+void
+initialize_builtins ()
+{
+ HASHNODE *hp;
+
+ install_spec ("__BASE_FILE__", T_BASE_FILE);
+ install_spec ("__DATE__", T_DATE);
+ install_spec ("__FILE__", T_FILE);
+ install_spec ("__TIME__", T_TIME);
+ install_spec ("__VERSION__", T_VERSION);
+ install_spec ("__INCLUDE_LEVEL__", T_INCLUDE_LEVEL);
+ install_spec ("__LINE__", T_SPECLINE);
+
+ install_value ("__SIZE_TYPE__", SIZE_TYPE);
+ install_value ("__PTRDIFF_TYPE__", PTRDIFF_TYPE);
+ install_value ("__WCHAR_TYPE__", WCHAR_TYPE);
+ install_value ("__REGISTER_PREFIX__", REGISTER_PREFIX);
+ install_value ("__USER_LABEL_PREFIX__", user_label_prefix);
+}
+#undef DSC
+#undef install_spec
+#undef install_value
+
+/*
+ * process a given definition string, for initialization
+ * If STR is just an identifier, define it with value 1.
+ * If STR has anything after the identifier, then it should
+ * be identifier-space-definition.
+ */
+void
+make_definition (str)
+ U_CHAR *str;
+{
+ FILE_BUF *ip;
+ struct directive *kt;
+ U_CHAR *buf, *p;
+
+ buf = str;
+ p = str;
+ while (is_idchar[*p]) p++;
+ if (p == str) {
+ error ("malformed option `-D %s'", str);
+ return;
+ }
+ if (*p == 0) {
+ buf = (U_CHAR *) alloca (p - buf + 4);
+ strcpy ((char *)buf, (char *)str);
+ strcat ((char *)buf, " 1");
+ } else if (*p != ' ') {
+ error ("malformed option `-D %s'", str);
+ return;
+ } else {
+ U_CHAR *q;
+ /* Copy the entire option so we can modify it. */
+ buf = (U_CHAR *) alloca (2 * strlen ((char *)str) + 1);
+ strncpy ((char *)buf, (char *)str, p - str);
+ /* Change the = to a space. */
+ buf[p - str] = ' ';
+ /* Scan for any backslash-newline and remove it. */
+ p++;
+ q = &buf[p - str];
+ while (*p) {
+ if (*p == '\\' && p[1] == '\n')
+ p += 2;
+ /* Change newline chars into newline-markers. */
+ else if (*p == '\n')
+ {
+ *q++ = '\n';
+ *q++ = '\n';
+ p++;
+ }
+ else
+ *q++ = *p++;
+ }
+ *q = 0;
+ }
+
+ ip = &instack[++indepth];
+ ip->fname = "*Initialization*";
+
+ ip->buf = ip->bufp = buf;
+ ip->length = strlen ((char *)buf);
+ ip->lineno = 1;
+ ip->macro = 0;
+ ip->free_ptr = 0;
+ ip->if_stack = if_stack;
+
+ for (kt = directive_table; kt->type != T_DEFINE; kt++)
+ ;
+
+ /* pass NULL as output ptr to do_define since we KNOW it never
+ does any output.... */
+ do_define (buf, buf + ip->length, NULL, kt);
+ --indepth;
+}
+
+/* JF, this does the work for the -U option */
+void
+make_undef (str)
+ U_CHAR *str;
+{
+ FILE_BUF *ip;
+ struct directive *kt;
+
+ ip = &instack[++indepth];
+ ip->fname = "*undef*";
+
+ ip->buf = ip->bufp = str;
+ ip->length = strlen ((char *)str);
+ ip->lineno = 1;
+ ip->macro = 0;
+ ip->free_ptr = 0;
+ ip->if_stack = if_stack;
+
+ for (kt = directive_table; kt->type != T_UNDEF; kt++)
+ ;
+
+ do_undef (str, str + ip->length, NULL, kt);
+ --indepth;
+}
+
+/* Add output to `deps_buffer' for the -M switch.
+ STRING points to the text to be output.
+ SIZE is the number of bytes, or 0 meaning output until a null.
+ If SIZE is nonzero, we break the line first, if it is long enough. */
+void
+deps_output (string, size)
+ const char *string;
+ int size;
+{
+#ifndef MAX_OUTPUT_COLUMNS
+#define MAX_OUTPUT_COLUMNS 75
+#endif
+ if (size != 0 && deps_column != 0
+ && size + deps_column > MAX_OUTPUT_COLUMNS) {
+ deps_output ("\\\n ", 0);
+ deps_column = 0;
+ }
+
+ if (size == 0)
+ size = strlen (string);
+
+ if (deps_size + size + 1 > deps_allocated_size) {
+ deps_allocated_size = deps_size + size + 50;
+ deps_allocated_size *= 2;
+ deps_buffer = (char *) xrealloc (deps_buffer, deps_allocated_size);
+ }
+ memcpy (&deps_buffer[deps_size], string, size);
+ deps_size += size;
+ deps_column += size;
+ deps_buffer[deps_size] = 0;
+}
+
+/* Get the file-mode and data size of the file open on FD
+ and store them in *MODE_POINTER and *SIZE_POINTER. */
+
+int
+file_size_and_mode (fd, mode_pointer, size_pointer)
+ int fd;
+ int *mode_pointer;
+ long *size_pointer;
+{
+ struct stat sbuf;
+
+ if (fstat (fd, &sbuf) < 0) return -1;
+ if (mode_pointer) *mode_pointer = sbuf.st_mode;
+ if (size_pointer) *size_pointer = sbuf.st_size;
+ return 0;
+}