* support\cpp2\cppexp.c, support\cpp2\hashtable.h,
authorborutr <borutr@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Mon, 27 Nov 2006 20:03:33 +0000 (20:03 +0000)
committerborutr <borutr@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Mon, 27 Nov 2006 20:03:33 +0000 (20:03 +0000)
  support\cpp2\Makefile.in, support\cpp2\cppfiles.c,
  support\cpp2\output.h, support\cpp2\cppinit.c,
  support\cpp2\cpplib.c, support\cpp2\cpplib.h,
  support\cpp2\Makefile.bcc, support\cpp2\cpphash.c,
  support\cpp2\cppdefault.c, support\cpp2\system.h,
  support\cpp2\cpphash.h, support\cpp2\cpplex.c,
  support\cpp2\cppdefault.h, support\cpp2\mbchar.c,
  support\cpp2\prefix.c, support\cpp2\except.h,
  support\cpp2\hwint.h, support\cpp2\cppmacro.c,
  support\cpp2\line-map.h, support\cpp2\sdcpp.dsp,
  support\cpp2\sdcc.h, support\cpp2\mkdeps.c,
  support\cpp2\version.c, support\cpp2\cppmain.c,
  support\cpp2\version.h, support\cpp2\hashtable.c,
  support\cpp2\cpperror.c:
  synchronized with GCC CPP release version 3.3.6,
  the latest where cppmain.c still exists.
* support\cpp2\sdcppmain.c, support\cpp2\sdcppinit.c: added

git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@4489 4a8a32a2-be11-0410-ad9d-d568d2c75423

32 files changed:
ChangeLog
support/cpp2/Makefile.bcc
support/cpp2/Makefile.in
support/cpp2/cppdefault.c
support/cpp2/cppdefault.h
support/cpp2/cpperror.c
support/cpp2/cppexp.c
support/cpp2/cppfiles.c
support/cpp2/cpphash.c
support/cpp2/cpphash.h
support/cpp2/cppinit.c
support/cpp2/cpplex.c
support/cpp2/cpplib.c
support/cpp2/cpplib.h
support/cpp2/cppmacro.c
support/cpp2/cppmain.c
support/cpp2/except.h
support/cpp2/hashtable.c
support/cpp2/hashtable.h
support/cpp2/hwint.h
support/cpp2/line-map.h
support/cpp2/mbchar.c
support/cpp2/mkdeps.c
support/cpp2/output.h
support/cpp2/prefix.c
support/cpp2/sdcc.h
support/cpp2/sdcpp.dsp
support/cpp2/sdcppinit.c [new file with mode: 0644]
support/cpp2/sdcppmain.c [new file with mode: 0644]
support/cpp2/system.h
support/cpp2/version.c
support/cpp2/version.h

index b1a62f9d6255523ddf0a97c2d1896f4eeb8fe4f8..0268b13c7e651300226f717467c8c8f86afb4d19 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+2006-11-27 Borut Razem <borut.razem AT siol.net>
+
+       * support\cpp2\cppexp.c, support\cpp2\hashtable.h,
+         support\cpp2\Makefile.in, support\cpp2\cppfiles.c,
+         support\cpp2\output.h, support\cpp2\cppinit.c,
+         support\cpp2\cpplib.c, support\cpp2\cpplib.h,
+         support\cpp2\Makefile.bcc, support\cpp2\cpphash.c,
+         support\cpp2\cppdefault.c, support\cpp2\system.h,
+         support\cpp2\cpphash.h, support\cpp2\cpplex.c,
+         support\cpp2\cppdefault.h, support\cpp2\mbchar.c,
+         support\cpp2\prefix.c, support\cpp2\except.h,
+         support\cpp2\hwint.h, support\cpp2\cppmacro.c,
+         support\cpp2\line-map.h, support\cpp2\sdcpp.dsp,
+         support\cpp2\sdcc.h, support\cpp2\mkdeps.c,
+         support\cpp2\version.c, support\cpp2\cppmain.c,
+         support\cpp2\version.h, support\cpp2\hashtable.c,
+         support\cpp2\cpperror.c:
+         synchronized with GCC CPP release version 3.3.6,
+         the latest where cppmain.c still exists.
+       * support\cpp2\sdcppmain.c, support\cpp2\sdcppinit.c: added
+
+2006-11-27 Borut Razem <borut.razem AT siol.net>
+
+       * support/cpp2/cpplex.c:
+         fixed _asm ... _endasm handling bug, introduce with GCC CPP
+         synchronization
+       * support/cpp2/cpplib.c: removed definitions of unused variables
+
 2006-11-26 Borut Razem <borut.razem AT siol.net>
 
        * support/cpp2/libiberty.h: commented out x*alloc() declarations
index 9847fefaef5b552f305027d9c1697264467f04bd..f342da1658932c768877da021c7660a9561ae011 100644 (file)
@@ -6,11 +6,11 @@ PRJDIR          = ../..
 
 CFLAGS = $(CFLAGS) -I. -I./libiberty -DHAVE_CONFIG_H
 
-OBJECTS         = cppmain.obj \
-                  cpplib.obj cpplex.obj cppmacro.obj cppexp.obj cppfiles.obj \
-                  cpphash.obj cpperror.obj cppinit.obj cppdefault.obj \
+OBJECTS         = sdcppmain.obj sdcppinit.obj \
+                  cppmain.obj cpplib.obj cpplex.obj cppmacro.obj cppexp.obj \
+                  cppfiles.obj cpphash.obj cpperror.obj cppdefault.obj \
                   hashtable.obj mkdeps.obj prefix.obj version.obj mbchar.obj \
-                  line-map.obj \
+                  line-map.obj cpptrad.obj \
                   safe-ctype.obj obstack.obj splay-tree.obj lbasename.obj \
                   hex.obj concat.obj
 
index b68dd17290f1c879ecdc2d9e9646aa3346859050..092a35381b9329756a0f5483a007db62f436e89e 100644 (file)
@@ -206,10 +206,10 @@ PREPROCESSOR_DEFINES = \
   -DCROSS_INCLUDE_DIR=\"$(gcc_tooldir)/sys-include\" \
   -DTOOL_INCLUDE_DIR=\"$(gcc_tooldir)/include\"
 
-LIBCPP_OBJS =  cpplib.o cpplex.o cppmacro.o cppexp.o cppfiles.o \
-               cpphash.o cpperror.o cppinit.o cppdefault.o \
+LIBCPP_OBJS =  cppmain.o cpplib.o cpplex.o cppmacro.o cppexp.o cppfiles.o \
+               cpphash.o cpperror.o cppdefault.o \
                hashtable.o mkdeps.o prefix.o version.o mbchar.o \
-               line-map.o
+               line-map.o cpptrad.o
 
 LIBCPP_DEPS =  cpplib.h cpphash.h hashtable.h intl.h $(OBSTACK_H) $(SYSTEM_H)
 
@@ -223,13 +223,16 @@ libcpp.a: $(LIBCPP_OBJS)
 MY_LIBIBERTY_BITS = safe-ctype.o obstack.o splay-tree.o \
                    lbasename.o hex.o concat.o
 
-$(TARGET): cppmain.o $(MY_LIBIBERTY_BITS) libcpp.a $(LIBDEPS)
+$(TARGET): sdcppmain.o sdcppinit.o $(MY_LIBIBERTY_BITS) libcpp.a $(LIBDEPS)
        mkdir -p $(dir $@)
-       $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ cppmain.o \
+       $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ sdcppmain.o sdcppinit.o \
        $(MY_LIBIBERTY_BITS) libcpp.a $(LIBS)
 
-cppmain.o:  cppmain.c  $(CONFIG_H) cpplib.h intl.h $(SYSTEM_H)
+sdcppmain.o:  sdcppmain.c  $(CONFIG_H) cpplib.h $(SYSTEM_H)
+sdcppinit.o:  sdcppinit.c  $(CONFIG_H) $(LIBCPP_DEPS) cppdefault.h \
+               mkdeps.h prefix.h output.h version.h
 
+cppmain.o:  cppmain.c  $(CONFIG_H) cpplib.h intl.h $(SYSTEM_H)
 cpperror.o: cpperror.c $(CONFIG_H) $(LIBCPP_DEPS)
 cppexp.o:   cppexp.c   $(CONFIG_H) $(LIBCPP_DEPS)
 cpplex.o:   cpplex.c   $(CONFIG_H) $(LIBCPP_DEPS) mbchar.h
@@ -237,8 +240,7 @@ cppmacro.o: cppmacro.c $(CONFIG_H) $(LIBCPP_DEPS)
 cpplib.o:   cpplib.c   $(CONFIG_H) $(LIBCPP_DEPS)
 cpphash.o:  cpphash.c  $(CONFIG_H) $(LIBCPP_DEPS)
 cppfiles.o: cppfiles.c $(CONFIG_H) $(LIBCPP_DEPS) $(SPLAY_TREE_H) mkdeps.h
-cppinit.o:  cppinit.c  $(CONFIG_H) $(LIBCPP_DEPS) cppdefault.h \
-               mkdeps.h prefix.h output.h version.h
+cpptrad.o:  cpptrad.c  $(CONFIG_H) $(LIBCPP_DEPS)
 safe-ctype.o: $(LIBIBERTY_DIR)/safe-ctype.c $(LIBIBERTY_DIR)/safe-ctype.h $(CONFIG_H) $(LIBCPP_DEPS)
        $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
 obstack.o: $(LIBIBERTY_DIR)/obstack.c $(LIBIBERTY_DIR)/obstack.h $(CONFIG_H) $(LIBCPP_DEPS)
index 81ee564ec7eec1af59ed6b538c20a3d457c835ae..fd29add6833b8bb4a3d963511f98385c09af592d 100644 (file)
@@ -33,44 +33,44 @@ const struct default_include cpp_include_defaults[]
 = {
 #ifdef GPLUSPLUS_INCLUDE_DIR
     /* Pick up GNU C++ generic include files.  */
-    { GPLUSPLUS_INCLUDE_DIR, "G++", 1, 1 },
+    { GPLUSPLUS_INCLUDE_DIR, "G++", 1, 1, 0 },
 #endif
 #ifdef GPLUSPLUS_TOOL_INCLUDE_DIR
     /* Pick up GNU C++ target-dependent include files.  */
-    { GPLUSPLUS_TOOL_INCLUDE_DIR, "G++", 1, 1 },
+    { GPLUSPLUS_TOOL_INCLUDE_DIR, "G++", 1, 1, 0 },
 #endif
 #ifdef GPLUSPLUS_BACKWARD_INCLUDE_DIR
     /* Pick up GNU C++ backward and deprecated include files.  */
-    { GPLUSPLUS_BACKWARD_INCLUDE_DIR, "G++", 1, 1 },
+    { GPLUSPLUS_BACKWARD_INCLUDE_DIR, "G++", 1, 1, 0 },
 #endif
 #ifdef LOCAL_INCLUDE_DIR
     /* /usr/local/include comes before the fixincluded header files.  */
-    { LOCAL_INCLUDE_DIR, 0, 0, 1 },
+    { LOCAL_INCLUDE_DIR, 0, 0, 1, 1 },
 #endif
 #ifdef PREFIX_INCLUDE_DIR
-    { PREFIX_INCLUDE_DIR, 0, 0, 1 },
+    { PREFIX_INCLUDE_DIR, 0, 0, 1, 0 },
 #endif
 #ifdef GCC_INCLUDE_DIR
     /* This is the dir for fixincludes and for gcc's private headers.  */
-    { GCC_INCLUDE_DIR, "GCC", 0, 0 },
+    { GCC_INCLUDE_DIR, "GCC", 0, 0, 0 },
 #endif
 #ifdef CROSS_INCLUDE_DIR
     /* One place the target system's headers might be.  */
-    { CROSS_INCLUDE_DIR, "GCC", 0, 0 },
+    { CROSS_INCLUDE_DIR, "GCC", 0, 0, 0 },
 #endif
 #ifdef TOOL_INCLUDE_DIR
     /* Another place the target system's headers might be.  */
-    { TOOL_INCLUDE_DIR, "BINUTILS", 0, 1 },
+    { TOOL_INCLUDE_DIR, "BINUTILS", 0, 1, 0 },
 #endif
 #ifdef SYSTEM_INCLUDE_DIR
     /* Some systems have an extra dir of include files.  */
-    { SYSTEM_INCLUDE_DIR, 0, 0, 0 },
+    { SYSTEM_INCLUDE_DIR, 0, 0, 0, 1 },
 #endif
 #ifdef STANDARD_INCLUDE_DIR
     /* /usr/include comes dead last.  */
-    { STANDARD_INCLUDE_DIR, STANDARD_INCLUDE_COMPONENT, 0, 0 },
+    { STANDARD_INCLUDE_DIR, STANDARD_INCLUDE_COMPONENT, 0, 0, 1 },
 #endif
-    { 0, 0, 0, 0 }
+    { 0, 0, 0, 0, 0 }
   };
 #endif /* no INCLUDE_DEFAULTS */
 
@@ -81,3 +81,9 @@ const size_t cpp_GCC_INCLUDE_DIR_len = sizeof GCC_INCLUDE_DIR - 8;
 const char cpp_GCC_INCLUDE_DIR[] = "";
 const size_t cpp_GCC_INCLUDE_DIR_len = 0;
 #endif
+
+#ifdef TARGET_SYSTEM_ROOT
+const char *cpp_SYSROOT = TARGET_SYSTEM_ROOT;
+#else
+const char *cpp_SYSROOT = "";
+#endif
index cda691d59567c90cff80df08a24ffbdea1d3f634..c87e27d5deec1a5d9ecca0916fee9d0c3e0eb86a 100644 (file)
@@ -34,54 +34,12 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #define STANDARD_INCLUDE_COMPONENT 0
 #endif
 
-#ifdef CROSS_COMPILE
-#undef LOCAL_INCLUDE_DIR
-#undef SYSTEM_INCLUDE_DIR
-#undef STANDARD_INCLUDE_DIR
+#if defined (CROSS_COMPILE) && !defined (TARGET_SYSTEM_ROOT)
+# undef LOCAL_INCLUDE_DIR
+# undef SYSTEM_INCLUDE_DIR
+# undef STANDARD_INCLUDE_DIR
 #else
-#undef CROSS_INCLUDE_DIR
-#endif
-
-/* We let tm.h override the types used here, to handle trivial differences
-   such as the choice of unsigned int or long unsigned int for size_t.
-   When machines start needing nontrivial differences in the size type,
-   it would be best to do something here to figure out automatically
-   from other information what type to use.  */
-
-/* The string value for __SIZE_TYPE__.  */
-
-#ifndef SIZE_TYPE
-#define SIZE_TYPE "long unsigned int"
-#endif
-
-/* The string value for __PTRDIFF_TYPE__.  */
-
-#ifndef PTRDIFF_TYPE
-#define PTRDIFF_TYPE "long int"
-#endif
-
-/* The string value for __WCHAR_TYPE__.  */
-
-#ifndef WCHAR_TYPE
-#define WCHAR_TYPE "int"
-#endif
-
-/* The string value for __WINT_TYPE__.  */
-
-#ifndef WINT_TYPE
-#define WINT_TYPE "unsigned int"
-#endif
-
-/* The string value for __USER_LABEL_PREFIX__ */
-
-#ifndef USER_LABEL_PREFIX
-#define USER_LABEL_PREFIX ""
-#endif
-
-/* The string value for __REGISTER_PREFIX__ */
-
-#ifndef REGISTER_PREFIX
-#define REGISTER_PREFIX ""
+# undef CROSS_INCLUDE_DIR
 #endif
 
 /* This is the default list of directories to search for include files.
@@ -103,10 +61,14 @@ struct default_include
   const int cxx_aware;         /* Includes in this directory don't need to
                                   be wrapped in extern "C" when compiling
                                   C++.  */
+  const int add_sysroot;       /* FNAME should be prefixed by
+                                  cpp_SYSROOT.  */
 };
 
 extern const struct default_include cpp_include_defaults[];
 extern const char cpp_GCC_INCLUDE_DIR[];
 extern const size_t cpp_GCC_INCLUDE_DIR_len;
 
+extern const char *cpp_SYSROOT;
+
 #endif /* ! GCC_CPPDEFAULT_H */
index 375dc2ba5b38143344d7d9eff29ecb4b5e8befad..360bc8ccef36f2a34959a23f1f9874bcf0d6e22a 100644 (file)
@@ -31,32 +31,21 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 static void print_location PARAMS ((cpp_reader *, unsigned int, unsigned int));
 
-/* Don't remove the blank before do, as otherwise the exgettext
-   script will mistake this as a function definition */
-#define v_message(msgid, ap) \
- do { vfprintf (stderr, _(msgid), ap); putc ('\n', stderr); } while (0)
-
 /* Print the logical file location (LINE, COL) in preparation for a
-   diagnostic.  Outputs the #include chain if it has changed.  */
+   diagnostic.  Outputs the #include chain if it has changed.  A line
+   of zero suppresses the include stack, and outputs the program name
+   instead.  */
 static void
 print_location (pfile, line, col)
      cpp_reader *pfile;
      unsigned int line, col;
 {
-  cpp_buffer *buffer = pfile->buffer;
-
-  if (!buffer)
+  if (!pfile->buffer || line == 0)
     fprintf (stderr, "%s: ", progname);
   else
     {
       const struct line_map *map;
 
-      if (line == 0)
-       {
-         line = pfile->cur_token[-1].line;
-         col = pfile->cur_token[-1].col;
-       }
-
       map = lookup_line (&pfile->line_maps, line);
       print_containing_files (&pfile->line_maps, map);
 
@@ -75,226 +64,129 @@ print_location (pfile, line, col)
     }
 }
 
-/* Set up for an error message: print the file and line, bump the error
+/* Set up for a diagnostic: print the file and line, bump the error
    counter, etc.  LINE is the logical line number; zero means to print
-   at the location of the previously lexed token, which tends to be the
-   correct place by default.  Returns 0 if the error has been suppressed.  */
+   at the location of the previously lexed token, which tends to be
+   the correct place by default.  Returns 0 if the error has been
+   suppressed.  */
 int
 _cpp_begin_message (pfile, code, line, column)
      cpp_reader *pfile;
-     enum error_type code;
+     int code;
      unsigned int line, column;
 {
-  int is_warning = 0;
+  int level = DL_EXTRACT (code);
 
-  switch (code)
+  switch (level)
     {
-    case PEDWARN:
-    case WARNING:
+    case DL_WARNING:
+    case DL_PEDWARN:
       if (CPP_IN_SYSTEM_HEADER (pfile)
          && ! CPP_OPTION (pfile, warn_system_headers))
        return 0;
-    case WARNING_SYSHDR:
+      /* Fall through.  */
+
+    case DL_WARNING_SYSHDR:
       if (CPP_OPTION (pfile, warnings_are_errors)
-         || (code == PEDWARN && CPP_OPTION (pfile, pedantic_errors)))
+         || (level == DL_PEDWARN && CPP_OPTION (pfile, pedantic_errors)))
        {
          if (CPP_OPTION (pfile, inhibit_errors))
            return 0;
-         if (pfile->errors < CPP_FATAL_LIMIT)
-           pfile->errors++;
-       }
-      else
-       {
-          if (CPP_OPTION (pfile, inhibit_warnings))
-           return 0;
-         is_warning = 1;
+         level = DL_ERROR;
+         pfile->errors++;
        }
+      else if (CPP_OPTION (pfile, inhibit_warnings))
+       return 0;
       break;
-       
-    case ERROR:
+
+    case DL_ERROR:
       if (CPP_OPTION (pfile, inhibit_errors))
        return 0;
-      if (pfile->errors < CPP_FATAL_LIMIT)
-       pfile->errors++;
-      break;
-      /* Fatal errors cannot be inhibited.  */
-    case FATAL:
-      pfile->errors = CPP_FATAL_LIMIT;
-      break;
-    case ICE:
-      fprintf (stderr, _("internal error: "));
-      pfile->errors = CPP_FATAL_LIMIT;
+      /* ICEs cannot be inhibited.  */
+    case DL_ICE:
+      pfile->errors++;
       break;
     }
 
   print_location (pfile, line, column);
-  if (is_warning)
+  if (DL_WARNING_P (level))
     fputs (_("warning: "), stderr);
+  else if (level == DL_ICE)
+    fputs (_("internal error: "), stderr);
 
   return 1;
 }
 
-/* Exported interface.  */
-
-/* For reporting internal errors.  Prints "internal error: " for you,
-   otherwise identical to cpp_fatal.  */
-void
-cpp_ice VPARAMS ((cpp_reader *pfile, const char *msgid, ...))
-{  
-  VA_OPEN (ap, msgid);
-  VA_FIXEDARG (ap, cpp_reader *, pfile);
-  VA_FIXEDARG (ap, const char *, msgid);
-
-  if (_cpp_begin_message (pfile, ICE, 0, 0))
-    v_message (msgid, ap);
-
-  VA_CLOSE (ap);
-}
-
-/* Same as cpp_error, except we consider the error to be "fatal",
-   such as inconsistent options.  I.e. there is little point in continuing.
-   (We do not exit, to support use of cpplib as a library.
-   Instead, it is the caller's responsibility to check
-   CPP_FATAL_ERRORS.  */
-void
-cpp_fatal VPARAMS ((cpp_reader *pfile, const char *msgid, ...))
-{  
-  VA_OPEN (ap, msgid);
-  VA_FIXEDARG (ap, cpp_reader *, pfile);
-  VA_FIXEDARG (ap, const char *, msgid);
-
-  if (_cpp_begin_message (pfile, FATAL, 0, 0))
-    v_message (msgid, ap);
+/* Don't remove the blank before do, as otherwise the exgettext
+   script will mistake this as a function definition */
+#define v_message(msgid, ap) \
+ do { vfprintf (stderr, _(msgid), ap); putc ('\n', stderr); } while (0)
 
-  VA_CLOSE (ap);
-}
+/* Exported interface.  */
 
 /* Print an error at the location of the previously lexed token.  */
 void
-cpp_error VPARAMS ((cpp_reader * pfile, const char *msgid, ...))
+cpp_error VPARAMS ((cpp_reader * pfile, int level, const char *msgid, ...))
 {
-  VA_OPEN (ap, msgid);
-  VA_FIXEDARG (ap, cpp_reader *, pfile);
-  VA_FIXEDARG (ap, const char *, msgid);
-
-  if (_cpp_begin_message (pfile, ERROR, 0, 0))
-    v_message (msgid, ap);
-
-  VA_CLOSE (ap);
-}
+  unsigned int line, column;
 
-/* Print an error at a specific location.  */
-void
-cpp_error_with_line VPARAMS ((cpp_reader *pfile, int line, int column,
-                            const char *msgid, ...))
-{
   VA_OPEN (ap, msgid);
   VA_FIXEDARG (ap, cpp_reader *, pfile);
-  VA_FIXEDARG (ap, int, line);
-  VA_FIXEDARG (ap, int, column);
+  VA_FIXEDARG (ap, int, level);
   VA_FIXEDARG (ap, const char *, msgid);
 
-  if (_cpp_begin_message (pfile, ERROR, line, column))
-    v_message (msgid, ap);
-
-  VA_CLOSE (ap);
-}
-
-/* Error including a message from `errno'.  */
-void
-cpp_error_from_errno (pfile, name)
-     cpp_reader *pfile;
-     const char *name;
-{
-  cpp_error (pfile, "%s: %s", name, xstrerror (errno));
-}
-
-/* Print a warning at the location of the previously lexed token.  */
-void
-cpp_warning VPARAMS ((cpp_reader * pfile, const char *msgid, ...))
-{
-  VA_OPEN (ap, msgid);
-  VA_FIXEDARG (ap, cpp_reader *, pfile);
-  VA_FIXEDARG (ap, const char *, msgid);
-
-  if (_cpp_begin_message (pfile, WARNING, 0, 0))
-    v_message (msgid, ap);
-
-  VA_CLOSE (ap);
-}
-
-/* Print a warning at a specific location.  */
-void
-cpp_warning_with_line VPARAMS ((cpp_reader * pfile, int line, int column,
-                              const char *msgid, ...))
-{
-  VA_OPEN (ap, msgid);
-  VA_FIXEDARG (ap, cpp_reader *, pfile);
-  VA_FIXEDARG (ap, int, line);
-  VA_FIXEDARG (ap, int, column);
-  VA_FIXEDARG (ap, const char *, msgid);
-
-  if (_cpp_begin_message (pfile, WARNING, line, column))
-    v_message (msgid, ap);
-
-  VA_CLOSE (ap);
-}
-
-/* Pedwarn at the location of the previously lexed token.  */
-void
-cpp_pedwarn VPARAMS ((cpp_reader * pfile, const char *msgid, ...))
-{
-  VA_OPEN (ap, msgid);
-  VA_FIXEDARG (ap, cpp_reader *, pfile);
-  VA_FIXEDARG (ap, const char *, msgid);
+  if (pfile->buffer)
+    {
+      if (CPP_OPTION (pfile, traditional))
+       {
+         if (pfile->state.in_directive)
+           line = pfile->directive_line;
+         else
+           line = pfile->line;
+         column = 0;
+       }
+      else
+       {
+         line = pfile->cur_token[-1].line;
+         column = pfile->cur_token[-1].col;
+       }
+    }
+  else
+    line = column = 0;
 
-  if (_cpp_begin_message (pfile, PEDWARN, 0, 0))
+  if (_cpp_begin_message (pfile, level, line, column))
     v_message (msgid, ap);
 
   VA_CLOSE (ap);
 }
 
-/* Pedwarn at a specific location.  */
+/* Print an error at a specific location.  */
 void
-cpp_pedwarn_with_line VPARAMS ((cpp_reader * pfile, int line, int column,
-                              const char *msgid, ...))
+cpp_error_with_line VPARAMS ((cpp_reader *pfile, int level,
+                             unsigned int line, unsigned int column,
+                             const char *msgid, ...))
 {
   VA_OPEN (ap, msgid);
   VA_FIXEDARG (ap, cpp_reader *, pfile);
-  VA_FIXEDARG (ap, int, line);
-  VA_FIXEDARG (ap, int, column);
+  VA_FIXEDARG (ap, int, level);
+  VA_FIXEDARG (ap, unsigned int, line);
+  VA_FIXEDARG (ap, unsigned int, column);
   VA_FIXEDARG (ap, const char *, msgid);
 
-  if (_cpp_begin_message (pfile, PEDWARN, line, column))
+  if (_cpp_begin_message (pfile, level, line, column))
     v_message (msgid, ap);
 
   VA_CLOSE (ap);
 }
 
-/* Print an error message not associated with the translation unit.  */
-void
-cpp_notice VPARAMS ((cpp_reader *pfile, const char *msgid, ...))
-{
-  VA_OPEN (ap, msgid);
-  VA_FIXEDARG (ap, cpp_reader *, pfile);
-  VA_FIXEDARG (ap, const char *, msgid);
-
-  if (pfile->errors < CPP_FATAL_LIMIT)
-    pfile->errors++;
-
-  v_message (msgid, ap);
-
-  VA_CLOSE (ap);
-}
-
-/* Print an error message originating from ERRNO and not associated
-   with the translation unit.  */
 void
-cpp_notice_from_errno (pfile, name)
+cpp_errno (pfile, level, msgid)
      cpp_reader *pfile;
-     const char *name;
+     int level;
+     const char *msgid;
 {
-  if (name[0] == '\0')
-    name = "stdout";
-  cpp_notice (pfile, "%s: %s", name, xstrerror (errno));
+  if (msgid[0] == '\0')
+    msgid = _("stdout");
+
+  cpp_error (pfile, level, "%s: %s", msgid, xstrerror (errno));
 }
index 1d4ceccde956462398139e0ff779d17a7e344c59..12919f6f88f14d4f5b5b8e50157715a1d04561d1 100644 (file)
@@ -23,197 +23,445 @@ Boston, MA 02111-1307, USA.  */
 #include "cpplib.h"
 #include "cpphash.h"
 
-/* Yield nonzero if adding two numbers with A's and B's signs can yield a
-   number with SUM's sign, where A, B, and SUM are all C integers.  */
-#define possible_sum_sign(a, b, sum) ((((a) ^ (b)) | ~ ((a) ^ (sum))) < 0)
-
-static void integer_overflow PARAMS ((cpp_reader *));
-static HOST_WIDEST_INT left_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT,
-                                          unsigned int,
-                                          unsigned HOST_WIDEST_INT));
-static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT,
-                                           unsigned int,
-                                           unsigned HOST_WIDEST_INT));
-static struct op parse_number PARAMS ((cpp_reader *, const cpp_token *));
-static struct op parse_defined PARAMS ((cpp_reader *));
-static struct op lex PARAMS ((cpp_reader *, int));
-static const unsigned char *op_as_text PARAMS ((cpp_reader *, enum cpp_ttype));
+#define PART_PRECISION (sizeof (cpp_num_part) * CHAR_BIT)
+#define HALF_MASK (~(cpp_num_part) 0 >> (PART_PRECISION / 2))
+#define LOW_PART(num_part) (num_part & HALF_MASK)
+#define HIGH_PART(num_part) (num_part >> (PART_PRECISION / 2))
 
 struct op
 {
+  const cpp_token *token;      /* The token forming op (for diagnostics).  */
+  cpp_num value;               /* The value logically "right" of op.  */
   enum cpp_ttype op;
-  U_CHAR prio;         /* Priority of op.  */
-  U_CHAR flags;
-  U_CHAR unsignedp;    /* True if value should be treated as unsigned.  */
-  HOST_WIDEST_INT value; /* The value logically "right" of op.  */
 };
 
-/* There is no "error" token, but we can't get comments in #if, so we can
-   abuse that token type.  */
-#define CPP_ERROR CPP_COMMENT
+/* Some simple utility routines on double integers.  */
+#define num_zerop(num) ((num.low | num.high) == 0)
+#define num_eq(num1, num2) (num1.low == num2.low && num1.high == num2.high)
+static bool num_positive PARAMS ((cpp_num, size_t));
+static bool num_greater_eq PARAMS ((cpp_num, cpp_num, size_t));
+static cpp_num num_trim PARAMS ((cpp_num, size_t));
+static cpp_num num_part_mul PARAMS ((cpp_num_part, cpp_num_part));
+
+static cpp_num num_unary_op PARAMS ((cpp_reader *, cpp_num, enum cpp_ttype));
+static cpp_num num_binary_op PARAMS ((cpp_reader *, cpp_num, cpp_num,
+                                     enum cpp_ttype));
+static cpp_num num_negate PARAMS ((cpp_num, size_t));
+static cpp_num num_bitwise_op PARAMS ((cpp_reader *, cpp_num, cpp_num,
+                                      enum cpp_ttype));
+static cpp_num num_inequality_op PARAMS ((cpp_reader *, cpp_num, cpp_num,
+                                         enum cpp_ttype));
+static cpp_num num_equality_op PARAMS ((cpp_reader *, cpp_num, cpp_num,
+                                       enum cpp_ttype));
+static cpp_num num_mul PARAMS ((cpp_reader *, cpp_num, cpp_num));
+static cpp_num num_div_op PARAMS ((cpp_reader *, cpp_num, cpp_num,
+                                  enum cpp_ttype));
+static cpp_num num_lshift PARAMS ((cpp_num, size_t, size_t));
+static cpp_num num_rshift PARAMS ((cpp_num, size_t, size_t));
+
+static cpp_num append_digit PARAMS ((cpp_num, int, int, size_t));
+static cpp_num parse_defined PARAMS ((cpp_reader *));
+static cpp_num eval_token PARAMS ((cpp_reader *, const cpp_token *));
+static struct op *reduce PARAMS ((cpp_reader *, struct op *, enum cpp_ttype));
+static unsigned int interpret_float_suffix PARAMS ((const uchar *, size_t));
+static unsigned int interpret_int_suffix PARAMS ((const uchar *, size_t));
+static void check_promotion PARAMS ((cpp_reader *, const struct op *));
+
+/* Token type abuse to create unary plus and minus operators.  */
+#define CPP_UPLUS (CPP_LAST_CPP_OP + 1)
+#define CPP_UMINUS (CPP_LAST_CPP_OP + 2)
 
 /* With -O2, gcc appears to produce nice code, moving the error
    message load and subsequent jump completely out of the main path.  */
-#define CPP_ICE(msgid) \
-  do { cpp_ice (pfile, msgid); goto syntax_error; } while(0)
 #define SYNTAX_ERROR(msgid) \
-  do { cpp_error (pfile, msgid); goto syntax_error; } while(0)
+  do { cpp_error (pfile, DL_ERROR, msgid); goto syntax_error; } while(0)
 #define SYNTAX_ERROR2(msgid, arg) \
-  do { cpp_error (pfile, msgid, arg); goto syntax_error; } while(0)
+  do { cpp_error (pfile, DL_ERROR, msgid, arg); goto syntax_error; } while(0)
+
+/* Subroutine of cpp_classify_number.  S points to a float suffix of
+   length LEN, possibly zero.  Returns 0 for an invalid suffix, or a
+   flag vector describing the suffix.  */
+static unsigned int
+interpret_float_suffix (s, len)
+     const uchar *s;
+     size_t len;
+{
+  size_t f = 0, l = 0, i = 0;
+
+  while (len--)
+    switch (s[len])
+      {
+      case 'f': case 'F': f++; break;
+      case 'l': case 'L': l++; break;
+      case 'i': case 'I':
+      case 'j': case 'J': i++; break;
+      default:
+       return 0;
+      }
+
+  if (f + l > 1 || i > 1)
+    return 0;
+
+  return ((i ? CPP_N_IMAGINARY : 0)
+         | (f ? CPP_N_SMALL :
+            l ? CPP_N_LARGE : CPP_N_MEDIUM));
+}
 
-struct suffix
+/* Subroutine of cpp_classify_number.  S points to an integer suffix
+   of length LEN, possibly zero. Returns 0 for an invalid suffix, or a
+   flag vector describing the suffix.  */
+static unsigned int
+interpret_int_suffix (s, len)
+     const uchar *s;
+     size_t len;
 {
-  const unsigned char s[4];
-  const unsigned char u;
-  const unsigned char l;
-};
+  size_t u, l, i;
 
-static const struct suffix vsuf_1[] = {
-  { "u", 1, 0 }, { "U", 1, 0 },
-  { "l", 0, 1 }, { "L", 0, 1 }
-};
+  u = l = i = 0;
 
-static const struct suffix vsuf_2[] = {
-  { "ul", 1, 1 }, { "UL", 1, 1 }, { "uL", 1, 1 }, { "Ul", 1, 1 },
-  { "lu", 1, 1 }, { "LU", 1, 1 }, { "Lu", 1, 1 }, { "lU", 1, 1 },
-  { "ll", 0, 2 }, { "LL", 0, 2 }
-};
+  while (len--)
+    switch (s[len])
+      {
+      case 'u': case 'U':      u++; break;
+      case 'i': case 'I':
+      case 'j': case 'J':      i++; break;
+      case 'l': case 'L':      l++;
+       /* If there are two Ls, they must be adjacent and the same case.  */
+       if (l == 2 && s[len] != s[len + 1])
+         return 0;
+       break;
+      default:
+       return 0;
+      }
 
-static const struct suffix vsuf_3[] = {
-  { "ull", 1, 2 }, { "ULL", 1, 2 }, { "uLL", 1, 2 }, { "Ull", 1, 2 },
-  { "llu", 1, 2 }, { "LLU", 1, 2 }, { "LLu", 1, 2 }, { "llU", 1, 2 }
-};
-#define Nsuff(tab) (sizeof tab / sizeof (struct suffix))
+  if (l > 2 || u > 1 || i > 1)
+    return 0;
 
-/* Parse and convert what is presumably an integer in TOK.  Accepts
-   decimal, hex, or octal with or without size suffixes.  Returned op
-   is CPP_ERROR on error, otherwise it is a CPP_NUMBER.  */
-static struct op
-parse_number (pfile, tok)
+  return ((i ? CPP_N_IMAGINARY : 0)
+         | (u ? CPP_N_UNSIGNED : 0)
+         | ((l == 0) ? CPP_N_SMALL
+            : (l == 1) ? CPP_N_MEDIUM : CPP_N_LARGE));
+}
+
+/* Categorize numeric constants according to their field (integer,
+   floating point, or invalid), radix (decimal, octal, hexadecimal),
+   and type suffixes.  */
+unsigned int
+cpp_classify_number (pfile, token)
      cpp_reader *pfile;
-     const cpp_token *tok;
+     const cpp_token *token;
 {
-  struct op op;
-  const U_CHAR *start = tok->val.str.text;
-  const U_CHAR *end = start + tok->val.str.len;
-  const U_CHAR *p = start;
-  int c = 0, i, nsuff;
-  unsigned HOST_WIDEST_INT n = 0, nd, MAX_over_base;
-  int base = 10;
-  int overflow = 0;
-  int digit, largest_digit = 0;
-  const struct suffix *sufftab;
+  const uchar *str = token->val.str.text;
+  const uchar *limit;
+  unsigned int max_digit, result, radix;
+  enum {NOT_FLOAT = 0, AFTER_POINT, AFTER_EXPON} float_flag;
+
+  /* If the lexer has done its job, length one can only be a single
+     digit.  Fast-path this very common case.  */
+  if (token->val.str.len == 1)
+    return CPP_N_INTEGER | CPP_N_SMALL | CPP_N_DECIMAL;
+
+  limit = str + token->val.str.len;
+  float_flag = NOT_FLOAT;
+  max_digit = 0;
+  radix = 10;
+
+  /* First, interpret the radix.  */
+  if (*str == '0')
+    {
+      radix = 8;
+      str++;
 
-  op.unsignedp = 0;
+      /* Require at least one hex digit to classify it as hex.  */
+      if ((*str == 'x' || *str == 'X') && ISXDIGIT (str[1]))
+       {
+         radix = 16;
+         str++;
+       }
+    }
 
-  if (p[0] == '0')
+  /* Now scan for a well-formed integer or float.  */
+  for (;;)
     {
-      if (end - start >= 3 && (p[1] == 'x' || p[1] == 'X'))
+      unsigned int c = *str++;
+
+      if (ISDIGIT (c) || (ISXDIGIT (c) && radix == 16))
        {
-         p += 2;
-         base = 16;
+         c = hex_value (c);
+         if (c > max_digit)
+           max_digit = c;
+       }
+      else if (c == '.')
+       {
+         if (float_flag == NOT_FLOAT)
+           float_flag = AFTER_POINT;
+         else
+           SYNTAX_ERROR ("too many decimal points in number");
+       }
+      else if ((radix <= 10 && (c == 'e' || c == 'E'))
+              || (radix == 16 && (c == 'p' || c == 'P')))
+       {
+         float_flag = AFTER_EXPON;
+         break;
        }
       else
        {
-         p += 1;
-         base = 8;
+         /* Start of suffix.  */
+         str--;
+         break;
        }
     }
 
-  /* Some buggy compilers (e.g. MPW C) seem to need both casts.  */
-  MAX_over_base = (((unsigned HOST_WIDEST_INT) -1)
-                  / ((unsigned HOST_WIDEST_INT) base));
+  if (float_flag != NOT_FLOAT && radix == 8)
+    radix = 10;
 
-  for(; p < end; p++)
+  if (max_digit >= radix)
+    SYNTAX_ERROR2 ("invalid digit \"%c\" in octal constant", '0' + max_digit);
+
+  if (float_flag != NOT_FLOAT)
     {
-      c = *p;
+      if (radix == 16 && CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, c99))
+       cpp_error (pfile, DL_PEDWARN,
+                  "use of C99 hexadecimal floating constant");
 
-      if (ISDIGIT (c)
-         || (base == 16 && ISXDIGIT (c)))
-       digit = hex_value (c);
-      else
-       break;
+      if (float_flag == AFTER_EXPON)
+       {
+         if (*str == '+' || *str == '-')
+           str++;
 
-      if (largest_digit < digit)
-       largest_digit = digit;
-      nd = n * base + digit;
-      overflow |= MAX_over_base < n || nd < n;
-      n = nd;
-    }
-
-  if (p < end)
-    {
-      /* Check for a floating point constant.  Note that float constants
-        with an exponent or suffix but no decimal point are technically
-        invalid (C99 6.4.4.2) but accepted elsewhere.  */
-      if ((c == '.' || c == 'F' || c == 'f')
-         || (base == 10 && (c == 'E' || c == 'e')
-             && p+1 < end && (p[1] == '+' || p[1] == '-'))
-         || (base == 16 && (c == 'P' || c == 'p')
-             && p+1 < end && (p[1] == '+' || p[1] == '-')))
-       SYNTAX_ERROR ("floating point numbers are not valid in #if");
-  
-      /* Determine the suffix. l means long, and u means unsigned.
-        See the suffix tables, above.  */
-      switch (end - p)
-       {
-       case 1: sufftab = vsuf_1; nsuff = Nsuff(vsuf_1); break;
-       case 2: sufftab = vsuf_2; nsuff = Nsuff(vsuf_2); break;
-       case 3: sufftab = vsuf_3; nsuff = Nsuff(vsuf_3); break;
-       default: goto invalid_suffix;
-       }
-
-      for (i = 0; i < nsuff; i++)
-       if (memcmp (p, sufftab[i].s, end - p) == 0)
-         break;
-      if (i == nsuff)
-       goto invalid_suffix;
-      op.unsignedp = sufftab[i].u;
+         /* Exponent is decimal, even if string is a hex float.  */
+         if (!ISDIGIT (*str))
+           SYNTAX_ERROR ("exponent has no digits");
+
+         do
+           str++;
+         while (ISDIGIT (*str));
+       }
+      else if (radix == 16)
+       SYNTAX_ERROR ("hexadecimal floating constants require an exponent");
+
+      result = interpret_float_suffix (str, limit - str);
+      if (result == 0)
+       {
+         cpp_error (pfile, DL_ERROR,
+                    "invalid suffix \"%.*s\" on floating constant",
+                    (int) (limit - str), str);
+         return CPP_N_INVALID;
+       }
 
-      if (CPP_WTRADITIONAL (pfile)
-         && sufftab[i].u
+      /* Traditional C didn't accept any floating suffixes.  */
+      if (limit != str
+         && CPP_WTRADITIONAL (pfile)
          && ! cpp_sys_macro_p (pfile))
-       cpp_warning (pfile, "traditional C rejects the `U' suffix");
-      if (sufftab[i].l == 2 && CPP_OPTION (pfile, pedantic)
-         && ! CPP_OPTION (pfile, c99))
-       cpp_pedwarn (pfile, "too many 'l' suffixes in integer constant");
+       cpp_error (pfile, DL_WARNING,
+                  "traditional C rejects the \"%.*s\" suffix",
+                  (int) (limit - str), str);
+
+      result |= CPP_N_FLOATING;
     }
-  
-  if (base <= largest_digit)
-    cpp_pedwarn (pfile, "integer constant contains digits beyond the radix");
+  else
+    {
+      result = interpret_int_suffix (str, limit - str);
+      if (result == 0)
+       {
+         cpp_error (pfile, DL_ERROR,
+                    "invalid suffix \"%.*s\" on integer constant",
+                    (int) (limit - str), str);
+         return CPP_N_INVALID;
+       }
 
-  if (overflow)
-    cpp_pedwarn (pfile, "integer constant out of range");
+      /* Traditional C only accepted the 'L' suffix.
+         Suppress warning about 'LL' with -Wno-long-long.  */
+      if (CPP_WTRADITIONAL (pfile) && ! cpp_sys_macro_p (pfile))
+       {
+         int u_or_i = (result & (CPP_N_UNSIGNED|CPP_N_IMAGINARY));
+         int large = (result & CPP_N_WIDTH) == CPP_N_LARGE;
 
-  /* If too big to be signed, consider it unsigned.  */
-  else if ((HOST_WIDEST_INT) n < 0 && ! op.unsignedp)
-    {
-      if (base == 10)
-       cpp_warning (pfile, "integer constant is so large that it is unsigned");
-      op.unsignedp = 1;
+         if (u_or_i || (large && CPP_OPTION (pfile, warn_long_long)))
+           cpp_error (pfile, DL_WARNING,
+                      "traditional C rejects the \"%.*s\" suffix",
+                      (int) (limit - str), str);
+       }
+
+      if ((result & CPP_N_WIDTH) == CPP_N_LARGE
+         && ! CPP_OPTION (pfile, c99)
+         && CPP_OPTION (pfile, warn_long_long))
+       cpp_error (pfile, DL_PEDWARN, "use of C99 long long integer constant");
+
+      result |= CPP_N_INTEGER;
     }
 
-  op.value = n;
-  op.op = CPP_NUMBER;
-  return op;
+  if ((result & CPP_N_IMAGINARY) && CPP_PEDANTIC (pfile))
+    cpp_error (pfile, DL_PEDWARN, "imaginary constants are a GCC extension");
+
+  if (radix == 10)
+    result |= CPP_N_DECIMAL;
+  else if (radix == 16)
+    result |= CPP_N_HEX;
+  else
+    result |= CPP_N_OCTAL;
+
+  return result;
 
- invalid_suffix:
-  cpp_error (pfile, "invalid suffix '%.*s' on integer constant",
-            (int) (end - p), p);
  syntax_error:
-  op.op = CPP_ERROR;
-  return op;
+  return CPP_N_INVALID;
+}
+
+/* cpp_interpret_integer converts an integer constant into a cpp_num,
+   of precision options->precision.
+
+   We do not provide any interface for decimal->float conversion,
+   because the preprocessor doesn't need it and the floating point
+   handling in GCC proper is too ugly to speak of.  */
+cpp_num
+cpp_interpret_integer (pfile, token, type)
+     cpp_reader *pfile;
+     const cpp_token *token;
+     unsigned int type;
+{
+  const uchar *p, *end;
+  cpp_num result;
+
+  result.low = 0;
+  result.high = 0;
+  result.unsignedp = !!(type & CPP_N_UNSIGNED);
+  result.overflow = false;
+
+  p = token->val.str.text;
+  end = p + token->val.str.len;
+
+  /* Common case of a single digit.  */
+  if (token->val.str.len == 1)
+    result.low = p[0] - '0';
+  else
+    {
+      cpp_num_part max;
+      size_t precision = CPP_OPTION (pfile, precision);
+      unsigned int base = 10, c = 0;
+      bool overflow = false;
+
+      if ((type & CPP_N_RADIX) == CPP_N_OCTAL)
+       {
+         base = 8;
+         p++;
+       }
+      else if ((type & CPP_N_RADIX) == CPP_N_HEX)
+       {
+         base = 16;
+         p += 2;
+       }
+
+      /* We can add a digit to numbers strictly less than this without
+        needing the precision and slowness of double integers.  */
+      max = ~(cpp_num_part) 0;
+      if (precision < PART_PRECISION)
+       max >>= PART_PRECISION - precision;
+      max = (max - base + 1) / base + 1;
+
+      for (; p < end; p++)
+       {
+         c = *p;
+
+         if (ISDIGIT (c) || (base == 16 && ISXDIGIT (c)))
+           c = hex_value (c);
+         else
+           break;
+
+         /* Strict inequality for when max is set to zero.  */
+         if (result.low < max)
+           result.low = result.low * base + c;
+         else
+           {
+             result = append_digit (result, c, base, precision);
+             overflow |= result.overflow;
+             max = 0;
+           }
+       }
+
+      if (overflow)
+       cpp_error (pfile, DL_PEDWARN,
+                  "integer constant is too large for its type");
+      /* If too big to be signed, consider it unsigned.  Only warn for
+        decimal numbers.  Traditional numbers were always signed (but
+        we still honor an explicit U suffix); but we only have
+        traditional semantics in directives.  */
+      else if (!result.unsignedp
+              && !(CPP_OPTION (pfile, traditional)
+                   && pfile->state.in_directive)
+              && !num_positive (result, precision))
+       {
+         if (base == 10)
+           cpp_error (pfile, DL_WARNING,
+                      "integer constant is so large that it is unsigned");
+         result.unsignedp = true;
+       }
+    }
+
+  return result;
+}
+
+/* Append DIGIT to NUM, a number of PRECISION bits being read in base
+   BASE.  */
+static cpp_num
+append_digit (num, digit, base, precision)
+     cpp_num num;
+     int digit, base;
+     size_t precision;
+{
+  cpp_num result;
+  unsigned int shift = 3 + (base == 16);
+  bool overflow;
+  cpp_num_part add_high, add_low;
+
+  /* Multiply by 8 or 16.  Catching this overflow here means we don't
+     need to worry about add_high overflowing.  */
+  overflow = !!(num.high >> (PART_PRECISION - shift));
+  result.high = num.high << shift;
+  result.low = num.low << shift;
+  result.high |= num.low >> (PART_PRECISION - shift);
+
+  if (base == 10)
+    {
+      add_low = num.low << 1;
+      add_high = (num.high << 1) + (num.low >> (PART_PRECISION - 1));
+    }
+  else
+    add_high = add_low = 0;
+
+  if (add_low + digit < add_low)
+    add_high++;
+  add_low += digit;
+    
+  if (result.low + add_low < result.low)
+    add_high++;
+  if (result.high + add_high < result.high)
+    overflow = true;
+
+  result.low += add_low;
+  result.high += add_high;
+
+  /* The above code catches overflow of a cpp_num type.  This catches
+     overflow of the (possibly shorter) target precision.  */
+  num.low = result.low;
+  num.high = result.high;
+  result = num_trim (result, precision);
+  if (!num_eq (result, num))
+    overflow = true;
+
+  result.unsignedp = num.unsignedp;
+  result.overflow = overflow;
+  return result;
 }
 
 /* Handle meeting "defined" in a preprocessor expression.  */
-static struct op
+static cpp_num
 parse_defined (pfile)
      cpp_reader *pfile;
 {
+  cpp_num result;
   int paren = 0;
   cpp_hashnode *node = 0;
   const cpp_token *token;
-  struct op op;
   cpp_context *initial_context = pfile->context;
 
   /* Don't expand macros.  */
@@ -231,36 +479,34 @@ parse_defined (pfile)
       node = token->val.node;
       if (paren && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN)
        {
-         cpp_error (pfile, "missing ')' after \"defined\"");
+         cpp_error (pfile, DL_ERROR, "missing ')' after \"defined\"");
          node = 0;
        }
     }
   else
     {
-      cpp_error (pfile, "operator \"defined\" requires an identifier");
+      cpp_error (pfile, DL_ERROR,
+                "operator \"defined\" requires an identifier");
       if (token->flags & NAMED_OP)
        {
          cpp_token op;
 
          op.flags = 0;
          op.type = token->type;
-         cpp_error (pfile,
+         cpp_error (pfile, DL_ERROR,
                     "(\"%s\" is an alternative token for \"%s\" in C++)",
                     cpp_token_as_text (pfile, token),
                     cpp_token_as_text (pfile, &op));
        }
     }
 
-  if (!node)
-    op.op = CPP_ERROR;
-  else
+  if (node)
     {
-      if (pfile->context != initial_context)
-       cpp_warning (pfile, "this use of \"defined\" may not be portable");
+      if (pfile->context != initial_context && CPP_PEDANTIC (pfile))
+       cpp_error (pfile, DL_WARNING,
+                  "this use of \"defined\" may not be portable");
 
-      op.value = node->type == NT_MACRO;
-      op.unsignedp = 0;
-      op.op = CPP_NUMBER;
+      _cpp_mark_macro_used (node);
 
       /* A possible controlling macro of the form #if !defined ().
         _cpp_parse_expr checks there was no other junk on the line.  */
@@ -268,49 +514,69 @@ parse_defined (pfile)
     }
 
   pfile->state.prevent_expansion--;
-  return op;
+
+  result.unsignedp = false;
+  result.high = 0;
+  result.overflow = false;
+  result.low = node && node->type == NT_MACRO;
+  return result;
 }
 
-/* Read a token.  The returned type is CPP_NUMBER for a valid number
-   (an interpreted preprocessing number or character constant, or the
-   result of the "defined" or "#" operators), CPP_ERROR on error,
-   CPP_EOF, or the type of an operator token.  */
-static struct op
-lex (pfile, skip_evaluation)
+/* Convert a token into a CPP_NUMBER (an interpreted preprocessing
+   number or character constant, or the result of the "defined" or "#"
+   operators).  */
+static cpp_num
+eval_token (pfile, token)
      cpp_reader *pfile;
-     int skip_evaluation;
+     const cpp_token *token;
 {
-  struct op op;
-  const cpp_token *token = cpp_get_token (pfile);
+  cpp_num result;
+  unsigned int temp;
+  int unsignedp = 0;
 
   switch (token->type)
     {
     case CPP_NUMBER:
-      return parse_number (pfile, token);
+      temp = cpp_classify_number (pfile, token);
+      switch (temp & CPP_N_CATEGORY)
+       {
+       case CPP_N_FLOATING:
+         cpp_error (pfile, DL_ERROR,
+                    "floating constant in preprocessor expression");
+         break;
+       case CPP_N_INTEGER:
+         if (!(temp & CPP_N_IMAGINARY))
+           return cpp_interpret_integer (pfile, token, temp);
+         cpp_error (pfile, DL_ERROR,
+                    "imaginary number in preprocessor expression");
+         break;
+
+       case CPP_N_INVALID:
+         /* Error already issued.  */
+         break;
+       }
+      result.high = result.low = 0;
+      break;
 
-    case CPP_CHAR:
     case CPP_WCHAR:
+    case CPP_CHAR:
       {
-       unsigned int chars_seen;
-
-       if (token->type == CPP_CHAR)
-         op.unsignedp = 0;
-       else
-         op.unsignedp = WCHAR_UNSIGNED;
-       op.op = CPP_NUMBER;
-       op.value = cpp_interpret_charconst (pfile, token, 1, 0, &chars_seen);
-       return op;
-      }
-
-    case CPP_STRING:
-    case CPP_WSTRING:
-      SYNTAX_ERROR ("string constants are not valid in #if");
+       cppchar_t cc = cpp_interpret_charconst (pfile, token,
+                                               &temp, &unsignedp);
 
-    case CPP_OTHER:
-      if (ISGRAPH (token->val.c))
-       SYNTAX_ERROR2 ("invalid character '%c' in #if", token->val.c);
-      else
-       SYNTAX_ERROR2 ("invalid character '\\%03o' in #if", token->val.c);
+       result.high = 0;
+       result.low = cc;
+       /* Sign-extend the result if necessary.  */
+       if (!unsignedp && (cppchar_signed_t) cc < 0)
+         {
+           if (PART_PRECISION > BITS_PER_CPPCHAR_T)
+             result.low |= ~(~(cpp_num_part) 0
+                             >> (PART_PRECISION - BITS_PER_CPPCHAR_T));
+           result.high = ~(cpp_num_part) 0;
+           result = num_trim (result, CPP_OPTION (pfile, precision));
+         }
+      }
+      break;
 
     case CPP_NAME:
       if (token->val.node == pfile->spec_nodes.n_defined)
@@ -319,571 +585,1021 @@ lex (pfile, skip_evaluation)
               && (token->val.node == pfile->spec_nodes.n_true
                   || token->val.node == pfile->spec_nodes.n_false))
        {
-         op.op = CPP_NUMBER;
-         op.unsignedp = 0;
-         op.value = (token->val.node == pfile->spec_nodes.n_true);
+         result.high = 0;
+         result.low = (token->val.node == pfile->spec_nodes.n_true);
 
          /* Warn about use of true or false in #if when pedantic
             and stdbool.h has not been included.  */
          if (CPP_PEDANTIC (pfile)
              && ! cpp_defined (pfile, DSC("__bool_true_false_are_defined")))
-           cpp_pedwarn (pfile, "ISO C++ does not permit \"%s\" in #if",
-                        NODE_NAME (token->val.node));
-         return op;
+           cpp_error (pfile, DL_PEDWARN,
+                      "ISO C++ does not permit \"%s\" in #if",
+                      NODE_NAME (token->val.node));
        }
       else
        {
-         op.op = CPP_NUMBER;
-         op.unsignedp = 0;
-         op.value = 0;
-
-         if (CPP_OPTION (pfile, warn_undef) && !skip_evaluation)
-           cpp_warning (pfile, "\"%s\" is not defined",
-                        NODE_NAME (token->val.node));
-         return op;
-       }
-
-    case CPP_HASH:
-      {
-       int temp;
-
-       op.op = CPP_NUMBER;
-       if (_cpp_test_assertion (pfile, &temp))
-         op.op = CPP_ERROR;
-       op.unsignedp = 0;
-       op.value = temp;
-       return op;
-      }
-
-    default:
-      if (((int) token->type > (int) CPP_EQ
-          && (int) token->type < (int) CPP_PLUS_EQ)
-         || token->type == CPP_EOF)
-       {
-         op.op = token->type;
-         return op;
+         result.high = 0;
+         result.low = 0;
+         if (CPP_OPTION (pfile, warn_undef) && !pfile->state.skip_eval)
+           cpp_error (pfile, DL_WARNING, "\"%s\" is not defined",
+                      NODE_NAME (token->val.node));
        }
+      break;
 
-      SYNTAX_ERROR2 ("\"%s\" is not valid in #if expressions",
-                    cpp_token_as_text (pfile, token));
-    }
-
- syntax_error:
-  op.op = CPP_ERROR;
-  return op;
-}
-
-/* Warn if appropriate on overflow.  */
-static void
-integer_overflow (pfile)
-     cpp_reader *pfile;
-{
-  if (CPP_PEDANTIC (pfile))
-    cpp_pedwarn (pfile, "integer overflow in preprocessor expression");
-}
-
-/* Handle shifting A left by B bits.  UNSIGNEDP is non-zero if A is
-   unsigned.  */
-static HOST_WIDEST_INT
-left_shift (pfile, a, unsignedp, b)
-     cpp_reader *pfile;
-     HOST_WIDEST_INT a;
-     unsigned int unsignedp;
-     unsigned HOST_WIDEST_INT b;
-{
-  if (b >= HOST_BITS_PER_WIDEST_INT)
-    {
-      if (! unsignedp && a != 0)
-       integer_overflow (pfile);
-      return 0;
+    default: /* CPP_HASH */
+      _cpp_test_assertion (pfile, &temp);
+      result.high = 0;
+      result.low = temp;
     }
-  else if (unsignedp)
-    return (unsigned HOST_WIDEST_INT) a << b;
-  else
-    {
-      HOST_WIDEST_INT l = a << b;
-      if (l >> b != a)
-       integer_overflow (pfile);
-      return l;
-    }
-}
 
-/* Handle shifting A right by B bits.  UNSIGNEDP is non-zero if A is
-   unsigned.  */
-static HOST_WIDEST_INT
-right_shift (pfile, a, unsignedp, b)
-     cpp_reader *pfile ATTRIBUTE_UNUSED;
-     HOST_WIDEST_INT a;
-     unsigned int unsignedp;
-     unsigned HOST_WIDEST_INT b;
-{
-  if (b >= HOST_BITS_PER_WIDEST_INT)
-    return unsignedp ? 0 : a >> (HOST_BITS_PER_WIDEST_INT - 1);
-  else if (unsignedp)
-    return (unsigned HOST_WIDEST_INT) a >> b;
-  else
-    return a >> b;
+  result.unsignedp = !!unsignedp;
+  result.overflow = false;
+  return result;
 }
 \f
 /* Operator precedence and flags table.
 
 After an operator is returned from the lexer, if it has priority less
-than or equal to the operator on the top of the stack, we reduce the
-stack by one operator and repeat the test.  Since equal priorities
-reduce, this is naturally left-associative.
-
-We handle right-associative operators by clearing the lower bit of all
-left-associative operators, and setting it for right-associative ones.
-After the reduction phase of a new operator, just before it is pushed
-onto the stack, its RIGHT_ASSOC bit is cleared.  The effect is that
-during the reduction phase, the current right-associative operator has
-a priority one greater than any other operator of otherwise equal
-precedence that has been pushed on the top of the stack.  This avoids
-a reduction pass, and effectively makes the logic right-associative.
+than the operator on the top of the stack, we reduce the stack by one
+operator and repeat the test.  Since equal priorities do not reduce,
+this is naturally right-associative.
+
+We handle left-associative operators by decrementing the priority of
+just-lexed operators by one, but retaining the priority of operators
+already on the stack.
 
 The remaining cases are '(' and ')'.  We handle '(' by skipping the
 reduction phase completely.  ')' is given lower priority than
 everything else, including '(', effectively forcing a reduction of the
-parenthesised expression.  If there is no matching '(', the stack will
-be reduced all the way to the beginning, exiting the parser in the
-same way as the ultra-low priority end-of-expression dummy operator.
-The exit code checks to see if the operator that caused it is ')', and
-if so outputs an appropriate error message.
-
-The parser assumes all shifted operators require a right operand
-unless the flag NO_R_OPERAND is set, and similarly for NO_L_OPERAND.
-These semantics are automatically checked, any extra semantics need to
-be handled with operator-specific code.  */
-
-#define FLAG_BITS  8
-#define FLAG_MASK ((1 << FLAG_BITS) - 1)
-#define PRIO_SHIFT (FLAG_BITS + 1)
-#define EXTRACT_PRIO(CNST) ((CNST) >> FLAG_BITS)
-#define EXTRACT_FLAGS(CNST) ((CNST) & FLAG_MASK)
-
-/* Flags.  */
-#define HAVE_VALUE     (1 << 0)
-#define NO_L_OPERAND   (1 << 1)
-#define NO_R_OPERAND   (1 << 2)
-#define SHORT_CIRCUIT  (1 << 3)
-
-/* Priority and flag combinations.  */
-#define RIGHT_ASSOC         (1 << FLAG_BITS)
-#define FORCE_REDUCE_PRIO   (0 << PRIO_SHIFT)
-#define CLOSE_PAREN_PRIO    (1 << PRIO_SHIFT)
-#define OPEN_PAREN_PRIO    ((2 << PRIO_SHIFT) | NO_L_OPERAND)
-#define COMMA_PRIO          (3 << PRIO_SHIFT)
-#define COND_PRIO          ((4 << PRIO_SHIFT) | RIGHT_ASSOC | SHORT_CIRCUIT)
-#define COLON_PRIO         ((5 << PRIO_SHIFT) | SHORT_CIRCUIT)
-#define OROR_PRIO          ((6 << PRIO_SHIFT) | SHORT_CIRCUIT)
-#define ANDAND_PRIO        ((7 << PRIO_SHIFT) | SHORT_CIRCUIT)
-#define OR_PRIO             (8 << PRIO_SHIFT)
-#define XOR_PRIO            (9 << PRIO_SHIFT)
-#define AND_PRIO           (10 << PRIO_SHIFT)
-#define MINMAX_PRIO       (11 << PRIO_SHIFT)
-#define EQUAL_PRIO         (12 << PRIO_SHIFT)
-#define LESS_PRIO          (13 << PRIO_SHIFT)
-#define SHIFT_PRIO         (14 << PRIO_SHIFT)
-#define PLUS_PRIO          (15 << PRIO_SHIFT)
-#define MUL_PRIO           (16 << PRIO_SHIFT)
-#define UNARY_PRIO        ((17 << PRIO_SHIFT) | RIGHT_ASSOC | NO_L_OPERAND)
+parenthesised expression.  If there is a matching '(', the routine
+reduce() exits immediately.  If the normal exit route sees a ')', then
+there cannot have been a matching '(' and an error message is output.
+
+The parser assumes all shifted operators require a left operand unless
+the flag NO_L_OPERAND is set.  These semantics are automatic; any
+extra semantics need to be handled with operator-specific code.  */
+
+/* Flags.  If CHECK_PROMOTION, we warn if the effective sign of an
+   operand changes because of integer promotions.  */
+#define NO_L_OPERAND   (1 << 0)
+#define LEFT_ASSOC     (1 << 1)
+#define CHECK_PROMOTION        (1 << 2)
 
 /* Operator to priority map.  Must be in the same order as the first
    N entries of enum cpp_ttype.  */
-static const short
-op_to_prio[] =
+static const struct operator
 {
-  /* EQ */             0,              /* dummy entry - can't happen */
-  /* NOT */            UNARY_PRIO,
-  /* GREATER */                LESS_PRIO,
-  /* LESS */           LESS_PRIO,
-  /* PLUS */           UNARY_PRIO,     /* note these two can be unary */
-  /* MINUS */          UNARY_PRIO,     /* or binary */
-  /* MULT */           MUL_PRIO,
-  /* DIV */            MUL_PRIO,
-  /* MOD */            MUL_PRIO,
-  /* AND */            AND_PRIO,
-  /* OR */             OR_PRIO,
-  /* XOR */            XOR_PRIO,
-  /* RSHIFT */         SHIFT_PRIO,
-  /* LSHIFT */         SHIFT_PRIO,
-  /* MIN */            MINMAX_PRIO,    /* C++ specific */
-  /* MAX */            MINMAX_PRIO,    /* extensions */
-
-  /* COMPL */          UNARY_PRIO,
-  /* AND_AND */                ANDAND_PRIO,
-  /* OR_OR */          OROR_PRIO,
-  /* QUERY */          COND_PRIO,
-  /* COLON */          COLON_PRIO,
-  /* COMMA */          COMMA_PRIO,
-  /* OPEN_PAREN */     OPEN_PAREN_PRIO,
-  /* CLOSE_PAREN */    CLOSE_PAREN_PRIO,
-  /* EQ_EQ */          EQUAL_PRIO,
-  /* NOT_EQ */         EQUAL_PRIO,
-  /* GREATER_EQ */     LESS_PRIO,
-  /* LESS_EQ */                LESS_PRIO
+  uchar prio;
+  uchar flags;
+} optab[] =
+{
+  /* EQ */             {0, 0}, /* Shouldn't happen.  */
+  /* NOT */            {16, NO_L_OPERAND},
+  /* GREATER */                {12, LEFT_ASSOC | CHECK_PROMOTION},
+  /* LESS */           {12, LEFT_ASSOC | CHECK_PROMOTION},
+  /* PLUS */           {14, LEFT_ASSOC | CHECK_PROMOTION},
+  /* MINUS */          {14, LEFT_ASSOC | CHECK_PROMOTION},
+  /* MULT */           {15, LEFT_ASSOC | CHECK_PROMOTION},
+  /* DIV */            {15, LEFT_ASSOC | CHECK_PROMOTION},
+  /* MOD */            {15, LEFT_ASSOC | CHECK_PROMOTION},
+  /* AND */            {9, LEFT_ASSOC | CHECK_PROMOTION},
+  /* OR */             {7, LEFT_ASSOC | CHECK_PROMOTION},
+  /* XOR */            {8, LEFT_ASSOC | CHECK_PROMOTION},
+  /* RSHIFT */         {13, LEFT_ASSOC},
+  /* LSHIFT */         {13, LEFT_ASSOC},
+
+  /* MIN */            {10, LEFT_ASSOC | CHECK_PROMOTION},
+  /* MAX */            {10, LEFT_ASSOC | CHECK_PROMOTION},
+
+  /* COMPL */          {16, NO_L_OPERAND},
+  /* AND_AND */                {6, LEFT_ASSOC},
+  /* OR_OR */          {5, LEFT_ASSOC},
+  /* QUERY */          {3, 0},
+  /* COLON */          {4, LEFT_ASSOC | CHECK_PROMOTION},
+  /* COMMA */          {2, LEFT_ASSOC},
+  /* OPEN_PAREN */     {1, NO_L_OPERAND},
+  /* CLOSE_PAREN */    {0, 0},
+  /* EOF */            {0, 0},
+  /* EQ_EQ */          {11, LEFT_ASSOC},
+  /* NOT_EQ */         {11, LEFT_ASSOC},
+  /* GREATER_EQ */     {12, LEFT_ASSOC | CHECK_PROMOTION},
+  /* LESS_EQ */                {12, LEFT_ASSOC | CHECK_PROMOTION},
+  /* UPLUS */          {16, NO_L_OPERAND},
+  /* UMINUS */         {16, NO_L_OPERAND}
 };
 
-#define COMPARE(OP) \
-  top->unsignedp = 0; \
-  top->value = (unsigned1 | unsigned2) \
-  ? (unsigned HOST_WIDEST_INT) v1 OP (unsigned HOST_WIDEST_INT) v2 \
-  : (v1 OP v2)
-#define EQUALITY(OP) \
-  top->value = v1 OP v2; \
-  top->unsignedp = 0;
-#define BITWISE(OP) \
-  top->value = v1 OP v2; \
-  top->unsignedp = unsigned1 | unsigned2;
-#define MINMAX(OP) \
-  top->value = (v1 OP v2) ? v1 : v2; \
-  top->unsignedp = unsigned1 | unsigned2;
-#define UNARY(OP) \
-  top->value = OP v2; \
-  top->unsignedp = unsigned2; \
-  top->flags |= HAVE_VALUE;
-#define SHIFT(PSH, MSH) \
-  if (skip_evaluation)  \
-    break;             \
-  top->unsignedp = unsigned1; \
-  if (v2 < 0 && ! unsigned2)  \
-    top->value = MSH (pfile, v1, unsigned1, -v2); \
-  else \
-    top->value = PSH (pfile, v1, unsigned1, v2);
-
 /* Parse and evaluate a C expression, reading from PFILE.
-   Returns the truth value of the expression.  */
-int
+   Returns the truth value of the expression.
+
+   The implementation is an operator precedence parser, i.e. a
+   bottom-up parser, using a stack for not-yet-reduced tokens.
+
+   The stack base is op_stack, and the current stack pointer is 'top'.
+   There is a stack element for each operator (only), and the most
+   recently pushed operator is 'top->op'.  An operand (value) is
+   stored in the 'value' field of the stack element of the operator
+   that precedes it.  */
+bool
 _cpp_parse_expr (pfile)
      cpp_reader *pfile;
 {
-  /* The implementation is an operator precedence parser, i.e. a
-     bottom-up parser, using a stack for not-yet-reduced tokens.
-
-     The stack base is 'stack', and the current stack pointer is 'top'.
-     There is a stack element for each operator (only),
-     and the most recently pushed operator is 'top->op'.
-     An operand (value) is stored in the 'value' field of the stack
-     element of the operator that precedes it.
-     In that case the 'flags' field has the HAVE_VALUE flag set.  */
-
-#define INIT_STACK_SIZE 20
-  struct op init_stack[INIT_STACK_SIZE];
-  struct op *stack = init_stack;
-  struct op *limit = stack + INIT_STACK_SIZE;
-  struct op *top = stack + 1;
-  int skip_evaluation = 0;
-  int result;
-  unsigned int lex_count, saw_leading_not;
+  struct op *top = pfile->op_stack;
+  unsigned int lex_count;
+  bool saw_leading_not, want_value = true;
+
+  pfile->state.skip_eval = 0;
 
   /* Set up detection of #if ! defined().  */
   pfile->mi_ind_cmacro = 0;
-  saw_leading_not = 0;
+  saw_leading_not = false;
   lex_count = 0;
 
-  /* We've finished when we try to reduce this.  */
+  /* Lowest priority operator prevents further reductions.  */
   top->op = CPP_EOF;
-  /* Nifty way to catch missing '('.  */
-  top->prio = EXTRACT_PRIO(CLOSE_PAREN_PRIO);
-  /* Avoid missing right operand checks.  */
-  top->flags = NO_R_OPERAND;
 
   for (;;)
     {
-      unsigned int prio;
-      unsigned int flags;
       struct op op;
 
-      /* Read a token */
-      op = lex (pfile, skip_evaluation);
       lex_count++;
+      op.token = cpp_get_token (pfile);
+      op.op = op.token->type;
 
-      /* If the token is an operand, push its value and get next
-        token.  If it is an operator, get its priority and flags, and
-        try to reduce the expression on the stack.  */
       switch (op.op)
        {
-       case CPP_ERROR:
-         goto syntax_error;
-       push_immediate:
+         /* These tokens convert into values.  */
        case CPP_NUMBER:
-         /* Push a value onto the stack.  */
-         if (top->flags & HAVE_VALUE)
-           SYNTAX_ERROR ("missing binary operator");
-         top->value = op.value;
-         top->unsignedp = op.unsignedp;
-         top->flags |= HAVE_VALUE;
+       case CPP_CHAR:
+       case CPP_WCHAR:
+       case CPP_NAME:
+       case CPP_HASH:
+         if (!want_value)
+           SYNTAX_ERROR2 ("missing binary operator before token \"%s\"",
+                          cpp_token_as_text (pfile, op.token));
+         want_value = false;
+         top->value = eval_token (pfile, op.token);
          continue;
 
-       case CPP_EOF:   prio = FORCE_REDUCE_PRIO;       break;
-
        case CPP_NOT:
          saw_leading_not = lex_count == 1;
-         prio = op_to_prio[op.op];
          break;
        case CPP_PLUS:
-       case CPP_MINUS: prio = PLUS_PRIO;  if (top->flags & HAVE_VALUE) break;
-          /* else unary; fall through */
-       default:        prio = op_to_prio[op.op];       break;
-       }
-
-      /* Separate the operator's code into priority and flags.  */
-      flags = EXTRACT_FLAGS(prio);
-      prio = EXTRACT_PRIO(prio);
-      if (prio == EXTRACT_PRIO(OPEN_PAREN_PRIO))
-       goto skip_reduction;
-
-      /* Check for reductions.  Then push the operator.  */
-      while (prio <= top->prio)
-       {
-         HOST_WIDEST_INT v1, v2;
-         unsigned int unsigned1, unsigned2;
-         
-         /* Most operators that can appear on the stack require a
-            right operand.  Check this before trying to reduce.  */
-         if ((top->flags & (HAVE_VALUE | NO_R_OPERAND)) == 0)
+         if (want_value)
+           op.op = CPP_UPLUS;
+         break;
+       case CPP_MINUS:
+         if (want_value)
+           op.op = CPP_UMINUS;
+         break;
+       case CPP_OTHER:
+         if (ISGRAPH (op.token->val.c))
+           SYNTAX_ERROR2 ("invalid character '%c' in #if", op.token->val.c);
+         else
+           SYNTAX_ERROR2 ("invalid character '\\%03o' in #if",
+                          op.token->val.c);
+
+       default:
+         if ((int) op.op <= (int) CPP_EQ || (int) op.op >= (int) CPP_PLUS_EQ)
+           SYNTAX_ERROR2 ("token \"%s\" is not valid in preprocessor expressions",
+                          cpp_token_as_text (pfile, op.token));
+         break;
+       }
+
+      /* Check we have a value or operator as appropriate.  */
+      if (optab[op.op].flags & NO_L_OPERAND)
+       {
+         if (!want_value)
+           SYNTAX_ERROR2 ("missing binary operator before token \"%s\"",
+                          cpp_token_as_text (pfile, op.token));
+       }
+      else if (want_value)
+       {
+         /* Ordering here is subtle and intended to favor the
+            missing parenthesis diagnostics over alternatives.  */
+         if (op.op == CPP_CLOSE_PAREN)
            {
              if (top->op == CPP_OPEN_PAREN)
                SYNTAX_ERROR ("void expression between '(' and ')'");
-             else
-               SYNTAX_ERROR2 ("operator '%s' has no right operand",
-                              op_as_text (pfile, top->op));
            }
+         else if (top->op == CPP_EOF)
+           SYNTAX_ERROR ("#if with no expression");
+         if (top->op != CPP_EOF && top->op != CPP_OPEN_PAREN)
+           SYNTAX_ERROR2 ("operator '%s' has no right operand",
+                          cpp_token_as_text (pfile, top->token));
+       }
+
+      top = reduce (pfile, top, op.op);
+      if (!top)
+       goto syntax_error;
+
+      if (op.op == CPP_EOF)
+       break;
+
+      switch (op.op)
+       {
+       case CPP_CLOSE_PAREN:
+         continue;
+       case CPP_OR_OR:
+         if (!num_zerop (top->value))
+           pfile->state.skip_eval++;
+         break;
+       case CPP_AND_AND:
+       case CPP_QUERY:
+         if (num_zerop (top->value))
+           pfile->state.skip_eval++;
+         break;
+       case CPP_COLON:
+         if (top->op != CPP_QUERY)
+           SYNTAX_ERROR (" ':' without preceding '?'");
+         if (!num_zerop (top[-1].value)) /* Was '?' condition true?  */
+           pfile->state.skip_eval++;
+         else
+           pfile->state.skip_eval--;
+       default:
+         break;
+       }
+
+      want_value = true;
+
+      /* Check for and handle stack overflow.  */
+      if (++top == pfile->op_limit)
+       top = _cpp_expand_op_stack (pfile);
+
+      top->op = op.op;
+      top->token = op.token;
+    }
+
+  /* The controlling macro expression is only valid if we called lex 3
+     times: <!> <defined expression> and <EOF>.  push_conditional ()
+     checks that we are at top-of-file.  */
+  if (pfile->mi_ind_cmacro && !(saw_leading_not && lex_count == 3))
+    pfile->mi_ind_cmacro = 0;
+
+  if (top != pfile->op_stack)
+    {
+      cpp_error (pfile, DL_ICE, "unbalanced stack in #if");
+    syntax_error:
+      return false;  /* Return false on syntax error.  */
+    }
+
+  return !num_zerop (top->value);
+}
+
+/* Reduce the operator / value stack if possible, in preparation for
+   pushing operator OP.  Returns NULL on error, otherwise the top of
+   the stack.  */
+static struct op *
+reduce (pfile, top, op)
+     cpp_reader *pfile;
+     struct op *top;
+     enum cpp_ttype op;
+{
+  unsigned int prio;
 
-         unsigned2 = top->unsignedp, v2 = top->value;
+  if (top->op <= CPP_EQ || top->op > CPP_LAST_CPP_OP + 2)
+    {
+    bad_op:
+      cpp_error (pfile, DL_ICE, "impossible operator '%u'", top->op);
+      return 0;
+    }
+
+  if (op == CPP_OPEN_PAREN)
+    return top;
+
+  /* Decrement the priority of left-associative operators to force a
+     reduction with operators of otherwise equal priority.  */
+  prio = optab[op].prio - ((optab[op].flags & LEFT_ASSOC) != 0);
+  while (prio < optab[top->op].prio)
+    {
+      if (CPP_OPTION (pfile, warn_num_sign_change)
+         && optab[top->op].flags & CHECK_PROMOTION)
+       check_promotion (pfile, top);
+
+      switch (top->op)
+       {
+       case CPP_UPLUS:
+       case CPP_UMINUS:
+       case CPP_NOT:
+       case CPP_COMPL:
+         top[-1].value = num_unary_op (pfile, top->value, top->op);
+         break;
+
+       case CPP_PLUS:
+       case CPP_MINUS:
+       case CPP_RSHIFT:
+       case CPP_LSHIFT:
+       case CPP_MIN:
+       case CPP_MAX:
+       case CPP_COMMA:
+         top[-1].value = num_binary_op (pfile, top[-1].value,
+                                        top->value, top->op);
+         break;
+
+       case CPP_GREATER:
+       case CPP_LESS:
+       case CPP_GREATER_EQ:
+       case CPP_LESS_EQ:
+         top[-1].value
+           = num_inequality_op (pfile, top[-1].value, top->value, top->op);
+         break;
+
+       case CPP_EQ_EQ:
+       case CPP_NOT_EQ:
+         top[-1].value
+           = num_equality_op (pfile, top[-1].value, top->value, top->op);
+         break;
+
+       case CPP_AND:
+       case CPP_OR:
+       case CPP_XOR:
+         top[-1].value
+           = num_bitwise_op (pfile, top[-1].value, top->value, top->op);
+         break;
+
+       case CPP_MULT:
+         top[-1].value = num_mul (pfile, top[-1].value, top->value);
+         break;
+
+       case CPP_DIV:
+       case CPP_MOD:
+         top[-1].value = num_div_op (pfile, top[-1].value,
+                                     top->value, top->op);
+         break;
+
+       case CPP_OR_OR:
+         top--;
+         if (!num_zerop (top->value))
+           pfile->state.skip_eval--;
+         top->value.low = (!num_zerop (top->value)
+                           || !num_zerop (top[1].value));
+         top->value.high = 0;
+         top->value.unsignedp = false;
+         top->value.overflow = false;
+         continue;
+
+       case CPP_AND_AND:
          top--;
-         unsigned1 = top->unsignedp, v1 = top->value;
+         if (num_zerop (top->value))
+           pfile->state.skip_eval--;
+         top->value.low = (!num_zerop (top->value)
+                           && !num_zerop (top[1].value));
+         top->value.high = 0;
+         top->value.unsignedp = false;
+         top->value.overflow = false;
+         continue;
 
-         /* Now set top->value = (top[1].op)(v1, v2); */
-         switch (top[1].op)
+       case CPP_OPEN_PAREN:
+         if (op != CPP_CLOSE_PAREN)
            {
-           default:
-             cpp_ice (pfile, "impossible operator '%s'",
-                              op_as_text (pfile, top[1].op));
-             goto syntax_error;
-
-           case CPP_NOT:        UNARY(!);      break;
-           case CPP_COMPL:      UNARY(~);      break;
-           case CPP_LESS:       COMPARE(<);    break;
-           case CPP_GREATER:    COMPARE(>);    break;
-           case CPP_LESS_EQ:    COMPARE(<=);   break;
-           case CPP_GREATER_EQ: COMPARE(>=);   break;
-           case CPP_EQ_EQ:      EQUALITY(==);  break;
-           case CPP_NOT_EQ:     EQUALITY(!=);  break;
-           case CPP_AND:        BITWISE(&);    break;
-           case CPP_XOR:        BITWISE(^);    break;
-           case CPP_OR:         BITWISE(|);    break;
-           case CPP_LSHIFT:     SHIFT(left_shift, right_shift); break;
-           case CPP_RSHIFT:     SHIFT(right_shift, left_shift); break;
-           case CPP_MIN:        MINMAX(<);     break;
-           case CPP_MAX:        MINMAX(>);     break;
-
-           case CPP_PLUS:
-             if (!(top->flags & HAVE_VALUE))
-               {
-                 /* Can't use UNARY(+) because K+R C did not have unary
-                    plus.  Can't use UNARY() because some compilers object
-                    to the empty argument.  */
-                 top->value = v2;
-                 top->unsignedp = unsigned2;
-                 top->flags |= HAVE_VALUE;
-
-                 if (CPP_WTRADITIONAL (pfile))
-                   cpp_warning (pfile,
-                       "traditional C rejects the unary plus operator");
-               }
-             else
-               {
-                 top->value = v1 + v2;
-                 top->unsignedp = unsigned1 | unsigned2;
-                 if (! top->unsignedp && ! skip_evaluation
-                     && ! possible_sum_sign (v1, v2, top->value))
-                   integer_overflow (pfile);
-               }
-             break;
-           case CPP_MINUS:
-             if (!(top->flags & HAVE_VALUE))
-               {
-                 UNARY(-);
-                 if (!skip_evaluation && (top->value & v2) < 0 && !unsigned2)
-                   integer_overflow (pfile);
-               }
-             else
-               { /* Binary '-' */
-                 top->value = v1 - v2;
-                 top->unsignedp = unsigned1 | unsigned2;
-                 if (! top->unsignedp && ! skip_evaluation
-                     && ! possible_sum_sign (top->value, v2, v1))
-                   integer_overflow (pfile);
-               }
-             break;
-           case CPP_MULT:
-             top->unsignedp = unsigned1 | unsigned2;
-             if (top->unsignedp)
-               top->value = (unsigned HOST_WIDEST_INT) v1 * v2;
-             else if (!skip_evaluation)
-               {
-                 top->value = v1 * v2;
-                 if (v1 && (top->value / v1 != v2
-                            || (top->value & v1 & v2) < 0))
-                   integer_overflow (pfile);
-               }
-             break;
-           case CPP_DIV:
-           case CPP_MOD:
-             if (skip_evaluation)
-               break;
-             if (v2 == 0)
-               SYNTAX_ERROR ("division by zero in #if");
-             top->unsignedp = unsigned1 | unsigned2;
-             if (top[1].op == CPP_DIV)
-               {
-                 if (top->unsignedp)
-                   top->value = (unsigned HOST_WIDEST_INT) v1 / v2;
-                 else
-                   {
-                     top->value = v1 / v2;
-                     if ((top->value & v1 & v2) < 0)
-                       integer_overflow (pfile);
-                   }
-               }
-             else
-               {
-                 if (top->unsignedp)
-                   top->value = (unsigned HOST_WIDEST_INT) v1 % v2;
-                 else
-                   top->value = v1 % v2;
-               }
-             break;
-
-           case CPP_OR_OR:
-             top->value = v1 || v2;
-             top->unsignedp = 0;
-             if (v1) skip_evaluation--;
-             break;
-           case CPP_AND_AND:
-             top->value = v1 && v2;
-             top->unsignedp = 0;
-             if (!v1) skip_evaluation--;
-             break;
-           case CPP_COMMA:
-             if (CPP_PEDANTIC (pfile))
-               cpp_pedwarn (pfile, "comma operator in operand of #if");
-             top->value = v2;
-             top->unsignedp = unsigned2;
-             break;
-           case CPP_QUERY:
-             SYNTAX_ERROR ("syntax error '?' without following ':'");
-           case CPP_COLON:
-             if (top[0].op != CPP_QUERY)
-               SYNTAX_ERROR ("syntax error ':' without preceding '?'");
-             top--;
-             if (top->value) skip_evaluation--;
-             top->value = top->value ? v1 : v2;
-             top->unsignedp = unsigned1 | unsigned2;
-             break;
-           case CPP_OPEN_PAREN:
-             if (op.op != CPP_CLOSE_PAREN)
-               SYNTAX_ERROR ("missing ')' in expression");
-             op.value = v2;
-             op.unsignedp = unsigned2;
-             goto push_immediate;
-           case CPP_EOF:
-             /* Reducing this dummy operator indicates we've finished.  */
-             if (op.op == CPP_CLOSE_PAREN)
-               SYNTAX_ERROR ("missing '(' in expression");
-             goto done;
+             cpp_error (pfile, DL_ERROR, "missing ')' in expression");
+             return 0;
            }
+         top--;
+         top->value = top[1].value;
+         return top;
+
+       case CPP_COLON:
+         top -= 2;
+         if (!num_zerop (top->value))
+           {
+             pfile->state.skip_eval--;
+             top->value = top[1].value;
+           }
+         else
+           top->value = top[2].value;
+         top->value.unsignedp = (top[1].value.unsignedp
+                                 || top[2].value.unsignedp);
+         continue;
+
+       case CPP_QUERY:
+         cpp_error (pfile, DL_ERROR, "'?' without following ':'");
+         return 0;
+
+       default:
+         goto bad_op;
        }
 
-      /* Handle short-circuit evaluations.  */
-      if (flags & SHORT_CIRCUIT)
-       switch (op.op)
-         {
-         case CPP_OR_OR:    if (top->value) skip_evaluation++; break;
-         case CPP_AND_AND:
-         case CPP_QUERY:    if (!top->value) skip_evaluation++; break;
-         case CPP_COLON:
-           if (top[-1].value) /* Was '?' condition true?  */
-             skip_evaluation++;
-           else
-             skip_evaluation--;
-         default:
-           break;
-         }
+      top--;
+      if (top->value.overflow && !pfile->state.skip_eval)
+       cpp_error (pfile, DL_PEDWARN,
+                  "integer overflow in preprocessor expression");
+    }
+
+  if (op == CPP_CLOSE_PAREN)
+    {
+      cpp_error (pfile, DL_ERROR, "missing '(' in expression");
+      return 0;
+    }
+
+  return top;
+}
+
+/* Returns the position of the old top of stack after expansion.  */
+struct op *
+_cpp_expand_op_stack (pfile)
+     cpp_reader *pfile;
+{
+  size_t old_size = (size_t) (pfile->op_limit - pfile->op_stack);
+  size_t new_size = old_size * 2 + 20;
+
+  pfile->op_stack = (struct op *) xrealloc (pfile->op_stack,
+                                           new_size * sizeof (struct op));
+  pfile->op_limit = pfile->op_stack + new_size;
+
+  return pfile->op_stack + old_size;
+}
+
+/* Emits a warning if the effective sign of either operand of OP
+   changes because of integer promotions.  */
+static void
+check_promotion (pfile, op)
+     cpp_reader *pfile;
+     const struct op *op;
+{
+  if (op->value.unsignedp == op[-1].value.unsignedp)
+    return;
+
+  if (op->value.unsignedp)
+    {
+      if (!num_positive (op[-1].value, CPP_OPTION (pfile, precision)))
+       cpp_error (pfile, DL_WARNING,
+                  "the left operand of \"%s\" changes sign when promoted",
+                  cpp_token_as_text (pfile, op->token));
+    }
+  else if (!num_positive (op->value, CPP_OPTION (pfile, precision)))
+    cpp_error (pfile, DL_WARNING,
+              "the right operand of \"%s\" changes sign when promoted",
+              cpp_token_as_text (pfile, op->token));
+}
+
+/* Clears the unused high order bits of the number pointed to by PNUM.  */
+static cpp_num
+num_trim (num, precision)
+     cpp_num num;
+     size_t precision;
+{
+  if (precision > PART_PRECISION)
+    {
+      precision -= PART_PRECISION;
+      if (precision < PART_PRECISION)
+       num.high &= ((cpp_num_part) 1 << precision) - 1;
+    }
+  else
+    {
+      if (precision < PART_PRECISION)
+       num.low &= ((cpp_num_part) 1 << precision) - 1;
+      num.high = 0;
+    }
+
+  return num;
+}
+
+/* True iff A (presumed signed) >= 0.  */
+static bool
+num_positive (num, precision)
+     cpp_num num;
+     size_t precision;
+{
+  if (precision > PART_PRECISION)
+    {
+      precision -= PART_PRECISION;
+      return (num.high & (cpp_num_part) 1 << (precision - 1)) == 0;
+    }
+
+  return (num.low & (cpp_num_part) 1 << (precision - 1)) == 0;
+}
+
+/* Sign extend a number, with PRECISION significant bits and all
+   others assumed clear, to fill out a cpp_num structure.  */
+cpp_num
+cpp_num_sign_extend (num, precision)
+     cpp_num num;
+     size_t precision;
+{
+  if (!num.unsignedp)
+    {
+      if (precision > PART_PRECISION)
+       {
+         precision -= PART_PRECISION;
+         if (precision < PART_PRECISION
+             && (num.high & (cpp_num_part) 1 << (precision - 1)))
+           num.high |= ~(~(cpp_num_part) 0 >> (PART_PRECISION - precision));
+       }
+      else if (num.low & (cpp_num_part) 1 << (precision - 1))
+       {
+         if (precision < PART_PRECISION)
+           num.low |= ~(~(cpp_num_part) 0 >> (PART_PRECISION - precision));
+         num.high = ~(cpp_num_part) 0;
+       }
+    }
+
+  return num;
+}
+
+/* Returns the negative of NUM.  */
+static cpp_num
+num_negate (num, precision)
+     cpp_num num;
+     size_t precision;
+{
+  cpp_num copy;
+
+  copy = num;
+  num.high = ~num.high;
+  num.low = ~num.low;
+  if (++num.low == 0)
+    num.high++;
+  num = num_trim (num, precision);
+  num.overflow = (!num.unsignedp && num_eq (num, copy) && !num_zerop (num));
+
+  return num;
+}
+
+/* Returns true if A >= B.  */
+static bool
+num_greater_eq (pa, pb, precision)
+     cpp_num pa, pb;
+     size_t precision;
+{
+  bool unsignedp;
+
+  unsignedp = pa.unsignedp || pb.unsignedp;
+
+  if (!unsignedp)
+    {
+      /* Both numbers have signed type.  If they are of different
+       sign, the answer is the sign of A.  */
+      unsignedp = num_positive (pa, precision);
+
+      if (unsignedp != num_positive (pb, precision))
+       return unsignedp;
+
+      /* Otherwise we can do an unsigned comparison.  */
+    }
+
+  return (pa.high > pb.high) || (pa.high == pb.high && pa.low >= pb.low);
+}
+
+/* Returns LHS OP RHS, where OP is a bit-wise operation.  */
+static cpp_num
+num_bitwise_op (pfile, lhs, rhs, op)
+     cpp_reader *pfile ATTRIBUTE_UNUSED;
+     cpp_num lhs, rhs;
+     enum cpp_ttype op;
+{
+  lhs.overflow = false;
+  lhs.unsignedp = lhs.unsignedp || rhs.unsignedp;
+
+  /* As excess precision is zeroed, there is no need to num_trim () as
+     these operations cannot introduce a set bit there.  */
+  if (op == CPP_AND)
+    {
+      lhs.low &= rhs.low;
+      lhs.high &= rhs.high;
+    }
+  else if (op == CPP_OR)
+    {
+      lhs.low |= rhs.low;
+      lhs.high |= rhs.high;
+    }
+  else
+    {
+      lhs.low ^= rhs.low;
+      lhs.high ^= rhs.high;
+    }
+
+  return lhs;
+}
+
+/* Returns LHS OP RHS, where OP is an inequality.  */
+static cpp_num
+num_inequality_op (pfile, lhs, rhs, op)
+     cpp_reader *pfile;
+     cpp_num lhs, rhs;
+     enum cpp_ttype op;
+{
+  bool gte = num_greater_eq (lhs, rhs, CPP_OPTION (pfile, precision));
+
+  if (op == CPP_GREATER_EQ)
+    lhs.low = gte;
+  else if (op == CPP_LESS)
+    lhs.low = !gte;
+  else if (op == CPP_GREATER)
+    lhs.low = gte && !num_eq (lhs, rhs);
+  else /* CPP_LESS_EQ.  */
+    lhs.low = !gte || num_eq (lhs, rhs);
+
+  lhs.high = 0;
+  lhs.overflow = false;
+  lhs.unsignedp = false;
+  return lhs;
+}
+
+/* Returns LHS OP RHS, where OP is == or !=.  */
+static cpp_num
+num_equality_op (pfile, lhs, rhs, op)
+     cpp_reader *pfile ATTRIBUTE_UNUSED;
+     cpp_num lhs, rhs;
+     enum cpp_ttype op;
+{
+  /* Work around a 3.0.4 bug; see PR 6950.  */
+  bool eq = num_eq (lhs, rhs);
+  if (op == CPP_NOT_EQ)
+    eq = !eq;
+  lhs.low = eq;
+  lhs.high = 0;
+  lhs.overflow = false;
+  lhs.unsignedp = false;
+  return lhs;
+}
+
+/* Shift NUM, of width PRECISION, right by N bits.  */
+static cpp_num
+num_rshift (num, precision, n)
+     cpp_num num;
+     size_t precision, n;
+{
+  cpp_num_part sign_mask;
+
+  if (num.unsignedp || num_positive (num, precision))
+    sign_mask = 0;
+  else
+    sign_mask = ~(cpp_num_part) 0;
+
+  if (n >= precision)
+    num.high = num.low = sign_mask;
+  else
+    {
+      /* Sign-extend.  */
+      if (precision < PART_PRECISION)
+       num.high = sign_mask, num.low |= sign_mask << precision;
+      else if (precision < 2 * PART_PRECISION)
+       num.high |= sign_mask << (precision - PART_PRECISION);
+
+      if (n >= PART_PRECISION)
+       {
+         n -= PART_PRECISION;
+         num.low = num.high;
+         num.high = sign_mask;
+       }
 
-    skip_reduction:
-      /* Check we have a left operand iff we need one.  */
-      if (flags & NO_L_OPERAND)
+      if (n)
        {
-         if (top->flags & HAVE_VALUE)
-           SYNTAX_ERROR2 ("missing binary operator before '%s'",
-                          op_as_text (pfile, op.op));
+         num.low = (num.low >> n) | (num.high << (PART_PRECISION - n));
+         num.high = (num.high >> n) | (sign_mask << (PART_PRECISION - n));
        }
+    }
+
+  num = num_trim (num, precision);
+  num.overflow = false;
+  return num;
+}
+
+/* Shift NUM, of width PRECISION, left by N bits.  */
+static cpp_num
+num_lshift (num, precision, n)
+     cpp_num num;
+     size_t precision, n;
+{
+  if (n >= precision)
+    {
+      num.overflow = !num.unsignedp && !num_zerop (num);
+      num.high = num.low = 0;
+    }
+  else
+    {
+      cpp_num orig, maybe_orig;
+      size_t m = n;
+
+      orig = num;
+      if (m >= PART_PRECISION)
+       {
+         m -= PART_PRECISION;
+         num.high = num.low;
+         num.low = 0;
+       }
+      if (m)
+       {
+         num.high = (num.high << m) | (num.low >> (PART_PRECISION - m));
+         num.low <<= m;
+       }
+      num = num_trim (num, precision);
+
+      if (num.unsignedp)
+       num.overflow = false;
       else
        {
-         if (!(top->flags & HAVE_VALUE))
-           SYNTAX_ERROR2 ("operator '%s' has no left operand",
-                          op_as_text (pfile, op.op));
+         maybe_orig = num_rshift (num, precision, n);
+         num.overflow = !num_eq (orig, maybe_orig);
        }
+    }
 
-      /* Check for and handle stack overflow.  */
-      top++;
-      if (top == limit)
-       {
-         struct op *new_stack;
-         int old_size = (char *) limit - (char *) stack;
-         int new_size = 2 * old_size;
-         if (stack != init_stack)
-           new_stack = (struct op *) xrealloc (stack, new_size);
+  return num;
+}
+
+/* The four unary operators: +, -, ! and ~.  */
+static cpp_num
+num_unary_op (pfile, num, op)
+     cpp_reader *pfile;
+     cpp_num num;
+     enum cpp_ttype op;
+{
+  switch (op)
+    {
+    case CPP_UPLUS:
+      if (CPP_WTRADITIONAL (pfile) && !pfile->state.skip_eval)
+       cpp_error (pfile, DL_WARNING,
+                  "traditional C rejects the unary plus operator");
+      num.overflow = false;
+      break;
+
+    case CPP_UMINUS:
+      num = num_negate (num, CPP_OPTION (pfile, precision));
+      break;
+
+    case CPP_COMPL:
+      num.high = ~num.high;
+      num.low = ~num.low;
+      num = num_trim (num, CPP_OPTION (pfile, precision));
+      num.overflow = false;
+      break;
+
+    default: /* case CPP_NOT: */
+      num.low = num_zerop (num);
+      num.high = 0;
+      num.overflow = false;
+      num.unsignedp = false;
+      break;
+    }
+
+  return num;
+}
+
+/* The various binary operators.  */
+static cpp_num
+num_binary_op (pfile, lhs, rhs, op)
+     cpp_reader *pfile;
+     cpp_num lhs, rhs;
+     enum cpp_ttype op;
+{
+  cpp_num result;
+  size_t precision = CPP_OPTION (pfile, precision);
+  bool gte;
+  size_t n;
+
+  switch (op)
+    {
+      /* Shifts.  */
+    case CPP_LSHIFT:
+    case CPP_RSHIFT:
+      if (!rhs.unsignedp && !num_positive (rhs, precision))
+       {
+         /* A negative shift is a positive shift the other way.  */
+         if (op == CPP_LSHIFT)
+           op = CPP_RSHIFT;
          else
-           {
-             new_stack = (struct op *) xmalloc (new_size);
-             memcpy (new_stack, stack, old_size);
-           }
-         stack = new_stack;
-         top = (struct op *) ((char *) new_stack + old_size);
-         limit = (struct op *) ((char *) new_stack + new_size);
+           op = CPP_LSHIFT;
+         rhs = num_negate (rhs, precision);
        }
-      
-      top->flags = flags;
-      top->prio = prio & ~EXTRACT_PRIO(RIGHT_ASSOC);
-      top->op = op.op;
+      if (rhs.high)
+       n = ~0;                 /* Maximal.  */
+      else
+       n = rhs.low;
+      if (op == CPP_LSHIFT)
+       lhs = num_lshift (lhs, precision, n);
+      else
+       lhs = num_rshift (lhs, precision, n);
+      break;
+
+      /* Min / Max.  */
+    case CPP_MIN:
+    case CPP_MAX:
+      {
+       bool unsignedp = lhs.unsignedp || rhs.unsignedp;
+
+       gte = num_greater_eq (lhs, rhs, precision);
+       if (op == CPP_MIN)
+         gte = !gte;
+       if (!gte)
+         lhs = rhs;
+       lhs.unsignedp = unsignedp;
+      }
+      break;
+
+      /* Arithmetic.  */
+    case CPP_MINUS:
+      rhs = num_negate (rhs, precision);
+    case CPP_PLUS:
+      result.low = lhs.low + rhs.low;
+      result.high = lhs.high + rhs.high;
+      if (result.low < lhs.low)
+       result.high++;
+
+      result = num_trim (result, precision);
+      result.unsignedp = lhs.unsignedp || rhs.unsignedp;
+      if (result.unsignedp)
+       result.overflow = false;
+      else
+       {
+         bool lhsp = num_positive (lhs, precision);
+         result.overflow = (lhsp == num_positive (rhs, precision)
+                            && lhsp != num_positive (result, precision));
+       }
+      return result;
+
+      /* Comma.  */
+    default: /* case CPP_COMMA: */
+      if (CPP_PEDANTIC (pfile) && !pfile->state.skip_eval)
+       cpp_error (pfile, DL_PEDWARN,
+                  "comma operator in operand of #if");
+      lhs = rhs;
+      break;
     }
 
- done:
-  /* The controlling macro expression is only valid if we called lex 3
-     times: <!> <defined expression> and <EOF>.  push_conditional ()
-     checks that we are at top-of-file.  */
-  if (pfile->mi_ind_cmacro && !(saw_leading_not && lex_count == 3))
-    pfile->mi_ind_cmacro = 0;
+  return lhs;
+}
+
+/* Multiplies two unsigned cpp_num_parts to give a cpp_num.  This
+   cannot overflow.  */
+static cpp_num
+num_part_mul (lhs, rhs)
+     cpp_num_part lhs, rhs;
+{
+  cpp_num result;
+  cpp_num_part middle[2], temp;
+
+  result.low = LOW_PART (lhs) * LOW_PART (rhs);
+  result.high = HIGH_PART (lhs) * HIGH_PART (rhs);
+
+  middle[0] = LOW_PART (lhs) * HIGH_PART (rhs);
+  middle[1] = HIGH_PART (lhs) * LOW_PART (rhs);
 
-  result = (top[1].value != 0);
+  temp = result.low;
+  result.low += LOW_PART (middle[0]) << (PART_PRECISION / 2);
+  if (result.low < temp)
+    result.high++;
 
-  if (top != stack)
-    CPP_ICE ("unbalanced stack in #if");
-  else if (!(top[1].flags & HAVE_VALUE))
+  temp = result.low;
+  result.low += LOW_PART (middle[1]) << (PART_PRECISION / 2);
+  if (result.low < temp)
+    result.high++;
+
+  result.high += HIGH_PART (middle[0]);
+  result.high += HIGH_PART (middle[1]);
+  result.unsignedp = 1;
+
+  return result;
+}
+
+/* Multiply two preprocessing numbers.  */
+static cpp_num
+num_mul (pfile, lhs, rhs)
+     cpp_reader *pfile;
+     cpp_num lhs, rhs;
+{
+  cpp_num result, temp;
+  bool unsignedp = lhs.unsignedp || rhs.unsignedp;
+  bool overflow, negate = false;
+  size_t precision = CPP_OPTION (pfile, precision);
+
+  /* Prepare for unsigned multiplication.  */
+  if (!unsignedp)
     {
-      SYNTAX_ERROR ("#if with no expression");
-    syntax_error:
-      result = 0;  /* Return 0 on syntax error.  */
+      if (!num_positive (lhs, precision))
+       negate = !negate, lhs = num_negate (lhs, precision);
+      if (!num_positive (rhs, precision))
+       negate = !negate, rhs = num_negate (rhs, precision);
     }
 
-  /* Free dynamic stack if we allocated one.  */
-  if (stack != init_stack)
-    free (stack);
+  overflow = lhs.high && rhs.high;
+  result = num_part_mul (lhs.low, rhs.low);
+
+  temp = num_part_mul (lhs.high, rhs.low);
+  result.high += temp.low;
+  if (temp.high)
+    overflow = true;
+
+  temp = num_part_mul (lhs.low, rhs.high);
+  result.high += temp.low;
+  if (temp.high)
+    overflow = true;
+
+  temp.low = result.low, temp.high = result.high;
+  result = num_trim (result, precision);
+  if (!num_eq (result, temp))
+    overflow = true;
+
+  if (negate)
+    result = num_negate (result, precision);
+
+  if (unsignedp)
+    result.overflow = false;
+  else
+    result.overflow = overflow || (num_positive (result, precision) ^ !negate
+                                  && !num_zerop (result));
+  result.unsignedp = unsignedp;
+
   return result;
 }
 
-/* Output OP as text for diagnostics.  */
-static const unsigned char *
-op_as_text (pfile, op)
+/* Divide two preprocessing numbers, returning the answer or the
+   remainder depending upon OP.  */
+static cpp_num
+num_div_op (pfile, lhs, rhs, op)
      cpp_reader *pfile;
+     cpp_num lhs, rhs;
      enum cpp_ttype op;
 {
-  cpp_token token;
+  cpp_num result, sub;
+  cpp_num_part mask;
+  bool unsignedp = lhs.unsignedp || rhs.unsignedp;
+  bool negate = false, lhs_neg = false;
+  size_t i, precision = CPP_OPTION (pfile, precision);
+
+  /* Prepare for unsigned division.  */
+  if (!unsignedp)
+    {
+      if (!num_positive (lhs, precision))
+       negate = !negate, lhs_neg = true, lhs = num_negate (lhs, precision);
+      if (!num_positive (rhs, precision))
+       negate = !negate, rhs = num_negate (rhs, precision);
+    }
+
+  /* Find the high bit.  */
+  if (rhs.high)
+    {
+      i = precision - 1;
+      mask = (cpp_num_part) 1 << (i - PART_PRECISION);
+      for (; ; i--, mask >>= 1)
+       if (rhs.high & mask)
+         break;
+    }
+  else if (rhs.low)
+    {
+      if (precision > PART_PRECISION)
+       i = precision - PART_PRECISION - 1;
+      else
+       i = precision - 1;
+      mask = (cpp_num_part) 1 << i;
+      for (; ; i--, mask >>= 1)
+       if (rhs.low & mask)
+         break;
+    }
+  else
+    {
+      if (!pfile->state.skip_eval)
+       cpp_error (pfile, DL_ERROR, "division by zero in #if");
+      return lhs;
+    }
+
+  /* First nonzero bit of RHS is bit I.  Do naive division by
+     shifting the RHS fully left, and subtracting from LHS if LHS is
+     at least as big, and then repeating but with one less shift.
+     This is not very efficient, but is easy to understand.  */
+
+  rhs.unsignedp = true;
+  lhs.unsignedp = true;
+  i = precision - i - 1;
+  sub = num_lshift (rhs, precision, i);
+
+  result.high = result.low = 0;
+  for (;;)
+    {
+      if (num_greater_eq (lhs, sub, precision))
+       {
+         lhs = num_binary_op (pfile, lhs, sub, CPP_MINUS);
+         if (i >= PART_PRECISION)
+           result.high |= (cpp_num_part) 1 << (i - PART_PRECISION);
+         else
+           result.low |= (cpp_num_part) 1 << i;
+       }
+      if (i-- == 0)
+       break;
+      sub.low = (sub.low >> 1) | (sub.high << (PART_PRECISION - 1));
+      sub.high >>= 1;
+    }
+
+  /* We divide so that the remainder has the sign of the LHS.  */
+  if (op == CPP_DIV)
+    {
+      result.unsignedp = unsignedp;
+      if (unsignedp)
+       result.overflow = false;
+      else
+       {
+         if (negate)
+           result = num_negate (result, precision);
+         result.overflow = num_positive (result, precision) ^ !negate;
+       }
+
+      return result;
+    }
+
+  /* CPP_MOD.  */
+  lhs.unsignedp = unsignedp;
+  lhs.overflow = false;
+  if (lhs_neg)
+    lhs = num_negate (lhs, precision);
 
-  token.type = op;
-  token.flags = 0;
-  return cpp_token_as_text (pfile, &token);
+  return lhs;
 }
index da9ee1874e7d702425e21ff899db605dfca465d3..29365a035377deced40cbcd43a68ee10753ac439 100644 (file)
@@ -27,6 +27,12 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "intl.h"
 #include "mkdeps.h"
 #include "splay-tree.h"
+#ifdef ENABLE_VALGRIND_CHECKING
+#include <valgrind.h>
+#else
+/* Avoid #ifdef:s when we can help it.  */
+#define VALGRIND_DISCARD(x)
+#endif
 
 #ifdef HAVE_MMAP_FILE
 # include <sys/mman.h>
@@ -77,8 +83,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #undef strcmp
 
 /* This structure is used for the table of all includes.  */
-struct include_file
-{
+struct include_file {
   const char *name;            /* actual path name of file */
   const cpp_hashnode *cmacro;  /* macro, if any, preventing reinclusion.  */
   const struct search_path *foundhere;
@@ -106,7 +111,7 @@ struct include_file
    included again.  If it's NEVER_REREAD, the file is never to be
    included again.  Otherwise it is a macro hashnode, and the file is
    to be included again if the macro is defined.  */
-#define NEVER_REREAD ((const cpp_hashnode *)-1)
+#define NEVER_REREAD ((const cpp_hashnode *) -1)
 #define DO_NOT_REREAD(inc) \
 ((inc)->cmacro && ((inc)->cmacro == NEVER_REREAD \
                   || (inc)->cmacro->type == NT_MACRO))
@@ -168,7 +173,7 @@ static void
 destroy_node (v)
      splay_tree_value v;
 {
-  struct include_file *f = (struct include_file *)v;
+  struct include_file *f = (struct include_file *) v;
 
   if (f)
     {
@@ -250,7 +255,7 @@ open_file (pfile, filename)
   /* Don't reopen an idempotent file.  */
   if (DO_NOT_REREAD (file))
     return file;
-      
+
   /* Don't reopen one which is already loaded.  */
   if (file->buffer != NULL)
     return file;
@@ -270,7 +275,15 @@ open_file (pfile, filename)
      Special case: the empty string is translated to stdin.  */
 
   if (filename[0] == '\0')
-    file->fd = 0;
+    {
+      file->fd = 0;
+#ifdef __DJGPP__
+      /* For DJGPP redirected input is opened in text mode. Change it
+         to binary mode.  */
+      if (! isatty (file->fd))
+       setmode (file->fd, O_BINARY);
+#endif
+    }
   else
     file->fd = open (file->name, O_RDONLY | O_NOCTTY | O_BINARY, 0666);
 
@@ -311,9 +324,9 @@ stack_include_file (pfile, inc)
              (inc->foundhere ? inc->foundhere->sysp : 0));
 
   /* Add the file to the dependencies on its first inclusion.  */
-  if (CPP_OPTION (pfile, print_deps) > !!sysp && !inc->include_count)
+  if (CPP_OPTION (pfile, deps.style) > !!sysp && !inc->include_count)
     {
-      if (pfile->buffer || CPP_OPTION (pfile, deps_ignore_main_file) == 0)
+      if (pfile->buffer || CPP_OPTION (pfile, deps.ignore_main_file) == 0)
        deps_add_dep (pfile->deps, inc->name);
     }
 
@@ -345,7 +358,7 @@ stack_include_file (pfile, inc)
   fp->inc = inc;
   fp->inc->refcnt++;
 
-  /* Initialise controlling macro state.  */
+  /* Initialize controlling macro state.  */
   pfile->mi_valid = true;
   pfile->mi_cmacro = 0;
 
@@ -378,7 +391,7 @@ read_include_file (pfile, inc)
      struct include_file *inc;
 {
   ssize_t size, offset, count;
-  U_CHAR *buf;
+  uchar *buf;
 #if MMAP_THRESHOLD
   static int pagesize = -1;
 #endif
@@ -396,9 +409,7 @@ read_include_file (pfile, inc)
 #ifndef __BORLANDC__
       if (inc->st.st_size > INTTYPE_MAXIMUM (ssize_t))
        {
-         cpp_error (pfile, "%s is too large (%lu > %lu)", inc->name,
-                    (unsigned long)inc->st.st_size,
-                    INTTYPE_MAXIMUM(ssize_t));
+         cpp_error (pfile, DL_ERROR, "%s is too large", inc->name);
          goto fail;
        }
 #endif
@@ -411,15 +422,20 @@ read_include_file (pfile, inc)
 
       if (SHOULD_MMAP (size, pagesize))
        {
-         buf = (U_CHAR *) mmap (0, size, PROT_READ, MAP_PRIVATE, inc->fd, 0);
-         if (buf == (U_CHAR *)-1)
+         buf = (uchar *) mmap (0, size, PROT_READ, MAP_PRIVATE, inc->fd, 0);
+         if (buf == (uchar *) -1)
            goto perror_fail;
+
+         /* We must tell Valgrind that the byte at buf[size] is actually
+            readable.  Discard the handle to avoid handle leak.  */
+         VALGRIND_DISCARD (VALGRIND_MAKE_READABLE (buf + size, 1));
+
          inc->mapped = 1;
        }
       else
 #endif
        {
-         buf = (U_CHAR *) xmalloc (size + 1);
+         buf = (uchar *) xmalloc (size + 1);
          offset = 0;
          while (offset < size)
            {
@@ -428,9 +444,9 @@ read_include_file (pfile, inc)
                goto perror_fail;
              if (count == 0)
                {
+#ifndef __BORLANDC__
                  if (!STAT_SIZE_TOO_BIG (inc->st))
                    {
-#ifndef __BORLANDC__
                      /* For some reason, even though we opened with O_BINARY,
                       * Borland C++ seems to insist on doing CR/LF -> LF
                       * translations for us, which results in the file appearing
@@ -438,10 +454,10 @@ read_include_file (pfile, inc)
                       *
                       * This sucks, but don't bother throwing a warning.
                       */
-                     cpp_warning (pfile, "%s is shorter than expected (expected %u, got %u)",
-                                  inc->name, inc->st.st_size, offset);
-#endif
+                     cpp_error (pfile, DL_WARNING,
+                                "%s is shorter than expected", inc->name);
                    }
+#endif
                  size = offset;
                  buf = xrealloc (buf, size + 1);
                  inc->st.st_size = size;
@@ -455,7 +471,7 @@ read_include_file (pfile, inc)
     }
   else if (S_ISBLK (inc->st.st_mode))
     {
-      cpp_error (pfile, "%s is a block device", inc->name);
+      cpp_error (pfile, DL_ERROR, "%s is a block device", inc->name);
       goto fail;
     }
   else
@@ -465,7 +481,7 @@ read_include_file (pfile, inc)
         bigger than the majority of C source files.  */
       size = 8 * 1024;
 
-      buf = (U_CHAR *) xmalloc (size + 1);
+      buf = (uchar *) xmalloc (size + 1);
       offset = 0;
       while ((count = read (inc->fd, buf + offset, size - offset)) > 0)
        {
@@ -491,7 +507,7 @@ read_include_file (pfile, inc)
   return 0;
 
  perror_fail:
-  cpp_error_from_errno (pfile, inc->name);
+  cpp_errno (pfile, DL_ERROR, inc->name);
  fail:
   return 1;
 }
@@ -505,7 +521,14 @@ purge_cache (inc)
     {
 #if MMAP_THRESHOLD
       if (inc->mapped)
-       munmap ((PTR) inc->buffer, inc->st.st_size);
+       {
+         /* Undo the previous annotation for the
+            known-zero-byte-after-mmap.  Discard the handle to avoid
+            handle leak.  */
+         VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS (inc->buffer
+                                                   + inc->st.st_size, 1));
+         munmap ((PTR) inc->buffer, inc->st.st_size);
+       }
       else
 #endif
        free ((PTR) inc->buffer);
@@ -530,7 +553,7 @@ cpp_included (pfile, fname)
       nd = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) fname);
       return (nd && nd->value);
     }
-      
+
   /* Search directory path for the file.  */
   name = (char *) alloca (strlen (fname) + pfile->max_include_len + 2);
   for (path = CPP_OPTION (pfile, quote_include); path; path = path->next)
@@ -581,7 +604,8 @@ find_include_file (pfile, header, type)
 
   if (path == NULL)
     {
-      cpp_error (pfile, "no include path in which to find %s", fname);
+      cpp_error (pfile, DL_ERROR, "no include path in which to find %s",
+                fname);
       return NO_INCLUDE_PATH;
     }
 
@@ -648,7 +672,7 @@ report_missing_guard (n, b)
      void *b;
 {
   struct include_file *f = (struct include_file *) n->value;
-  int *bannerp = (int *)b;
+  int *bannerp = (int *) b;
 
   if (f && f->cmacro == 0 && f->include_count == 1)
     {
@@ -664,7 +688,7 @@ report_missing_guard (n, b)
 }
 
 /* Create a dependency for file FNAME, or issue an error message as
-   appropriate.  ANGLE_BRACKETS is non-zero if the file was bracketed
+   appropriate.  ANGLE_BRACKETS is nonzero if the file was bracketed
    like <..>.  */
 static void
 handle_missing_header (pfile, fname, angle_brackets)
@@ -672,43 +696,19 @@ handle_missing_header (pfile, fname, angle_brackets)
      const char *fname;
      int angle_brackets;
 {
-  int print_dep = CPP_PRINT_DEPS(pfile) > (angle_brackets || pfile->map->sysp);
-
-  if (CPP_OPTION (pfile, print_deps_missing_files) && print_dep)
-    {
-      if (!angle_brackets || IS_ABSOLUTE_PATHNAME (fname))
-       deps_add_dep (pfile->deps, fname);
-      else
-       {
-         /* If requested as a system header, assume it belongs in
-            the first system header directory.  */
-         struct search_path *ptr = CPP_OPTION (pfile, bracket_include);
-         char *p;
-         int len = 0, fname_len = strlen (fname);
-
-         if (ptr)
-           len = ptr->len;
+  bool print_dep
+    = CPP_OPTION (pfile, deps.style) > (angle_brackets || pfile->map->sysp);
 
-         p = (char *) alloca (len + fname_len + 2);
-         if (len)
-           {
-             memcpy (p, ptr->name, len);
-             p[len++] = '/';
-           }
-         memcpy (p + len, fname, fname_len + 1);
-         deps_add_dep (pfile->deps, p);
-       }
-    }
+  if (CPP_OPTION (pfile, deps.missing_files) && print_dep)
+    deps_add_dep (pfile->deps, fname);
   /* If -M was specified, then don't count this as an error, because
      we can still produce correct output.  Otherwise, we can't produce
      correct output, because there may be dependencies we need inside
      the missing file, and we don't know what directory this missing
-     file exists in.  FIXME: Use a future cpp_diagnostic_with_errno ()
-     for both of these cases.  */
-  else if (CPP_PRINT_DEPS (pfile) && ! print_dep)
-    cpp_warning (pfile, "%s: %s", fname, xstrerror (errno));
+     file exists in.  */
   else
-    cpp_error_from_errno (pfile, fname);
+    cpp_errno (pfile, CPP_OPTION (pfile, deps.style) && ! print_dep
+              ? DL_WARNING: DL_ERROR, fname);
 }
 
 /* Handles #include-family directives (distinguished by TYPE),
@@ -746,7 +746,7 @@ _cpp_compare_file_date (pfile, header)
      const cpp_token *header;
 {
   struct include_file *inc = find_include_file (pfile, header, 0);
-  
+
   if (inc == NULL || inc == NO_INCLUDE_PATH)
     return -1;
 
@@ -755,7 +755,7 @@ _cpp_compare_file_date (pfile, header)
       close (inc->fd);
       inc->fd = -1;
     }
-    
+
   return inc->st.st_mtime > pfile->buffer->inc->st.st_mtime;
 }
 
@@ -772,7 +772,7 @@ _cpp_read_file (pfile, fname)
 
   if (f == NULL)
     {
-      cpp_error_from_errno (pfile, fname);
+      cpp_errno (pfile, DL_ERROR, fname);
       return false;
     }
 
@@ -780,14 +780,12 @@ _cpp_read_file (pfile, fname)
 }
 
 /* Do appropriate cleanup when a file INC's buffer is popped off the
-   input stack.  Push the next -include file, if any remain.  */
-bool
+   input stack.  */
+void
 _cpp_pop_file_buffer (pfile, inc)
      cpp_reader *pfile;
      struct include_file *inc;
 {
-  bool pushed = false;
-
   /* Record the inclusion-preventing macro, which could be NULL
      meaning no controlling macro.  */
   if (pfile->mi_valid && inc->cmacro == NULL)
@@ -799,18 +797,6 @@ _cpp_pop_file_buffer (pfile, inc)
   inc->refcnt--;
   if (inc->refcnt == 0 && DO_NOT_REREAD (inc))
     purge_cache (inc);
-
-  /* Don't generate a callback for popping the main file.  */
-  if (pfile->buffer)
-    {
-      _cpp_do_file_change (pfile, LC_LEAVE, 0, 0, 0);
-
-      /* Finally, push the next -included file, if any.  */
-      if (!pfile->buffer->prev)
-       pushed = _cpp_push_next_buffer (pfile);
-    }
-
-  return pushed;
 }
 
 /* Returns the first place in the include chain to start searching for
@@ -874,8 +860,7 @@ search_from (pfile, type)
    such as DOS.  The format of the file name map file is just a series
    of lines with two tokens on each line.  The first token is the name
    to map, and the second token is the actual name to use.  */
-struct file_name_map
-{
+struct file_name_map {
   struct file_name_map *map_next;
   char *map_from;
   char *map_to;
@@ -895,10 +880,10 @@ read_filename_string (ch, f)
 
   len = 20;
   set = alloc = xmalloc (len + 1);
-  if (! is_space(ch))
+  if (! is_space (ch))
     {
       *set++ = ch;
-      while ((ch = getc (f)) != EOF && ! is_space(ch))
+      while ((ch = getc (f)) != EOF && ! is_space (ch))
        {
          if (set - alloc == len)
            {
@@ -915,8 +900,7 @@ read_filename_string (ch, f)
 }
 
 /* This structure holds a linked list of file name maps, one per directory.  */
-struct file_name_map_list
-{
+struct file_name_map_list {
   struct file_name_map_list *map_list_next;
   char *map_list_name;
   struct file_name_map *map_list_map;
@@ -956,17 +940,16 @@ read_name_map (pfile, dirname)
   if (f)
     {
       int ch;
-      int dirlen = strlen (dirname);
 
       while ((ch = getc (f)) != EOF)
        {
          char *from, *to;
          struct file_name_map *ptr;
 
-         if (is_space(ch))
+         if (is_space (ch))
            continue;
          from = read_filename_string (ch, f);
-         while ((ch = getc (f)) != EOF && is_hspace(ch))
+         while ((ch = getc (f)) != EOF && is_hspace (ch))
            ;
          to = read_filename_string (ch, f);
 
@@ -979,12 +962,9 @@ read_name_map (pfile, dirname)
            ptr->map_to = to;
          else
            {
-             ptr->map_to = xmalloc (dirlen + strlen (to) + 2);
-             strcpy (ptr->map_to, dirname);
-             ptr->map_to[dirlen] = '/';
-             strcpy (ptr->map_to + dirlen + 1, to);
+             ptr->map_to = concat (dirname, "/", to, NULL);
              free (to);
-           }         
+           }
 
          ptr->map_next = map_list_ptr->map_list_map;
          map_list_ptr->map_list_map = ptr;
@@ -995,13 +975,13 @@ read_name_map (pfile, dirname)
        }
       fclose (f);
     }
-  
+
   /* Add this information to the cache.  */
   map_list_ptr->map_list_next = CPP_OPTION (pfile, map_list);
   CPP_OPTION (pfile, map_list) = map_list_ptr;
 
   return map_list_ptr->map_list_map;
-}  
+}
 
 /* Remap an unsimplified path NAME based on the file_name_map (if any)
    for LOC.  */
@@ -1026,10 +1006,10 @@ remap_filename (pfile, name, loc)
       if (! loc->name_map)
        return name;
     }
-  
+
   /* This works since NAME has not been simplified yet.  */
   from = name + loc->len + 1;
-  
+
   for (map = loc->name_map; map; map = map->map_next)
     if (!strcmp (map->map_from, from))
       return map->map_to;
@@ -1044,13 +1024,13 @@ remap_filename (pfile, name, loc)
 
   /* We know p != name as absolute paths don't call remap_filename.  */
   if (p == name)
-    cpp_ice (pfile, "absolute file name in remap_filename");
+    cpp_error (pfile, DL_ICE, "absolute file name in remap_filename");
 
   dir = (char *) alloca (p - name + 1);
   memcpy (dir, name, p - name);
   dir[p - name] = '\0';
   from = p + 1;
-  
+
   for (map = read_name_map (pfile, dir); map; map = map->map_next)
     if (! strcmp (map->map_from, from))
       return map->map_to;
@@ -1100,7 +1080,7 @@ remove_component_p (path)
    nonzero if an error occurred when using stat () or lstat ().  */
 char *
 _cpp_simplify_pathname (path)
-    char *path;
+     char *path;
 {
 #ifndef VMS
   char *from, *to;
@@ -1116,7 +1096,7 @@ _cpp_simplify_pathname (path)
   /* Convert all backslashes to slashes.  */
   for (from = path; *from; from++)
     if (*from == '\\') *from = '/';
-    
+
   /* Skip over leading drive letter if present.  */
   if (ISALPHA (path[0]) && path[1] == ':')
     from = to = &path[2];
@@ -1125,7 +1105,7 @@ _cpp_simplify_pathname (path)
 #else
   from = to = path;
 #endif
-    
+
   /* Remove redundant leading /s.  */
   if (*from == '/')
     {
@@ -1200,7 +1180,7 @@ _cpp_simplify_pathname (path)
       if (move_base)
        base = to;
     }
-    
+
   /* Change the empty string to "." so that it is not treated as stdin.
      Null terminate.  */
   if (to == path)
index 6d10b5d66eb6ed44f9cb7082a91a11e7e85d19dc..e23b38e69e1fc322a4cb14ce4796e22e946b3753 100644 (file)
@@ -72,7 +72,6 @@ _cpp_init_hashtable (pfile, table)
   s->n_defined         = cpp_lookup (pfile, DSC("defined"));
   s->n_true            = cpp_lookup (pfile, DSC("true"));
   s->n_false           = cpp_lookup (pfile, DSC("false"));
-  s->n__STRICT_ANSI__   = cpp_lookup (pfile, DSC("__STRICT_ANSI__"));
   s->n__VA_ARGS__       = cpp_lookup (pfile, DSC("__VA_ARGS__"));
   s->n__VA_ARGS__->flags |= NODE_DIAGNOSTIC;
   /* SDCC _asm specific */
index f9c9dc4ad8a9104dace67bfa8bbac5106862b64f..0643f93bd7a138f51b21c21757ff01faca9e56da 100644 (file)
@@ -26,6 +26,15 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "hashtable.h"
 
 struct directive;              /* Deliberately incomplete.  */
+struct pending_option;
+struct op;
+
+#ifndef HAVE_UCHAR
+typedef unsigned char uchar;
+#endif
+#define U (const uchar *)  /* Intended use: U"string" */
+
+#define BITS_PER_CPPCHAR_T (CHAR_BIT * sizeof (cppchar_t))
 
 /* Test if a sign is valid within a preprocessing number.  */
 #define VALID_SIGN(c, prevc) \
@@ -43,6 +52,63 @@ struct directive;            /* Deliberately incomplete.  */
    efficiency, and partly to limit runaway recursion.  */
 #define CPP_STACK_MAX 200
 
+/* Host alignment handling.  */
+struct dummy
+{
+  char c;
+  union
+  {
+    double d;
+    int *p;
+  } u;
+};
+
+#define DEFAULT_ALIGNMENT offsetof (struct dummy, u)
+#define CPP_ALIGN2(size, align) (((size) + ((align) - 1)) & ~((align) - 1))
+#define CPP_ALIGN(size) CPP_ALIGN2 (size, DEFAULT_ALIGNMENT)
+
+/* Each macro definition is recorded in a cpp_macro structure.
+   Variadic macros cannot occur with traditional cpp.  */
+struct cpp_macro
+{
+  /* Parameters, if any.  */
+  cpp_hashnode **params;
+
+  /* Replacement tokens (ISO) or replacement text (traditional).  See
+     comment at top of cpptrad.c for how traditional function-like
+     macros are encoded.  */
+  union
+  {
+    cpp_token *tokens;
+    const uchar *text;
+  } exp;
+
+  /* Definition line number.  */
+  unsigned int line;
+
+  /* Number of tokens in expansion, or bytes for traditional macros.  */
+  unsigned int count;
+
+  /* Number of parameters.  */
+  unsigned short paramc;
+
+  /* If a function-like macro.  */
+  unsigned int fun_like : 1;
+
+  /* If a variadic macro.  */
+  unsigned int variadic : 1;
+
+  /* If macro defined in system header.  */
+  unsigned int syshdr   : 1;
+
+  /* Nonzero if it has been expanded or had its existence tested.  */
+  unsigned int used     : 1;
+};
+
+#define _cpp_mark_macro_used(NODE) do {                                        \
+  if ((NODE)->type == NT_MACRO && !((NODE)->flags & NODE_BUILTIN))     \
+    (NODE)->value.macro->used = 1; } while (0)
+
 /* A generic memory buffer, and operations on it.  */
 typedef struct _cpp_buff _cpp_buff;
 struct _cpp_buff
@@ -77,7 +143,7 @@ struct search_path
      of an earlier directory on the search path.  */
   ino_t ino;
   dev_t dev;
-  /* Non-zero if it is a system include directory.  */
+  /* Nonzero if it is a system include directory.  */
   int sysp;
   /* Mapping of file names for this directory.  Only used on MS-DOS
      and related platforms.  */
@@ -101,16 +167,36 @@ struct tokenrun
   cpp_token *base, *limit;
 };
 
+/* Accessor macros for struct cpp_context.  */
+#define FIRST(c) ((c)->u.iso.first)
+#define LAST(c) ((c)->u.iso.last)
+#define CUR(c) ((c)->u.trad.cur)
+#define RLIMIT(c) ((c)->u.trad.rlimit)
+
 typedef struct cpp_context cpp_context;
 struct cpp_context
 {
   /* Doubly-linked list.  */
   cpp_context *next, *prev;
 
-  /* Contexts other than the base context are contiguous tokens.
-     e.g. macro expansions, expanded argument tokens.  */
-  union utoken first;
-  union utoken last;
+  union
+  {
+    /* For ISO macro expansion.  Contexts other than the base context
+       are contiguous tokens.  e.g. macro expansions, expanded
+       argument tokens.  */
+    struct
+    {
+      union utoken first;
+      union utoken last;
+    } iso;
+
+    /* For traditional macro expansion.  */
+    struct
+    {
+      const uchar *cur;
+      const uchar *rlimit;
+    } trad;
+  } u;
 
   /* If non-NULL, a buffer used for storage related to this context.
      When the context is popped, the buffer is released.  */
@@ -128,12 +214,20 @@ struct lexer_state
   /* Nonzero if first token on line is CPP_HASH.  */
   unsigned char in_directive;
 
+  /* Nonzero if in a directive that will handle padding tokens itself.
+     #include needs this to avoid problems with computed include and
+     spacing between tokens.  */
+  unsigned char directive_wants_padding;
+
   /* True if we are skipping a failed conditional group.  */
   unsigned char skipping;
 
   /* Nonzero if in a directive that takes angle-bracketed headers.  */
   unsigned char angled_headers;
 
+  /* Nonzero if in a #if or #elif directive.  */
+  unsigned char in_expression;
+
   /* Nonzero to save comments.  Turned off if discard_comments, and in
      all directives apart from #define.  */
   unsigned char save_comments;
@@ -148,10 +242,13 @@ struct lexer_state
   unsigned char poisoned_ok;
 
   /* Nonzero to prevent macro expansion.  */
-  unsigned char prevent_expansion;  
+  unsigned char prevent_expansion;
 
   /* Nonzero when parsing arguments to a function-like macro.  */
   unsigned char parsing_args;
+
+  /* Nonzero to skip evaluating part of an expression.  */
+  unsigned int skip_eval;
 };
 
 /* Special nodes - identifiers with predefined significance.  */
@@ -160,12 +257,23 @@ struct spec_nodes
   cpp_hashnode *n_defined;             /* defined operator */
   cpp_hashnode *n_true;                        /* C++ keyword true */
   cpp_hashnode *n_false;               /* C++ keyword false */
-  cpp_hashnode *n__STRICT_ANSI__;      /* STDC_0_IN_SYSTEM_HEADERS */
   cpp_hashnode *n__VA_ARGS__;          /* C99 vararg macros */
   /* SDCC _asm specific */
   cpp_hashnode *n__asm;                /* _asm ... _endasm ; */
 };
 
+/* Encapsulates state used to convert a stream of tokens into a text
+   file.  */
+struct printer
+{
+  FILE *outf;                  /* Stream to write to.  */
+  const struct line_map *map;  /* Logical to physical line mappings.  */
+  const cpp_token *prev;       /* Previous token.  */
+  const cpp_token *source;     /* Source token for spacing.  */
+  unsigned int line;           /* Line currently being written.  */
+  unsigned char printed;       /* Nonzero if something output at line.  */
+};
+
 /* Represents the contents of a file cpplib has read in.  */
 struct cpp_buffer
 {
@@ -219,6 +327,9 @@ struct cpp_buffer
   /* The directory of the this buffer's file.  Its NAME member is not
      allocated, so we don't need to worry about freeing it.  */
   struct search_path dir;
+
+  /* Used for buffer overlays by cpptrad.c.  */
+  const uchar *saved_cur, *saved_rlimit;
 };
 
 /* A cpp_reader encapsulates the "state" of a pre-processor run.
@@ -229,6 +340,9 @@ struct cpp_reader
   /* Top of buffer stack.  */
   cpp_buffer *buffer;
 
+  /* Overlaid buffer (can be different after processing #include).  */
+  cpp_buffer *overlaid_buffer;
+
   /* Lexer state.  */
   struct lexer_state state;
 
@@ -252,6 +366,11 @@ struct cpp_reader
   /* If in_directive, the directive if known.  */
   const struct directive *directive;
 
+  /* The next -include-d file; NULL if they all are done.  If it
+     points to NULL, the last one is in progress, and
+     _cpp_maybe_push_include_file has yet to restore the line map.  */
+  struct pending_option **next_include_file;
+
   /* Multiple inlcude optimisation.  */
   const cpp_hashnode *mi_cmacro;
   const cpp_hashnode *mi_ind_cmacro;
@@ -262,17 +381,12 @@ struct cpp_reader
   tokenrun base_run, *cur_run;
   unsigned int lookaheads;
 
-  /* Non-zero prevents the lexer from re-using the token runs.  */
+  /* Nonzero prevents the lexer from re-using the token runs.  */
   unsigned int keep_tokens;
 
   /* Error counter for exit code.  */
   unsigned int errors;
 
-  /* Line and column where a newline was first seen in a string
-     constant (multi-line strings).  */
-  unsigned int mls_line;
-  unsigned int mls_col;
-
   /* Buffer to hold macro definition string.  */
   unsigned char *macro_buffer;
   unsigned int macro_buffer_len;
@@ -284,15 +398,18 @@ struct cpp_reader
      for include files.  (Altered as we get more of them.)  */
   unsigned int max_include_len;
 
-  /* Date and time tokens.  Calculated together if either is requested.  */
-  cpp_token date;
-  cpp_token time;
+  /* Macros on or after this line are warned about if unused.  */
+  unsigned int first_unused_line;
+
+  /* Date and time text.  Calculated together if either is requested.  */
+  const uchar *date;
+  const uchar *time;
 
   /* EOF token, and a token forcing paste avoidance.  */
   cpp_token avoid_paste;
   cpp_token eof;
 
-  /* Opaque handle to the dependencies of mkdeps.c.  Used by -M etc.  */
+  /* Opaque handle to the dependencies of mkdeps.c.  */
   struct deps *deps;
 
   /* Obstack holding all macro hash nodes.  This never shrinks.
@@ -310,9 +427,12 @@ struct cpp_reader
   /* Call backs.  */
   struct cpp_callbacks cb;
 
-  /* Identifier hash table.  */ 
+  /* Identifier hash table.  */
   struct ht *hash_table;
 
+  /* Expression parser stack.  */
+  struct op *op_stack, *op_limit;
+
   /* User visible options.  */
   struct cpp_options opts;
 
@@ -320,12 +440,28 @@ struct cpp_reader
      preprocessor.  */
   struct spec_nodes spec_nodes;
 
+  /* Used when doing preprocessed output.  */
+  struct printer print;
+
   /* Whether to print our version number.  Done this way so
      we don't get it twice for -v -version.  */
   unsigned char print_version;
 
   /* Whether cpplib owns the hashtable.  */
   unsigned char our_hashtable;
+
+  /* Traditional preprocessing output buffer (a logical line).  */
+  struct
+  {
+    uchar *base;
+    uchar *limit;
+    uchar *cur;
+    unsigned int first_line;
+  } out;
+
+  /* Used to save the original line number during traditional
+     preprocessing.  */
+  unsigned int saved_line;
 };
 
 /* Character classes.  Based on the more primitive macros in safe-ctype.h.
@@ -357,21 +493,29 @@ extern unsigned char _cpp_trigraph_map[UCHAR_MAX + 1];
 
 /* Macros.  */
 
-#define CPP_PRINT_DEPS(PFILE) CPP_OPTION (PFILE, print_deps)
 #define CPP_IN_SYSTEM_HEADER(PFILE) ((PFILE)->map && (PFILE)->map->sysp)
 #define CPP_PEDANTIC(PF) CPP_OPTION (PF, pedantic)
 #define CPP_WTRADITIONAL(PF) CPP_OPTION (PF, warn_traditional)
 
 /* In cpperror.c  */
-enum error_type { WARNING = 0, WARNING_SYSHDR, PEDWARN, ERROR, FATAL, ICE };
-extern int _cpp_begin_message PARAMS ((cpp_reader *, enum error_type,
+extern int _cpp_begin_message PARAMS ((cpp_reader *, int,
                                       unsigned int, unsigned int));
 
 /* In cppmacro.c */
 extern void _cpp_free_definition       PARAMS ((cpp_hashnode *));
-extern int _cpp_create_definition      PARAMS ((cpp_reader *, cpp_hashnode *));
+extern bool _cpp_create_definition     PARAMS ((cpp_reader *, cpp_hashnode *));
 extern void _cpp_pop_context           PARAMS ((cpp_reader *));
-
+extern void _cpp_push_text_context     PARAMS ((cpp_reader *, cpp_hashnode *,
+                                                const uchar *, size_t));
+extern bool _cpp_save_parameter                PARAMS ((cpp_reader *, cpp_macro *,
+                                                cpp_hashnode *));
+extern bool _cpp_arguments_ok          PARAMS ((cpp_reader *, cpp_macro *,
+                                                const cpp_hashnode *,
+                                                unsigned int));
+extern const uchar *_cpp_builtin_macro_text PARAMS ((cpp_reader *,
+                                                    cpp_hashnode *));
+int _cpp_warn_if_unused_macro          PARAMS ((cpp_reader *, cpp_hashnode *,
+                                                void *));
 /* In cpphash.c */
 extern void _cpp_init_hashtable                PARAMS ((cpp_reader *, hash_table *));
 extern void _cpp_destroy_hashtable     PARAMS ((cpp_reader *));
@@ -389,11 +533,12 @@ extern int _cpp_compare_file_date       PARAMS ((cpp_reader *,
 extern void _cpp_report_missing_guards PARAMS ((cpp_reader *));
 extern void _cpp_init_includes         PARAMS ((cpp_reader *));
 extern void _cpp_cleanup_includes      PARAMS ((cpp_reader *));
-extern bool _cpp_pop_file_buffer       PARAMS ((cpp_reader *,
+extern void _cpp_pop_file_buffer       PARAMS ((cpp_reader *,
                                                 struct include_file *));
 
 /* In cppexp.c */
-extern int _cpp_parse_expr             PARAMS ((cpp_reader *));
+extern bool _cpp_parse_expr            PARAMS ((cpp_reader *));
+extern struct op *_cpp_expand_op_stack PARAMS ((cpp_reader *));
 
 /* In cpplex.c */
 extern cpp_token *_cpp_temp_token      PARAMS ((cpp_reader *));
@@ -404,10 +549,10 @@ extern int _cpp_equiv_tokens              PARAMS ((const cpp_token *,
 extern void _cpp_init_tokenrun         PARAMS ((tokenrun *, unsigned int));
 
 /* In cppinit.c.  */
-extern bool _cpp_push_next_buffer      PARAMS ((cpp_reader *));
+extern void _cpp_maybe_push_include_file PARAMS ((cpp_reader *));
 
 /* In cpplib.c */
-extern int _cpp_test_assertion PARAMS ((cpp_reader *, int *));
+extern int _cpp_test_assertion PARAMS ((cpp_reader *, unsigned int *));
 extern int _cpp_handle_directive PARAMS ((cpp_reader *, int));
 extern void _cpp_define_builtin        PARAMS ((cpp_reader *, const char *));
 extern void _cpp_do__Pragma    PARAMS ((cpp_reader *));
@@ -418,8 +563,19 @@ extern void _cpp_do_file_change PARAMS ((cpp_reader *, enum lc_reason,
                                         unsigned int, unsigned int));
 extern void _cpp_pop_buffer PARAMS ((cpp_reader *));
 
+/* In cpptrad.c.  */
+extern bool _cpp_read_logical_line_trad PARAMS ((cpp_reader *));
+extern void _cpp_overlay_buffer PARAMS ((cpp_reader *pfile, const uchar *,
+                                        size_t));
+extern void _cpp_remove_overlay PARAMS ((cpp_reader *));
+extern bool _cpp_create_trad_definition PARAMS ((cpp_reader *, cpp_macro *));
+extern bool _cpp_expansions_different_trad PARAMS ((const cpp_macro *,
+                                                   const cpp_macro *));
+extern uchar *_cpp_copy_replacement_text PARAMS ((const cpp_macro *, uchar *));
+extern size_t _cpp_replacement_text_len PARAMS ((const cpp_macro *));
+
 /* Utility routines and macros.  */
-#define DSC(str) (const U_CHAR *)str, sizeof str - 1
+#define DSC(str) (const uchar *)str, sizeof str - 1
 #define xnew(T)                (T *) xmalloc (sizeof(T))
 #define xcnew(T)       (T *) xcalloc (1, sizeof(T))
 #define xnewvec(T, N)  (T *) xmalloc (sizeof(T) * (N))
@@ -428,27 +584,24 @@ extern void _cpp_pop_buffer PARAMS ((cpp_reader *));
 
 /* These are inline functions instead of macros so we can get type
    checking.  */
-typedef unsigned char U_CHAR;
-#define U (const U_CHAR *)  /* Intended use: U"string" */
-
-static inline int ustrcmp      PARAMS ((const U_CHAR *, const U_CHAR *));
-static inline int ustrncmp     PARAMS ((const U_CHAR *, const U_CHAR *,
+static inline int ustrcmp      PARAMS ((const uchar *, const uchar *));
+static inline int ustrncmp     PARAMS ((const uchar *, const uchar *,
                                         size_t));
-static inline size_t ustrlen   PARAMS ((const U_CHAR *));
-static inline U_CHAR *uxstrdup PARAMS ((const U_CHAR *));
-static inline U_CHAR *ustrchr  PARAMS ((const U_CHAR *, int));
-static inline int ufputs       PARAMS ((const U_CHAR *, FILE *));
+static inline size_t ustrlen   PARAMS ((const uchar *));
+static inline uchar *uxstrdup  PARAMS ((const uchar *));
+static inline uchar *ustrchr   PARAMS ((const uchar *, int));
+static inline int ufputs       PARAMS ((const uchar *, FILE *));
 
 static inline int
 ustrcmp (s1, s2)
-     const U_CHAR *s1, *s2;
+     const uchar *s1, *s2;
 {
   return strcmp ((const char *)s1, (const char *)s2);
 }
 
 static inline int
 ustrncmp (s1, s2, n)
-     const U_CHAR *s1, *s2;
+     const uchar *s1, *s2;
      size_t n;
 {
   return strncmp ((const char *)s1, (const char *)s2, n);
@@ -456,29 +609,29 @@ ustrncmp (s1, s2, n)
 
 static inline size_t
 ustrlen (s1)
-     const U_CHAR *s1;
+     const uchar *s1;
 {
   return strlen ((const char *)s1);
 }
 
-static inline U_CHAR *
+static inline uchar *
 uxstrdup (s1)
-     const U_CHAR *s1;
+     const uchar *s1;
 {
-  return (U_CHAR *) xstrdup ((const char *)s1);
+  return (uchar *) xstrdup ((const char *)s1);
 }
 
-static inline U_CHAR *
+static inline uchar *
 ustrchr (s1, c)
-     const U_CHAR *s1;
+     const uchar *s1;
      int c;
 {
-  return (U_CHAR *) strchr ((const char *)s1, c);
+  return (uchar *) strchr ((const char *)s1, c);
 }
 
 static inline int
 ufputs (s, f)
-     const U_CHAR *s;
+     const uchar *s;
      FILE *f;
 {
   return fputs ((const char *)s, f);
index 6fd0c0fa93fcf044da4cb70022aced06f602c52f..14f64d8f7d05856f6176f8f9437eb6ba6e5bd09d 100644 (file)
@@ -1,6 +1,6 @@
 /* CPP Library.
    Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
    Contributed by Per Bothner, 1994-95.
    Based on CCCP program by Paul Rubin, June 1986
    Adapted to ANSI C, Richard Stallman, Jan 1987
@@ -25,16 +25,8 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "cpphash.h"
 #include "prefix.h"
 #include "intl.h"
-#include "version.h"
 #include "mkdeps.h"
 #include "cppdefault.h"
-#include "except.h"    /* for USING_SJLJ_EXCEPTIONS */
-
-/* Predefined symbols, built-in macros, and the default include path.  */
-
-#ifndef GET_ENV_PATH_LIST
-#define GET_ENV_PATH_LIST(VAR,NAME)    do { (VAR) = getenv (NAME); } while (0)
-#endif
 
 /* Windows does not natively support inodes, and neither does MSDOS.
    Cygwin's emulation can generate non-unique inodes, so don't use it.
@@ -94,7 +86,6 @@ struct cpp_pending
   } while (0)
 #endif
 
-static void print_help                  PARAMS ((void));
 static void path_include               PARAMS ((cpp_reader *,
                                                 char *, int));
 static void init_library               PARAMS ((void));
@@ -114,15 +105,13 @@ static void merge_include_chains  PARAMS ((cpp_reader *));
 static bool push_include               PARAMS ((cpp_reader *,
                                                 struct pending_option *));
 static void free_chain                 PARAMS ((struct pending_option *));
-static void set_lang                   PARAMS ((cpp_reader *, enum c_lang));
-static void init_dependency_output     PARAMS ((cpp_reader *));
 static void init_standard_includes     PARAMS ((cpp_reader *));
 static void read_original_filename     PARAMS ((cpp_reader *));
 static void new_pending_directive      PARAMS ((struct cpp_pending *,
                                                 const char *,
                                                 cl_directive_handler));
-static void output_deps                        PARAMS ((cpp_reader *));
 static int parse_option                        PARAMS ((const char *));
+static void post_options               PARAMS ((cpp_reader *));
 
 /* Fourth argument to append_include_chain: chain to use.
    Note it's never asked to append to the quote chain.  */
@@ -135,14 +124,14 @@ enum { BRACKET = 0, SYSTEM, AFTER };
 
 #define init_trigraph_map()  /* Nothing.  */
 #define TRIGRAPH_MAP \
-__extension__ const U_CHAR _cpp_trigraph_map[UCHAR_MAX + 1] = {
+__extension__ const uchar _cpp_trigraph_map[UCHAR_MAX + 1] = {
 
 #define END };
 #define s(p, v) [p] = v,
 
 #else
 
-#define TRIGRAPH_MAP U_CHAR _cpp_trigraph_map[UCHAR_MAX + 1] = { 0 }; \
+#define TRIGRAPH_MAP uchar _cpp_trigraph_map[UCHAR_MAX + 1] = { 0 }; \
  static void init_trigraph_map PARAMS ((void)) { \
  unsigned char *x = _cpp_trigraph_map;
 
@@ -205,14 +194,14 @@ path_include (pfile, list, path)
 
 /* Append DIR to include path PATH.  DIR must be allocated on the
    heap; this routine takes responsibility for freeing it.  CXX_AWARE
-   is non-zero if the header contains extern "C" guards for C++,
+   is nonzero if the header contains extern "C" guards for C++,
    otherwise it is zero.  */
 static void
 append_include_chain (pfile, dir, path, cxx_aware)
      cpp_reader *pfile;
      char *dir;
      int path;
-     int cxx_aware ATTRIBUTE_UNUSED;
+     int cxx_aware;
 {
   struct cpp_pending *pend = CPP_OPTION (pfile, pending);
   struct search_path *new;
@@ -230,7 +219,7 @@ append_include_chain (pfile, dir, path, cxx_aware)
     {
       /* Dirs that don't exist are silently ignored.  */
       if (errno != ENOENT)
-       cpp_notice_from_errno (pfile, dir);
+       cpp_errno (pfile, DL_ERROR, dir);
       else if (CPP_OPTION (pfile, verbose))
        fprintf (stderr, _("ignoring nonexistent directory \"%s\"\n"), dir);
       free (dir);
@@ -239,7 +228,7 @@ append_include_chain (pfile, dir, path, cxx_aware)
 
   if (!S_ISDIR (st.st_mode))
     {
-      cpp_notice (pfile, "%s: Not a directory", dir);
+      cpp_error_with_line (pfile, DL_ERROR, 0, 0, "%s: Not a directory", dir);
       free (dir);
       return;
     }
@@ -257,11 +246,7 @@ append_include_chain (pfile, dir, path, cxx_aware)
      include files since these two lists are really just a concatenation
      of one "system" list.  */
   if (path == SYSTEM || path == AFTER)
-#ifdef NO_IMPLICIT_EXTERN_C
-    new->sysp = 1;
-#else
     new->sysp = cxx_aware ? 1 : 2;
-#endif
   else
     new->sysp = 0;
   new->name_map = NULL;
@@ -308,9 +293,9 @@ remove_dup_dir (pfile, prev, head_ptr)
 }
 
 /* Remove duplicate non-system directories for which there is an equivalent
-   system directory later in the chain.  The range for removal is between
+   system directory latter in the chain.  The range for removal is between
    *HEAD_PTR and END.  Returns the directory before END, or NULL if none.
-   This algorithm is quadratic in the number of system directories, which is
+   This algorithm is quadratic in the number system directories, which is
    acceptable since there aren't usually that many of them.  */
 static struct search_path *
 remove_dup_nonsys_dirs (pfile, head_ptr, end)
@@ -365,7 +350,7 @@ remove_dup_dirs (pfile, head_ptr)
   for (cur = *head_ptr; cur; cur = cur->next)
     {
       for (other = *head_ptr; other != cur; other = other->next)
-        if (INO_T_EQ (cur->ino, other->ino) && cur->dev == other->dev)
+       if (INO_T_EQ (cur->ino, other->ino) && cur->dev == other->dev)
          {
            cur = remove_dup_dir (pfile, prev, head_ptr);
            break;
@@ -445,7 +430,6 @@ merge_include_chains (pfile)
 struct lang_flags
 {
   char c99;
-  char objc;
   char cplusplus;
   char extended_numbers;
   char std;
@@ -456,31 +440,28 @@ struct lang_flags
 
 /* ??? Enable $ in identifiers in assembly? */
 static const struct lang_flags lang_defaults[] =
-{ /*              c99 objc c++ xnum std dollar c++comm digr  */
-  /* GNUC89 */  { 0,  0,   0,  1,   0,   1,     1,      1     },
-  /* GNUC99 */  { 1,  0,   0,  1,   0,   1,     1,      1     },
-  /* STDC89 */  { 0,  0,   0,  0,   1,   0,     0,      0     },
-  /* STDC94 */  { 0,  0,   0,  0,   1,   0,     0,      1     },
-  /* STDC99 */  { 1,  0,   0,  1,   1,   0,     1,      1     },
-  /* GNUCXX */  { 0,  0,   1,  1,   0,   1,     1,      1     },
-  /* CXX98  */  { 0,  0,   1,  1,   1,   0,     1,      1     },
-  /* OBJC   */  { 0,  1,   0,  1,   0,   1,     1,      1     },
-  /* OBJCXX */  { 0,  1,   1,  1,   0,   1,     1,      1     },
-  /* ASM    */  { 0,  0,   0,  1,   0,   0,     1,      0     }
+{ /*              c99 c++ xnum std dollar c++comm digr  */
+  /* GNUC89 */  { 0,  0,  1,   0,   1,     1,      1     },
+  /* GNUC99 */  { 1,  0,  1,   0,   1,     1,      1     },
+  /* STDC89 */  { 0,  0,  0,   1,   0,     0,      0     },
+  /* STDC94 */  { 0,  0,  0,   1,   0,     0,      1     },
+  /* STDC99 */  { 1,  0,  1,   1,   0,     1,      1     },
+  /* GNUCXX */  { 0,  1,  1,   0,   1,     1,      1     },
+  /* CXX98  */  { 0,  1,  1,   1,   0,     1,      1     },
+  /* ASM    */  { 0,  0,  1,   0,   0,     1,      0     }
 };
 
 /* Sets internal flags correctly for a given language.  */
-static void
-set_lang (pfile, lang)
+void
+cpp_set_lang (pfile, lang)
      cpp_reader *pfile;
      enum c_lang lang;
 {
   const struct lang_flags *l = &lang_defaults[(int) lang];
-  
+
   CPP_OPTION (pfile, lang) = lang;
 
   CPP_OPTION (pfile, c99)               = l->c99;
-  CPP_OPTION (pfile, objc)              = l->objc;
   CPP_OPTION (pfile, cplusplus)                 = l->cplusplus;
   CPP_OPTION (pfile, extended_numbers)  = l->extended_numbers;
   CPP_OPTION (pfile, std)               = l->std;
@@ -534,33 +515,38 @@ cpp_create_reader (lang)
 {
   cpp_reader *pfile;
 
-  /* Initialise this instance of the library if it hasn't been already.  */
+  /* Initialize this instance of the library if it hasn't been already.  */
   init_library ();
 
   pfile = (cpp_reader *) xcalloc (1, sizeof (cpp_reader));
 
-  set_lang (pfile, lang);
+  cpp_set_lang (pfile, lang);
   CPP_OPTION (pfile, warn_import) = 1;
+  CPP_OPTION (pfile, warn_multichar) = 1;
   CPP_OPTION (pfile, discard_comments) = 1;
+  CPP_OPTION (pfile, discard_comments_in_macro_exp) = 1;
   CPP_OPTION (pfile, show_column) = 1;
   CPP_OPTION (pfile, tabstop) = 8;
   CPP_OPTION (pfile, operator_names) = 1;
-#if DEFAULT_SIGNED_CHAR
-  CPP_OPTION (pfile, signed_char) = 1;
-#else
-  CPP_OPTION (pfile, signed_char) = 0;
-#endif
+  CPP_OPTION (pfile, warn_endif_labels) = 1;
+  CPP_OPTION (pfile, warn_long_long) = !CPP_OPTION (pfile, c99);
+  CPP_OPTION (pfile, sysroot) = cpp_SYSROOT;
   /* SDCC _asm specific */
   CPP_OPTION (pfile, preproc_asm) = 1;
 
   CPP_OPTION (pfile, pending) =
     (struct cpp_pending *) xcalloc (1, sizeof (struct cpp_pending));
 
-  /* It's simplest to just create this struct whether or not it will
-     be needed.  */
-  pfile->deps = deps_init ();
+  /* Default CPP arithmetic to something sensible for the host for the
+     benefit of dumb users like fix-header.  */
+  CPP_OPTION (pfile, precision) = CHAR_BIT * sizeof (long);
+  CPP_OPTION (pfile, char_precision) = CHAR_BIT;
+  CPP_OPTION (pfile, wchar_precision) = CHAR_BIT * sizeof (int);
+  CPP_OPTION (pfile, int_precision) = CHAR_BIT * sizeof (int);
+  CPP_OPTION (pfile, unsigned_char) = 0;
+  CPP_OPTION (pfile, unsigned_wchar) = 1;
 
-  /* Initialise the line map.  Start at logical line 1, so we can use
+  /* Initialize the line map.  Start at logical line 1, so we can use
      a line number of zero for special states.  */
   init_line_maps (&pfile->line_maps);
   pfile->line = 1;
@@ -569,7 +555,6 @@ cpp_create_reader (lang)
   pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);
 
   /* Set up static tokens.  */
-  pfile->date.type = CPP_EOF;
   pfile->avoid_paste.type = CPP_PADDING;
   pfile->avoid_paste.val.source = NULL;
   pfile->eof.type = CPP_EOF;
@@ -580,7 +565,7 @@ cpp_create_reader (lang)
   pfile->cur_run = &pfile->base_run;
   pfile->cur_token = pfile->base_run.base;
 
-  /* Initialise the base context.  */
+  /* Initialize the base context.  */
   pfile->context = &pfile->base_context;
   pfile->base_context.macro = 0;
   pfile->base_context.prev = pfile->base_context.next = 0;
@@ -589,7 +574,10 @@ cpp_create_reader (lang)
   pfile->a_buff = _cpp_get_buff (pfile, 0);
   pfile->u_buff = _cpp_get_buff (pfile, 0);
 
-  /* Initialise the buffer obstack.  */
+  /* The expression parser stack.  */
+  _cpp_expand_op_stack (pfile);
+
+  /* Initialize the buffer obstack.  */
   gcc_obstack_init (&pfile->buffer_ob);
 
   _cpp_init_includes (pfile);
@@ -598,19 +586,25 @@ cpp_create_reader (lang)
 }
 
 /* Free resources used by PFILE.  Accessing PFILE after this function
-   returns leads to undefined behaviour.  Returns the error count.  */
-int
+   returns leads to undefined behavior.  Returns the error count.  */
+void
 cpp_destroy (pfile)
      cpp_reader *pfile;
 {
-  int result;
   struct search_path *dir, *dirn;
   cpp_context *context, *contextn;
   tokenrun *run, *runn;
 
+  free_chain (CPP_OPTION (pfile, pending)->include_head);
+  free (CPP_OPTION (pfile, pending));
+  free (pfile->op_stack);
+
   while (CPP_BUFFER (pfile) != NULL)
     _cpp_pop_buffer (pfile);
 
+  if (pfile->out.base)
+    free (pfile->out.base);
+
   if (pfile->macro_buffer)
     {
       free ((PTR) pfile->macro_buffer);
@@ -618,7 +612,8 @@ cpp_destroy (pfile)
       pfile->macro_buffer_len = 0;
     }
 
-  deps_free (pfile->deps);
+  if (pfile->deps)
+    deps_free (pfile->deps);
   obstack_free (&pfile->buffer_ob, 0);
 
   _cpp_destroy_hashtable (pfile);
@@ -650,40 +645,31 @@ cpp_destroy (pfile)
     }
 
   free_line_maps (&pfile->line_maps);
-
-  result = pfile->errors;
   free (pfile);
-
-  return result;
 }
 
-
 /* This structure defines one built-in identifier.  A node will be
-   entered in the hash table under the name NAME, with value VALUE (if
-   any).  If flags has OPERATOR, the node's operator field is used; if
-   flags has BUILTIN the node's builtin field is used.  Macros that are
-   known at build time should not be flagged BUILTIN, as then they do
-   not appear in macro dumps with e.g. -dM or -dD.
-
-   Two values are not compile time constants, so we tag
-   them in the FLAGS field instead:
-   VERS                value is the global version_string, quoted
-   ULP         value is the global user_label_prefix  */
+   entered in the hash table under the name NAME, with value VALUE.
+
+   There are two tables of these.  builtin_array holds all the
+   "builtin" macros: these are handled by builtin_macro() in
+   cppmacro.c.  Builtin is somewhat of a misnomer -- the property of
+   interest is that these macros require special code to compute their
+   expansions.  The value is a "builtin_type" enumerator.
+
+   operator_array holds the C++ named operators.  These are keywords
+   which act as aliases for punctuators.  In C++, they cannot be
+   altered through #define, and #if recognizes them as operators.  In
+   C, these are not entered into the hash table at all (but see
+   <iso646.h>).  The value is a token-type enumerator.  */
 struct builtin
 {
-  const U_CHAR *name;
-  const char *value;
-  unsigned char builtin;
-  unsigned short flags;
+  const uchar *name;
   unsigned short len;
+  unsigned short value;
 };
-#define VERS           0x01
-#define ULP            0x02
-#define BUILTIN                0x08
 
-#define B(n, t)       { U n, 0, t, BUILTIN, sizeof n - 1 }
-#define C(n, v)       { U n, v, 0, 0, sizeof n - 1 }
-#define X(n, f)       { U n, 0, 0, f, sizeof n - 1 }
+#define B(n, t)    { DSC(n), t }
 static const struct builtin builtin_array[] =
 {
   B("__TIME__",                 BT_TIME),
@@ -692,51 +678,14 @@ static const struct builtin builtin_array[] =
   B("__BASE_FILE__",    BT_BASE_FILE),
   B("__LINE__",                 BT_SPECLINE),
   B("__INCLUDE_LEVEL__", BT_INCLUDE_LEVEL),
+  /* Keep builtins not used for -traditional-cpp at the end, and
+     update init_builtins() if any more are added.  */
   B("_Pragma",          BT_PRAGMA),
-
-  X("__VERSION__",             VERS),
-  X("__USER_LABEL_PREFIX__",   ULP),
-  C("__REGISTER_PREFIX__",     REGISTER_PREFIX),
-  C("__HAVE_BUILTIN_SETJMP__", "1"),
-#if USING_SJLJ_EXCEPTIONS
-  /* libgcc needs to know this.  */
-  C("__USING_SJLJ_EXCEPTIONS__","1"),
-#endif
-#ifndef NO_BUILTIN_SIZE_TYPE
-  C("__SIZE_TYPE__",           SIZE_TYPE),
-#endif
-#ifndef NO_BUILTIN_PTRDIFF_TYPE
-  C("__PTRDIFF_TYPE__",                PTRDIFF_TYPE),
-#endif
-#ifndef NO_BUILTIN_WCHAR_TYPE
-  C("__WCHAR_TYPE__",          WCHAR_TYPE),
-#endif
-#ifndef NO_BUILTIN_WINT_TYPE
-  C("__WINT_TYPE__",           WINT_TYPE),
-#endif
-#ifdef STDC_0_IN_SYSTEM_HEADERS
   B("__STDC__",                 BT_STDC),
-#else
-  C("__STDC__",                 "1"),
-#endif
 };
-#undef B
-#undef C
-#undef X
-#define builtin_array_end \
- builtin_array + sizeof(builtin_array)/sizeof(struct builtin)
-
-/* Named operators known to the preprocessor.  These cannot be
-   #defined and always have their stated meaning.  They are treated
-   like normal identifiers except for the type code and the meaning.
-   Most of them are only for C++ (but see iso646.h).  */
-#define B(n, t)    { DSC(n), t }
-static const struct named_op
+
+static const struct builtin operator_array[] =
 {
-  const U_CHAR *name;
-  unsigned int len;
-  enum cpp_ttype value;
-} operator_array[] = {
   B("and",     CPP_AND_AND),
   B("and_eq",  CPP_AND_EQ),
   B("bitand",  CPP_AND),
@@ -756,7 +705,7 @@ static void
 mark_named_operators (pfile)
      cpp_reader *pfile;
 {
-  const struct named_op *b;
+  const struct builtin *b;
 
   for (b = operator_array;
        b < (operator_array + ARRAY_SIZE (operator_array));
@@ -775,74 +724,34 @@ init_builtins (pfile)
      cpp_reader *pfile;
 {
   const struct builtin *b;
+  size_t n = ARRAY_SIZE (builtin_array);
 
-  for(b = builtin_array; b < builtin_array_end; b++)
-    {
-      if (b->flags & BUILTIN)
-       {
-         cpp_hashnode *hp = cpp_lookup (pfile, b->name, b->len);
-         hp->type = NT_MACRO;
-         hp->flags |= NODE_BUILTIN | NODE_WARN;
-         hp->value.builtin = b->builtin;
-       }
-      else                     /* A standard macro of some kind.  */
-       {
-         const char *val;
-         char *str;
+  if (CPP_OPTION (pfile, traditional))
+    n -= 2;
 
-         if (b->flags & VERS)
-           {
-             /* Allocate enough space for 'name "value"\n\0'.  */
-             str = alloca (b->len + strlen (version_string) + 5);
-             sprintf (str, "%s \"%s\"\n", b->name, version_string);
-           }
-         else
-           {
-             if (b->flags & ULP)
-               val = CPP_OPTION (pfile, user_label_prefix);
-             else
-               val = b->value;
-
-             /* Allocate enough space for "name value\n\0".  */
-             str = alloca (b->len + strlen (val) + 3);
-             sprintf(str, "%s %s\n", b->name, val);
-           }
-
-         _cpp_define_builtin (pfile, str);
-       }
-    }
-
-  if (CPP_OPTION (pfile, cplusplus))
+  for(b = builtin_array; b < builtin_array + n; b++)
     {
-      _cpp_define_builtin (pfile, "__cplusplus 1");
-      if (SUPPORTS_ONE_ONLY)
-       _cpp_define_builtin (pfile, "__GXX_WEAK__ 1");
-      else
-       _cpp_define_builtin (pfile, "__GXX_WEAK__ 0");
+      cpp_hashnode *hp = cpp_lookup (pfile, b->name, b->len);
+      hp->type = NT_MACRO;
+      hp->flags |= NODE_BUILTIN | NODE_WARN;
+      hp->value.builtin = b->value;
     }
-  if (CPP_OPTION (pfile, objc))
-    _cpp_define_builtin (pfile, "__OBJC__ 1");
 
-  if (CPP_OPTION (pfile, lang) == CLK_STDC94)
+  if (CPP_OPTION (pfile, cplusplus))
+    _cpp_define_builtin (pfile, "__cplusplus 1");
+  else if (CPP_OPTION (pfile, lang) == CLK_ASM)
+    _cpp_define_builtin (pfile, "__ASSEMBLER__ 1");
+  else if (CPP_OPTION (pfile, lang) == CLK_STDC94)
     _cpp_define_builtin (pfile, "__STDC_VERSION__ 199409L");
   else if (CPP_OPTION (pfile, c99))
     _cpp_define_builtin (pfile, "__STDC_VERSION__ 199901L");
 
-  if (CPP_OPTION (pfile, signed_char) == 0)
-    _cpp_define_builtin (pfile, "__CHAR_UNSIGNED__ 1");
+  if (CPP_OPTION (pfile, objc))
+    _cpp_define_builtin (pfile, "__OBJC__ 1");
 
-  if (CPP_OPTION (pfile, lang) == CLK_STDC89
-      || CPP_OPTION (pfile, lang) == CLK_STDC94
-      || CPP_OPTION (pfile, lang) == CLK_STDC99)
-    _cpp_define_builtin (pfile, "__STRICT_ANSI__ 1");
-  else if (CPP_OPTION (pfile, lang) == CLK_ASM)
-    _cpp_define_builtin (pfile, "__ASSEMBLER__ 1");
+  if (pfile->cb.register_builtins)
+    (*pfile->cb.register_builtins) (pfile);
 }
-#undef BUILTIN
-#undef OPERATOR
-#undef VERS
-#undef ULP
-#undef builtin_array_end
 
 /* And another subroutine.  This one sets up the standard include path.  */
 static void
@@ -852,6 +761,8 @@ init_standard_includes (pfile)
   char *path;
   const struct default_include *p;
   const char *specd_prefix = CPP_OPTION (pfile, include_prefix);
+  int default_len, specd_len;
+  char *default_prefix;
 
   /* Several environment variables may add to the include search path.
      CPATH specifies an additional list of directories to be searched
@@ -859,23 +770,23 @@ init_standard_includes (pfile)
      etc. specify an additional list of directories to be searched as
      if specified with -isystem, for the language indicated.  */
 
-  GET_ENV_PATH_LIST (path, "CPATH");
+  GET_ENVIRONMENT (path, "CPATH");
   if (path != 0 && *path != 0)
     path_include (pfile, path, BRACKET);
 
   switch ((CPP_OPTION (pfile, objc) << 1) + CPP_OPTION (pfile, cplusplus))
     {
     case 0:
-      GET_ENV_PATH_LIST (path, "C_INCLUDE_PATH");
+      GET_ENVIRONMENT (path, "C_INCLUDE_PATH");
       break;
     case 1:
-      GET_ENV_PATH_LIST (path, "CPLUS_INCLUDE_PATH");
+      GET_ENVIRONMENT (path, "CPLUS_INCLUDE_PATH");
       break;
     case 2:
-      GET_ENV_PATH_LIST (path, "OBJC_INCLUDE_PATH");
+      GET_ENVIRONMENT (path, "OBJC_INCLUDE_PATH");
       break;
     case 3:
-      GET_ENV_PATH_LIST (path, "OBJCPLUS_INCLUDE_PATH");
+      GET_ENVIRONMENT (path, "OBJCPLUS_INCLUDE_PATH");
       break;
     }
   if (path != 0 && *path != 0)
@@ -883,13 +794,16 @@ init_standard_includes (pfile)
 
   /* Search "translated" versions of GNU directories.
      These have /usr/local/lib/gcc... replaced by specd_prefix.  */
+  default_len = 0;
+  specd_len = 0;
+  default_prefix = NULL;
   if (specd_prefix != 0 && cpp_GCC_INCLUDE_DIR_len)
     {
       /* Remove the `include' from /usr/local/lib/gcc.../include.
         GCC_INCLUDE_DIR will always end in /include.  */
-      int default_len = cpp_GCC_INCLUDE_DIR_len;
-      char *default_prefix = (char *) alloca (default_len + 1);
-      int specd_len = strlen (specd_prefix);
+      default_len = cpp_GCC_INCLUDE_DIR_len;
+      default_prefix = (char *) alloca (default_len + 1);
+      specd_len = strlen (specd_prefix);
 
       memcpy (default_prefix, cpp_GCC_INCLUDE_DIR, default_len);
       default_prefix[default_len] = '\0';
@@ -901,13 +815,23 @@ init_standard_includes (pfile)
              || (CPP_OPTION (pfile, cplusplus)
                  && !CPP_OPTION (pfile, no_standard_cplusplus_includes)))
            {
+             char *str;
+
+             /* Should we be translating sysrooted dirs too?  Assume
+                that iprefix and sysroot are mutually exclusive, for
+                now.  */
+             if (p->add_sysroot && CPP_OPTION (pfile, sysroot)
+                 && *(CPP_OPTION (pfile, sysroot)))
+               continue;
+
              /* Does this dir start with the prefix?  */
              if (!strncmp (p->fname, default_prefix, default_len))
                {
                  /* Yes; change prefix and add to search list.  */
                  int flen = strlen (p->fname);
                  int this_len = specd_len + flen - default_len;
-                 char *str = (char *) xmalloc (this_len + 1);
+
+                 str = (char *) xmalloc (this_len + 1);
                  memcpy (str, specd_prefix, specd_len);
                  memcpy (str + specd_len,
                          p->fname + default_len,
@@ -919,7 +843,6 @@ init_standard_includes (pfile)
        }
     }
 
-  /* Search ordinary names for GNU include directories.  */
   for (p = cpp_include_defaults; p->fname; p++)
     {
       /* Some standard dirs are only for C++.  */
@@ -927,14 +850,23 @@ init_standard_includes (pfile)
          || (CPP_OPTION (pfile, cplusplus)
              && !CPP_OPTION (pfile, no_standard_cplusplus_includes)))
        {
-         char *str = update_path (p->fname, p->component);
+         char *str;
+
+         /* Should this dir start with the sysroot?  */
+         if (p->add_sysroot && CPP_OPTION (pfile, sysroot)
+             && *(CPP_OPTION (pfile, sysroot)))
+           str = concat (CPP_OPTION (pfile, sysroot), p->fname, NULL);
+
+         else
+           str = update_path (p->fname, p->component);
+
          append_include_chain (pfile, str, SYSTEM, p->cxx_aware);
        }
     }
 }
 
 /* Pushes a command line -imacro and -include file indicated by P onto
-   the buffer stack.  Returns non-zero if successful.  */
+   the buffer stack.  Returns nonzero if successful.  */
 static bool
 push_include (pfile, p)
      cpp_reader *pfile;
@@ -968,6 +900,72 @@ free_chain (head)
     }
 }
 
+/* Sanity-checks are dependent on command-line options, so it is
+   called as a subroutine of cpp_read_main_file ().  */
+#if ENABLE_CHECKING
+static void sanity_checks PARAMS ((cpp_reader *));
+static void sanity_checks (pfile)
+     cpp_reader *pfile;
+{
+  cppchar_t test = 0;
+  size_t max_precision = 2 * CHAR_BIT * sizeof (cpp_num_part);
+
+  /* Sanity checks for assumptions about CPP arithmetic and target
+     type precisions made by cpplib.  */
+  test--;
+  if (test < 1)
+    cpp_error (pfile, DL_ICE, "cppchar_t must be an unsigned type");
+
+  if (CPP_OPTION (pfile, precision) > max_precision)
+    cpp_error (pfile, DL_ICE,
+              "preprocessor arithmetic has maximum precision of %lu bits; target requires %lu bits",
+              (unsigned long) max_precision,
+              (unsigned long) CPP_OPTION (pfile, precision));
+
+  if (CPP_OPTION (pfile, precision) < CPP_OPTION (pfile, int_precision))
+    cpp_error (pfile, DL_ICE,
+              "CPP arithmetic must be at least as precise as a target int");
+
+  if (CPP_OPTION (pfile, char_precision) < 8)
+    cpp_error (pfile, DL_ICE, "target char is less than 8 bits wide");
+
+  if (CPP_OPTION (pfile, wchar_precision) < CPP_OPTION (pfile, char_precision))
+    cpp_error (pfile, DL_ICE,
+              "target wchar_t is narrower than target char");
+
+  if (CPP_OPTION (pfile, int_precision) < CPP_OPTION (pfile, char_precision))
+    cpp_error (pfile, DL_ICE,
+              "target int is narrower than target char");
+
+  /* This is assumed in eval_token() and could be fixed if necessary.  */
+  if (sizeof (cppchar_t) > sizeof (cpp_num_part))
+    cpp_error (pfile, DL_ICE, "CPP half-integer narrower than CPP character");
+
+  if (CPP_OPTION (pfile, wchar_precision) > BITS_PER_CPPCHAR_T)
+    cpp_error (pfile, DL_ICE,
+              "CPP on this host cannot handle wide character constants over %lu bits, but the target requires %lu bits",
+              (unsigned long) BITS_PER_CPPCHAR_T,
+              (unsigned long) CPP_OPTION (pfile, wchar_precision));
+}
+#else
+# define sanity_checks(PFILE)
+#endif
+
+/* Add a dependency target.  Can be called any number of times before
+   cpp_read_main_file().  If no targets have been added before
+   cpp_read_main_file(), then the default target is used.  */
+void
+cpp_add_dependency_target (pfile, target, quote)
+     cpp_reader *pfile;
+     const char *target;
+     int quote;
+{
+  if (!pfile->deps)
+    pfile->deps = deps_init ();
+
+  deps_add_target (pfile->deps, target, quote);
+}
+
 /* This is called after options have been parsed, and partially
    processed.  Setup for processing input from the file named FNAME,
    or stdin if it is the empty string.  Return the original filename
@@ -978,6 +976,10 @@ cpp_read_main_file (pfile, fname, table)
      const char *fname;
      hash_table *table;
 {
+  sanity_checks (pfile);
+
+  post_options (pfile);
+
   /* The front ends don't set up the hash table until they have
      finished processing the command line options, so initializing the
      hashtable is deferred until now.  */
@@ -1003,17 +1005,22 @@ cpp_read_main_file (pfile, fname, table)
       fprintf (stderr, _("End of search list.\n"));
     }
 
-  if (CPP_OPTION (pfile, print_deps))
-    /* Set the default target (if there is none already).  */
-    deps_add_default_target (pfile, fname);
+  if (CPP_OPTION (pfile, deps.style) != DEPS_NONE)
+    {
+      if (!pfile->deps)
+       pfile->deps = deps_init ();
+
+      /* Set the default target (if there is none already).  */
+      deps_add_default_target (pfile, fname);
+    }
 
   /* Open the main input file.  */
   if (!_cpp_read_file (pfile, fname))
     return NULL;
 
-  /* Set this after cpp_post_options so the client can change the
-     option if it wishes, and after stacking the main file so we don't
-     trace the main file.  */
+  /* Set this here so the client can change the option if it wishes,
+     and after stacking the main file so we don't trace the main
+     file.  */
   pfile->line_maps.trace_includes = CPP_OPTION (pfile, print_include_names);
 
   /* For foo.i, read the original filename foo.c now, for the benefit
@@ -1071,116 +1078,71 @@ cpp_finish_options (pfile)
     {
       struct pending_option *p;
 
+      /* Prevent -Wunused-macros with command-line redefinitions.  */
+      pfile->first_unused_line = (unsigned int) -1;
       _cpp_do_file_change (pfile, LC_RENAME, _("<built-in>"), 1, 0);
       init_builtins (pfile);
       _cpp_do_file_change (pfile, LC_RENAME, _("<command line>"), 1, 0);
       for (p = CPP_OPTION (pfile, pending)->directive_head; p; p = p->next)
        (*p->handler) (pfile, p->arg);
 
-      /* Scan -imacros files after command line defines, but before
-        files given with -include.  */
-      while ((p = CPP_OPTION (pfile, pending)->imacros_head) != NULL)
-       {
-         if (push_include (pfile, p))
-           {
-             pfile->buffer->return_at_eof = true;
-             cpp_scan_nooutput (pfile);
-           }
-         CPP_OPTION (pfile, pending)->imacros_head = p->next;
-         free (p);
-       }
+      /* Scan -imacros files after -D, -U, but before -include.
+        pfile->next_include_file is NULL, so _cpp_pop_buffer does not
+        push -include files.  */
+      for (p = CPP_OPTION (pfile, pending)->imacros_head; p; p = p->next)
+       if (push_include (pfile, p))
+         cpp_scan_nooutput (pfile);
+
+      pfile->next_include_file = &CPP_OPTION (pfile, pending)->include_head;
+      _cpp_maybe_push_include_file (pfile);
     }
 
+  pfile->first_unused_line = pfile->line;
+
+  free_chain (CPP_OPTION (pfile, pending)->imacros_head);
   free_chain (CPP_OPTION (pfile, pending)->directive_head);
-  _cpp_push_next_buffer (pfile);
 }
 
-/* Called to push the next buffer on the stack given by -include.  If
-   there are none, free the pending structure and restore the line map
-   for the main file.  */
-bool
-_cpp_push_next_buffer (pfile)
+/* Push the next buffer on the stack given by -include, if any.  */
+void
+_cpp_maybe_push_include_file (pfile)
      cpp_reader *pfile;
 {
-  bool pushed = false;
-
-  /* This is't pretty; we'd rather not be relying on this as a boolean
-     for reverting the line map.  Further, we only free the chains in
-     this conditional, so an early call to cpp_finish / cpp_destroy
-     will leak that memory.  */
-  if (CPP_OPTION (pfile, pending)
-      && CPP_OPTION (pfile, pending)->imacros_head == NULL)
+  if (pfile->next_include_file)
     {
-      while (!pushed)
-       {
-         struct pending_option *p = CPP_OPTION (pfile, pending)->include_head;
+      struct pending_option *head = *pfile->next_include_file;
 
-         if (p == NULL)
-           break;
-         if (! CPP_OPTION (pfile, preprocessed))
-           pushed = push_include (pfile, p);
-         CPP_OPTION (pfile, pending)->include_head = p->next;
-         free (p);
-       }
+      while (head && !push_include (pfile, head))
+       head = head->next;
 
-      if (!pushed)
+      if (head)
+       pfile->next_include_file = &head->next;
+      else
        {
-         free (CPP_OPTION (pfile, pending));
-         CPP_OPTION (pfile, pending) = NULL;
-
-         /* Restore the line map for the main file.  */
-         if (! CPP_OPTION (pfile, preprocessed))
-           _cpp_do_file_change (pfile, LC_RENAME,
-                                pfile->line_maps.maps[0].to_file, 1, 0);
+         /* All done; restore the line map from <command line>.  */
+         _cpp_do_file_change (pfile, LC_RENAME,
+                              pfile->line_maps.maps[0].to_file, 1, 0);
+         /* Don't come back here again.  */
+         pfile->next_include_file = NULL;
        }
     }
-
-  return pushed;
 }
 
-/* Use mkdeps.c to output dependency information.  */
-static void
-output_deps (pfile)
-     cpp_reader *pfile;
-{
-  /* Stream on which to print the dependency information.  */
-  FILE *deps_stream = 0;
-  const char *const deps_mode =
-    CPP_OPTION (pfile, print_deps_append) ? "a" : "w";
-
-  if (CPP_OPTION (pfile, deps_file)[0] == '\0')
-    deps_stream = stdout;
-  else
-    {
-      deps_stream = fopen (CPP_OPTION (pfile, deps_file), deps_mode);
-      if (deps_stream == 0)
-       {
-         cpp_notice_from_errno (pfile, CPP_OPTION (pfile, deps_file));
-         return;
-       }
-    }
-
-  deps_write (pfile->deps, deps_stream, 72);
-
-  if (CPP_OPTION (pfile, deps_phony_targets))
-    deps_phony_targets (pfile->deps, deps_stream);
+/* This is called at the end of preprocessing.  It pops the last
+   buffer and writes dependency output, and returns the number of
+   errors.
 
-  /* Don't close stdout.  */
-  if (deps_stream != stdout)
-    {
-      if (ferror (deps_stream) || fclose (deps_stream) != 0)
-       cpp_fatal (pfile, "I/O error on output");
-    }
-}
-
-/* This is called at the end of preprocessing.  It pops the
-   last buffer and writes dependency output.  It should also
-   clear macro definitions, such that you could call cpp_start_read
-   with a new filename to restart processing.  */
-void
-cpp_finish (pfile)
+   Maybe it should also reset state, such that you could call
+   cpp_start_read with a new filename to restart processing.  */
+int
+cpp_finish (pfile, deps_stream)
      cpp_reader *pfile;
+     FILE *deps_stream;
 {
+  /* Warn about unused macros before popping the final buffer.  */
+  if (CPP_OPTION (pfile, warn_unused_macros))
+    cpp_forall_identifiers (pfile, _cpp_warn_if_unused_macro, NULL);
+
   /* cpplex.c leaves the final buffer on the stack.  This it so that
      it returns an unending stream of CPP_EOFs to the client.  If we
      popped the buffer, we'd dereference a NULL buffer pointer and
@@ -1189,13 +1151,21 @@ cpp_finish (pfile)
   while (pfile->buffer)
     _cpp_pop_buffer (pfile);
 
-  /* Don't write the deps file if preprocessing has failed.  */
-  if (CPP_OPTION (pfile, print_deps) && pfile->errors == 0)
-    output_deps (pfile);
+  /* Don't write the deps file if there are errors.  */
+  if (CPP_OPTION (pfile, deps.style) != DEPS_NONE
+      && deps_stream && pfile->errors == 0)
+    {
+      deps_write (pfile->deps, deps_stream, 72);
+
+      if (CPP_OPTION (pfile, deps.phony_targets))
+       deps_phony_targets (pfile->deps, deps_stream);
+    }
 
   /* Report on headers that could use multiple include guards.  */
   if (CPP_OPTION (pfile, print_include_names))
     _cpp_report_missing_guards (pfile);
+
+  return pfile->errors;
 }
 
 /* Add a directive to be handled later in the initialization phase.  */
@@ -1217,88 +1187,27 @@ new_pending_directive (pend, text, handler)
 /* Irix6 "cc -n32" and OSF4 cc have problems with char foo[] = ("string");
    I.e. a const string initializer with parens around it.  That is
    what N_("string") resolves to, so we make no_* be macros instead.  */
-#define no_arg N_("argument missing after %s")
 #define no_ass N_("assertion missing after %s")
 #define no_dir N_("directory name missing after %s")
 #define no_fil N_("file name missing after %s")
 #define no_mac N_("macro name missing after %s")
 #define no_pth N_("path name missing after %s")
-#define no_num N_("number missing after %s")
-#define no_tgt N_("target missing after %s")
 
 /* This is the list of all command line options, with the leading
    "-" removed.  It must be sorted in ASCII collating order.  */
 #define COMMAND_LINE_OPTIONS                                                  \
-  DEF_OPT("$",                        0,      OPT_dollar)                     \
-  DEF_OPT("+",                        0,      OPT_plus)                       \
-  DEF_OPT("-help",                    0,      OPT__help)                      \
-  DEF_OPT("-target-help",             0,      OPT_target__help)               \
-  DEF_OPT("-version",                 0,      OPT__version)                   \
   DEF_OPT("A",                        no_ass, OPT_A)                          \
-  DEF_OPT("C",                        0,      OPT_C)                          \
   DEF_OPT("D",                        no_mac, OPT_D)                          \
-  DEF_OPT("H",                        0,      OPT_H)                          \
   DEF_OPT("I",                        no_dir, OPT_I)                          \
-  DEF_OPT("M",                        0,      OPT_M)                          \
-  DEF_OPT("MD",                       no_fil, OPT_MD)                         \
-  DEF_OPT("MF",                       no_fil, OPT_MF)                         \
-  DEF_OPT("MG",                       0,      OPT_MG)                         \
-  DEF_OPT("MM",                       0,      OPT_MM)                         \
-  DEF_OPT("MMD",                      no_fil, OPT_MMD)                        \
-  DEF_OPT("MP",                       0,      OPT_MP)                         \
-  DEF_OPT("MQ",                       no_tgt, OPT_MQ)                         \
-  DEF_OPT("MT",                       no_tgt, OPT_MT)                         \
-  DEF_OPT("P",                        0,      OPT_P)                          \
   DEF_OPT("U",                        no_mac, OPT_U)                          \
-  DEF_OPT("W",                        no_arg, OPT_W)  /* arg optional */      \
-  DEF_OPT("d",                        no_arg, OPT_d)                          \
-  DEF_OPT("fleading-underscore",      0,      OPT_fleading_underscore)        \
-  DEF_OPT("fno-leading-underscore",   0,      OPT_fno_leading_underscore)     \
-  DEF_OPT("fno-operator-names",       0,      OPT_fno_operator_names)         \
-  DEF_OPT("fno-preprocessed",         0,      OPT_fno_preprocessed)           \
-  DEF_OPT("fno-show-column",          0,      OPT_fno_show_column)            \
-  DEF_OPT("fpreprocessed",            0,      OPT_fpreprocessed)              \
-  DEF_OPT("fshow-column",             0,      OPT_fshow_column)               \
-  DEF_OPT("fsigned-char",             0,      OPT_fsigned_char)               \
-  DEF_OPT("ftabstop=",                no_num, OPT_ftabstop)                   \
-  DEF_OPT("funsigned-char",           0,      OPT_funsigned_char)             \
-  DEF_OPT("h",                        0,      OPT_h)                          \
   DEF_OPT("idirafter",                no_dir, OPT_idirafter)                  \
   DEF_OPT("imacros",                  no_fil, OPT_imacros)                    \
   DEF_OPT("include",                  no_fil, OPT_include)                    \
   DEF_OPT("iprefix",                  no_pth, OPT_iprefix)                    \
+  DEF_OPT("isysroot",                 no_dir, OPT_isysroot)                   \
   DEF_OPT("isystem",                  no_dir, OPT_isystem)                    \
   DEF_OPT("iwithprefix",              no_dir, OPT_iwithprefix)                \
-  DEF_OPT("iwithprefixbefore",        no_dir, OPT_iwithprefixbefore)          \
-  DEF_OPT("lang-asm",                 0,      OPT_lang_asm)                   \
-  DEF_OPT("lang-c",                   0,      OPT_lang_c)                     \
-  DEF_OPT("lang-c++",                 0,      OPT_lang_cplusplus)             \
-  DEF_OPT("lang-c89",                 0,      OPT_lang_c89)                   \
-  DEF_OPT("lang-objc",                0,      OPT_lang_objc)                  \
-  DEF_OPT("lang-objc++",              0,      OPT_lang_objcplusplus)          \
-  DEF_OPT("nostdinc",                 0,      OPT_nostdinc)                   \
-  DEF_OPT("nostdinc++",               0,      OPT_nostdincplusplus)           \
-  DEF_OPT("o",                        no_fil, OPT_o)                          \
-  /* SDCC specific */                                                         \
-  DEF_OPT("obj-ext=",                 no_arg, OPT_obj_ext)                    \
-  DEF_OPT("pedantic",                 0,      OPT_pedantic)                   \
-  DEF_OPT("pedantic-errors",          0,      OPT_pedantic_errors)            \
-  DEF_OPT("remap",                    0,      OPT_remap)                      \
-  DEF_OPT("std=c++98",                0,      OPT_std_cplusplus98)            \
-  DEF_OPT("std=c89",                  0,      OPT_std_c89)                    \
-  DEF_OPT("std=c99",                  0,      OPT_std_c99)                    \
-  DEF_OPT("std=c9x",                  0,      OPT_std_c9x)                    \
-  DEF_OPT("std=gnu89",                0,      OPT_std_gnu89)                  \
-  DEF_OPT("std=gnu99",                0,      OPT_std_gnu99)                  \
-  DEF_OPT("std=gnu9x",                0,      OPT_std_gnu9x)                  \
-  DEF_OPT("std=iso9899:1990",         0,      OPT_std_iso9899_1990)           \
-  DEF_OPT("std=iso9899:199409",       0,      OPT_std_iso9899_199409)         \
-  DEF_OPT("std=iso9899:1999",         0,      OPT_std_iso9899_1999)           \
-  DEF_OPT("std=iso9899:199x",         0,      OPT_std_iso9899_199x)           \
-  DEF_OPT("trigraphs",                0,      OPT_trigraphs)                  \
-  DEF_OPT("v",                        0,      OPT_v)                          \
-  DEF_OPT("version",                  0,      OPT_version)                    \
-  DEF_OPT("w",                        0,      OPT_w)
+  DEF_OPT("iwithprefixbefore",        no_dir, OPT_iwithprefixbefore)
 
 #define DEF_OPT(text, msg, code) code,
 enum opt_code
@@ -1332,10 +1241,7 @@ static const struct cl_option cl_options[] =
    command-line matches.  Returns its index in the option array,
    negative on failure.  Complications arise since some options can be
    suffixed with an argument, and multiple complete matches can occur,
-   e.g. -iwithprefix and -iwithprefixbefore.  Moreover, we need to
-   accept options beginning with -W that we do not recognise, but not
-   to swallow any subsequent command line argument; this is handled as
-   special cases in cpp_handle_option.  */
+   e.g. -pedantic and -pedantic-errors.  */
 static int
 parse_option (input)
      const char *input;
@@ -1394,30 +1300,16 @@ parse_option (input)
 
 /* Handle one command-line option in (argc, argv).
    Can be called multiple times, to handle multiple sets of options.
-   If ignore is non-zero, this will ignore unrecognized -W* options.
    Returns number of strings consumed.  */
 int
-cpp_handle_option (pfile, argc, argv, ignore)
+cpp_handle_option (pfile, argc, argv)
      cpp_reader *pfile;
      int argc;
      char **argv;
-     int ignore;
 {
   int i = 0;
   struct cpp_pending *pend = CPP_OPTION (pfile, pending);
 
-  /* Interpret "-" or a non-option as a file name.  */
-  if (argv[i][0] != '-' || argv[i][1] == '\0')
-    {
-      if (CPP_OPTION (pfile, in_fname) == NULL)
-       CPP_OPTION (pfile, in_fname) = argv[i];
-      else if (CPP_OPTION (pfile, out_fname) == NULL)
-       CPP_OPTION (pfile, out_fname) = argv[i];
-      else
-       cpp_fatal (pfile, "too many filenames. Type %s --help for usage info",
-                  progname);
-    }
-  else
     {
       enum opt_code opt_code;
       int opt_index;
@@ -1432,16 +1324,13 @@ cpp_handle_option (pfile, argc, argv, ignore)
       if (cl_options[opt_index].msg)
        {
          arg = &argv[i][cl_options[opt_index].opt_len + 1];
-
-         /* Yuk. Special case for -W as it must not swallow
-            up any following argument.  If this becomes common, add
-            another field to the cl_options table.  */
-         if (arg[0] == '\0' && opt_code != OPT_W)
+         if (arg[0] == '\0')
            {
              arg = argv[++i];
              if (!arg)
                {
-                 cpp_fatal (pfile, cl_options[opt_index].msg, argv[i - 1]);
+                 cpp_error (pfile, DL_ERROR,
+                            cl_options[opt_index].msg, argv[i - 1]);
                  return argc;
                }
            }
@@ -1451,245 +1340,22 @@ cpp_handle_option (pfile, argc, argv, ignore)
        {
        case N_OPTS: /* Shut GCC up.  */
          break;
-       case OPT_fleading_underscore:
-         CPP_OPTION (pfile, user_label_prefix) = "_";
-         break;
-       case OPT_fno_leading_underscore:
-         CPP_OPTION (pfile, user_label_prefix) = "";
-         break;
-       case OPT_fno_operator_names:
-         CPP_OPTION (pfile, operator_names) = 0;
-         break;
-       case OPT_fpreprocessed:
-         CPP_OPTION (pfile, preprocessed) = 1;
-         break;
-       case OPT_fno_preprocessed:
-         CPP_OPTION (pfile, preprocessed) = 0;
-         break;
-       case OPT_fshow_column:
-         CPP_OPTION (pfile, show_column) = 1;
-         break;
-       case OPT_fno_show_column:
-         CPP_OPTION (pfile, show_column) = 0;
-         break;
-       case OPT_fsigned_char:
-         CPP_OPTION (pfile, signed_char) = 1;
-         break;
-       case OPT_funsigned_char:
-         CPP_OPTION (pfile, signed_char) = 0;
-         break;
-       case OPT_ftabstop:
-         /* Silently ignore empty string, non-longs and silly values.  */
-         if (arg[0] != '\0')
-           {
-             char *endptr;
-             long tabstop = strtol (arg, &endptr, 10);
-             if (*endptr == '\0' && tabstop >= 1 && tabstop <= 100)
-               CPP_OPTION (pfile, tabstop) = tabstop;
-           }
-         break;
-       case OPT_w:
-         CPP_OPTION (pfile, inhibit_warnings) = 1;
-         break;
-       case OPT_h:
-       case OPT__help:
-         print_help ();
-         CPP_OPTION (pfile, help_only) = 1;
-         break;
-       case OPT_target__help:
-          /* Print if any target specific options. cpplib has none, but
-            make sure help_only gets set.  */
-         CPP_OPTION (pfile, help_only) = 1;
-          break;
-
-         /* --version inhibits compilation, -version doesn't. -v means
-            verbose and -version.  Historical reasons, don't ask.  */
-       case OPT__version:
-         CPP_OPTION (pfile, help_only) = 1;
-         pfile->print_version = 1;
-         break;
-       case OPT_v:
-         CPP_OPTION (pfile, verbose) = 1;
-         pfile->print_version = 1;
-         break;
-       case OPT_version:
-         pfile->print_version = 1;
-         break;
 
-       case OPT_C:
-         CPP_OPTION (pfile, discard_comments) = 0;
-         break;
-       case OPT_P:
-         CPP_OPTION (pfile, no_line_commands) = 1;
-         break;
-       case OPT_dollar:        /* Don't include $ in identifiers.  */
-         CPP_OPTION (pfile, dollars_in_ident) = 0;
-         break;
-       case OPT_H:
-         CPP_OPTION (pfile, print_include_names) = 1;
-         break;
        case OPT_D:
          new_pending_directive (pend, arg, cpp_define);
          break;
-       case OPT_pedantic_errors:
-         CPP_OPTION (pfile, pedantic_errors) = 1;
-         /* fall through */
-       case OPT_pedantic:
-         CPP_OPTION (pfile, pedantic) = 1;
-         break;
-       case OPT_trigraphs:
-         CPP_OPTION (pfile, trigraphs) = 1;
-         break;
-       case OPT_plus:
-         CPP_OPTION (pfile, cplusplus) = 1;
-         CPP_OPTION (pfile, cplusplus_comments) = 1;
-         break;
-       case OPT_remap:
-         CPP_OPTION (pfile, remap) = 1;
-         break;
        case OPT_iprefix:
          CPP_OPTION (pfile, include_prefix) = arg;
          CPP_OPTION (pfile, include_prefix_len) = strlen (arg);
          break;
-       case OPT_lang_c:
-         set_lang (pfile, CLK_GNUC89);
-         break;
-       case OPT_lang_cplusplus:
-         set_lang (pfile, CLK_GNUCXX);
-         break;
-       case OPT_lang_objc:
-         set_lang (pfile, CLK_OBJC);
-         break;
-       case OPT_lang_objcplusplus:
-         set_lang (pfile, CLK_OBJCXX);
-         break;
-       case OPT_lang_asm:
-         set_lang (pfile, CLK_ASM);
-         break;
-       case OPT_std_cplusplus98:
-         set_lang (pfile, CLK_CXX98);
-         break;
-       case OPT_std_gnu89:
-         set_lang (pfile, CLK_GNUC89);
-         break;
-       case OPT_std_gnu9x:
-       case OPT_std_gnu99:
-         set_lang (pfile, CLK_GNUC99);
-         break;
-       case OPT_std_iso9899_199409:
-         set_lang (pfile, CLK_STDC94);
-         break;
-       case OPT_std_iso9899_1990:
-       case OPT_std_c89:
-       case OPT_lang_c89:
-         set_lang (pfile, CLK_STDC89);
-         break;
-       case OPT_std_iso9899_199x:
-       case OPT_std_iso9899_1999:
-       case OPT_std_c9x:
-       case OPT_std_c99:
-         set_lang (pfile, CLK_STDC99);
-         break;
-       case OPT_nostdinc:
-         /* -nostdinc causes no default include directories.
-            You must specify all include-file directories with -I.  */
-         CPP_OPTION (pfile, no_standard_includes) = 1;
-         break;
-       case OPT_nostdincplusplus:
-         /* -nostdinc++ causes no default C++-specific include directories.  */
-         CPP_OPTION (pfile, no_standard_cplusplus_includes) = 1;
-         break;
-       case OPT_o:
-         if (CPP_OPTION (pfile, out_fname) == NULL)
-           CPP_OPTION (pfile, out_fname) = arg;
-         else
-           {
-             cpp_fatal (pfile, "output filename specified twice");
-             return argc;
-           }
-         break;
-       case OPT_d:
-         /* Args to -d specify what parts of macros to dump.
-            Silently ignore unrecognised options; they may
-            be aimed at the compiler proper.  */
-         {
-           char c;
-
-           while ((c = *arg++) != '\0')
-             switch (c)
-               {
-               case 'M':
-                 CPP_OPTION (pfile, dump_macros) = dump_only;
-                 break;
-               case 'N':
-                 CPP_OPTION (pfile, dump_macros) = dump_names;
-                 break;
-               case 'D':
-                 CPP_OPTION (pfile, dump_macros) = dump_definitions;
-                 break;
-               case 'I':
-                 CPP_OPTION (pfile, dump_includes) = 1;
-                 break;
-               }
-         }
-         break;
 
-       case OPT_MG:
-         CPP_OPTION (pfile, print_deps_missing_files) = 1;
-         break;
-       case OPT_M:
-         /* When doing dependencies with -M or -MM, suppress normal
-            preprocessed output, but still do -dM etc. as software
-            depends on this.  Preprocessed output occurs if -MD, -MMD
-            or environment var dependency generation is used.  */
-         CPP_OPTION (pfile, print_deps) = 2;
-         CPP_OPTION (pfile, no_output) = 1;
-         break;
-       case OPT_MM:
-         CPP_OPTION (pfile, print_deps) = 1;
-         CPP_OPTION (pfile, no_output) = 1;
-         break;
-       case OPT_MF:
-         CPP_OPTION (pfile, deps_file) = arg;
-         break;
-       case OPT_MP:
-         CPP_OPTION (pfile, deps_phony_targets) = 1;
-         break;
-       case OPT_MQ:
-       case OPT_MT:
-         /* Add a target.  -MQ quotes for Make.  */
-         deps_add_target (pfile->deps, arg, opt_code == OPT_MQ);
-         break;
-
-       case OPT_MD:
-         CPP_OPTION (pfile, print_deps) = 2;
-         CPP_OPTION (pfile, deps_file) = arg;
-         break;
-       case OPT_MMD:
-         CPP_OPTION (pfile, print_deps) = 1;
-         CPP_OPTION (pfile, deps_file) = arg;
+       case OPT_isysroot:
+         CPP_OPTION (pfile, sysroot) = arg;
          break;
 
        case OPT_A:
          if (arg[0] == '-')
-           {
-             /* -A with an argument beginning with '-' acts as
-                #unassert on whatever immediately follows the '-'.
-                If "-" is the whole argument, we eliminate all
-                predefined macros and assertions, including those
-                that were specified earlier on the command line.
-                That way we can get rid of any that were passed
-                automatically in from GCC.  */
-
-             if (arg[1] == '\0')
-               {
-                 free_chain (pend->directive_head);
-                 pend->directive_head = NULL;
-                 pend->directive_tail = NULL;
-               }
-             else
-               new_pending_directive (pend, arg + 1, cpp_unassert);
-           }
+           new_pending_directive (pend, arg + 1, cpp_unassert);
          else
            new_pending_directive (pend, arg, cpp_assert);
          break;
@@ -1698,7 +1364,7 @@ cpp_handle_option (pfile, argc, argv, ignore)
          break;
        case OPT_I:           /* Add directory to path for includes.  */
          if (!strcmp (arg, "-"))
-           {
+           {
              /* -I- means:
                 Use the preceding -I directories for #include "..."
                 but not #include <...>.
@@ -1715,17 +1381,17 @@ cpp_handle_option (pfile, argc, argv, ignore)
                }
              else
                {
-                 cpp_fatal (pfile, "-I- specified twice");
+                 cpp_error (pfile, DL_ERROR, "-I- specified twice");
                  return argc;
                }
-           }
-         else
-           append_include_chain (pfile, (char *)xstrdup(arg), BRACKET, 0);
+           }
+         else
+           append_include_chain (pfile, (char *)xstrdup (arg), BRACKET, 0);
          break;
        case OPT_isystem:
          /* Add directory to beginning of system include path, as a system
             include directory.  */
-         append_include_chain (pfile, (char *)xstrdup(arg), SYSTEM, 0);
+         append_include_chain (pfile, (char *)xstrdup (arg), SYSTEM, 0);
          break;
        case OPT_include:
        case OPT_imacros:
@@ -1778,53 +1444,7 @@ cpp_handle_option (pfile, argc, argv, ignore)
          /* Add directory to end of path for includes.  */
          append_include_chain (pfile, (char *)xstrdup (arg), AFTER, 0);
          break;
-       case OPT_W:
-         /* Silently ignore unrecognised options.  */
-         if (!strcmp (argv[i], "-Wall"))
-           {
-             CPP_OPTION (pfile, warn_trigraphs) = 1;
-             CPP_OPTION (pfile, warn_comments) = 1;
-           }
-         else if (!strcmp (argv[i], "-Wtraditional"))
-           CPP_OPTION (pfile, warn_traditional) = 1;
-         else if (!strcmp (argv[i], "-Wtrigraphs"))
-           CPP_OPTION (pfile, warn_trigraphs) = 1;
-         else if (!strcmp (argv[i], "-Wcomment"))
-           CPP_OPTION (pfile, warn_comments) = 1;
-         else if (!strcmp (argv[i], "-Wcomments"))
-           CPP_OPTION (pfile, warn_comments) = 1;
-         else if (!strcmp (argv[i], "-Wundef"))
-           CPP_OPTION (pfile, warn_undef) = 1;
-         else if (!strcmp (argv[i], "-Wimport"))
-           CPP_OPTION (pfile, warn_import) = 1;
-         else if (!strcmp (argv[i], "-Werror"))
-           CPP_OPTION (pfile, warnings_are_errors) = 1;
-         else if (!strcmp (argv[i], "-Wsystem-headers"))
-           CPP_OPTION (pfile, warn_system_headers) = 1;
-         else if (!strcmp (argv[i], "-Wno-traditional"))
-           CPP_OPTION (pfile, warn_traditional) = 0;
-         else if (!strcmp (argv[i], "-Wno-trigraphs"))
-           CPP_OPTION (pfile, warn_trigraphs) = 0;
-         else if (!strcmp (argv[i], "-Wno-comment"))
-           CPP_OPTION (pfile, warn_comments) = 0;
-         else if (!strcmp (argv[i], "-Wno-comments"))
-           CPP_OPTION (pfile, warn_comments) = 0;
-         else if (!strcmp (argv[i], "-Wno-undef"))
-           CPP_OPTION (pfile, warn_undef) = 0;
-         else if (!strcmp (argv[i], "-Wno-import"))
-           CPP_OPTION (pfile, warn_import) = 0;
-         else if (!strcmp (argv[i], "-Wno-error"))
-           CPP_OPTION (pfile, warnings_are_errors) = 0;
-         else if (!strcmp (argv[i], "-Wno-system-headers"))
-           CPP_OPTION (pfile, warn_system_headers) = 0;
-         else if (! ignore)
-           return i;
-         break;
-       /* SDCC specific */
-       case OPT_obj_ext:
-         CPP_OPTION (pfile, obj_ext) = arg;
-         break;
-       }
+       }
     }
   return i + 1;
 }
@@ -1844,7 +1464,7 @@ cpp_handle_options (pfile, argc, argv)
 
   for (i = 0; i < argc; i += strings_processed)
     {
-      strings_processed = cpp_handle_option (pfile, argc - i, argv + i, 1);
+      strings_processed = cpp_handle_option (pfile, argc - i, argv + i);
       if (strings_processed == 0)
        break;
     }
@@ -1852,232 +1472,23 @@ cpp_handle_options (pfile, argc, argv)
   return i;
 }
 
-/* Extra processing when all options are parsed, after all calls to
-   cpp_handle_option[s].  Consistency checks etc.  */
-void
-cpp_post_options (pfile)
+static void
+post_options (pfile)
      cpp_reader *pfile;
 {
-  if (pfile->print_version)
-    {
-      fprintf (stderr, _("GNU CPP version %s (cpplib)"), version_string);
-#ifdef TARGET_VERSION
-      TARGET_VERSION;
-#endif
-      fputc ('\n', stderr);
-    }
-
-  /* Canonicalize in_fname and out_fname.  We guarantee they are not
-     NULL, and that the empty string represents stdin / stdout.  */
-  if (CPP_OPTION (pfile, in_fname) == NULL
-      || !strcmp (CPP_OPTION (pfile, in_fname), "-"))
-    CPP_OPTION (pfile, in_fname) = "";
-
-  if (CPP_OPTION (pfile, out_fname) == NULL
-      || !strcmp (CPP_OPTION (pfile, out_fname), "-"))
-    CPP_OPTION (pfile, out_fname) = "";
-
   /* -Wtraditional is not useful in C++ mode.  */
   if (CPP_OPTION (pfile, cplusplus))
     CPP_OPTION (pfile, warn_traditional) = 0;
 
-  /* Set this if it hasn't been set already.  */
-  if (CPP_OPTION (pfile, user_label_prefix) == NULL)
-    CPP_OPTION (pfile, user_label_prefix) = USER_LABEL_PREFIX;
-
   /* Permanently disable macro expansion if we are rescanning
-     preprocessed text.  */
+     preprocessed text.  Read preprocesed source in ISO mode.  */
   if (CPP_OPTION (pfile, preprocessed))
-    pfile->state.prevent_expansion = 1;
-
-  /* -dM makes no normal output.  This is set here so that -dM -dD
-     works as expected.  */
-  if (CPP_OPTION (pfile, dump_macros) == dump_only)
-    CPP_OPTION (pfile, no_output) = 1;
-
-  /* Disable -dD, -dN and -dI if we should make no normal output
-     (such as with -M). Allow -M -dM since some software relies on
-     this.  */
-  if (CPP_OPTION (pfile, no_output))
-    {
-      if (CPP_OPTION (pfile, dump_macros) != dump_only)
-       CPP_OPTION (pfile, dump_macros) = dump_none;
-      CPP_OPTION (pfile, dump_includes) = 0;
-    }
-
-  /* We need to do this after option processing and before
-     cpp_start_read, as cppmain.c relies on the options->no_output to
-     set its callbacks correctly before calling cpp_start_read.  */
-  init_dependency_output (pfile);
-
-  /* After checking the environment variables, check if -M or -MM has
-     not been specified, but other -M options have.  */
-  if (CPP_OPTION (pfile, print_deps) == 0 &&
-      (CPP_OPTION (pfile, print_deps_missing_files)
-       || CPP_OPTION (pfile, deps_file)
-       || CPP_OPTION (pfile, deps_phony_targets)))
-    cpp_fatal (pfile, "you must additionally specify either -M or -MM");
-}
-
-/* Set up dependency-file output.  On exit, if print_deps is non-zero
-   then deps_file is not NULL; stdout is the empty string.  */
-static void
-init_dependency_output (pfile)
-     cpp_reader *pfile;
-{
-  char *spec, *s, *output_file;
-
-  /* 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 (CPP_OPTION (pfile, print_deps) == 0)
     {
-      spec = getenv ("DEPENDENCIES_OUTPUT");
-      if (spec)
-       CPP_OPTION (pfile, print_deps) = 1;
-      else
-       {
-         spec = getenv ("SUNPRO_DEPENDENCIES");
-         if (spec)
-           {
-             CPP_OPTION (pfile, print_deps) = 2;
-             CPP_OPTION (pfile, deps_ignore_main_file) = 1;
-           }
-         else
-           return;
-       }
-
-      /* Find the space before the DEPS_TARGET, if there is one.  */
-      s = strchr (spec, ' ');
-      if (s)
-       {
-         /* Let the caller perform MAKE quoting.  */
-         deps_add_target (pfile->deps, s + 1, 0);
-         output_file = (char *) xmalloc (s - spec + 1);
-         memcpy (output_file, spec, s - spec);
-         output_file[s - spec] = 0;
-       }
-      else
-       output_file = spec;
-
-      /* Command line -MF overrides environment variables and default.  */
-      if (CPP_OPTION (pfile, deps_file) == 0)
-       CPP_OPTION (pfile, deps_file) = output_file;
-
-      CPP_OPTION (pfile, print_deps_append) = 1;
+      pfile->state.prevent_expansion = 1;
+      CPP_OPTION (pfile, traditional) = 0;
     }
-  else if (CPP_OPTION (pfile, deps_file) == 0)
-    /* If -M or -MM was seen without -MF, default output to wherever
-       was specified with -o.  out_fname is non-NULL here.  */
-    CPP_OPTION (pfile, deps_file) = CPP_OPTION (pfile, out_fname);
-}
 
-/* Handle --help output.  */
-static void
-print_help ()
-{
-  /* To keep the lines from getting too long for some compilers, limit
-     to about 500 characters (6 lines) per chunk.  */
-  fputs (_("\
-Switches:\n\
-  -include <file>           Include the contents of <file> before other files\n\
-  -imacros <file>           Accept definition of macros in <file>\n\
-  -iprefix <path>           Specify <path> as a prefix for next two options\n\
-  -iwithprefix <dir>        Add <dir> to the end of the system include path\n\
-  -iwithprefixbefore <dir>  Add <dir> to the end of the main include path\n\
-  -isystem <dir>            Add <dir> to the start of the system include path\n\
-"), stdout);
-  fputs (_("\
-  -idirafter <dir>          Add <dir> to the end of the system include path\n\
-  -I <dir>                  Add <dir> to the end of the main include path\n\
-  -I-                       Fine-grained include path control; see info docs\n\
-  -nostdinc                 Do not search system include directories\n\
-                             (dirs specified with -isystem will still be used)\n\
-  -nostdinc++               Do not search system include directories for C++\n\
-  -o <file>                 Put output into <file>\n\
-"), stdout);
-  fputs (_("\
-  -pedantic                 Issue all warnings demanded by strict ISO C\n\
-  -pedantic-errors          Issue -pedantic warnings as errors instead\n\
-  -trigraphs                Support ISO C trigraphs\n\
-  -lang-c                   Assume that the input sources are in C\n\
-  -lang-c89                 Assume that the input sources are in C89\n\
-"), stdout);
-  fputs (_("\
-  -lang-c++                 Assume that the input sources are in C++\n\
-  -lang-objc                Assume that the input sources are in ObjectiveC\n\
-  -lang-objc++              Assume that the input sources are in ObjectiveC++\n\
-  -lang-asm                 Assume that the input sources are in assembler\n\
-"), stdout);
-  fputs (_("\
-  -std=<std name>           Specify the conformance standard; one of:\n\
-                            gnu89, gnu99, c89, c99, iso9899:1990,\n\
-                            iso9899:199409, iso9899:1999\n\
-  -+                        Allow parsing of C++ style features\n\
-  -w                        Inhibit warning messages\n\
-  -Wtrigraphs               Warn if trigraphs are encountered\n\
-  -Wno-trigraphs            Do not warn about trigraphs\n\
-  -Wcomment{s}              Warn if one comment starts inside another\n\
-"), stdout);
-  fputs (_("\
-  -Wno-comment{s}           Do not warn about comments\n\
-  -Wtraditional             Warn about features not present in traditional C\n\
-  -Wno-traditional          Do not warn about traditional C\n\
-  -Wundef                   Warn if an undefined macro is used by #if\n\
-  -Wno-undef                Do not warn about testing undefined macros\n\
-  -Wimport                  Warn about the use of the #import directive\n\
-"), stdout);
-  fputs (_("\
-  -Wno-import               Do not warn about the use of #import\n\
-  -Werror                   Treat all warnings as errors\n\
-  -Wno-error                Do not treat warnings as errors\n\
-  -Wsystem-headers          Do not suppress warnings from system headers\n\
-  -Wno-system-headers       Suppress warnings from system headers\n\
-  -Wall                     Enable all preprocessor warnings\n\
-"), stdout);
-  fputs (_("\
-  -M                        Generate make dependencies\n\
-  -MM                       As -M, but ignore system header files\n\
-  -MD                       Generate make dependencies and compile\n\
-  -MMD                      As -MD, but ignore system header files\n\
-  -MF <file>                Write dependency output to the given file\n\
-  -MG                       Treat missing header file as generated files\n\
-"), stdout);
-  fputs (_("\
-  -MP                      Generate phony targets for all headers\n\
-  -MQ <target>              Add a MAKE-quoted target\n\
-  -MT <target>              Add an unquoted target\n\
-"), stdout);
-  /* SDCC specific */
-  fputs (_("\
-  -obj-ext=<extension>      Define object file extension, used for generation\n\
-                            of make dependencies\n\
-"), stdout);
-  fputs (_("\
-  -D<macro>                 Define a <macro> with string '1' as its value\n\
-  -D<macro>=<val>           Define a <macro> with <val> as its value\n\
-  -A<question>=<answer>     Assert the <answer> to <question>\n\
-  -A-<question>=<answer>    Disable the <answer> to <question>\n\
-  -U<macro>                 Undefine <macro> \n\
-  -v                        Display the version number\n\
-"), stdout);
-  fputs (_("\
-  -H                        Print the name of header files as they are used\n\
-  -C                        Do not discard comments\n\
-  -dM                       Display a list of macro definitions active at end\n\
-  -dD                       Preserve macro definitions in output\n\
-  -dN                       As -dD except that only the names are preserved\n\
-  -dI                       Include #include directives in the output\n\
-"), stdout);
-  fputs (_("\
-  -fpreprocessed            Treat the input file as already preprocessed\n\
-  -ftabstop=<number>        Distance between tab stops for column reporting\n\
-  -P                        Do not generate #line directives\n\
-  -$                        Do not allow '$' in identifiers\n\
-  -remap                    Remap file names when including files\n\
-  --version                 Display version information\n\
-  -h or --help              Display this information\n\
-"), stdout);
+  /* Traditional CPP does not accurately track column information.  */
+  if (CPP_OPTION (pfile, traditional))
+    CPP_OPTION (pfile, show_column) = 0;
 }
index 483128bb5da8d4430a5d354a9915e0031fc1f15c..b5b8ba723c6f1610d65ab15203b898c91093521c 100644 (file)
@@ -26,13 +26,6 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "cpphash.h"
 #include <assert.h>
 
-/* MULTIBYTE_CHARS support only works for native compilers.
-   ??? Ideally what we want is to model widechar support after
-   the current floating point support.  */
-#ifdef CROSS_COMPILE
-#undef MULTIBYTE_CHARS
-#endif
-
 #ifdef MULTIBYTE_CHARS
 #include "mbchar.h"
 #include <locale.h>
@@ -79,19 +72,20 @@ static int skip_line_comment PARAMS ((cpp_reader *));
 static void adjust_column PARAMS ((cpp_reader *));
 static int skip_whitespace PARAMS ((cpp_reader *, cppchar_t));
 static cpp_hashnode *parse_identifier PARAMS ((cpp_reader *));
-static cpp_hashnode *parse_identifier_slow PARAMS ((cpp_reader *,
-                                                   const U_CHAR *));
-static void parse_number PARAMS ((cpp_reader *, cpp_string *, cppchar_t, int));
-static int unescaped_terminator_p PARAMS ((cpp_reader *, const U_CHAR *));
+static uchar *parse_slow PARAMS ((cpp_reader *, const uchar *, int,
+                                 unsigned int *));
+static void parse_number PARAMS ((cpp_reader *, cpp_string *, int));
+static int unescaped_terminator_p PARAMS ((cpp_reader *, const uchar *));
 static void parse_string PARAMS ((cpp_reader *, cpp_token *, cppchar_t));
-static void unterminated PARAMS ((cpp_reader *, int));
 static bool trigraph_p PARAMS ((cpp_reader *));
 static unsigned int copy_text_chars PARAMS ((char *, const char *, unsigned int));
-static void save_asm PARAMS ((cpp_reader *, cpp_token *, const U_CHAR *));
-static void save_comment PARAMS ((cpp_reader *, cpp_token *, const U_CHAR *));
+static void save_asm PARAMS ((cpp_reader *, cpp_token *, const uchar *));
+static void save_comment PARAMS ((cpp_reader *, cpp_token *, const uchar *,
+                                 cppchar_t));
+static bool continue_after_nul PARAMS ((cpp_reader *));
 static int name_p PARAMS ((cpp_reader *, const cpp_string *));
 static int maybe_read_ucs PARAMS ((cpp_reader *, const unsigned char **,
-                                  const unsigned char *, unsigned int *));
+                                  const unsigned char *, cppchar_t *));
 static tokenrun *next_tokenrun PARAMS ((tokenrun *));
 
 static unsigned int hex_digit_value PARAMS ((unsigned int));
@@ -109,7 +103,7 @@ cpp_ideq (token, string)
   if (token->type != CPP_NAME)
     return 0;
 
-  return !ustrcmp (NODE_NAME (token->val.node), (const U_CHAR *) string);
+  return !ustrcmp (NODE_NAME (token->val.node), (const uchar *) string);
 }
 
 /* Call when meeting a newline, assumed to be in buffer->cur[-1].
@@ -122,7 +116,7 @@ handle_newline (pfile)
   cpp_buffer *buffer = pfile->buffer;
 
   /* Handle CR-LF and LF-CR.  Most other implementations (e.g. java)
-     only accept CR-LF; maybe we should fall back to that behaviour?  */
+     only accept CR-LF; maybe we should fall back to that behavior?  */
   if (buffer->cur[-1] + buffer->cur[0] == '\r' + '\n')
     buffer->cur++;
 
@@ -136,7 +130,7 @@ handle_newline (pfile)
    the second '?'.
 
    Warn if necessary, and returns true if the sequence forms a
-   trigraph and the trigraph should be honoured.  */
+   trigraph and the trigraph should be honored.  */
 static bool
 trigraph_p (pfile)
      cpp_reader *pfile;
@@ -154,16 +148,17 @@ trigraph_p (pfile)
   if (CPP_OPTION (pfile, warn_trigraphs) && !pfile->state.lexing_comment)
     {
       if (accept)
-       cpp_warning_with_line (pfile, pfile->line, CPP_BUF_COL (buffer) - 1,
-                              "trigraph ??%c converted to %c",
-                              (int) from_char,
-                              (int) _cpp_trigraph_map[from_char]);
+       cpp_error_with_line (pfile, DL_WARNING,
+                            pfile->line, CPP_BUF_COL (buffer) - 1,
+                            "trigraph ??%c converted to %c",
+                            (int) from_char,
+                            (int) _cpp_trigraph_map[from_char]);
       else if (buffer->cur != buffer->last_Wtrigraphs)
        {
          buffer->last_Wtrigraphs = buffer->cur;
-         cpp_warning_with_line (pfile, pfile->line,
-                                CPP_BUF_COL (buffer) - 1,
-                                "trigraph ??%c ignored", (int) from_char);
+         cpp_error_with_line (pfile, DL_WARNING,
+                              pfile->line, CPP_BUF_COL (buffer) - 1,
+                              "trigraph ??%c ignored", (int) from_char);
        }
     }
 
@@ -219,13 +214,15 @@ skip_escaped_newlines (pfile)
 
          if (saved_cur != buffer->cur - 1
              && !pfile->state.lexing_comment)
-           cpp_warning (pfile, "backslash and newline separated by space");
+           cpp_error (pfile, DL_WARNING,
+                      "backslash and newline separated by space");
 
          handle_newline (pfile);
          buffer->backup_to = buffer->cur;
          if (buffer->cur == buffer->rlimit)
            {
-             cpp_pedwarn (pfile, "backslash-newline at end of file");
+             cpp_error (pfile, DL_PEDWARN,
+                        "backslash-newline at end of file");
              next = EOF;
            }
          else
@@ -254,7 +251,7 @@ get_effective_char (pfile)
   if (__builtin_expect (next == '?' || next == '\\', 0))
     next = skip_escaped_newlines (pfile);
 
-   return next;
+  return next;
 }
 
 /* SDCC _asm specific */
@@ -309,7 +306,7 @@ skip_asm_block (pfile)
 
 /* Skip a C-style block comment.  We find the end of the comment by
    seeing if an asterisk is before every '/' we encounter.  Returns
-   non-zero if comment terminated by EOF, zero otherwise.  */
+   nonzero if comment terminated by EOF, zero otherwise.  */
 static int
 skip_block_comment (pfile)
      cpp_reader *pfile;
@@ -339,9 +336,9 @@ skip_block_comment (pfile)
             Don't bother to get it right across escaped newlines.  */
          if (CPP_OPTION (pfile, warn_comments)
              && buffer->cur[0] == '*' && buffer->cur[1] != '/')
-           cpp_warning_with_line (pfile,
-                                  pfile->line, CPP_BUF_COL (buffer),
-                                  "\"/*\" within comment");
+           cpp_error_with_line (pfile, DL_WARNING,
+                                pfile->line, CPP_BUF_COL (buffer),
+                                "\"/*\" within comment");
        }
       else if (is_vspace (c))
        handle_newline (pfile);
@@ -354,7 +351,7 @@ skip_block_comment (pfile)
 }
 
 /* Skip a C++ line comment, leaving buffer->cur pointing to the
-   terminating newline.  Handles escaped newlines.  Returns non-zero
+   terminating newline.  Handles escaped newlines.  Returns nonzero
    if a multiline comment.  */
 static int
 skip_line_comment (pfile)
@@ -363,14 +360,39 @@ skip_line_comment (pfile)
   cpp_buffer *buffer = pfile->buffer;
   unsigned int orig_line = pfile->line;
   cppchar_t c;
+#ifdef MULTIBYTE_CHARS
+  wchar_t wc;
+  int char_len;
+#endif
 
   pfile->state.lexing_comment = 1;
+#ifdef MULTIBYTE_CHARS
+  /* Reset multibyte conversion state.  */
+  (void) local_mbtowc (NULL, NULL, 0);
+#endif
   do
     {
       if (buffer->cur == buffer->rlimit)
        goto at_eof;
 
+#ifdef MULTIBYTE_CHARS
+      char_len = local_mbtowc (&wc, (const char *) buffer->cur,
+                              buffer->rlimit - buffer->cur);
+      if (char_len == -1)
+       {
+         cpp_error (pfile, DL_WARNING,
+                    "ignoring invalid multibyte character");
+         char_len = 1;
+         c = *buffer->cur++;
+       }
+      else
+       {
+         buffer->cur += char_len;
+         c = wc;
+       }
+#else
       c = *buffer->cur++;
+#endif
       if (c == '?' || c == '\\')
        c = skip_escaped_newlines (pfile);
     }
@@ -424,15 +446,15 @@ skip_whitespace (pfile, c)
            return 0;
          if (!warned)
            {
-             cpp_warning (pfile, "null character(s) ignored");
+             cpp_error (pfile, DL_WARNING, "null character(s) ignored");
              warned = 1;
            }
        }
       else if (pfile->state.in_directive && CPP_PEDANTIC (pfile))
-       cpp_pedwarn_with_line (pfile, pfile->line,
-                              CPP_BUF_COL (buffer),
-                              "%s in preprocessing directive",
-                              c == '\f' ? "form feed" : "vertical tab");
+       cpp_error_with_line (pfile, DL_PEDWARN, pfile->line,
+                            CPP_BUF_COL (buffer),
+                            "%s in preprocessing directive",
+                            c == '\f' ? "form feed" : "vertical tab");
 
       c = *buffer->cur++;
     }
@@ -466,13 +488,13 @@ name_p (pfile, string)
    seen:unseen identifiers in normal code; the distribution is
    Poisson-like).  Second most common case is a new identifier, not
    split and no dollar sign.  The other possibilities are rare and
-   have been relegated to parse_identifier_slow.  */
+   have been relegated to parse_slow.  */
 static cpp_hashnode *
 parse_identifier (pfile)
      cpp_reader *pfile;
 {
   cpp_hashnode *result;
-  const U_CHAR *cur;
+  const uchar *cur, *base;
 
   /* Fast-path loop.  Skim over a normal identifier.
      N.B. ISIDNUM does not include $.  */
@@ -482,13 +504,19 @@ parse_identifier (pfile)
 
   /* Check for slow-path cases.  */
   if (*cur == '?' || *cur == '\\' || *cur == '$')
-    result = parse_identifier_slow (pfile, cur);
+    {
+      unsigned int len;
+
+      base = parse_slow (pfile, cur, 0, &len);
+      result = (cpp_hashnode *)
+       ht_lookup (pfile->hash_table, base, len, HT_ALLOCED);
+    }
   else
     {
-      const U_CHAR *base = pfile->buffer->cur - 1;
+      base = pfile->buffer->cur - 1;
+      pfile->buffer->cur = cur;
       result = (cpp_hashnode *)
        ht_lookup (pfile->hash_table, base, cur - base, HT_ALLOC);
-      pfile->buffer->cur = cur;
     }
 
   /* Rarely, identifiers require diagnostics when lexed.
@@ -498,59 +526,78 @@ parse_identifier (pfile)
     {
       /* It is allowed to poison the same identifier twice.  */
       if ((result->flags & NODE_POISONED) && !pfile->state.poisoned_ok)
-       cpp_error (pfile, "attempt to use poisoned \"%s\"",
+       cpp_error (pfile, DL_ERROR, "attempt to use poisoned \"%s\"",
                   NODE_NAME (result));
 
       /* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the
         replacement list of a variadic macro.  */
       if (result == pfile->spec_nodes.n__VA_ARGS__
          && !pfile->state.va_args_ok)
-       cpp_pedwarn (pfile,
+       cpp_error (pfile, DL_PEDWARN,
        "__VA_ARGS__ can only appear in the expansion of a C99 variadic macro");
     }
 
   return result;
 }
 
-/* Slow path.  This handles identifiers which have been split, and
-   identifiers which contain dollar signs.  The part of the identifier
-   from PFILE->buffer->cur-1 to CUR has already been scanned.  */
-static cpp_hashnode *
-parse_identifier_slow (pfile, cur)
+/* Slow path.  This handles numbers and identifiers which have been
+   split, or contain dollar signs.  The part of the token from
+   PFILE->buffer->cur-1 to CUR has already been scanned.  NUMBER_P is
+   1 if it's a number, and 2 if it has a leading period.  Returns a
+   pointer to the token's NUL-terminated spelling in permanent
+   storage, and sets PLEN to its length.  */
+static uchar *
+parse_slow (pfile, cur, number_p, plen)
      cpp_reader *pfile;
-     const U_CHAR *cur;
+     const uchar *cur;
+     int number_p;
+     unsigned int *plen;
 {
   cpp_buffer *buffer = pfile->buffer;
-  const U_CHAR *base = buffer->cur - 1;
+  const uchar *base = buffer->cur - 1;
   struct obstack *stack = &pfile->hash_table->stack;
-  unsigned int c, saw_dollar = 0, len;
+  unsigned int c, prevc, saw_dollar = 0;
+
+  /* Place any leading period.  */
+  if (number_p == 2)
+    obstack_1grow (stack, '.');
 
   /* Copy the part of the token which is known to be okay.  */
   obstack_grow (stack, base, cur - base);
 
   /* Now process the part which isn't.  We are looking at one of
      '$', '\\', or '?' on entry to this loop.  */
+  prevc = cur[-1];
   c = *cur++;
   buffer->cur = cur;
-  do
+  for (;;)
     {
-      while (is_idchar (c))
-        {
-          obstack_1grow (stack, c);
+      /* Potential escaped newline?  */
+      buffer->backup_to = buffer->cur - 1;
+      if (c == '?' || c == '\\')
+       c = skip_escaped_newlines (pfile);
 
-          if (c == '$')
-            saw_dollar++;
+      if (!is_idchar (c))
+       {
+         if (!number_p)
+           break;
+         if (c != '.' && !VALID_SIGN (c, prevc))
+           break;
+       }
 
-          c = *buffer->cur++;
-        }
+      /* Handle normal identifier characters in this loop.  */
+      do
+       {
+         prevc = c;
+         obstack_1grow (stack, c);
 
-      /* Potential escaped newline?  */
-      buffer->backup_to = buffer->cur - 1;
-      if (c != '?' && c != '\\')
-        break;
-      c = skip_escaped_newlines (pfile);
+         if (c == '$')
+           saw_dollar++;
+
+         c = *buffer->cur++;
+       }
+      while (is_idchar (c));
     }
-  while (is_idchar (c));
 
   /* Step back over the unwanted char.  */
   BACKUP ();
@@ -559,94 +606,48 @@ parse_identifier_slow (pfile, cur)
      accepted as an extension.  Don't warn about it in skipped
      conditional blocks.  */
   if (saw_dollar && CPP_PEDANTIC (pfile) && ! pfile->state.skipping)
-    cpp_pedwarn (pfile, "'$' character(s) in identifier");
+    cpp_error (pfile, DL_PEDWARN, "'$' character(s) in identifier or number");
 
-  /* Identifiers are null-terminated.  */
-  len = obstack_object_size (stack);
+  /* Identifiers and numbers are null-terminated.  */
+  *plen = obstack_object_size (stack);
   obstack_1grow (stack, '\0');
-
-  return (cpp_hashnode *)
-    ht_lookup (pfile->hash_table, obstack_finish (stack), len, HT_ALLOCED);
+  return obstack_finish (stack);
 }
 
 /* Parse a number, beginning with character C, skipping embedded
-   backslash-newlines.  LEADING_PERIOD is non-zero if there was a "."
+   backslash-newlines.  LEADING_PERIOD is nonzero if there was a "."
    before C.  Place the result in NUMBER.  */
 static void
-parse_number (pfile, number, c, leading_period)
+parse_number (pfile, number, leading_period)
      cpp_reader *pfile;
      cpp_string *number;
-     cppchar_t c;
      int leading_period;
 {
-  cpp_buffer *buffer = pfile->buffer;
-  unsigned char *dest, *limit;
-
-  dest = BUFF_FRONT (pfile->u_buff);
-  limit = BUFF_LIMIT (pfile->u_buff);
+  const uchar *cur;
 
-  /* Place a leading period.  */
-  if (leading_period)
-    {
-      if (dest == limit)
-       {
-         _cpp_extend_buff (pfile, &pfile->u_buff, 1);
-         dest = BUFF_FRONT (pfile->u_buff);
-         limit = BUFF_LIMIT (pfile->u_buff);
-       }
-      *dest++ = '.';
-    }
+  /* Fast-path loop.  Skim over a normal number.
+     N.B. ISIDNUM does not include $.  */
+  cur = pfile->buffer->cur;
+  while (ISIDNUM (*cur) || *cur == '.' || VALID_SIGN (*cur, cur[-1]))
+    cur++;
 
-  do
+  /* Check for slow-path cases.  */
+  if (*cur == '?' || *cur == '\\' || *cur == '$')
+    number->text = parse_slow (pfile, cur, 1 + leading_period, &number->len);
+  else
     {
-      do
-       {
-         /* Need room for terminating null.  */
-         if ((size_t) (limit - dest) < 2)
-           {
-             size_t len_so_far = dest - BUFF_FRONT (pfile->u_buff);
-             _cpp_extend_buff (pfile, &pfile->u_buff, 2);
-             dest = BUFF_FRONT (pfile->u_buff) + len_so_far;
-             limit = BUFF_LIMIT (pfile->u_buff);
-           }
-         *dest++ = c;
-
-         c = *buffer->cur++;
-       }
-      while (is_numchar (c) || c == '.' || VALID_SIGN (c, dest[-1]));
-
-      /* Potential escaped newline?  */
-      buffer->backup_to = buffer->cur - 1;
-      if (c != '?' && c != '\\')
-       break;
-      c = skip_escaped_newlines (pfile);
-    }
-  while (is_numchar (c) || c == '.' || VALID_SIGN (c, dest[-1]));
-
-  /* Step back over the unwanted char.  */
-  BACKUP ();
+      const uchar *base = pfile->buffer->cur - 1;
+      uchar *dest;
 
-  /* Null-terminate the number.  */
-  *dest = '\0';
+      number->len = cur - base + leading_period;
+      dest = _cpp_unaligned_alloc (pfile, number->len + 1);
+      dest[number->len] = '\0';
+      number->text = dest;
 
-  number->text = BUFF_FRONT (pfile->u_buff);
-  number->len = dest - number->text;
-  BUFF_FRONT (pfile->u_buff) = dest + 1;
-}
-
-/* Subroutine of parse_string.  Emits error for unterminated strings.  */
-static void
-unterminated (pfile, term)
-     cpp_reader *pfile;
-     int term;
-{
-  cpp_error (pfile, "missing terminating %c character", term);
-
-  if (term == '\"' && pfile->mls_line && pfile->mls_line != pfile->line)
-    {
-      cpp_error_with_line (pfile, pfile->mls_line, pfile->mls_col,
-                          "possible start of unterminated string literal");
-      pfile->mls_line = 0;
+      if (leading_period)
+       *dest++ = '.';
+      memcpy (dest, base, cur - base);
+      pfile->buffer->cur = cur;
     }
 }
 
@@ -676,7 +677,6 @@ unescaped_terminator_p (pfile, dest)
    name.  Handles embedded trigraphs and escaped newlines.  The stored
    string is guaranteed NUL-terminated, but it is not guaranteed that
    this is the first NUL since embedded NULs are preserved.
-   Multi-line strings are allowed, but they are deprecated.
 
    When this function returns, buffer->cur points to the next
    character to be processed.  */
@@ -689,11 +689,19 @@ parse_string (pfile, token, terminator)
   cpp_buffer *buffer = pfile->buffer;
   unsigned char *dest, *limit;
   cppchar_t c;
-  bool warned_nulls = false, warned_multi = false;
+  bool warned_nulls = false;
+#ifdef MULTIBYTE_CHARS
+  wchar_t wc;
+  int char_len;
+#endif
 
   dest = BUFF_FRONT (pfile->u_buff);
   limit = BUFF_LIMIT (pfile->u_buff);
 
+#ifdef MULTIBYTE_CHARS
+  /* Reset multibyte conversion state.  */
+  (void) local_mbtowc (NULL, NULL, 0);
+#endif
   for (;;)
     {
       /* We need room for another char, possibly the terminating NUL.  */
@@ -705,8 +713,26 @@ parse_string (pfile, token, terminator)
          limit = BUFF_LIMIT (pfile->u_buff);
        }
 
-      /* Handle trigraphs, escaped newlines etc.  */
+#ifdef MULTIBYTE_CHARS
+      char_len = local_mbtowc (&wc, (const char *) buffer->cur,
+                              buffer->rlimit - buffer->cur);
+      if (char_len == -1)
+       {
+         cpp_error (pfile, DL_WARNING,
+                    "ignoring invalid multibyte character");
+         char_len = 1;
+         c = *buffer->cur++;
+       }
+      else
+       {
+         buffer->cur += char_len;
+         c = wc;
+       }
+#else
       c = *buffer->cur++;
+#endif
+
+      /* Handle trigraphs, escaped newlines etc.  */
       if (c == '?' || c == '\\')
        c = skip_escaped_newlines (pfile);
 
@@ -717,57 +743,37 @@ parse_string (pfile, token, terminator)
        }
       else if (is_vspace (c))
        {
-         /* In assembly language, silently terminate string and
-            character literals at end of line.  This is a kludge
-            around not knowing where comments are.  */
-         if (CPP_OPTION (pfile, lang) == CLK_ASM && terminator != '>')
-           {
-             buffer->cur--;
-             break;
-           }
-
-         /* Character constants and header names may not extend over
-            multiple lines.  In Standard C, neither may strings.
-            Unfortunately, we accept multiline strings as an
-            extension, except in #include family directives.  */
-         if (terminator != '"' || pfile->state.angled_headers)
-           {
-             unterminated (pfile, terminator);
-             buffer->cur--;
-             break;
-           }
-
-         if (!warned_multi)
-           {
-             warned_multi = true;
-             cpp_pedwarn (pfile, "multi-line string literals are deprecated");
-           }
-
-         if (pfile->mls_line == 0)
-           {
-             pfile->mls_line = token->line;
-             pfile->mls_col = token->col;
-           }
-
-         handle_newline (pfile);
-         c = '\n';
+         /* No string literal may extend over multiple lines.  In
+            assembly language, suppress the error except for <>
+            includes.  This is a kludge around not knowing where
+            comments are.  */
+       unterminated:
+         if (CPP_OPTION (pfile, lang) != CLK_ASM || terminator == '>')
+           cpp_error (pfile, DL_ERROR, "missing terminating %c character",
+                      (int) terminator);
+         buffer->cur--;
+         break;
        }
       else if (c == '\0')
        {
          if (buffer->cur - 1 == buffer->rlimit)
-           {
-             unterminated (pfile, terminator);
-             buffer->cur--;
-             break;
-           }
+           goto unterminated;
          if (!warned_nulls)
            {
              warned_nulls = true;
-             cpp_warning (pfile, "null character(s) preserved in literal");
+             cpp_error (pfile, DL_WARNING,
+                        "null character(s) preserved in literal");
            }
        }
-
-      *dest++ = c;
+#ifdef MULTIBYTE_CHARS
+      if (char_len > 1)
+       {
+         for ( ; char_len > 0; --char_len)
+           *dest++ = (*buffer->cur - char_len);
+       }
+      else
+#endif
+       *dest++ = c;
     }
 
   *dest = '\0';
@@ -838,13 +844,14 @@ save_asm (pfile, token, from)
 
 /* The stored comment includes the comment start and any terminator.  */
 static void
-save_comment (pfile, token, from)
+save_comment (pfile, token, from, type)
      cpp_reader *pfile;
      cpp_token *token;
      const unsigned char *from;
+     cppchar_t type;
 {
   unsigned char *buffer;
-  unsigned int len;
+  unsigned int len, clen;
 
   len = pfile->buffer->cur - from + 1; /* + 1 for the initial '/'.  */
 
@@ -852,14 +859,31 @@ save_comment (pfile, token, from)
      line, which we don't want to save in the comment.  */
   if (is_vspace (pfile->buffer->cur[-1]))
     len--;
-  buffer = _cpp_unaligned_alloc (pfile, len);
+
+  /* If we are currently in a directive, then we need to store all
+     C++ comments as C comments internally, and so we need to
+     allocate a little extra space in that case.
+
+     Note that the only time we encounter a directive here is
+     when we are saving comments in a "#define".  */
+  clen = (pfile->state.in_directive && type == '/') ? len + 2 : len;
+
+  buffer = _cpp_unaligned_alloc (pfile, clen);
 
   token->type = CPP_COMMENT;
-  token->val.str.len = len;
+  token->val.str.len = clen;
   token->val.str.text = buffer;
 
   buffer[0] = '/';
   copy_text_chars (buffer + 1, from, len);
+
+  /* Finish conversion to a C comment, if necessary.  */
+  if (pfile->state.in_directive && type == '/')
+    {
+      buffer[1] = '*';
+      buffer[clen - 2] = '*';
+      buffer[clen - 1] = '/';
+    }
 }
 
 /* Allocate COUNT tokens for RUN.  */
@@ -941,7 +965,10 @@ _cpp_lex_token (pfile)
          /* Is this a directive.  If _cpp_handle_directive returns
             false, it is an assembler #.  */
          if (result->type == CPP_HASH
-             && !pfile->state.parsing_args
+             /* 6.10.3 p 11: Directives in a list of macro arguments
+                gives undefined behavior.  This implementation
+                handles the directive as normal.  */
+             && pfile->state.parsing_args != 1
              && _cpp_handle_directive (pfile, result->flags & PREV_WHITE))
            continue;
          if (pfile->cb.line_change && !pfile->state.skipping)
@@ -964,6 +991,57 @@ _cpp_lex_token (pfile)
   return result;
 }
 
+/* A NUL terminates the current buffer.  For ISO preprocessing this is
+   EOF, but for traditional preprocessing it indicates we need a line
+   refill.  Returns TRUE to continue preprocessing a new buffer, FALSE
+   to return a CPP_EOF to the caller.  */
+static bool
+continue_after_nul (pfile)
+     cpp_reader *pfile;
+{
+  cpp_buffer *buffer = pfile->buffer;
+  bool more = false;
+
+  buffer->saved_flags = BOL;
+  if (CPP_OPTION (pfile, traditional))
+    {
+      if (pfile->state.in_directive)
+       return false;
+
+      _cpp_remove_overlay (pfile);
+      more = _cpp_read_logical_line_trad (pfile);
+      _cpp_overlay_buffer (pfile, pfile->out.base,
+                          pfile->out.cur - pfile->out.base);
+      pfile->line = pfile->out.first_line;
+    }
+  else
+    {
+      /* Stop parsing arguments with a CPP_EOF.  When we finally come
+        back here, do the work of popping the buffer.  */
+      if (!pfile->state.parsing_args)
+       {
+         if (buffer->cur != buffer->line_base)
+           {
+             /* Non-empty files should end in a newline.  Don't warn
+                for command line and _Pragma buffers.  */
+             if (!buffer->from_stage3)
+               cpp_error (pfile, DL_PEDWARN, "no newline at end of file");
+             handle_newline (pfile);
+           }
+
+         /* Similarly, finish an in-progress directive with CPP_EOF
+            before popping the buffer.  */
+         if (!pfile->state.in_directive && buffer->prev)
+           {
+             more = !buffer->return_at_eof;
+             _cpp_pop_buffer (pfile);
+           }
+       }
+    }
+
+  return more;
+}
+
 #define IF_NEXT_IS(CHAR, THEN_TYPE, ELSE_TYPE) \
   do {                                         \
     if (get_effective_char (pfile) == CHAR)    \
@@ -1014,30 +1092,10 @@ _cpp_lex_direct (pfile)
       if (skip_whitespace (pfile, c))
        goto skipped_white;
 
-      /* EOF.  */
+      /* End of buffer.  */
       buffer->cur--;
-      buffer->saved_flags = BOL;
-      if (!pfile->state.parsing_args && !pfile->state.in_directive)
-       {
-         if (buffer->cur != buffer->line_base)
-           {
-             /* Non-empty files should end in a newline.  Don't warn
-                for command line and _Pragma buffers.  */
-             if (!buffer->from_stage3)
-               cpp_pedwarn (pfile, "no newline at end of file");
-             handle_newline (pfile);
-           }
-
-         /* Don't pop the last buffer.  */
-         if (buffer->prev)
-           {
-             unsigned char stop = buffer->return_at_eof;
-
-             _cpp_pop_buffer (pfile);
-             if (!stop)
-               goto fresh_line;
-           }
-       }
+      if (continue_after_nul (pfile))
+       goto fresh_line;
       result->type = CPP_EOF;
       break;
 
@@ -1088,24 +1146,24 @@ _cpp_lex_direct (pfile)
     case '0': case '1': case '2': case '3': case '4':
     case '5': case '6': case '7': case '8': case '9':
       result->type = CPP_NUMBER;
-      parse_number (pfile, &result->val.str, c, 0);
+      parse_number (pfile, &result->val.str, 0);
       break;
 
     case 'L':
       /* 'L' may introduce wide characters or strings.  */
-       {
-         const unsigned char *pos = buffer->cur;
+      {
+       const unsigned char *pos = buffer->cur;
 
-         c = get_effective_char (pfile);
-         if (c == '\'' || c == '"')
-           {
-             result->type = (c == '"' ? CPP_WSTRING: CPP_WCHAR);
-             parse_string (pfile, result, c);
-             break;
-           }
-         buffer->cur = pos;
-       }
-       /* Fall through.  */
+       c = get_effective_char (pfile);
+       if (c == '\'' || c == '"')
+         {
+           result->type = (c == '"' ? CPP_WSTRING: CPP_WCHAR);
+           parse_string (pfile, result, c);
+           break;
+         }
+       buffer->cur = pos;
+      }
+      /* Fall through.  */
 
     start_ident:
     case '_':
@@ -1154,7 +1212,7 @@ _cpp_lex_direct (pfile)
       if (c == '*')
        {
          if (skip_block_comment (pfile))
-           cpp_error (pfile, "unterminated comment");
+           cpp_error (pfile, DL_ERROR, "unterminated comment");
        }
       else if (c == '/' && (CPP_OPTION (pfile, cplusplus_comments)
                            || CPP_IN_SYSTEM_HEADER (pfile)))
@@ -1164,15 +1222,15 @@ _cpp_lex_direct (pfile)
          if (CPP_OPTION (pfile, lang) == CLK_GNUC89 && CPP_PEDANTIC (pfile)
              && ! buffer->warned_cplusplus_comments)
            {
-             cpp_pedwarn (pfile,
-                          "C++ style comments are not allowed in ISO C89");
-             cpp_pedwarn (pfile,
-                          "(this will be reported only once per input file)");
+             cpp_error (pfile, DL_PEDWARN,
+                        "C++ style comments are not allowed in ISO C90");
+             cpp_error (pfile, DL_PEDWARN,
+                        "(this will be reported only once per input file)");
              buffer->warned_cplusplus_comments = 1;
            }
 
          if (skip_line_comment (pfile) && CPP_OPTION (pfile, warn_comments))
-           cpp_warning (pfile, "multi-line comment");
+           cpp_error (pfile, DL_WARNING, "multi-line comment");
        }
       else if (c == '=')
        {
@@ -1193,7 +1251,7 @@ _cpp_lex_direct (pfile)
        }
 
       /* Save the comment as a token in its own right.  */
-      save_comment (pfile, result, comment_start);
+      save_comment (pfile, result, comment_start, c);
       break;
 
     case '<':
@@ -1291,7 +1349,7 @@ _cpp_lex_direct (pfile)
       else if (ISDIGIT (c))
        {
          result->type = CPP_NUMBER;
-         parse_number (pfile, &result->val.str, c, 1);
+         parse_number (pfile, &result->val.str, 1);
        }
       else if (c == '*' && CPP_OPTION (pfile, cplusplus))
        result->type = CPP_DOT_STAR;
@@ -1394,7 +1452,7 @@ _cpp_lex_direct (pfile)
     case '}': result->type = CPP_CLOSE_BRACE; break;
     case ';': result->type = CPP_SEMICOLON; break;
 
-      /* @ is a punctuator in Objective C.  */
+      /* @ is a punctuator in Objective-C.  */
     case '@': result->type = CPP_ATSIGN; break;
 
     case '$':
@@ -1487,7 +1545,8 @@ cpp_spell_token (pfile, token, buffer)
          case CPP_WCHAR:       left = '\''; right = '\''; tag = 'L';  break;
          case CPP_HEADER_NAME: left = '<';  right = '>';  tag = '\0'; break;
          default:
-           cpp_ice (pfile, "unknown string token %s\n", TOKEN_NAME (token));
+           cpp_error (pfile, DL_ICE, "unknown string token %s\n",
+                      TOKEN_NAME (token));
            return buffer;
          }
        if (tag) *buffer++ = tag;
@@ -1499,7 +1558,7 @@ cpp_spell_token (pfile, token, buffer)
       break;
 
     case SPELL_NONE:
-      cpp_ice (pfile, "unspellable token %s", TOKEN_NAME (token));
+      cpp_error (pfile, DL_ICE, "unspellable token %s", TOKEN_NAME (token));
       break;
     }
 
@@ -1592,7 +1651,8 @@ cpp_output_token (token, fp)
        if (tag) putc (tag, fp);
        if (left) putc (left, fp);
        fwrite (token->val.str.text, 1, token->val.str.len, fp);
-       if (right) putc (right, fp);      }
+       if (right) putc (right, fp);
+      }
       break;
 
     case SPELL_NONE:
@@ -1744,7 +1804,7 @@ maybe_read_ucs (pfile, pstr, limit, pc)
      cpp_reader *pfile;
      const unsigned char **pstr;
      const unsigned char *limit;
-     unsigned int *pc;
+     cppchar_t *pc;
 {
   const unsigned char *p = *pstr;
   unsigned int code = 0;
@@ -1755,13 +1815,14 @@ maybe_read_ucs (pfile, pstr, limit, pc)
     return 1;
 
   if (CPP_WTRADITIONAL (pfile))
-    cpp_warning (pfile, "the meaning of '\\%c' varies with -traditional", c);
+    cpp_error (pfile, DL_WARNING,
+              "the meaning of '\\%c' is different in traditional C", c);
 
   length = (c == 'u' ? 4: 8);
 
   if ((size_t) (limit - p) < length)
     {
-      cpp_error (pfile, "incomplete universal-character-name");
+      cpp_error (pfile, DL_ERROR, "incomplete universal-character-name");
       /* Skip to the end to avoid more diagnostics.  */
       p = limit;
     }
@@ -1774,7 +1835,7 @@ maybe_read_ucs (pfile, pstr, limit, pc)
            code = (code << 4) + hex_digit_value (c);
          else
            {
-             cpp_error (pfile,
+             cpp_error (pfile, DL_ERROR,
                         "non-hex digit '%c' in universal-character-name", c);
              /* We shouldn't skip in case there are multibyte chars.  */
              break;
@@ -1783,7 +1844,7 @@ maybe_read_ucs (pfile, pstr, limit, pc)
     }
 
 #ifdef TARGET_EBCDIC
-  cpp_error (pfile, "universal-character-name on EBCDIC target");
+  cpp_error (pfile, DL_ERROR, "universal-character-name on EBCDIC target");
   code = 0x3f;  /* EBCDIC invalid character */
 #else
  /* True extended characters are OK.  */
@@ -1797,7 +1858,7 @@ maybe_read_ucs (pfile, pstr, limit, pc)
     ;
   /* Don't give another error if one occurred above.  */
   else if (length == 0)
-    cpp_error (pfile, "universal-character-name out of range");
+    cpp_error (pfile, DL_ERROR, "universal-character-name out of range");
 #endif
 
   *pstr = p;
@@ -1805,25 +1866,33 @@ maybe_read_ucs (pfile, pstr, limit, pc)
   return 0;
 }
 
-/* Interpret an escape sequence, and return its value.  PSTR points to
-   the input pointer, which is just after the backslash.  LIMIT is how
-   much text we have.  MASK is a bitmask for the precision for the
-   destination type (char or wchar_t).  TRADITIONAL, if true, does not
-   interpret escapes that did not exist in traditional C.
-
-   Handles all relevant diagnostics.  */
-unsigned int
-cpp_parse_escape (pfile, pstr, limit, mask, traditional)
+/* Returns the value of an escape sequence, truncated to the correct
+   target precision.  PSTR points to the input pointer, which is just
+   after the backslash.  LIMIT is how much text we have.  WIDE is true
+   if the escape sequence is part of a wide character constant or
+   string literal.  Handles all relevant diagnostics.  */
+cppchar_t
+cpp_parse_escape (pfile, pstr, limit, wide)
      cpp_reader *pfile;
      const unsigned char **pstr;
      const unsigned char *limit;
-     unsigned HOST_WIDE_INT mask;
-     int traditional;
+     int wide;
 {
   int unknown = 0;
   const unsigned char *str = *pstr;
-  unsigned int c = *str++;
+  cppchar_t c, mask;
+  unsigned int width;
+
+  if (wide)
+    width = CPP_OPTION (pfile, wchar_precision);
+  else
+    width = CPP_OPTION (pfile, char_precision);
+  if (width < BITS_PER_CPPCHAR_T)
+    mask = ((cppchar_t) 1 << width) - 1;
+  else
+    mask = ~0;
 
+  c = *str++;
   switch (c)
     {
     case '\\': case '\'': case '"': case '?': break;
@@ -1842,14 +1911,15 @@ cpp_parse_escape (pfile, pstr, limit, mask, traditional)
 
     case 'a':
       if (CPP_WTRADITIONAL (pfile))
-       cpp_warning (pfile, "the meaning of '\\a' varies with -traditional");
-      if (!traditional)
-       c = TARGET_BELL;
+       cpp_error (pfile, DL_WARNING,
+                  "the meaning of '\\a' is different in traditional C");
+      c = TARGET_BELL;
       break;
 
     case 'e': case 'E':
       if (CPP_PEDANTIC (pfile))
-       cpp_pedwarn (pfile, "non-ISO-standard escape sequence, '\\%c'", c);
+       cpp_error (pfile, DL_PEDWARN,
+                  "non-ISO-standard escape sequence, '\\%c'", (int) c);
       c = TARGET_ESC;
       break;
 
@@ -1859,41 +1929,43 @@ cpp_parse_escape (pfile, pstr, limit, mask, traditional)
 
     case 'x':
       if (CPP_WTRADITIONAL (pfile))
-       cpp_warning (pfile, "the meaning of '\\x' varies with -traditional");
+       cpp_error (pfile, DL_WARNING,
+                  "the meaning of '\\x' is different in traditional C");
 
-      if (!traditional)
-       {
-         unsigned int i = 0, overflow = 0;
-         int digits_found = 0;
+      {
+       cppchar_t i = 0, overflow = 0;
+       int digits_found = 0;
 
-         while (str < limit)
-           {
-             c = *str;
-             if (! ISXDIGIT (c))
-               break;
-             str++;
-             overflow |= i ^ (i << 4 >> 4);
-             i = (i << 4) + hex_digit_value (c);
-             digits_found = 1;
-           }
+       while (str < limit)
+         {
+           c = *str;
+           if (! ISXDIGIT (c))
+             break;
+           str++;
+           overflow |= i ^ (i << 4 >> 4);
+           i = (i << 4) + hex_digit_value (c);
+           digits_found = 1;
+         }
 
-         if (!digits_found)
-           cpp_error (pfile, "\\x used with no following hex digits");
+       if (!digits_found)
+         cpp_error (pfile, DL_ERROR,
+                      "\\x used with no following hex digits");
 
-         if (overflow | (i != (i & mask)))
-           {
-             cpp_pedwarn (pfile, "hex escape sequence out of range");
-             i &= mask;
-           }
-         c = i;
-       }
+       if (overflow | (i != (i & mask)))
+         {
+           cpp_error (pfile, DL_PEDWARN,
+                      "hex escape sequence out of range");
+           i &= mask;
+         }
+       c = i;
+      }
       break;
 
     case '0':  case '1':  case '2':  case '3':
     case '4':  case '5':  case '6':  case '7':
       {
-       unsigned int i = c - '0';
-       int count = 0;
+       size_t count = 0;
+       cppchar_t i = c - '0';
 
        while (str < limit && ++count < 3)
          {
@@ -1906,7 +1978,8 @@ cpp_parse_escape (pfile, pstr, limit, mask, traditional)
 
        if (i != (i & mask))
          {
-           cpp_pedwarn (pfile, "octal escape sequence out of range");
+           cpp_error (pfile, DL_PEDWARN,
+                      "octal escape sequence out of range");
            i &= mask;
          }
        c = i;
@@ -1921,45 +1994,40 @@ cpp_parse_escape (pfile, pstr, limit, mask, traditional)
   if (unknown)
     {
       if (ISGRAPH (c))
-       cpp_pedwarn (pfile, "unknown escape sequence '\\%c'", c);
+       cpp_error (pfile, DL_PEDWARN,
+                  "unknown escape sequence '\\%c'", (int) c);
       else
-       cpp_pedwarn (pfile, "unknown escape sequence: '\\%03o'", c);
+       cpp_error (pfile, DL_PEDWARN,
+                  "unknown escape sequence: '\\%03o'", (int) c);
     }
 
   if (c > mask)
-    cpp_pedwarn (pfile, "escape sequence out of range for character");
+    {
+      cpp_error (pfile, DL_PEDWARN, "escape sequence out of range for its type");
+      c &= mask;
+    }
 
   *pstr = str;
   return c;
 }
 
-#ifndef MAX_CHAR_TYPE_SIZE
-#define MAX_CHAR_TYPE_SIZE CHAR_TYPE_SIZE
-#endif
-
-#ifndef MAX_WCHAR_TYPE_SIZE
-#define MAX_WCHAR_TYPE_SIZE WCHAR_TYPE_SIZE
-#endif
-
 /* Interpret a (possibly wide) character constant in TOKEN.
-   WARN_MULTI warns about multi-character charconsts, if not
-   TRADITIONAL.  TRADITIONAL also indicates not to interpret escapes
-   that did not exist in traditional C.  PCHARS_SEEN points to a
-   variable that is filled in with the number of characters seen.  */
-HOST_WIDE_INT
-cpp_interpret_charconst (pfile, token, warn_multi, traditional, pchars_seen)
+   WARN_MULTI warns about multi-character charconsts.  PCHARS_SEEN
+   points to a variable that is filled in with the number of
+   characters seen, and UNSIGNEDP to a variable that indicates whether
+   the result has signed type.  */
+cppchar_t
+cpp_interpret_charconst (pfile, token, pchars_seen, unsignedp)
      cpp_reader *pfile;
      const cpp_token *token;
-     int warn_multi;
-     int traditional;
      unsigned int *pchars_seen;
+     int *unsignedp;
 {
   const unsigned char *str = token->val.str.text;
   const unsigned char *limit = str + token->val.str.len;
   unsigned int chars_seen = 0;
-  unsigned int width, max_chars, c;
-  unsigned HOST_WIDE_INT mask;
-  HOST_WIDE_INT result = 0;
+  size_t width, max_chars;
+  cppchar_t c, mask, result = 0;
   bool unsigned_p;
 
 #ifdef MULTIBYTE_CHARS
@@ -1969,20 +2037,21 @@ cpp_interpret_charconst (pfile, token, warn_multi, traditional, pchars_seen)
   /* Width in bits.  */
   if (token->type == CPP_CHAR)
     {
-      width = MAX_CHAR_TYPE_SIZE;
-      unsigned_p = CPP_OPTION (pfile, signed_char) == 0;
+      width = CPP_OPTION (pfile, char_precision);
+      max_chars = CPP_OPTION (pfile, int_precision) / width;
+      unsigned_p = CPP_OPTION (pfile, unsigned_char);
     }
   else
     {
-      width = MAX_WCHAR_TYPE_SIZE;
-      unsigned_p = WCHAR_UNSIGNED;
+      width = CPP_OPTION (pfile, wchar_precision);
+      max_chars = 1;
+      unsigned_p = CPP_OPTION (pfile, unsigned_wchar);
     }
 
-  if (width < HOST_BITS_PER_WIDE_INT)
-    mask = ((unsigned HOST_WIDE_INT) 1 << width) - 1;
+  if (width < BITS_PER_CPPCHAR_T)
+    mask = ((cppchar_t) 1 << width) - 1;
   else
     mask = ~0;
-  max_chars = HOST_BITS_PER_WIDE_INT / width;
 
   while (str < limit)
     {
@@ -1993,7 +2062,8 @@ cpp_interpret_charconst (pfile, token, warn_multi, traditional, pchars_seen)
       char_len = local_mbtowc (&wc, str, limit - str);
       if (char_len == -1)
        {
-         cpp_warning (pfile, "ignoring invalid multibyte character");
+         cpp_error (pfile, DL_WARNING,
+                    "ignoring invalid multibyte character");
          c = *str++;
        }
       else
@@ -2006,46 +2076,56 @@ cpp_interpret_charconst (pfile, token, warn_multi, traditional, pchars_seen)
 #endif
 
       if (c == '\\')
-       c = cpp_parse_escape (pfile, &str, limit, mask, traditional);
+       c = cpp_parse_escape (pfile, &str, limit, token->type == CPP_WCHAR);
 
 #ifdef MAP_CHARACTER
       if (ISPRINT (c))
        c = MAP_CHARACTER (c);
 #endif
 
-      /* Merge character into result; ignore excess chars.  */
-      if (++chars_seen <= max_chars)
-       {
-         if (width < HOST_BITS_PER_WIDE_INT)
-           result = (result << width) | (c & mask);
-         else
-           result = c;
-       }
+      chars_seen++;
+
+      /* Truncate the character, scale the result and merge the two.  */
+      c &= mask;
+      if (width < BITS_PER_CPPCHAR_T)
+       result = (result << width) | c;
+      else
+       result = c;
     }
 
   if (chars_seen == 0)
-    cpp_error (pfile, "empty character constant");
-  else if (chars_seen > max_chars)
+    cpp_error (pfile, DL_ERROR, "empty character constant");
+  else if (chars_seen > 1)
     {
-      chars_seen = max_chars;
-      cpp_warning (pfile, "character constant too long");
+      /* Multichar charconsts are of type int and therefore signed.  */
+      unsigned_p = 0;
+
+      if (chars_seen > max_chars)
+       {
+         chars_seen = max_chars;
+         cpp_error (pfile, DL_WARNING,
+                    "character constant too long for its type");
+       }
+      else if (CPP_OPTION (pfile, warn_multichar))
+       cpp_error (pfile, DL_WARNING, "multi-character character constant");
     }
-  else if (chars_seen > 1 && !traditional && warn_multi)
-    cpp_warning (pfile, "multi-character character constant");
 
-  /* If relevant type is signed, sign-extend the constant.  */
-  if (chars_seen)
+  /* Sign-extend or truncate the constant to cppchar_t.  The value is
+     in WIDTH bits, but for multi-char charconsts it's value is the
+     full target type's width.  */
+  if (chars_seen > 1)
+    width *= max_chars;
+  if (width < BITS_PER_CPPCHAR_T)
     {
-      unsigned int nbits = chars_seen * width;
-
-      mask = (unsigned HOST_WIDE_INT) ~0 >> (HOST_BITS_PER_WIDE_INT - nbits);
-      if (unsigned_p || ((result >> (nbits - 1)) & 1) == 0)
+      mask = ((cppchar_t) 1 << width) - 1;
+      if (unsigned_p || !(result & (1 << (width - 1))))
        result &= mask;
       else
        result |= ~mask;
     }
 
   *pchars_seen = chars_seen;
+  *unsignedp = unsigned_p;
   return result;
 }
 
@@ -2064,19 +2144,6 @@ cpp_interpret_charconst (pfile, token, warn_multi, traditional, pchars_seen)
   #error BUFF_SIZE_UPPER_BOUND must be at least as large as MIN_BUFF_SIZE!
 #endif
 
-struct dummy
-{
-  char c;
-  union
-  {
-    double d;
-    int *p;
-  } u;
-};
-
-#define DEFAULT_ALIGNMENT (offsetof (struct dummy, u))
-#define CPP_ALIGN(size, align) (((size) + ((align) - 1)) & ~((align) - 1))
-
 /* Create a new allocation buffer.  Place the control block at the end
    of the buffer, so that buffer overflows will cause immediate chaos.  */
 static _cpp_buff *
@@ -2088,7 +2155,7 @@ new_buff (len)
 
   if (len < MIN_BUFF_SIZE)
     len = MIN_BUFF_SIZE;
-  len = CPP_ALIGN (len, DEFAULT_ALIGNMENT);
+  len = CPP_ALIGN (len);
 
   base = xmalloc (len + sizeof (_cpp_buff));
   result = (_cpp_buff *) (base + len);
index 286c22f634fe62395f8c15c22a627bbf79909ba3..567147e4dc4da6a5e55de83c19754857a9b63f06 100644 (file)
@@ -1,6 +1,6 @@
 /* CPP Library. (Directive handling.)
    Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
    Contributed by Per Bothner, 1994-95.
    Based on CCCP program by Paul Rubin, June 1986
    Adapted to ANSI C, Richard Stallman, Jan 1987
@@ -70,11 +70,14 @@ struct pragma_entry
    conditional; IF_COND an opening conditional.  INCL means to treat
    "..." and <...> as q-char and h-char sequences respectively.  IN_I
    means this directive should be handled even if -fpreprocessed is in
-   effect (these are the directives with callback hooks).  */
+   effect (these are the directives with callback hooks).
+
+   EXPAND is set on directives that are always macro-expanded.  */
 #define COND           (1 << 0)
 #define IF_COND                (1 << 1)
 #define INCL           (1 << 2)
 #define IN_I           (1 << 3)
+#define EXPAND         (1 << 4)
 
 /* Defines one #-directive, including how to handle it.  */
 typedef void (*directive_handler) PARAMS ((cpp_reader *));
@@ -82,7 +85,7 @@ typedef struct directive directive;
 struct directive
 {
   directive_handler handler;   /* Function to handle directive.  */
-  const U_CHAR *name;          /* Name of directive.  */
+  const uchar *name;           /* Name of directive.  */
   unsigned short length;       /* Length of name.  */
   unsigned char origin;                /* Origin of directive.  */
   unsigned char flags;         /* Flags describing this directive.  */
@@ -93,6 +96,7 @@ struct directive
 static void skip_rest_of_line  PARAMS ((cpp_reader *));
 static void check_eol          PARAMS ((cpp_reader *));
 static void start_directive    PARAMS ((cpp_reader *));
+static void prepare_directive_trad PARAMS ((cpp_reader *));
 static void end_directive      PARAMS ((cpp_reader *, int));
 static void directive_diagnostics
        PARAMS ((cpp_reader *, const directive *, int));
@@ -103,11 +107,11 @@ static const cpp_token *parse_include PARAMS ((cpp_reader *));
 static void push_conditional   PARAMS ((cpp_reader *, int, int,
                                         const cpp_hashnode *));
 static unsigned int read_flag  PARAMS ((cpp_reader *, unsigned int));
-static U_CHAR *dequote_string  PARAMS ((cpp_reader *, const U_CHAR *,
+static uchar *dequote_string   PARAMS ((cpp_reader *, const uchar *,
                                         unsigned int));
-static int  strtoul_for_line   PARAMS ((const U_CHAR *, unsigned int,
+static int  strtoul_for_line   PARAMS ((const uchar *, unsigned int,
                                         unsigned long *));
-static void do_diagnostic      PARAMS ((cpp_reader *, enum error_type, int));
+static void do_diagnostic      PARAMS ((cpp_reader *, int, int));
 static cpp_hashnode *lex_macro_node    PARAMS ((cpp_reader *));
 static void do_include_common  PARAMS ((cpp_reader *, enum include_type));
 static struct pragma_entry *lookup_pragma_entry
@@ -133,8 +137,6 @@ static struct answer ** find_answer PARAMS ((cpp_hashnode *,
                                             const struct answer *));
 static void handle_assertion   PARAMS ((cpp_reader *, const char *, int));
 
-extern cpp_output_string       PARAMS ((const char *s));
-
 /* This is the table of directive handlers.  It is ordered by
    frequency of occurrence; the numbers at the end are directive
    counts from all the source code I have lying around (egcs and libc
@@ -146,31 +148,24 @@ extern cpp_output_string  PARAMS ((const char *s));
 
 #define DIRECTIVE_TABLE                                                        \
 D(define,      T_DEFINE = 0,   KANDR,     IN_I)           /* 270554 */ \
-D(include,     T_INCLUDE,      KANDR,     INCL)           /*  52262 */ \
+D(include,     T_INCLUDE,      KANDR,     INCL | EXPAND)  /*  52262 */ \
 D(endif,       T_ENDIF,        KANDR,     COND)           /*  45855 */ \
 D(ifdef,       T_IFDEF,        KANDR,     COND | IF_COND) /*  22000 */ \
-D(if,          T_IF,           KANDR,     COND | IF_COND) /*  18162 */ \
+D(if,          T_IF,           KANDR, COND | IF_COND | EXPAND) /*  18162 */ \
 D(else,                T_ELSE,         KANDR,     COND)           /*   9863 */ \
 D(ifndef,      T_IFNDEF,       KANDR,     COND | IF_COND) /*   9675 */ \
 D(undef,       T_UNDEF,        KANDR,     IN_I)           /*   4837 */ \
-D(line,                T_LINE,         KANDR,     0)              /*   2465 */ \
-D(elif,                T_ELIF,         STDC89,    COND)           /*    610 */ \
+D(line,                T_LINE,         KANDR,     EXPAND)         /*   2465 */ \
+D(elif,                T_ELIF,         STDC89,    COND | EXPAND)  /*    610 */ \
 D(error,       T_ERROR,        STDC89,    0)              /*    475 */ \
 D(pragma,      T_PRAGMA,       STDC89,    IN_I)           /*    195 */ \
 D(warning,     T_WARNING,      EXTENSION, 0)              /*     22 */ \
-D(include_next,        T_INCLUDE_NEXT, EXTENSION, INCL)           /*     19 */ \
+D(include_next,        T_INCLUDE_NEXT, EXTENSION, INCL | EXPAND)  /*     19 */ \
 D(ident,       T_IDENT,        EXTENSION, IN_I)           /*     11 */ \
-D(import,      T_IMPORT,       EXTENSION, INCL)           /* 0 ObjC */ \
+D(import,      T_IMPORT,       EXTENSION, INCL | EXPAND)  /* 0 ObjC */ \
 D(assert,      T_ASSERT,       EXTENSION, 0)              /* 0 SVR4 */ \
 D(unassert,    T_UNASSERT,     EXTENSION, 0)              /* 0 SVR4 */ \
-SCCS_ENTRY                                                /* 0 SVR4? */
-
-/* #sccs is not always recognized.  */
-#ifdef SCCS_DIRECTIVE
-# define SCCS_ENTRY D(sccs, T_SCCS, EXTENSION, 0)
-#else
-# define SCCS_ENTRY /* nothing */
-#endif
+D(sccs,                T_SCCS,         EXTENSION, 0)              /* 0 SVR4? */
 
 /* Use the table to generate a series of prototypes, an enum for the
    directive names, and an array of directive handlers.  */
@@ -190,7 +185,7 @@ enum
 
 /* Don't invoke CONCAT2 with any whitespace or K&R cc will fail.  */
 #define D(name, t, origin, flags) \
-{ CONCAT2(do_,name), (const U_CHAR *) STRINGX(name), \
+{ CONCAT2(do_,name), (const uchar *) STRINGX(name), \
   sizeof STRINGX(name) - 1, origin, flags },
 static const directive dtable[] =
 {
@@ -230,8 +225,8 @@ check_eol (pfile)
      cpp_reader *pfile;
 {
   if (! SEEN_EOL () && _cpp_lex_token (pfile)->type != CPP_EOF)
-    cpp_pedwarn (pfile, "extra tokens at end of #%s directive",
-                pfile->directive->name);
+    cpp_error (pfile, DL_PEDWARN, "extra tokens at end of #%s directive",
+              pfile->directive->name);
 }
 
 /* Called when entering a directive, _Pragma or command-line directive.  */
@@ -253,8 +248,16 @@ end_directive (pfile, skip_line)
      cpp_reader *pfile;
      int skip_line;
 {
+  if (CPP_OPTION (pfile, traditional))
+    {
+      /* Revert change of prepare_directive_trad.  */
+      pfile->state.prevent_expansion--;
+
+      if (pfile->directive != &dtable[T_DEFINE])
+       _cpp_remove_overlay (pfile);
+    }
   /* We don't skip for an assembler #.  */
-  if (skip_line)
+  else if (skip_line)
     {
       skip_rest_of_line (pfile);
       if (!pfile->keep_tokens)
@@ -267,11 +270,40 @@ end_directive (pfile, skip_line)
   /* Restore state.  */
   pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);
   pfile->state.in_directive = 0;
+  pfile->state.in_expression = 0;
   pfile->state.angled_headers = 0;
   pfile->directive = 0;
 }
 
-/* Output diagnostics for a directive DIR.  INDENTED is non-zero if
+/* Prepare to handle the directive in pfile->directive.  */
+static void
+prepare_directive_trad (pfile)
+     cpp_reader *pfile;
+{
+  if (pfile->directive != &dtable[T_DEFINE])
+    {
+      bool no_expand = (pfile->directive
+                       && ! (pfile->directive->flags & EXPAND));
+      bool was_skipping = pfile->state.skipping;
+
+      pfile->state.skipping = false;
+      pfile->state.in_expression = (pfile->directive == &dtable[T_IF]
+                                   || pfile->directive == &dtable[T_ELIF]);
+      if (no_expand)
+       pfile->state.prevent_expansion++;
+      _cpp_read_logical_line_trad (pfile);
+      if (no_expand)
+       pfile->state.prevent_expansion--;
+      pfile->state.skipping = was_skipping;
+      _cpp_overlay_buffer (pfile, pfile->out.base,
+                          pfile->out.cur - pfile->out.base);
+    }
+
+  /* Stop ISO C from expanding anything.  */
+  pfile->state.prevent_expansion++;
+}
+
+/* Output diagnostics for a directive DIR.  INDENTED is nonzero if
    the '#' was indented.  */
 static void
 directive_diagnostics (pfile, dir, indented)
@@ -283,7 +315,7 @@ directive_diagnostics (pfile, dir, indented)
   if (CPP_PEDANTIC (pfile)
       && ! pfile->state.skipping
       && dir->origin == EXTENSION)
-    cpp_pedwarn (pfile, "#%s is a GCC extension", dir->name);
+    cpp_error (pfile, DL_PEDWARN, "#%s is a GCC extension", dir->name);
 
   /* Traditionally, a directive is ignored unless its # is in
      column 1.  Therefore in code intended to work with K+R
@@ -294,22 +326,23 @@ directive_diagnostics (pfile, dir, indented)
   if (CPP_WTRADITIONAL (pfile))
     {
       if (dir == &dtable[T_ELIF])
-       cpp_warning (pfile, "suggest not using #elif in traditional C");
+       cpp_error (pfile, DL_WARNING,
+                  "suggest not using #elif in traditional C");
       else if (indented && dir->origin == KANDR)
-       cpp_warning (pfile,
-                    "traditional C ignores #%s with the # indented",
-                    dir->name);
+       cpp_error (pfile, DL_WARNING,
+                  "traditional C ignores #%s with the # indented",
+                  dir->name);
       else if (!indented && dir->origin != KANDR)
-       cpp_warning (pfile,
-                    "suggest hiding #%s from traditional C with an indented #",
-                    dir->name);
+       cpp_error (pfile, DL_WARNING,
+                  "suggest hiding #%s from traditional C with an indented #",
+                  dir->name);
     }
 }
 
-/* Check if we have a known directive.  INDENTED is non-zero if the
+/* Check if we have a known directive.  INDENTED is nonzero if the
    '#' of the directive was indented.  This function is in this file
    to save unnecessarily exporting dtable etc. to cpplex.c.  Returns
-   non-zero if the line of tokens has been handled, zero if we should
+   nonzero if the line of tokens has been handled, zero if we should
    continue processing the line.  */
 int
 _cpp_handle_directive (pfile, indented)
@@ -318,8 +351,17 @@ _cpp_handle_directive (pfile, indented)
 {
   const directive *dir = 0;
   const cpp_token *dname;
+  bool was_parsing_args = pfile->state.parsing_args;
   int skip = 1;
 
+  if (was_parsing_args)
+    {
+      if (CPP_OPTION (pfile, pedantic))
+       cpp_error (pfile, DL_PEDWARN,
+            "embedding a directive within macro arguments is not portable");
+      pfile->state.parsing_args = 0;
+      pfile->state.prevent_expansion = 0;
+    }
   start_directive (pfile);
   dname = _cpp_lex_token (pfile);
 
@@ -328,14 +370,15 @@ _cpp_handle_directive (pfile, indented)
       if (dname->val.node->directive_index)
        dir = &dtable[dname->val.node->directive_index - 1];
     }
-  /* We do not recognise the # followed by a number extension in
+  /* We do not recognize the # followed by a number extension in
      assembler code.  */
   else if (dname->type == CPP_NUMBER && CPP_OPTION (pfile, lang) != CLK_ASM)
     {
       dir = &linemarker_dir;
       if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, preprocessed)
          && ! pfile->state.skipping)
-       cpp_pedwarn (pfile, "style of line directive is a GCC extension");
+       cpp_error (pfile, DL_PEDWARN,
+                  "style of line directive is a GCC extension");
     }
 
   if (dir)
@@ -367,6 +410,7 @@ _cpp_handle_directive (pfile, indented)
             skipping or not, we should lex angle-bracketed headers
             correctly, and maybe output some diagnostics.  */
          pfile->state.angled_headers = dir->flags & INCL;
+         pfile->state.directive_wants_padding = dir->flags & INCL;
          if (! CPP_OPTION (pfile, preprocessed))
            directive_diagnostics (pfile, dir, indented);
          if (pfile->state.skipping && !(dir->flags & COND))
@@ -384,19 +428,27 @@ _cpp_handle_directive (pfile, indented)
       if (CPP_OPTION (pfile, lang) == CLK_ASM)
        skip = 0;
       else if (!pfile->state.skipping)
-       cpp_error (pfile, "invalid preprocessing directive #%s",
+       cpp_error (pfile, DL_ERROR, "invalid preprocessing directive #%s",
                   cpp_token_as_text (pfile, dname));
     }
 
+  pfile->directive = dir;
+  if (CPP_OPTION (pfile, traditional))
+    prepare_directive_trad (pfile);
+
   if (dir)
-    {
-      pfile->directive = dir;
-      (*pfile->directive->handler) (pfile);
-    }
+    (*pfile->directive->handler) (pfile);
   else if (skip == 0)
     _cpp_backup_tokens (pfile, 1);
 
   end_directive (pfile, skip);
+  if (was_parsing_args)
+    {
+      /* Restore state when within macro args.  */
+      pfile->state.parsing_args = 2;
+      pfile->state.prevent_expansion = 1;
+      pfile->buffer->saved_flags |= PREV_WHITE;
+    }
   return skip;
 }
 
@@ -409,7 +461,7 @@ run_directive (pfile, dir_no, buf, count)
      const char *buf;
      size_t count;
 {
-  cpp_push_buffer (pfile, (const U_CHAR *) buf, count,
+  cpp_push_buffer (pfile, (const uchar *) buf, count,
                   /* from_stage3 */ true, 1);
   /* Disgusting hack.  */
   if (dir_no == T_PRAGMA)
@@ -418,6 +470,8 @@ run_directive (pfile, dir_no, buf, count)
   /* We don't want a leading # to be interpreted as a directive.  */
   pfile->buffer->saved_flags = 0;
   pfile->directive = &dtable[dir_no];
+  if (CPP_OPTION (pfile, traditional))
+    prepare_directive_trad (pfile);
   (void) (*pfile->directive->handler) (pfile);
   end_directive (pfile, 1);
   if (dir_no == T_PRAGMA)
@@ -431,7 +485,6 @@ static cpp_hashnode *
 lex_macro_node (pfile)
      cpp_reader *pfile;
 {
-  cpp_hashnode *node;
   const cpp_token *token = _cpp_lex_token (pfile);
 
   /* The token immediately after #define must be an identifier.  That
@@ -441,33 +494,27 @@ lex_macro_node (pfile)
      Finally, the identifier may not have been poisoned.  (In that case
      the lexer has issued the error message for us.)  */
 
-  if (token->type != CPP_NAME)
+  if (token->type == CPP_NAME)
     {
-      if (token->type == CPP_EOF)
-       cpp_error (pfile, "no macro name given in #%s directive",
-                  pfile->directive->name);
-      else if (token->flags & NAMED_OP)
-       cpp_error (pfile,
-          "\"%s\" cannot be used as a macro name as it is an operator in C++",
-                  NODE_NAME (token->val.node));
-      else
-       cpp_error (pfile, "macro names must be identifiers");
-
-      return 0;
-    }
+      cpp_hashnode *node = token->val.node;
 
-  node = token->val.node;
-  if (node->flags & NODE_POISONED)
-    return 0;
-
-  if (node == pfile->spec_nodes.n_defined)
-    {
-      cpp_error (pfile, "\"%s\" cannot be used as a macro name",
-                NODE_NAME (node));
-      return 0;
+      if (node == pfile->spec_nodes.n_defined)
+       cpp_error (pfile, DL_ERROR,
+                  "\"defined\" cannot be used as a macro name");
+      else if (! (node->flags & NODE_POISONED))
+       return node;
     }
+  else if (token->flags & NAMED_OP)
+    cpp_error (pfile, DL_ERROR,
+       "\"%s\" cannot be used as a macro name as it is an operator in C++",
+              NODE_NAME (token->val.node));
+  else if (token->type == CPP_EOF)
+    cpp_error (pfile, DL_ERROR, "no macro name given in #%s directive",
+              pfile->directive->name);
+  else
+    cpp_error (pfile, DL_ERROR, "macro names must be identifiers");
 
-  return node;
+  return NULL;
 }
 
 /* Process a #define directive.  Most work is done in cppmacro.c.  */
@@ -479,6 +526,11 @@ do_define (pfile)
 
   if (node)
     {
+      /* If we have been requested to expand comments into macros,
+        then re-enable saving of comments.  */
+      pfile->state.save_comments =
+       ! CPP_OPTION (pfile, discard_comments_in_macro_exp);
+
       if (_cpp_create_definition (pfile, node))
        if (pfile->cb.define)
          (*pfile->cb.define) (pfile, pfile->directive_line, node);
@@ -500,7 +552,10 @@ do_undef (pfile)
        (*pfile->cb.undef) (pfile, pfile->directive_line, node);
 
       if (node->flags & NODE_WARN)
-       cpp_warning (pfile, "undefining \"%s\"", NODE_NAME (node));
+       cpp_error (pfile, DL_WARNING, "undefining \"%s\"", NODE_NAME (node));
+
+      if (CPP_OPTION (pfile, warn_unused_macros))
+       _cpp_warn_if_unused_macro (pfile, node, NULL);
 
       _cpp_free_definition (node);
     }
@@ -524,7 +579,7 @@ glue_header_name (pfile)
   buffer = (unsigned char *) xmalloc (capacity);
   for (;;)
     {
-      token = cpp_get_token (pfile);
+      token = get_token_no_padding (pfile);
 
       if (token->type == CPP_GREATER || token->type == CPP_EOF)
        break;
@@ -543,7 +598,7 @@ glue_header_name (pfile)
     }
 
   if (token->type == CPP_EOF)
-    cpp_error (pfile, "missing terminating > character");
+    cpp_error (pfile, DL_ERROR, "missing terminating > character");
   else
     {
       unsigned char *token_mem = _cpp_unaligned_alloc (pfile, total_len + 1);
@@ -576,12 +631,13 @@ parse_include (pfile)
     dir = pfile->directive->name;
 
   /* Allow macro expansion.  */
-  header = cpp_get_token (pfile);
+  header = get_token_no_padding (pfile);
   if (header->type != CPP_STRING && header->type != CPP_HEADER_NAME)
     {
       if (header->type != CPP_LESS)
        {
-         cpp_error (pfile, "#%s expects \"FILENAME\" or <FILENAME>", dir);
+         cpp_error (pfile, DL_ERROR,
+                    "#%s expects \"FILENAME\" or <FILENAME>", dir);
          return NULL;
        }
 
@@ -592,7 +648,7 @@ parse_include (pfile)
 
   if (header->val.str.len == 0)
     {
-      cpp_error (pfile, "empty file name in #%s", dir);
+      cpp_error (pfile, DL_ERROR, "empty file name in #%s", dir);
       return NULL;
     }
 
@@ -611,13 +667,13 @@ do_include_common (pfile, type)
      use the normal search logic.  */
   if (type == IT_INCLUDE_NEXT && ! pfile->buffer->prev)
     {
-      cpp_warning (pfile, "#include_next in primary source file");
+      cpp_error (pfile, DL_WARNING, "#include_next in primary source file");
       type = IT_INCLUDE;
     }
   else if (type == IT_IMPORT && CPP_OPTION (pfile, warn_import))
     {
       CPP_OPTION (pfile, warn_import) = 0;
-      cpp_warning (pfile,
+      cpp_error (pfile, DL_WARNING,
           "#import is obsolete, use an #ifndef wrapper in the header file");
     }
 
@@ -626,7 +682,7 @@ do_include_common (pfile, type)
     {
       /* Prevent #include recursion.  */
       if (pfile->line_maps.depth >= CPP_STACK_MAX)
-       cpp_fatal (pfile, "#include nested too deeply");
+       cpp_error (pfile, DL_ERROR, "#include nested too deeply");
       else
        {
          check_eol (pfile);
@@ -635,7 +691,6 @@ do_include_common (pfile, type)
          if (pfile->cb.include)
            (*pfile->cb.include) (pfile, pfile->directive_line,
                                  pfile->directive->name, header);
-
          _cpp_execute_include (pfile, header, type);
        }
     }
@@ -684,7 +739,7 @@ read_flag (pfile, last)
     }
 
   if (token->type != CPP_EOF)
-    cpp_error (pfile, "invalid flag \"%s\" in line directive",
+    cpp_error (pfile, DL_ERROR, "invalid flag \"%s\" in line directive",
               cpp_token_as_text (pfile, token));
   return 0;
 }
@@ -692,24 +747,16 @@ read_flag (pfile, last)
 /* Subroutine of do_line and do_linemarker.  Returns a version of STR
    which has a NUL terminator and all escape sequences converted to
    their equivalents.  Temporary, hopefully.  */
-static U_CHAR *
+static uchar *
 dequote_string (pfile, str, len)
      cpp_reader *pfile;
-     const U_CHAR *str;
+     const uchar *str;
      unsigned int len;
 {
-  U_CHAR *result = _cpp_unaligned_alloc (pfile, len + 1);
-  U_CHAR *dst = result;
-  const U_CHAR *limit = str + len;
-  unsigned int c;
-  unsigned HOST_WIDE_INT mask;
-
-  /* We need the mask to match the host's 'unsigned char', not the
-     target's.  */
-  if (CHAR_BIT < HOST_BITS_PER_WIDE_INT)
-    mask = ((unsigned HOST_WIDE_INT) 1 << CHAR_BIT) - 1;
-  else
-    mask = ~(unsigned HOST_WIDE_INT)0;
+  uchar *result = _cpp_unaligned_alloc (pfile, len + 1);
+  uchar *dst = result;
+  const uchar *limit = str + len;
+  cppchar_t c;
 
   while (str < limit)
     {
@@ -717,7 +764,7 @@ dequote_string (pfile, str, len)
       if (c != '\\')
        *dst++ = c;
       else
-       *dst++ = cpp_parse_escape (pfile, (const U_CHAR **)&str, limit, mask, 0);
+       *dst++ = cpp_parse_escape (pfile, &str, limit, 0);
     }
   *dst++ = '\0';
   return result;
@@ -728,12 +775,12 @@ dequote_string (pfile, str, len)
    number was well-formed, 1 if not.  Temporary, hopefully.  */
 static int
 strtoul_for_line (str, len, nump)
-     const U_CHAR *str;
+     const uchar *str;
      unsigned int len;
      unsigned long *nump;
 {
   unsigned long reg = 0;
-  U_CHAR c;
+  uchar c;
   while (len--)
     {
       c = *str++;
@@ -766,13 +813,14 @@ do_line (pfile)
       || strtoul_for_line (token->val.str.text, token->val.str.len,
                           &new_lineno))
     {
-      cpp_error (pfile, "\"%s\" after #line is not a positive integer",
+      cpp_error (pfile, DL_ERROR,
+                "\"%s\" after #line is not a positive integer",
                 cpp_token_as_text (pfile, token));
       return;
     }
 
   if (CPP_PEDANTIC (pfile) && (new_lineno == 0 || new_lineno > cap))
-    cpp_pedwarn (pfile, "line number out of range");
+    cpp_error (pfile, DL_PEDWARN, "line number out of range");
 
   token = cpp_get_token (pfile);
   if (token->type == CPP_STRING)
@@ -783,7 +831,7 @@ do_line (pfile)
     }
   else if (token->type != CPP_EOF)
     {
-      cpp_error (pfile, "\"%s\" is not a valid filename",
+      cpp_error (pfile, DL_ERROR, "\"%s\" is not a valid filename",
                 cpp_token_as_text (pfile, token));
       return;
     }
@@ -818,7 +866,7 @@ do_linemarker (pfile)
       || strtoul_for_line (token->val.str.text, token->val.str.len,
                           &new_lineno))
     {
-      cpp_error (pfile, "\"%s\" after # is not a positive integer",
+      cpp_error (pfile, DL_ERROR, "\"%s\" after # is not a positive integer",
                 cpp_token_as_text (pfile, token));
       return;
     }
@@ -854,7 +902,7 @@ do_linemarker (pfile)
     }
   else if (token->type != CPP_EOF)
     {
-      cpp_error (pfile, "\"%s\" is not a valid filename",
+      cpp_error (pfile, DL_ERROR, "\"%s\" is not a valid filename",
                 cpp_token_as_text (pfile, token));
       return;
     }
@@ -887,10 +935,12 @@ _cpp_do_file_change (pfile, reason, to_file, file_line, sysp)
 static void
 do_diagnostic (pfile, code, print_dir)
      cpp_reader *pfile;
-     enum error_type code;
+     int code;
      int print_dir;
 {
-  if (_cpp_begin_message (pfile, code, 0, 0))
+  if (_cpp_begin_message (pfile, code,
+                         pfile->cur_token[-1].line,
+                         pfile->cur_token[-1].col))
     {
       if (print_dir)
        fprintf (stderr, "#%s ", pfile->directive->name);
@@ -904,7 +954,7 @@ static void
 do_error (pfile)
      cpp_reader *pfile;
 {
-  do_diagnostic (pfile, ERROR, 1);
+  do_diagnostic (pfile, DL_ERROR, 1);
 }
 
 static void
@@ -912,7 +962,7 @@ do_warning (pfile)
      cpp_reader *pfile;
 {
   /* We want #warning diagnostics to be emitted in system headers too.  */
-  do_diagnostic (pfile, WARNING_SYSHDR, 1);
+  do_diagnostic (pfile, DL_WARNING_SYSHDR, 1);
 }
 
 /* Report program identification.  */
@@ -923,7 +973,7 @@ do_ident (pfile)
   const cpp_token *str = cpp_get_token (pfile);
 
   if (str->type != CPP_STRING)
-    cpp_error (pfile, "invalid #ident directive");
+    cpp_error (pfile, DL_ERROR, "invalid #ident directive");
   else if (pfile->cb.ident)
     (*pfile->cb.ident) (pfile, pfile->directive_line, &str->val.str);
 
@@ -1010,13 +1060,14 @@ cpp_register_pragma (pfile, space, name, handler)
     {
       if (entry->is_nspace)
        clash:
-       cpp_ice (pfile,
+       cpp_error (pfile, DL_ICE,
                 "registering \"%s\" as both a pragma and a pragma namespace",
                 NODE_NAME (node));
       else if (space)
-       cpp_ice (pfile, "#pragma %s %s is already registered", space, name);
+       cpp_error (pfile, DL_ICE, "#pragma %s %s is already registered",
+                  space, name);
       else
-       cpp_ice (pfile, "#pragma %s is already registered", name);
+       cpp_error (pfile, DL_ICE, "#pragma %s is already registered", name);
     }
   else
     insert_pragma_entry (pfile, chain, node, handler);
@@ -1028,7 +1079,6 @@ _cpp_init_internal_pragmas (pfile)
      cpp_reader *pfile;
 {
   /* Pragmas in the global namespace.  */
-  cpp_register_pragma (pfile, 0, "poison", do_pragma_poison);
   cpp_register_pragma (pfile, 0, "once", do_pragma_once);
 
   /* New GCC-specific pragmas should be put in the GCC namespace.  */
@@ -1052,7 +1102,7 @@ do_pragma (pfile)
      cpp_reader *pfile;
 {
   const struct pragma_entry *p = NULL;
-  const cpp_token *token;
+  const cpp_token *token, *pragma_token = pfile->cur_token;
   unsigned int count = 1;
 
   pfile->state.prevent_expansion++;
@@ -1072,16 +1122,15 @@ do_pragma (pfile)
        }
     }
 
-  /* FIXME.  This is an awful kludge to get the front ends to update
-     their notion of line number for diagnostic purposes.  The line
-     number should be passed to the handler and they should do it
-     themselves.  Stand-alone CPP must ignore us, otherwise it will
-     prefix the directive with spaces, hence the 1.  Ugh.  */
-  if (pfile->cb.line_change)
-    (*pfile->cb.line_change)(pfile, token, 1);
-
   if (p)
-    (*p->u.handler) (pfile);
+    {
+      /* Since the handler below doesn't get the line number, that it
+        might need for diagnostics, make sure it has the right
+        numbers in place.  */
+      if (pfile->cb.line_change)
+       (*pfile->cb.line_change) (pfile, pragma_token, false);
+      (*p->u.handler) (pfile);
+    }
   else if (pfile->cb.def_pragma)
     {
       _cpp_backup_tokens (pfile, count);
@@ -1096,18 +1145,18 @@ static void
 do_pragma_once (pfile)
      cpp_reader *pfile;
 {
-  cpp_warning (pfile, "#pragma once is obsolete");
+  cpp_error (pfile, DL_WARNING, "#pragma once is obsolete");
 
   if (pfile->buffer->prev == NULL)
-    cpp_warning (pfile, "#pragma once in main file");
+    cpp_error (pfile, DL_WARNING, "#pragma once in main file");
   else
     _cpp_never_reread (pfile->buffer->inc);
 
   check_eol (pfile);
 }
 
-/* Handle #pragma poison, to poison one or more identifiers so that
-   the lexer produces a hard error for each subsequent usage.  */
+/* Handle #pragma GCC poison, to poison one or more identifiers so
+   that the lexer produces a hard error for each subsequent usage.  */
 static void
 do_pragma_poison (pfile)
      cpp_reader *pfile;
@@ -1123,7 +1172,7 @@ do_pragma_poison (pfile)
        break;
       if (tok->type != CPP_NAME)
        {
-         cpp_error (pfile, "invalid #pragma GCC poison directive");
+         cpp_error (pfile, DL_ERROR, "invalid #pragma GCC poison directive");
          break;
        }
 
@@ -1132,7 +1181,8 @@ do_pragma_poison (pfile)
        continue;
 
       if (hp->type == NT_MACRO)
-       cpp_warning (pfile, "poisoning existing macro \"%s\"", NODE_NAME (hp));
+       cpp_error (pfile, DL_WARNING, "poisoning existing macro \"%s\"",
+                  NODE_NAME (hp));
       _cpp_free_definition (hp);
       hp->flags |= NODE_POISONED | NODE_DIAGNOSTIC;
     }
@@ -1155,7 +1205,8 @@ do_pragma_sdcc_hash (pfile)
     }
     else
     {
-       cpp_error (pfile, "invalid #pragma sdcc_hash directive, need '+' or '-'");
+       cpp_error (pfile, DL_ERROR,
+                  "invalid #pragma sdcc_hash directive, need '+' or '-'");
     }
 }
 
@@ -1177,7 +1228,8 @@ do_pragma_preproc_asm (pfile)
     }
   else
     {
-      cpp_error (pfile, "invalid #pragma preproc_asm directive, need '+' or '-'");
+      cpp_error (pfile, DL_ERROR,
+                "invalid #pragma preproc_asm directive, need '+' or '-'");
     }
 }
 
@@ -1194,7 +1246,8 @@ do_pragma_system_header (pfile)
   cpp_buffer *buffer = pfile->buffer;
 
   if (buffer->prev == 0)
-    cpp_warning (pfile, "#pragma system_header ignored outside include file");
+    cpp_error (pfile, DL_WARNING,
+              "#pragma system_header ignored outside include file");
   else
     {
       check_eol (pfile);
@@ -1219,16 +1272,16 @@ do_pragma_dependency (pfile)
 
   ordering = _cpp_compare_file_date (pfile, header);
   if (ordering < 0)
-    cpp_warning (pfile, "cannot find source %s",
-                cpp_token_as_text (pfile, header));
+    cpp_error (pfile, DL_WARNING, "cannot find source %s",
+              cpp_token_as_text (pfile, header));
   else if (ordering > 0)
     {
-      cpp_warning (pfile, "current file is older than %s",
-                  cpp_token_as_text (pfile, header));
+      cpp_error (pfile, DL_WARNING, "current file is older than %s",
+                cpp_token_as_text (pfile, header));
       if (cpp_get_token (pfile)->type != CPP_EOF)
        {
          _cpp_backup_tokens (pfile, 1);
-         do_diagnostic (pfile, WARNING, 0);
+         do_diagnostic (pfile, DL_WARNING, 0);
        }
     }
 }
@@ -1331,6 +1384,7 @@ destringize_and_run (pfile, in)
     pfile->context = saved_context;
     pfile->cur_token = saved_cur_token;
     pfile->cur_run = saved_cur_run;
+    pfile->line--;
   }
 
   /* See above comment.  For the moment, we'd like
@@ -1339,11 +1393,11 @@ destringize_and_run (pfile, in)
 
      to be output as
 
-             token1
-             # 7 "file.c"
-             #pragma foo
-             # 7 "file.c"
-                            token2
+               token1
+               # 7 "file.c"
+               #pragma foo
+               # 7 "file.c"
+                              token2
 
       Getting the line markers is a little tricky.  */
   if (pfile->cb.line_change)
@@ -1363,23 +1417,22 @@ _cpp_do__Pragma (pfile)
 
       unsigned char *buffer = destringize (&string->val.str, &len);
       buffer[len] = 0;
-      cpp_output_string ("\n#pragma ");
-      cpp_output_string (buffer);
-      cpp_output_string ("\n");
+      fputs ("\n#pragma ", pfile->print.outf);
+      fputs (buffer, pfile->print.outf);
+      putc ('\n', pfile->print.outf);
       free ((PTR) buffer);
     }
   else
-    cpp_error (pfile, "_Pragma takes a parenthesized string literal");
+    cpp_error (pfile, DL_ERROR,
+              "_Pragma takes a parenthesized string literal");
 }
 
-/* Just ignore #sccs, on systems where we define it at all.  */
-#ifdef SCCS_DIRECTIVE
+/* Just ignore #sccs on all systems.  */
 static void
 do_sccs (pfile)
      cpp_reader *pfile ATTRIBUTE_UNUSED;
 {
 }
-#endif
 
 /* Handle #ifdef.  */
 static void
@@ -1393,10 +1446,11 @@ do_ifdef (pfile)
       const cpp_hashnode *node = lex_macro_node (pfile);
 
       if (node)
-       skip = node->type != NT_MACRO;
-
-      if (node)
-       check_eol (pfile);
+       {
+         skip = node->type != NT_MACRO;
+         _cpp_mark_macro_used (node);
+         check_eol (pfile);
+       }
     }
 
   push_conditional (pfile, skip, T_IFDEF, 0);
@@ -1413,11 +1467,13 @@ do_ifndef (pfile)
   if (! pfile->state.skipping)
     {
       node = lex_macro_node (pfile);
-      if (node)
-       skip = node->type == NT_MACRO;
 
       if (node)
-       check_eol (pfile);
+       {
+         skip = node->type == NT_MACRO;
+         _cpp_mark_macro_used (node);
+         check_eol (pfile);
+       }
     }
 
   push_conditional (pfile, skip, T_IFNDEF, node);
@@ -1435,7 +1491,7 @@ do_if (pfile)
   int skip = 1;
 
   if (! pfile->state.skipping)
-    skip = _cpp_parse_expr (pfile) == 0;
+    skip = _cpp_parse_expr (pfile) == false;
 
   push_conditional (pfile, skip, T_IF, pfile->mi_ind_cmacro);
 }
@@ -1451,13 +1507,13 @@ do_else (pfile)
   struct if_stack *ifs = buffer->if_stack;
 
   if (ifs == NULL)
-    cpp_error (pfile, "#else without #if");
+    cpp_error (pfile, DL_ERROR, "#else without #if");
   else
     {
       if (ifs->type == T_ELSE)
        {
-         cpp_error (pfile, "#else after #else");
-         cpp_error_with_line (pfile, ifs->line, 0,
+         cpp_error (pfile, DL_ERROR, "#else after #else");
+         cpp_error_with_line (pfile, DL_ERROR, ifs->line, 0,
                               "the conditional began here");
        }
       ifs->type = T_ELSE;
@@ -1470,7 +1526,7 @@ do_else (pfile)
       ifs->mi_cmacro = 0;
 
       /* Only check EOL if was not originally skipping.  */
-      if (!ifs->was_skipping)
+      if (!ifs->was_skipping && CPP_OPTION (pfile, warn_endif_labels))
        check_eol (pfile);
     }
 }
@@ -1485,13 +1541,13 @@ do_elif (pfile)
   struct if_stack *ifs = buffer->if_stack;
 
   if (ifs == NULL)
-    cpp_error (pfile, "#elif without #if");
+    cpp_error (pfile, DL_ERROR, "#elif without #if");
   else
     {
       if (ifs->type == T_ELSE)
        {
-         cpp_error (pfile, "#elif after #else");
-         cpp_error_with_line (pfile, ifs->line, 0,
+         cpp_error (pfile, DL_ERROR, "#elif after #else");
+         cpp_error_with_line (pfile, DL_ERROR, ifs->line, 0,
                               "the conditional began here");
        }
       ifs->type = T_ELIF;
@@ -1521,11 +1577,11 @@ do_endif (pfile)
   struct if_stack *ifs = buffer->if_stack;
 
   if (ifs == NULL)
-    cpp_error (pfile, "#endif without #if");
+    cpp_error (pfile, DL_ERROR, "#endif without #if");
   else
     {
       /* Only check EOL if was not originally skipping.  */
-      if (!ifs->was_skipping)
+      if (!ifs->was_skipping && CPP_OPTION (pfile, warn_endif_labels))
        check_eol (pfile);
 
       /* If potential control macro, we go back outside again.  */
@@ -1604,7 +1660,7 @@ parse_answer (pfile, answerp, type)
       if (type == T_UNASSERT && paren->type == CPP_EOF)
        return 0;
 
-      cpp_error (pfile, "missing '(' after predicate");
+      cpp_error (pfile, DL_ERROR, "missing '(' after predicate");
       return 1;
     }
 
@@ -1619,7 +1675,7 @@ parse_answer (pfile, answerp, type)
 
       if (token->type == CPP_EOF)
        {
-         cpp_error (pfile, "missing ')' to complete answer");
+         cpp_error (pfile, DL_ERROR, "missing ')' to complete answer");
          return 1;
        }
 
@@ -1639,7 +1695,7 @@ parse_answer (pfile, answerp, type)
 
   if (acount == 0)
     {
-      cpp_error (pfile, "predicate's answer is empty");
+      cpp_error (pfile, DL_ERROR, "predicate's answer is empty");
       return 1;
     }
 
@@ -1669,9 +1725,9 @@ parse_assertion (pfile, answerp, type)
   *answerp = 0;
   predicate = cpp_get_token (pfile);
   if (predicate->type == CPP_EOF)
-    cpp_error (pfile, "assertion without predicate");
+    cpp_error (pfile, DL_ERROR, "assertion without predicate");
   else if (predicate->type != CPP_NAME)
-    cpp_error (pfile, "predicate must be an identifier");
+    cpp_error (pfile, DL_ERROR, "predicate must be an identifier");
   else if (parse_answer (pfile, answerp, type) == 0)
     {
       unsigned int len = NODE_LEN (predicate->val.node);
@@ -1716,20 +1772,27 @@ find_answer (node, candidate)
 }
 
 /* Test an assertion within a preprocessor conditional.  Returns
-   non-zero on failure, zero on success.  On success, the result of
-   the test is written into VALUE.  */
+   nonzero on failure, zero on success.  On success, the result of
+   the test is written into VALUE, otherwise the value 0.  */
 int
 _cpp_test_assertion (pfile, value)
      cpp_reader *pfile;
-     int *value;
+     unsigned int *value;
 {
   struct answer *answer;
   cpp_hashnode *node;
 
   node = parse_assertion (pfile, &answer, T_IF);
+
+  /* For recovery, an erroneous assertion expression is handled as a
+     failing assertion.  */
+  *value = 0;
+
   if (node)
     *value = (node->type == NT_ASSERTION &&
              (answer == 0 || *find_answer (node, answer) != 0));
+  else if (pfile->cur_token[-1].type == CPP_EOF)
+    _cpp_backup_tokens (pfile, 1);
 
   /* We don't commit the memory for the answer - it's temporary only.  */
   return node == 0;
@@ -1753,7 +1816,8 @@ do_assert (pfile)
        {
          if (*find_answer (node, new_answer))
            {
-             cpp_warning (pfile, "\"%s\" re-asserted", NODE_NAME (node) + 1);
+             cpp_error (pfile, DL_WARNING, "\"%s\" re-asserted",
+                        NODE_NAME (node) + 1);
              return;
            }
          new_answer->next = node->value.answers;
@@ -1946,7 +2010,7 @@ cpp_set_callbacks (pfile, cb)
 cpp_buffer *
 cpp_push_buffer (pfile, buffer, len, from_stage3, return_at_eof)
      cpp_reader *pfile;
-     const U_CHAR *buffer;
+     const uchar *buffer;
      size_t len;
      int from_stage3;
      int return_at_eof;
@@ -1958,7 +2022,7 @@ cpp_push_buffer (pfile, buffer, len, from_stage3, return_at_eof)
 
   new->line_base = new->buf = new->cur = buffer;
   new->rlimit = buffer + len;
-  new->from_stage3 = from_stage3;
+  new->from_stage3 = from_stage3 || CPP_OPTION (pfile, traditional);
   new->prev = pfile->buffer;
   new->return_at_eof = return_at_eof;
   new->saved_flags = BOL;
@@ -1968,37 +2032,50 @@ cpp_push_buffer (pfile, buffer, len, from_stage3, return_at_eof)
   return new;
 }
 
-/* If called from do_line, pops a single buffer.  Otherwise pops all
-   buffers until a real file is reached.  Generates appropriate
-   call-backs.  */
+/* Pops a single buffer, with a file change call-back if appropriate.
+   Then pushes the next -include file, if any remain.  */
 void
 _cpp_pop_buffer (pfile)
      cpp_reader *pfile;
 {
   cpp_buffer *buffer = pfile->buffer;
+  struct include_file *inc = buffer->inc;
   struct if_stack *ifs;
-  bool pushed = false;
 
   /* Walk back up the conditional stack till we reach its level at
      entry to this file, issuing error messages.  */
   for (ifs = buffer->if_stack; ifs; ifs = ifs->next)
-    cpp_error_with_line (pfile, ifs->line, 0,
+    cpp_error_with_line (pfile, DL_ERROR, ifs->line, 0,
                         "unterminated #%s", dtable[ifs->type].name);
 
   /* In case of a missing #endif.  */
   pfile->state.skipping = 0;
 
-  /* Update the reader's buffer before _cpp_do_file_change.  */
+  /* _cpp_do_file_change expects pfile->buffer to be the new one.  */
   pfile->buffer = buffer->prev;
 
-  if (buffer->inc)
-    pushed = _cpp_pop_file_buffer (pfile, buffer->inc);
+  /* Free the buffer object now; we may want to push a new buffer
+     in _cpp_push_next_include_file.  */
+  obstack_free (&pfile->buffer_ob, buffer);
+
+  if (inc)
+    {
+      _cpp_pop_file_buffer (pfile, inc);
+
+      /* Don't generate a callback for popping the main file.  */
+      if (pfile->buffer)
+       {
+         _cpp_do_file_change (pfile, LC_LEAVE, 0, 0, 0);
 
-  if (!pushed)
-    obstack_free (&pfile->buffer_ob, buffer);
+         /* If this is the main file, there may be some -include
+            files left to push.  */
+         if (!pfile->buffer->prev)
+           _cpp_maybe_push_include_file (pfile);
+       }
+    }
 }
 
-/* Enter all recognised directives in the hash table.  */
+/* Enter all recognized directives in the hash table.  */
 void
 _cpp_init_directives (pfile)
      cpp_reader *pfile;
index 807f00f21f3ce8b7dd7b8ea43c3d256209dfa275..8b788128362aa578b23fb7cb29b5826de6d40c60 100644 (file)
@@ -46,9 +46,9 @@ typedef struct cpp_callbacks cpp_callbacks;
 struct answer;
 struct file_name_map_list;
 
-/* The first two groups, apart from '=', can appear in preprocessor
-   expressions.  This allows a lookup table to be implemented in
-   _cpp_parse_expr.
+/* The first three groups, apart from '=', can appear in preprocessor
+   expressions (+= and -= are used to indicate unary + and - resp.).
+   This allows a lookup table to be implemented in _cpp_parse_expr.
 
    The first group, to CPP_LAST_EQ, can be immediately followed by an
    '='.  The lexer needs operators ending in '=', like ">>=", to be in
@@ -58,6 +58,7 @@ struct file_name_map_list;
 #define CPP_LAST_EQ CPP_MAX
 #define CPP_FIRST_DIGRAPH CPP_HASH
 #define CPP_LAST_PUNCTUATOR CPP_DOT_STAR
+#define CPP_LAST_CPP_OP CPP_LESS_EQ
 
 #define TTYPE_TABLE                            \
   OP(CPP_EQ = 0,       "=")                    \
@@ -85,13 +86,16 @@ struct file_name_map_list;
   OP(CPP_COMMA,                ",")    /* grouping */  \
   OP(CPP_OPEN_PAREN,   "(")                    \
   OP(CPP_CLOSE_PAREN,  ")")                    \
+  TK(CPP_EOF,          SPELL_NONE)             \
   OP(CPP_EQ_EQ,                "==")   /* compare */   \
   OP(CPP_NOT_EQ,       "!=")                   \
   OP(CPP_GREATER_EQ,   ">=")                   \
   OP(CPP_LESS_EQ,      "<=")                   \
 \
+  /* These two are unary + / - in preprocessor expressions.  */ \
   OP(CPP_PLUS_EQ,      "+=")   /* math */      \
   OP(CPP_MINUS_EQ,     "-=")                   \
+\
   OP(CPP_MULT_EQ,      "*=")                   \
   OP(CPP_DIV_EQ,       "/=")                   \
   OP(CPP_MOD_EQ,       "%=")                   \
@@ -119,7 +123,7 @@ struct file_name_map_list;
   OP(CPP_SCOPE,                "::")                   \
   OP(CPP_DEREF_STAR,   "->*")                  \
   OP(CPP_DOT_STAR,     ".*")                   \
-  OP(CPP_ATSIGN,       "@")  /* used in Objective C */ \
+  OP(CPP_ATSIGN,       "@")  /* used in Objective-C */ \
 \
   TK(CPP_NAME,         SPELL_IDENT)    /* word */                      \
   TK(CPP_NUMBER,       SPELL_NUMBER)   /* 34_be+ta  */                 \
@@ -136,11 +140,9 @@ struct file_name_map_list;
                                         /* SPELL_NUMBER happens to DTRT.  */ \
   TK(CPP_MACRO_ARG,    SPELL_NONE)     /* Macro argument.  */          \
   TK(CPP_PADDING,      SPELL_NONE)     /* Whitespace for cpp0.  */     \
-  TK(CPP_EOF,          SPELL_NONE)     /* End of line or file.  */     \
 \
   /* SDCC _asm specific */                                             \
   TK(CPP_ASM,          SPELL_STRING)   /* _asm ... _endasm ; */
-
 #define OP(e, s) e,
 #define TK(e, s) e,
 enum cpp_ttype
@@ -153,7 +155,7 @@ enum cpp_ttype
 
 /* C language kind, used when calling cpp_reader_init.  */
 enum c_lang {CLK_GNUC89 = 0, CLK_GNUC99, CLK_STDC89, CLK_STDC94, CLK_STDC99,
-            CLK_GNUCXX, CLK_CXX98, CLK_OBJC, CLK_OBJCXX, CLK_ASM};
+            CLK_GNUCXX, CLK_CXX98, CLK_ASM};
 
 /* Payload of a NUMBER, STRING, CHAR or COMMENT token.  */
 struct cpp_string
@@ -190,9 +192,23 @@ struct cpp_token
   } val;
 };
 
-/* A standalone character.  We may want to make it unsigned for the
-   same reason we use unsigned char - to avoid signedness issues.  */
-typedef int cppchar_t;
+/* A type wide enough to hold any multibyte source character.
+   cpplib's character constant interpreter requires an unsigned type.
+   Also, a typedef for the signed equivalent.  */
+#ifndef MAX_WCHAR_TYPE_SIZE
+# define MAX_WCHAR_TYPE_SIZE WCHAR_TYPE_SIZE
+#endif
+#if CHAR_BIT * SIZEOF_INT >= MAX_WCHAR_TYPE_SIZE
+# define CPPCHAR_SIGNED_T int
+#else
+# if CHAR_BIT * SIZEOF_LONG >= MAX_WCHAR_TYPE_SIZE || !HAVE_LONG_LONG
+#  define CPPCHAR_SIGNED_T long
+# else
+#  define CPPCHAR_SIGNED_T long long
+# endif
+#endif
+typedef unsigned CPPCHAR_SIGNED_T cppchar_t;
+typedef CPPCHAR_SIGNED_T cppchar_signed_t;
 
 /* Values for opts.dump_macros.
   dump_only means inhibit output of the preprocessed text
@@ -217,10 +233,6 @@ struct cpp_options
   /* Pending options - -D, -U, -A, -I, -ixxx.  */
   struct cpp_pending *pending;
 
-  /* File name which deps are being written to.  This is 0 if deps are
-     being written to stdout.  */
-  const char *deps_file;
-
   /* Search paths for include files.  */
   struct search_path *quote_include;   /* "" */
   struct search_path *bracket_include;  /* <> */
@@ -234,8 +246,9 @@ struct cpp_options
   const char *include_prefix;
   unsigned int include_prefix_len;
 
-  /* -fleading_underscore sets this to "_".  */
-  const char *user_label_prefix;
+  /* Directory prefix for system include directories in the standard search
+     path.  */
+  const char *sysroot;
 
   /* The language we're preprocessing.  */
   enum c_lang lang;
@@ -243,21 +256,23 @@ struct cpp_options
   /* Non-0 means -v, so print the full set of include dirs.  */
   unsigned char verbose;
 
-  /* Nonzero means chars are signed.  */
-  unsigned char signed_char;
-
   /* Nonzero means use extra default include directories for C++.  */
   unsigned char cplusplus;
 
   /* Nonzero means handle cplusplus style comments */
   unsigned char cplusplus_comments;
 
-  /* Nonzero means handle #import, for objective C.  */
+  /* Nonzero means define __OBJC__, treat @ as a special token, and
+     use the OBJC[PLUS]_INCLUDE_PATH environment variable.  */
   unsigned char objc;
 
   /* Nonzero means don't copy comments into the output file.  */
   unsigned char discard_comments;
 
+  /* Nonzero means don't copy comments into the output file during
+     macro expansion.  */
+  unsigned char discard_comments_in_macro_exp;
+
   /* Nonzero means process the ISO trigraph sequences.  */
   unsigned char trigraphs;
 
@@ -267,24 +282,6 @@ struct cpp_options
   /* Nonzero means to allow hexadecimal floats and LL suffixes.  */
   unsigned char extended_numbers;
 
-  /* Nonzero means print the names of included files rather than the
-     preprocessed output.  1 means just the #include "...", 2 means
-     #include <...> as well.  */
-  unsigned char print_deps;
-
-  /* Nonzero if phony targets are created for each header.  */
-  unsigned char deps_phony_targets;
-
-  /* Nonzero if missing .h files in -M output are assumed to be
-     generated files and not errors.  */
-  unsigned char print_deps_missing_files;
-
-  /* If true, fopen (deps_file, "a") else fopen (deps_file, "w").  */
-  unsigned char print_deps_append;
-
-  /* If true, no dependency is generated on the main file.  */
-  unsigned char deps_ignore_main_file;
-
   /* Nonzero means print names of header files (-H).  */
   unsigned char print_include_names;
 
@@ -310,10 +307,23 @@ struct cpp_options
   /* Nonzero means warn if #import is used.  */
   unsigned char warn_import;
 
+  /* Nonzero means warn about multicharacter charconsts.  */
+  unsigned char warn_multichar;
+
   /* Nonzero means warn about various incompatibilities with
      traditional C.  */
   unsigned char warn_traditional;
 
+  /* Nonzero means warn about long long numeric constants.  */
+  unsigned char warn_long_long;
+
+  /* Nonzero means warn about text after an #endif (or #else).  */
+  unsigned char warn_endif_labels;
+
+  /* Nonzero means warn about implicit sign changes owing to integer
+     promotions.  */
+  unsigned char warn_num_sign_change;
+
   /* Nonzero means turn warnings into errors.  */
   unsigned char warnings_are_errors;
 
@@ -338,10 +348,13 @@ struct cpp_options
   /* Nonzero means warn if undefined identifiers are evaluated in an #if.  */
   unsigned char warn_undef;
 
+  /* Nonzero means warn of unused macros from the main file.  */
+  unsigned char warn_unused_macros;
+
   /* Nonzero for the 1999 C Standard, including corrigenda and amendments.  */
   unsigned char c99;
 
-  /* Nonzero if conforming to some particular standard.  */
+  /* Nonzero if we are conforming to a specific C or C++ standard.  */
   unsigned char std;
 
   /* Nonzero means give all the error messages the ANSI standard requires.  */
@@ -369,6 +382,9 @@ struct cpp_options
   /* Nonzero means handle C++ alternate operator names.  */
   unsigned char operator_names;
 
+  /* True for traditional preprocessing.  */
+  unsigned char traditional;
+
   /* True if --help, --version or --target-help appeared in the
      options.  Stand-alone CPP should then bail out after option
      parsing; drivers might want to continue printing help.  */
@@ -386,6 +402,42 @@ struct cpp_options
   /* SDCC specific
      object file exetnsion */
   const char *obj_ext;
+
+  /* Dependency generation.  */
+  struct
+  {
+    /* Style of header dependencies to generate.  */
+    enum {DEPS_NONE = 0, DEPS_USER, DEPS_SYSTEM } style;
+
+    /* Assume missing files are generated files.  */
+    bool missing_files;
+
+    /* Generate phony targets for each dependency apart from the first
+       one.  */
+    bool phony_targets;
+
+    /* If true, fopen (deps_file, "a") else fopen (deps_file, "w").  */
+    unsigned char append;
+
+    /* If true, no dependency is generated on the main file.  */
+    bool ignore_main_file;
+
+    /* File name which deps are being written to.  This is 0 if deps are
+       being written to stdout.  */
+    const char *file;
+  } deps;
+
+  /* Target-specific features set by the front end or client.  */
+
+  /* Precision for target CPP arithmetic, target characters, target
+     ints and target wide characters, respectively.  */
+  size_t precision, char_precision, int_precision, wchar_precision;
+
+  /* True means chars (wide chars) are unsigned.  */
+  bool unsigned_char, unsigned_wchar;
+
+  /* Nonzero means __STDC__ should have the value 0 in system headers.  */
+  unsigned char stdc_0_in_system_headers;
 };
 
 /* Call backs.  */
@@ -400,12 +452,11 @@ struct cpp_callbacks
   void (*undef) PARAMS ((cpp_reader *, unsigned int, cpp_hashnode *));
   void (*ident) PARAMS ((cpp_reader *, unsigned int, const cpp_string *));
   void (*def_pragma) PARAMS ((cpp_reader *, unsigned int));
+  /* Called when the client has a chance to properly register
+     built-ins with cpp_define() and cpp_assert().  */
+  void (*register_builtins) PARAMS ((cpp_reader *));
 };
 
-#define CPP_FATAL_LIMIT 1000
-/* True if we have seen a "fatal" error.  */
-#define CPP_FATAL_ERRORS(PFILE) (cpp_errors (PFILE) >= CPP_FATAL_LIMIT)
-
 /* Name under which this program was invoked.  */
 extern const char *progname;
 
@@ -479,6 +530,18 @@ struct cpp_hashnode
 /* Call this first to get a handle to pass to other functions.  */
 extern cpp_reader *cpp_create_reader PARAMS ((enum c_lang));
 
+/* Call this to change the selected language standard (e.g. because of
+   command line options).  */
+extern void cpp_set_lang PARAMS ((cpp_reader *, enum c_lang));
+
+/* Add a dependency TARGET.  Quote it for "make" if QUOTE.  Can be
+   called any number of times before cpp_read_main_file().  If no
+   targets have been added before cpp_read_main_file(), then the
+   default target is used.  */
+extern void cpp_add_dependency_target PARAMS ((cpp_reader *,
+                                              const char * target,
+                                              int quote));
+
 /* Call these to get pointers to the options and callback structures
    for a given reader.  These pointers are good until you call
    cpp_finish on that reader.  You can either edit the callbacks
@@ -492,14 +555,10 @@ extern void cpp_set_callbacks PARAMS ((cpp_reader *, cpp_callbacks *));
 /* Now call cpp_handle_option[s] to handle 1[or more] switches.  The
    return value is the number of arguments used.  If
    cpp_handle_options returns without using all arguments, it couldn't
-   understand the next switch.  When there are no switches left, you
-   must call cpp_post_options before calling cpp_read_main_file.  Only
-   after cpp_post_options are the contents of the cpp_options
-   structure reliable.  Options processing is not completed until you
-   call cpp_finish_options.  */
+   understand the next switch.  Options processing is not completed
+   until you call cpp_finish_options.  */
 extern int cpp_handle_options PARAMS ((cpp_reader *, int, char **));
-extern int cpp_handle_option PARAMS ((cpp_reader *, int, char **, int));
-extern void cpp_post_options PARAMS ((cpp_reader *));
+extern int cpp_handle_option PARAMS ((cpp_reader *, int, char **));
 
 /* This function reads the file, but does not start preprocessing.  It
    returns the name of the original file; this is the same as the
@@ -508,7 +567,7 @@ extern void cpp_post_options PARAMS ((cpp_reader *));
    too.  If there was an error opening the file, it returns NULL.
 
    If you want cpplib to manage its own hashtable, pass in a NULL
-   pointer.  Otherise you should pass in an initialised hash table
+   pointer.  Otherise you should pass in an initialized hash table
    that cpplib will share; this technique is used by the C front
    ends.  */
 extern const char *cpp_read_main_file PARAMS ((cpp_reader *, const char *,
@@ -521,10 +580,17 @@ extern const char *cpp_read_main_file PARAMS ((cpp_reader *, const char *,
    from cpp_read_main_file, before they get debug callbacks.  */
 extern void cpp_finish_options PARAMS ((cpp_reader *));
 
+/* Call this to finish preprocessing.  If you requested dependency
+   generation, pass an open stream to write the information to,
+   otherwise NULL.  It is your responsibility to close the stream.
+
+   Returns cpp_errors (pfile).  */
+extern int cpp_finish PARAMS ((cpp_reader *, FILE *deps_stream));
+
 /* Call this to release the handle at the end of preprocessing.  Any
    use of the handle after this function returns is invalid.  Returns
    cpp_errors (pfile).  */
-extern int cpp_destroy PARAMS ((cpp_reader *));
+extern void cpp_destroy PARAMS ((cpp_reader *));
 
 /* Error count.  */
 extern unsigned int cpp_errors PARAMS ((cpp_reader *));
@@ -538,7 +604,6 @@ extern void cpp_register_pragma PARAMS ((cpp_reader *,
                                         const char *, const char *,
                                         void (*) PARAMS ((cpp_reader *))));
 
-extern void cpp_finish PARAMS ((cpp_reader *));
 extern int cpp_avoid_paste PARAMS ((cpp_reader *, const cpp_token *,
                                    const cpp_token *));
 extern const cpp_token *cpp_get_token PARAMS ((cpp_reader *));
@@ -547,10 +612,12 @@ extern const unsigned char *cpp_macro_definition PARAMS ((cpp_reader *,
 extern void _cpp_backup_tokens PARAMS ((cpp_reader *, unsigned int));
 
 /* Evaluate a CPP_CHAR or CPP_WCHAR token.  */
-extern HOST_WIDE_INT
+extern cppchar_t
 cpp_interpret_charconst PARAMS ((cpp_reader *, const cpp_token *,
-                                int, int, unsigned int *));
+                                unsigned int *, int *));
 
+/* Used to register builtins during the register_builtins callback.
+   The text is the same as the command line argument.  */
 extern void cpp_define PARAMS ((cpp_reader *, const char *));
 extern void cpp_assert PARAMS ((cpp_reader *, const char *));
 extern void cpp_undef  PARAMS ((cpp_reader *, const char *));
@@ -561,32 +628,95 @@ extern cpp_buffer *cpp_push_buffer PARAMS ((cpp_reader *,
                                            int, int));
 extern int cpp_defined PARAMS ((cpp_reader *, const unsigned char *, int));
 
+/* A preprocessing number.  Code assumes that any unused high bits of
+   the double integer are set to zero.  */
+typedef unsigned HOST_WIDE_INT cpp_num_part;
+typedef struct cpp_num cpp_num;
+struct cpp_num
+{
+  cpp_num_part high;
+  cpp_num_part low;
+  bool unsignedp;  /* True if value should be treated as unsigned.  */
+  bool overflow;   /* True if the most recent calculation overflowed.  */
+};
+
+/* cpplib provides two interfaces for interpretation of preprocessing
+   numbers.
+
+   cpp_classify_number categorizes numeric constants according to
+   their field (integer, floating point, or invalid), radix (decimal,
+   octal, hexadecimal), and type suffixes.  */
+
+#define CPP_N_CATEGORY  0x000F
+#define CPP_N_INVALID  0x0000
+#define CPP_N_INTEGER  0x0001
+#define CPP_N_FLOATING 0x0002
+
+#define CPP_N_WIDTH    0x00F0
+#define CPP_N_SMALL    0x0010  /* int, float.  */
+#define CPP_N_MEDIUM   0x0020  /* long, double.  */
+#define CPP_N_LARGE    0x0040  /* long long, long double.  */
+
+#define CPP_N_RADIX    0x0F00
+#define CPP_N_DECIMAL  0x0100
+#define CPP_N_HEX      0x0200
+#define CPP_N_OCTAL    0x0400
+
+#define CPP_N_UNSIGNED 0x1000  /* Properties.  */
+#define CPP_N_IMAGINARY        0x2000
+
+/* Classify a CPP_NUMBER token.  The return value is a combination of
+   the flags from the above sets.  */
+extern unsigned cpp_classify_number PARAMS ((cpp_reader *, const cpp_token *));
+
+/* Evaluate a token classified as category CPP_N_INTEGER.  */
+extern cpp_num cpp_interpret_integer PARAMS ((cpp_reader *, const cpp_token *,
+                                             unsigned int type));
+
+/* Sign extend a number, with PRECISION significant bits and all
+   others assumed clear, to fill out a cpp_num structure.  */
+cpp_num cpp_num_sign_extend PARAMS ((cpp_num, size_t));
+
+/* Diagnostic levels.  To get a dianostic without associating a
+   position in the translation unit with it, use cpp_error_with_line
+   with a line number of zero.  */
+
+/* Warning, an error with -Werror.  */
+#define DL_WARNING             0x00
+/* Same as DL_WARNING, except it is not suppressed in system headers.  */
+#define DL_WARNING_SYSHDR      0x01
+/* Warning, an error with -pedantic-errors or -Werror.  */
+#define DL_PEDWARN             0x02
+/* An error.  */
+#define DL_ERROR               0x03
+/* An internal consistency check failed.  Prints "internal error: ",
+   otherwise the same as DL_ERROR.  */
+#define DL_ICE                 0x04
+/* Extracts a diagnostic level from an int.  */
+#define DL_EXTRACT(l)          (l & 0xf)
+/* Nonzero if a diagnostic level is one of the warnings.  */
+#define DL_WARNING_P(l)                (DL_EXTRACT (l) >= DL_WARNING \
+                                && DL_EXTRACT (l) <= DL_PEDWARN)
+
 /* N.B. The error-message-printer prototypes have not been nicely
    formatted because exgettext needs to see 'msgid' on the same line
    as the name of the function in order to work properly.  Only the
    string argument gets a name in an effort to keep the lines from
    getting ridiculously oversized.  */
 
-extern void cpp_ice PARAMS ((cpp_reader *, const char *msgid, ...))
-  ATTRIBUTE_PRINTF_2;
-extern void cpp_fatal PARAMS ((cpp_reader *, const char *msgid, ...))
-  ATTRIBUTE_PRINTF_2;
-extern void cpp_error PARAMS ((cpp_reader *, const char *msgid, ...))
-  ATTRIBUTE_PRINTF_2;
-extern void cpp_warning PARAMS ((cpp_reader *, const char *msgid, ...))
-  ATTRIBUTE_PRINTF_2;
-extern void cpp_pedwarn PARAMS ((cpp_reader *, const char *msgid, ...))
-  ATTRIBUTE_PRINTF_2;
-extern void cpp_notice PARAMS ((cpp_reader *, const char *msgid, ...))
-  ATTRIBUTE_PRINTF_2;
-extern void cpp_error_with_line PARAMS ((cpp_reader *, int, int, const char *msgid, ...))
-  ATTRIBUTE_PRINTF_4;
-extern void cpp_warning_with_line PARAMS ((cpp_reader *, int, int, const char *msgid, ...))
-  ATTRIBUTE_PRINTF_4;
-extern void cpp_pedwarn_with_line PARAMS ((cpp_reader *, int, int, const char *msgid, ...))
-  ATTRIBUTE_PRINTF_4;
-extern void cpp_error_from_errno PARAMS ((cpp_reader *, const char *));
-extern void cpp_notice_from_errno PARAMS ((cpp_reader *, const char *));
+/* Output a diagnostic of some kind.  */
+extern void cpp_error PARAMS ((cpp_reader *, int, const char *msgid, ...))
+  ATTRIBUTE_PRINTF_3;
+
+/* Output a diagnostic of severity LEVEL, with "MSG: " preceding the
+   error string of errno.  No location is printed.  */
+extern void cpp_errno PARAMS ((cpp_reader *, int level, const char *msg));
+
+/* Same as cpp_error, except additionally specifies a position as a
+   (translation unit) physical line and physical column.  If the line is
+   zero, then no location is printed.  */
+extern void cpp_error_with_line PARAMS ((cpp_reader *, int, unsigned, unsigned, const char *msgid, ...))
+  ATTRIBUTE_PRINTF_5;
 
 /* In cpplex.c */
 extern int cpp_ideq                    PARAMS ((const cpp_token *,
@@ -594,10 +724,15 @@ extern int cpp_ideq                       PARAMS ((const cpp_token *,
 extern void cpp_output_line            PARAMS ((cpp_reader *, FILE *));
 extern void cpp_output_token           PARAMS ((const cpp_token *, FILE *));
 extern const char *cpp_type2name       PARAMS ((enum cpp_ttype));
-extern unsigned int cpp_parse_escape   PARAMS ((cpp_reader *,
-                                                const unsigned char **,
-                                                const unsigned char *,
-                                                unsigned HOST_WIDE_INT, int));
+/* Returns the value of an escape sequence, truncated to the correct
+   target precision.  PSTR points to the input pointer, which is just
+   after the backslash.  LIMIT is how much text we have.  WIDE is true
+   if the escape sequence is part of a wide character constant or
+   string literal.  Handles all relevant diagnostics.  */
+extern cppchar_t cpp_parse_escape      PARAMS ((cpp_reader *,
+                                                const unsigned char ** pstr,
+                                                const unsigned char *limit,
+                                                int wide));
 
 /* In cpphash.c */
 
@@ -622,6 +757,9 @@ extern unsigned char *cpp_quote_string      PARAMS ((unsigned char *,
 extern int cpp_included        PARAMS ((cpp_reader *, const char *));
 extern void cpp_make_system_header PARAMS ((cpp_reader *, int, int));
 
+/* In cppmain.c */
+extern void cpp_preprocess_file PARAMS ((cpp_reader *, const char *, FILE *));
+
 #ifdef __cplusplus
 }
 #endif
index 38103aa4ecf6fce6747b27d118c9df814be7df2d..60646bce20eeaa97a1ee8785a55c33cff3496caf 100644 (file)
@@ -28,18 +28,6 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 #include "cpplib.h"
 #include "cpphash.h"
 
-struct cpp_macro
-{
-  cpp_hashnode **params;       /* Parameters, if any.  */
-  cpp_token *expansion;                /* First token of replacement list.  */
-  unsigned int line;           /* Starting line number.  */
-  unsigned int count;          /* Number of tokens in expansion.  */
-  unsigned short paramc;       /* Number of parameters.  */
-  unsigned int fun_like : 1;   /* If a function-like macro.  */
-  unsigned int variadic : 1;   /* If a variadic macro.  */
-  unsigned int syshdr   : 1;   /* If macro defined in system header.  */
-};
-
 typedef struct macro_arg macro_arg;
 struct macro_arg
 {
@@ -64,28 +52,51 @@ static cpp_context *next_context PARAMS ((cpp_reader *));
 static const cpp_token *padding_token
   PARAMS ((cpp_reader *, const cpp_token *));
 static void expand_arg PARAMS ((cpp_reader *, macro_arg *));
-static const cpp_token *new_string_token PARAMS ((cpp_reader *, U_CHAR *,
+static const cpp_token *new_string_token PARAMS ((cpp_reader *, uchar *,
                                                  unsigned int));
-static const cpp_token *new_number_token PARAMS ((cpp_reader *, unsigned int));
 static const cpp_token *stringify_arg PARAMS ((cpp_reader *, macro_arg *));
 static void paste_all_tokens PARAMS ((cpp_reader *, const cpp_token *));
 static bool paste_tokens PARAMS ((cpp_reader *, const cpp_token **,
                                  const cpp_token *));
-static void replace_args PARAMS ((cpp_reader *, cpp_hashnode *, macro_arg *));
+static void replace_args PARAMS ((cpp_reader *, cpp_hashnode *, cpp_macro *,
+                                 macro_arg *));
 static _cpp_buff *funlike_invocation_p PARAMS ((cpp_reader *, cpp_hashnode *));
+static bool create_iso_definition PARAMS ((cpp_reader *, cpp_macro *));
 
 /* #define directive parsing and handling.  */
 
 static cpp_token *alloc_expansion_token PARAMS ((cpp_reader *, cpp_macro *));
 static cpp_token *lex_expansion_token PARAMS ((cpp_reader *, cpp_macro *));
-static int warn_of_redefinition PARAMS ((const cpp_hashnode *,
-                                        const cpp_macro *));
-static int save_parameter PARAMS ((cpp_reader *, cpp_macro *, cpp_hashnode *));
-static int parse_params PARAMS ((cpp_reader *, cpp_macro *));
+static bool warn_of_redefinition PARAMS ((cpp_reader *, const cpp_hashnode *,
+                                         const cpp_macro *));
+static bool parse_params PARAMS ((cpp_reader *, cpp_macro *));
 static void check_trad_stringification PARAMS ((cpp_reader *,
                                                const cpp_macro *,
                                                const cpp_string *));
 
+/* Emits a warning if NODE is a macro defined in the main file that
+   has not been used.  */
+int
+_cpp_warn_if_unused_macro (pfile, node, v)
+     cpp_reader *pfile;
+     cpp_hashnode *node;
+     void *v ATTRIBUTE_UNUSED;
+{
+  if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN))
+    {
+      cpp_macro *macro = node->value.macro;
+
+      if (!macro->used
+         /* Skip front-end built-ins and command line macros.  */
+         && macro->line >= pfile->first_unused_line
+         && MAIN_FILE_P (lookup_line (&pfile->line_maps, macro->line)))
+       cpp_error_with_line (pfile, DL_WARNING, macro->line, 0,
+                            "macro \"%s\" is not used", NODE_NAME (node));
+    }
+
+  return 1;
+}
+
 /* Allocates and returns a CPP_STRING token, containing TEXT of length
    LEN, after null-terminating it.  TEXT must be in permanent storage.  */
 static const cpp_token *
@@ -104,24 +115,6 @@ new_string_token (pfile, text, len)
   return token;
 }
 
-/* Allocates and returns a CPP_NUMBER token evaluating to NUMBER.  */
-static const cpp_token *
-new_number_token (pfile, number)
-     cpp_reader *pfile;
-     unsigned int number;
-{
-  cpp_token *token = _cpp_temp_token (pfile);
-  /* 21 bytes holds all NUL-terminated unsigned 64-bit numbers.  */
-  unsigned char *buf = _cpp_unaligned_alloc (pfile, 21);
-
-  sprintf ((char *) buf, "%u", number);
-  token->type = CPP_NUMBER;
-  token->val.str.text = buf;
-  token->val.str.len = ustrlen (buf);
-  token->flags = 0;
-  return token;
-}
-
 static const char * const monthnames[] =
 {
   "Jan", "Feb", "Mar", "Apr", "May", "Jun",
@@ -132,25 +125,27 @@ static const char * const monthnames[] =
    on the context stack.  Also handles _Pragma, for which no new token
    is created.  Returns 1 if it generates a new token context, 0 to
    return the token to the caller.  */
-static int
-builtin_macro (pfile, node)
+const uchar *
+_cpp_builtin_macro_text (pfile, node)
      cpp_reader *pfile;
      cpp_hashnode *node;
 {
-  const cpp_token *result;
+  const uchar *result = NULL;
+  unsigned int number = 1;
 
   switch (node->value.builtin)
     {
     default:
-      cpp_ice (pfile, "invalid built-in macro \"%s\"", NODE_NAME (node));
-      return 0;
+      cpp_error (pfile, DL_ICE, "invalid built-in macro \"%s\"",
+                NODE_NAME (node));
+      break;
 
     case BT_FILE:
     case BT_BASE_FILE:
       {
        unsigned int len;
        const char *name;
-       U_CHAR *buf;
+       uchar *buf;
        const struct line_map *map = pfile->map;
 
        if (node->value.builtin == BT_BASE_FILE)
@@ -159,10 +154,12 @@ builtin_macro (pfile, node)
 
        name = map->to_file;
        len = strlen (name);
-       buf = _cpp_unaligned_alloc (pfile, len * 4 + 1);
-       len = cpp_quote_string (buf, (const unsigned char *) name, len) - buf;
-
-       result = new_string_token (pfile, buf, len);
+       buf = _cpp_unaligned_alloc (pfile, len * 4 + 3);
+       result = buf;
+       *buf = '"';
+       buf = cpp_quote_string (buf + 1, (const unsigned char *) name, len);
+       *buf++ = '"';
+       *buf = '\0';
       }
       break;
 
@@ -170,61 +167,107 @@ builtin_macro (pfile, node)
       /* The line map depth counts the primary source as level 1, but
         historically __INCLUDE_DEPTH__ has called the primary source
         level 0.  */
-      result = new_number_token (pfile, pfile->line_maps.depth - 1);
+      number = pfile->line_maps.depth - 1;
       break;
 
     case BT_SPECLINE:
       /* If __LINE__ is embedded in a macro, it must expand to the
         line of the macro's invocation, not its definition.
         Otherwise things like assert() will not work properly.  */
-      result = new_number_token (pfile,
-                                SOURCE_LINE (pfile->map,
-                                             pfile->cur_token[-1].line));
+      if (CPP_OPTION (pfile, traditional))
+       number = pfile->line;
+      else
+       number = pfile->cur_token[-1].line;
+      number = SOURCE_LINE (pfile->map, number);
       break;
 
+      /* __STDC__ has the value 1 under normal circumstances.
+        However, if (a) we are in a system header, (b) the option
+        stdc_0_in_system_headers is true (set by target config), and
+        (c) we are not in strictly conforming mode, then it has the
+        value 0.  */
     case BT_STDC:
       {
-       int stdc = (!CPP_IN_SYSTEM_HEADER (pfile)
-                   || pfile->spec_nodes.n__STRICT_ANSI__->type != NT_VOID);
-       result = new_number_token (pfile, stdc);
+       if (CPP_IN_SYSTEM_HEADER (pfile)
+           && CPP_OPTION (pfile, stdc_0_in_system_headers)
+           && !CPP_OPTION (pfile,std))
+         number = 0;
+       else
+         number = 1;
       }
       break;
 
     case BT_DATE:
     case BT_TIME:
-      if (pfile->date.type == CPP_EOF)
+      if (pfile->date == NULL)
        {
          /* Allocate __DATE__ and __TIME__ strings from permanent
             storage.  We only do this once, and don't generate them
             at init time, because time() and localtime() are very
             slow on some systems.  */
-         time_t tt = time (NULL);
-         struct tm *tb = localtime (&tt);
-
-         pfile->date.val.str.text =
-           _cpp_unaligned_alloc (pfile, sizeof ("Oct 11 1347"));
-         pfile->date.val.str.len = sizeof ("Oct 11 1347") - 1;
-         pfile->date.type = CPP_STRING;
-         pfile->date.flags = 0;
-         sprintf ((char *) pfile->date.val.str.text, "%s %2d %4d",
-                  monthnames[tb->tm_mon], tb->tm_mday, tb->tm_year + 1900);
-
-         pfile->time.val.str.text =
-           _cpp_unaligned_alloc (pfile, sizeof ("12:34:56"));
-         pfile->time.val.str.len = sizeof ("12:34:56") - 1;
-         pfile->time.type = CPP_STRING;
-         pfile->time.flags = 0;
-         sprintf ((char *) pfile->time.val.str.text, "%02d:%02d:%02d",
-                  tb->tm_hour, tb->tm_min, tb->tm_sec);
+         time_t tt;
+         struct tm *tb = NULL;
+
+         /* (time_t) -1 is a legitimate value for "number of seconds
+            since the Epoch", so we have to do a little dance to
+            distinguish that from a genuine error.  */
+         errno = 0;
+         tt = time(NULL);
+         if (tt != (time_t)-1 || errno == 0)
+           tb = localtime (&tt);
+
+         if (tb)
+           {
+             pfile->date = _cpp_unaligned_alloc (pfile,
+                                                 sizeof ("\"Oct 11 1347\""));
+             sprintf ((char *) pfile->date, "\"%s %2d %4d\"",
+                      monthnames[tb->tm_mon], tb->tm_mday, tb->tm_year + 1900);
+
+             pfile->time = _cpp_unaligned_alloc (pfile,
+                                                 sizeof ("\"12:34:56\""));
+             sprintf ((char *) pfile->time, "\"%02d:%02d:%02d\"",
+                      tb->tm_hour, tb->tm_min, tb->tm_sec);
+           }
+         else
+           {
+             cpp_errno (pfile, DL_WARNING,
+                        "could not determine date and time");
+               
+             pfile->date = U"\"??? ?? ????\"";
+             pfile->time = U"\"??:??:??\"";
+           }
        }
 
       if (node->value.builtin == BT_DATE)
-       result = &pfile->date;
+       result = pfile->date;
       else
-       result = &pfile->time;
+       result = pfile->time;
       break;
+    }
+
+  if (result == NULL)
+    {
+      /* 21 bytes holds all NUL-terminated unsigned 64-bit numbers.  */
+      result = _cpp_unaligned_alloc (pfile, 21);
+      sprintf ((char *) result, "%u", number);
+    }
+
+  return result;      
+}
+
+/* Convert builtin macros like __FILE__ to a token and push it on the
+   context stack.  Also handles _Pragma, for which no new token is
+   created.  Returns 1 if it generates a new token context, 0 to
+   return the token to the caller.  */
+static int
+builtin_macro (pfile, node)
+     cpp_reader *pfile;
+     cpp_hashnode *node;
+{
+  const uchar *buf;
 
-    case BT_PRAGMA:
+  if (node->value.builtin == BT_PRAGMA)
+    {
       /* Don't interpret _Pragma within directives.  The standard is
          not clear on this, but to me this makes most sense.  */
       if (pfile->state.in_directive)
@@ -234,7 +277,24 @@ builtin_macro (pfile, node)
       return 1;
     }
 
-  push_token_context (pfile, NULL, result, 1);
+  buf = _cpp_builtin_macro_text (pfile, node);
+
+  cpp_push_buffer (pfile, buf, ustrlen (buf), /* from_stage3 */ true, 1);
+
+  /* Tweak the column number the lexer will report.  */
+  pfile->buffer->col_adjust = pfile->cur_token[-1].col - 1;
+
+  /* We don't want a leading # to be interpreted as a directive.  */
+  pfile->buffer->saved_flags = 0;
+
+  /* Set pfile->cur_token as required by _cpp_lex_direct.  */
+  pfile->cur_token = _cpp_temp_token (pfile);
+  push_token_context (pfile, NULL, _cpp_lex_direct (pfile), 1);
+  if (pfile->buffer->cur != pfile->buffer->rlimit)
+    cpp_error (pfile, DL_ICE, "invalid built-in macro \"%s\"",
+              NODE_NAME (node));
+  _cpp_pop_buffer (pfile);
+
   return 1;
 }
 
@@ -242,15 +302,15 @@ builtin_macro (pfile, node)
    backslashes and double quotes.  Non-printable characters are
    converted to octal.  DEST must be of sufficient size.  Returns
    a pointer to the end of the string.  */
-U_CHAR *
+uchar *
 cpp_quote_string (dest, src, len)
-     U_CHAR *dest;
-     const U_CHAR *src;
+     uchar *dest;
+     const uchar *src;
      unsigned int len;
 {
   while (len--)
     {
-      U_CHAR c = *src++;
+      uchar c = *src++;
 
       if (c == '\\' || c == '"')
        {
@@ -343,7 +403,8 @@ stringify_arg (pfile, arg)
   /* Ignore the final \ of invalid string literals.  */
   if (backslash_count & 1)
     {
-      cpp_warning (pfile, "invalid string literal, ignoring final '\\'");
+      cpp_error (pfile, DL_WARNING,
+                "invalid string literal, ignoring final '\\'");
       dest--;
     }
 
@@ -359,7 +420,7 @@ stringify_arg (pfile, arg)
   return new_string_token (pfile, dest - len, len);
 }
 
-/* Try to paste two tokens.  On success, return non-zero.  In any
+/* Try to paste two tokens.  On success, return nonzero.  In any
    case, PLHS is updated to point to the pasted token, which is
    guaranteed to not have the PASTE_LEFT flag set.  */
 static bool
@@ -381,8 +442,7 @@ paste_tokens (pfile, plhs, rhs)
      It is simpler to insert a space here, rather than modifying the
      lexer to ignore comments in some circumstances.  Simply returning
      false doesn't work, since we want to clear the PASTE_LEFT flag.  */
-  if (lhs->type == CPP_DIV
-      && (rhs->type == CPP_MULT || rhs->type == CPP_DIV))
+  if (lhs->type == CPP_DIV && rhs->type != CPP_EQ)
     *end++ = ' ';
   end = cpp_spell_token (pfile, rhs, end);
   *end = '\0';
@@ -427,9 +487,9 @@ paste_all_tokens (pfile, lhs)
         inserted.  In either case, the constraints to #define
         guarantee we have at least one more token.  */
       if (context->direct_p)
-       rhs = context->first.token++;
+       rhs = FIRST (context).token++;
       else
-       rhs = *context->first.ptoken++;
+       rhs = *FIRST (context).ptoken++;
 
       if (rhs->type == CPP_PADDING)
        abort ();
@@ -438,12 +498,12 @@ paste_all_tokens (pfile, lhs)
        {
          _cpp_backup_tokens (pfile, 1);
 
-         /* Mandatory warning for all apart from assembler.  */
+         /* Mandatory error for all apart from assembler.  */
          if (CPP_OPTION (pfile, lang) != CLK_ASM)
-           cpp_warning (pfile,
+           cpp_error (pfile, DL_ERROR,
         "pasting \"%s\" and \"%s\" does not give a valid preprocessing token",
-                        cpp_token_as_text (pfile, lhs),
-                        cpp_token_as_text (pfile, rhs));
+                      cpp_token_as_text (pfile, lhs),
+                      cpp_token_as_text (pfile, rhs));
          break;
        }
     }
@@ -453,6 +513,52 @@ paste_all_tokens (pfile, lhs)
   push_token_context (pfile, NULL, lhs, 1);
 }
 
+/* Returns TRUE if the number of arguments ARGC supplied in an
+   invocation of the MACRO referenced by NODE is valid.  An empty
+   invocation to a macro with no parameters should pass ARGC as zero.
+
+   Note that MACRO cannot necessarily be deduced from NODE, in case
+   NODE was redefined whilst collecting arguments.  */
+bool
+_cpp_arguments_ok (pfile, macro, node, argc)
+     cpp_reader *pfile;
+     cpp_macro *macro;
+     const cpp_hashnode *node;
+     unsigned int argc;
+{
+  if (argc == macro->paramc)
+    return true;
+
+  if (argc < macro->paramc)
+    {
+      /* As an extension, a rest argument is allowed to not appear in
+        the invocation at all.
+        e.g. #define debug(format, args...) something
+        debug("string");
+
+        This is exactly the same as if there had been an empty rest
+        argument - debug("string", ).  */
+
+      if (argc + 1 == macro->paramc && macro->variadic)
+       {
+         if (CPP_PEDANTIC (pfile) && ! macro->syshdr)
+           cpp_error (pfile, DL_PEDWARN,
+                      "ISO C99 requires rest arguments to be used");
+         return true;
+       }
+
+      cpp_error (pfile, DL_ERROR,
+                "macro \"%s\" requires %u arguments, but only %u given",
+                NODE_NAME (node), macro->paramc, argc);
+    }
+  else
+    cpp_error (pfile, DL_ERROR,
+              "macro \"%s\" passed %u arguments, but takes just %u",
+              NODE_NAME (node), argc, macro->paramc);
+
+  return false;
+}
+
 /* Reads and returns the arguments to a function-like macro
    invocation.  Assumes the opening parenthesis has been processed.
    If there is an error, emits an appropriate diagnostic and returns
@@ -468,7 +574,6 @@ collect_args (pfile, node)
   macro_arg *args, *arg;
   const cpp_token *token;
   unsigned int argc;
-  bool error = false;
 
   macro = node->value.macro;
   if (macro->paramc)
@@ -550,90 +655,43 @@ collect_args (pfile, node)
            arg++;
        }
     }
-  while (token->type != CPP_CLOSE_PAREN
-        && token->type != CPP_EOF
-        && token->type != CPP_HASH);
+  while (token->type != CPP_CLOSE_PAREN && token->type != CPP_EOF);
 
-  if (token->type == CPP_EOF || token->type == CPP_HASH)
+  if (token->type == CPP_EOF)
     {
-      bool step_back = false;
-
-      /* 6.10.3 paragraph 11: If there are sequences of preprocessing
-        tokens within the list of arguments that would otherwise act
-        as preprocessing directives, the behavior is undefined.
-
-        This implementation will report a hard error, terminate the
-        macro invocation, and proceed to process the directive.  */
-      if (token->type == CPP_HASH)
-       {
-         cpp_error (pfile,
-                    "directives may not be used inside a macro argument");
-         step_back = true;
-       }
-      else
-       step_back = (pfile->context->prev || pfile->state.in_directive);
-
       /* We still need the CPP_EOF to end directives, and to end
         pre-expansion of a macro argument.  Step back is not
         unconditional, since we don't want to return a CPP_EOF to our
         callers at the end of an -include-d file.  */
-      if (step_back)
+      if (pfile->context->prev || pfile->state.in_directive)
        _cpp_backup_tokens (pfile, 1);
-      cpp_error (pfile, "unterminated argument list invoking macro \"%s\"",
+      cpp_error (pfile, DL_ERROR,
+                "unterminated argument list invoking macro \"%s\"",
                 NODE_NAME (node));
-      error = true;
-    }
-  else if (argc < macro->paramc)
-    {
-      /* As an extension, a rest argument is allowed to not appear in
-        the invocation at all.
-        e.g. #define debug(format, args...) something
-        debug("string");
-        
-        This is exactly the same as if there had been an empty rest
-        argument - debug("string", ).  */
-
-      if (argc + 1 == macro->paramc && macro->variadic)
-       {
-         if (CPP_PEDANTIC (pfile) && ! macro->syshdr)
-           cpp_pedwarn (pfile, "ISO C99 requires rest arguments to be used");
-       }
-      else
-       {
-         cpp_error (pfile,
-                    "macro \"%s\" requires %u arguments, but only %u given",
-                    NODE_NAME (node), macro->paramc, argc);
-         error = true;
-       }
     }
-  else if (argc > macro->paramc)
+  else
     {
-      /* Empty argument to a macro taking no arguments is OK.  */
-      if (argc != 1 || arg->count)
+      /* A single empty argument is counted as no argument.  */
+      if (argc == 1 && macro->paramc == 0 && args[0].count == 0)
+       argc = 0;
+      if (_cpp_arguments_ok (pfile, macro, node, argc))
        {
-         cpp_error (pfile,
-                    "macro \"%s\" passed %u arguments, but takes just %u",
-                    NODE_NAME (node), argc, macro->paramc);
-         error = true;
+         /* GCC has special semantics for , ## b where b is a varargs
+            parameter: we remove the comma if b was omitted entirely.
+            If b was merely an empty argument, the comma is retained.
+            If the macro takes just one (varargs) parameter, then we
+            retain the comma only if we are standards conforming.
+
+            If FIRST is NULL replace_args () swallows the comma.  */
+         if (macro->variadic && (argc < macro->paramc
+                                 || (argc == 1 && args[0].count == 0
+                                     && !CPP_OPTION (pfile, std))))
+           args[macro->paramc - 1].first = NULL;
+         return base_buff;
        }
     }
 
-  if (!error)
-    {
-      /* GCC has special semantics for , ## b where b is a varargs
-        parameter: we remove the comma if b was omitted entirely.
-        If b was merely an empty argument, the comma is retained.
-        If the macro takes just one (varargs) parameter, then we
-        retain the comma only if we are standards conforming.
-
-        If FIRST is NULL replace_args () swallows the comma.  */
-      if (macro->variadic && (argc < macro->paramc
-                             || (argc == 1 && args[0].count == 0
-                                 && !CPP_OPTION (pfile, std))))
-       args[macro->paramc - 1].first = NULL;
-      return base_buff;
-    }
-
+  /* An error occurred.  */
   _cpp_release_buff (pfile, base_buff);
   return NULL;
 }
@@ -714,23 +772,25 @@ enter_macro_context (pfile, node)
          if (buff == NULL)
            {
              if (CPP_WTRADITIONAL (pfile) && ! node->value.macro->syshdr)
-               cpp_warning (pfile,
+               cpp_error (pfile, DL_WARNING,
  "function-like macro \"%s\" must be used with arguments in traditional C",
-                            NODE_NAME (node));
+                          NODE_NAME (node));
 
              return 0;
            }
 
-         if (node->value.macro->paramc > 0)
-           replace_args (pfile, node, (macro_arg *) buff->base);
+         if (macro->paramc > 0)
+           replace_args (pfile, node, macro, (macro_arg *) buff->base);
          _cpp_release_buff (pfile, buff);
        }
 
       /* Disable the macro within its expansion.  */
       node->flags |= NODE_DISABLED;
 
+      macro->used = 1;
+
       if (macro->paramc == 0)
-       push_token_context (pfile, node, macro->expansion, macro->count);
+       push_token_context (pfile, node, macro->exp.tokens, macro->count);
 
       return 1;
     }
@@ -744,9 +804,10 @@ enter_macro_context (pfile, node)
    Expand each argument before replacing, unless it is operated upon
    by the # or ## operators.  */
 static void
-replace_args (pfile, node, args)
+replace_args (pfile, node, macro, args)
      cpp_reader *pfile;
      cpp_hashnode *node;
+     cpp_macro *macro;
      macro_arg *args;
 {
   unsigned int i, total;
@@ -754,17 +815,15 @@ replace_args (pfile, node, args)
   const cpp_token **dest, **first;
   macro_arg *arg;
   _cpp_buff *buff;
-  cpp_macro *macro;
 
   /* First, fully macro-expand arguments, calculating the number of
      tokens in the final expansion as we go.  The ordering of the if
      statements below is subtle; we must handle stringification before
      pasting.  */
-  macro = node->value.macro;
   total = macro->count;
-  limit = macro->expansion + macro->count;
+  limit = macro->exp.tokens + macro->count;
 
-  for (src = macro->expansion; src < limit; src++)
+  for (src = macro->exp.tokens; src < limit; src++)
     if (src->type == CPP_MACRO_ARG)
       {
        /* Leading and trailing padding tokens.  */
@@ -780,7 +839,7 @@ replace_args (pfile, node, args)
              arg->stringified = stringify_arg (pfile, arg);
          }
        else if ((src->flags & PASTE_LEFT)
-                || (src > macro->expansion && (src[-1].flags & PASTE_LEFT)))
+                || (src > macro->exp.tokens && (src[-1].flags & PASTE_LEFT)))
          total += arg->count - 1;
        else
          {
@@ -796,7 +855,7 @@ replace_args (pfile, node, args)
   first = (const cpp_token **) buff->base;
   dest = first;
 
-  for (src = macro->expansion; src < limit; src++)
+  for (src = macro->exp.tokens; src < limit; src++)
     {
       unsigned int count;
       const cpp_token **from, **paste_flag;
@@ -813,7 +872,7 @@ replace_args (pfile, node, args)
        count = 1, from = &arg->stringified;
       else if (src->flags & PASTE_LEFT)
        count = arg->count, from = arg->first;
-      else if (src != macro->expansion && (src[-1].flags & PASTE_LEFT))
+      else if (src != macro->exp.tokens && (src[-1].flags & PASTE_LEFT))
        {
          count = arg->count, from = arg->first;
          if (dest != first)
@@ -838,8 +897,8 @@ replace_args (pfile, node, args)
        count = arg->expanded_count, from = arg->expanded;
 
       /* Padding on the left of an argument (unless RHS of ##).  */
-      if (!pfile->state.in_directive
-         && src != macro->expansion && !(src[-1].flags & PASTE_LEFT))
+      if ((!pfile->state.in_directive || pfile->state.directive_wants_padding)
+         && src != macro->exp.tokens && !(src[-1].flags & PASTE_LEFT))
        *dest++ = padding_token (pfile, src);
 
       if (count)
@@ -927,8 +986,8 @@ push_ptoken_context (pfile, macro, buff, first, count)
   context->direct_p = false;
   context->macro = macro;
   context->buff = buff;
-  context->first.ptoken = first;
-  context->last.ptoken = first + count;
+  FIRST (context).ptoken = first;
+  LAST (context).ptoken = first + count;
 }
 
 /* Push a list of tokens.  */
@@ -944,8 +1003,26 @@ push_token_context (pfile, macro, first, count)
   context->direct_p = true;
   context->macro = macro;
   context->buff = NULL;
-  context->first.token = first;
-  context->last.token = first + count;
+  FIRST (context).token = first;
+  LAST (context).token = first + count;
+}
+
+/* Push a traditional macro's replacement text.  */
+void
+_cpp_push_text_context (pfile, macro, start, len)
+     cpp_reader *pfile;
+     cpp_hashnode *macro;
+     const uchar *start;
+     size_t len;
+{
+  cpp_context *context = next_context (pfile);
+
+  context->direct_p = true;
+  context->macro = macro;
+  context->buff = NULL;
+  CUR (context) = start;
+  RLIMIT (context) = start + len;
+  macro->flags |= NODE_DISABLED;
 }
 
 /* Expand an argument ARG before replacing parameters in a
@@ -960,10 +1037,15 @@ expand_arg (pfile, arg)
      macro_arg *arg;
 {
   unsigned int capacity;
+  bool saved_warn_trad;
 
   if (arg->count == 0)
     return;
 
+  /* Don't warn about funlike macros when pre-expanding.  */
+  saved_warn_trad = CPP_WTRADITIONAL (pfile);
+  CPP_WTRADITIONAL (pfile) = 0;
+
   /* Loop, reading in the arguments.  */
   capacity = 256;
   arg->expanded = (const cpp_token **)
@@ -990,6 +1072,8 @@ expand_arg (pfile, arg)
     }
 
   _cpp_pop_context (pfile);
+
+  CPP_WTRADITIONAL (pfile) = saved_warn_trad;
 }
 
 /* Pop the current context off the stack, re-enabling the macro if the
@@ -1035,12 +1119,12 @@ cpp_get_token (pfile)
       /* Context->prev == 0 <=> base context.  */
       if (!context->prev)
        result = _cpp_lex_token (pfile);
-      else if (context->first.token != context->last.token)
+      else if (FIRST (context).token != LAST (context).token)
        {
          if (context->direct_p)
-           result = context->first.token++;
+           result = FIRST (context).token++;
          else
-           result = *context->first.ptoken++;
+           result = *FIRST (context).ptoken++;
 
          if (result->flags & PASTE_LEFT)
            {
@@ -1058,6 +1142,9 @@ cpp_get_token (pfile)
          return &pfile->avoid_paste;
        }
 
+      if (pfile->state.in_directive && result->type == CPP_COMMENT)
+       continue;
+
       if (result->type != CPP_NAME)
        break;
 
@@ -1065,7 +1152,7 @@ cpp_get_token (pfile)
 
       if (node->type != NT_MACRO || (result->flags & NO_EXPAND))
        break;
-      
+
       if (!(node->flags & NODE_DISABLED))
        {
          if (!pfile->state.prevent_expansion
@@ -1105,14 +1192,22 @@ cpp_sys_macro_p (pfile)
   return node && node->value.macro && node->value.macro->syshdr;
 }
 
-/* Read each token in, until EOF.  Directives are transparently
-   processed.  */
+/* Read each token in, until end of the current file.  Directives are
+   transparently processed.  */
 void
 cpp_scan_nooutput (pfile)
      cpp_reader *pfile;
 {
-  while (cpp_get_token (pfile)->type != CPP_EOF)
-    ;
+  /* Request a CPP_EOF token at the end of this file, rather than
+     transparently continuing with the including file.  */
+  pfile->buffer->return_at_eof = true;
+
+  if (CPP_OPTION (pfile, traditional))
+    while (_cpp_read_logical_line_trad (pfile))
+      ;
+  else
+    while (cpp_get_token (pfile)->type != CPP_EOF)
+      ;
 }
 
 /* Step back one (or more) tokens.  Can only step mack more than 1 if
@@ -1142,17 +1237,18 @@ _cpp_backup_tokens (pfile, count)
       if (count != 1)
        abort ();
       if (pfile->context->direct_p)
-       pfile->context->first.token--;
+       FIRST (pfile->context).token--;
       else
-       pfile->context->first.ptoken--;
+       FIRST (pfile->context).ptoken--;
     }
 }
 
 /* #define directive parsing and handling.  */
 
-/* Returns non-zero if a macro redefinition warning is required.  */
-static int
-warn_of_redefinition (node, macro2)
+/* Returns nonzero if a macro redefinition warning is required.  */
+static bool
+warn_of_redefinition (pfile, node, macro2)
+     cpp_reader *pfile;
      const cpp_hashnode *node;
      const cpp_macro *macro2;
 {
@@ -1161,30 +1257,36 @@ warn_of_redefinition (node, macro2)
 
   /* Some redefinitions need to be warned about regardless.  */
   if (node->flags & NODE_WARN)
-    return 1;
+    return true;
 
   /* Redefinition of a macro is allowed if and only if the old and new
      definitions are the same.  (6.10.3 paragraph 2).  */
   macro1 = node->value.macro;
 
-  /* The quick failures.  */
-  if (macro1->count != macro2->count
-      || macro1->paramc != macro2->paramc
+  /* Don't check count here as it can be different in valid
+     traditional redefinitions with just whitespace differences.  */
+  if (macro1->paramc != macro2->paramc
       || macro1->fun_like != macro2->fun_like
       || macro1->variadic != macro2->variadic)
-    return 1;
-
-  /* Check each token.  */
-  for (i = 0; i < macro1->count; i++)
-    if (! _cpp_equiv_tokens (&macro1->expansion[i], &macro2->expansion[i]))
-      return 1;
+    return true;
 
   /* Check parameter spellings.  */
   for (i = 0; i < macro1->paramc; i++)
     if (macro1->params[i] != macro2->params[i])
-      return 1;
+      return true;
+
+  /* Check the replacement text or tokens.  */
+  if (CPP_OPTION (pfile, traditional))
+    return _cpp_expansions_different_trad (macro1, macro2);
+
+  if (macro1->count != macro2->count)
+    return true;
+
+  for (i = 0; i < macro1->count; i++)
+    if (!_cpp_equiv_tokens (&macro1->exp.tokens[i], &macro2->exp.tokens[i]))
+      return true;
 
-  return 0;
+  return false;
 }
 
 /* Free the definition of hashnode H.  */
@@ -1199,9 +1301,9 @@ _cpp_free_definition (h)
 }
 
 /* Save parameter NODE to the parameter list of macro MACRO.  Returns
-   zero on success, non-zero if the parameter is a duplicate.  */
-static int
-save_parameter (pfile, macro, node)
+   zero on success, nonzero if the parameter is a duplicate.  */
+bool
+_cpp_save_parameter (pfile, macro, node)
      cpp_reader *pfile;
      cpp_macro *macro;
      cpp_hashnode *node;
@@ -1209,8 +1311,9 @@ save_parameter (pfile, macro, node)
   /* Constraint 6.10.3.6 - duplicate parameter names.  */
   if (node->arg_index)
     {
-      cpp_error (pfile, "duplicate macro parameter \"%s\"", NODE_NAME (node));
-      return 1;
+      cpp_error (pfile, DL_ERROR, "duplicate macro parameter \"%s\"",
+                NODE_NAME (node));
+      return true;
     }
 
   if (BUFF_ROOM (pfile->a_buff)
@@ -1219,11 +1322,12 @@ save_parameter (pfile, macro, node)
 
   ((cpp_hashnode **) BUFF_FRONT (pfile->a_buff))[macro->paramc++] = node;
   node->arg_index = macro->paramc;
-  return 0;
+  return false;
 }
 
-/* Check the syntax of the parameters in a MACRO definition.  */
-static int
+/* Check the syntax of the parameters in a MACRO definition.  Returns
+   false if an error occurs.  */
+static bool
 parse_params (pfile, macro)
      cpp_reader *pfile;
      cpp_macro *macro;
@@ -1237,32 +1341,40 @@ parse_params (pfile, macro)
       switch (token->type)
        {
        default:
-         cpp_error (pfile, "\"%s\" may not appear in macro parameter list",
+         /* Allow/ignore comments in parameter lists if we are
+            preserving comments in macro expansions.  */
+         if (token->type == CPP_COMMENT
+             && ! CPP_OPTION (pfile, discard_comments_in_macro_exp))
+           continue;
+
+         cpp_error (pfile, DL_ERROR,
+                    "\"%s\" may not appear in macro parameter list",
                     cpp_token_as_text (pfile, token));
-         return 0;
+         return false;
 
        case CPP_NAME:
          if (prev_ident)
            {
-             cpp_error (pfile, "macro parameters must be comma-separated");
-             return 0;
+             cpp_error (pfile, DL_ERROR,
+                        "macro parameters must be comma-separated");
+             return false;
            }
          prev_ident = 1;
 
-         if (save_parameter (pfile, macro, token->val.node))
-           return 0;
+         if (_cpp_save_parameter (pfile, macro, token->val.node))
+           return false;
          continue;
 
        case CPP_CLOSE_PAREN:
          if (prev_ident || macro->paramc == 0)
-           return 1;
+           return true;
 
          /* Fall through to pick up the error.  */
        case CPP_COMMA:
          if (!prev_ident)
            {
-             cpp_error (pfile, "parameter name missing");
-             return 0;
+             cpp_error (pfile, DL_ERROR, "parameter name missing");
+             return false;
            }
          prev_ident = 0;
          continue;
@@ -1271,24 +1383,26 @@ parse_params (pfile, macro)
          macro->variadic = 1;
          if (!prev_ident)
            {
-             save_parameter (pfile, macro, pfile->spec_nodes.n__VA_ARGS__);
+             _cpp_save_parameter (pfile, macro,
+                                  pfile->spec_nodes.n__VA_ARGS__);
              pfile->state.va_args_ok = 1;
              if (! CPP_OPTION (pfile, c99) && CPP_OPTION (pfile, pedantic))
-               cpp_pedwarn (pfile,
-                    "anonymous variadic macros were introduced in C99");
+               cpp_error (pfile, DL_PEDWARN,
+                          "anonymous variadic macros were introduced in C99");
            }
          else if (CPP_OPTION (pfile, pedantic))
-           cpp_pedwarn (pfile, "ISO C does not permit named variadic macros");
+           cpp_error (pfile, DL_PEDWARN,
+                      "ISO C does not permit named variadic macros");
 
          /* We're at the end, and just expect a closing parenthesis.  */
          token = _cpp_lex_token (pfile);
          if (token->type == CPP_CLOSE_PAREN)
-           return 1;
+           return true;
          /* Fall through.  */
 
        case CPP_EOF:
-         cpp_error (pfile, "missing ')' in macro parameter list");
-         return 0;
+         cpp_error (pfile, DL_ERROR, "missing ')' in macro parameter list");
+         return false;
        }
     }
 }
@@ -1330,24 +1444,13 @@ lex_expansion_token (pfile, macro)
   return token;
 }
 
-/* Parse a macro and save its expansion.  Returns non-zero on success.  */
-int
-_cpp_create_definition (pfile, node)
+static bool
+create_iso_definition (pfile, macro)
      cpp_reader *pfile;
-     cpp_hashnode *node;
+     cpp_macro *macro;
 {
-  cpp_macro *macro;
-  cpp_token *token, *saved_cur_token;
+  cpp_token *token;
   const cpp_token *ctoken;
-  unsigned int i, ok = 1;
-
-  macro = (cpp_macro *) _cpp_aligned_alloc (pfile, sizeof (cpp_macro));
-  macro->line = pfile->directive_line;
-  macro->params = 0;
-  macro->paramc = 0;
-  macro->variadic = 0;
-  macro->count = 0;
-  macro->fun_like = 0;
 
   /* Get the first token of the expansion (or the '(' of a
      function-like macro).  */
@@ -1355,19 +1458,18 @@ _cpp_create_definition (pfile, node)
 
   if (ctoken->type == CPP_OPEN_PAREN && !(ctoken->flags & PREV_WHITE))
     {
-      ok = parse_params (pfile, macro);
+      bool ok = parse_params (pfile, macro);
       macro->params = (cpp_hashnode **) BUFF_FRONT (pfile->a_buff);
       if (!ok)
-       goto cleanup2;
+       return false;
 
       /* Success.  Commit the parameter array.  */
-      BUFF_FRONT (pfile->a_buff) = (U_CHAR *) &macro->params[macro->paramc];
+      BUFF_FRONT (pfile->a_buff) = (uchar *) &macro->params[macro->paramc];
       macro->fun_like = 1;
     }
   else if (ctoken->type != CPP_EOF && !(ctoken->flags & PREV_WHITE))
-    cpp_pedwarn (pfile, "ISO C requires whitespace after the macro name");
-
-  saved_cur_token = pfile->cur_token;
+    cpp_error (pfile, DL_PEDWARN,
+              "ISO C requires whitespace after the macro name");
 
   if (macro->fun_like)
     token = lex_expansion_token (pfile, macro);
@@ -1395,9 +1497,9 @@ _cpp_create_definition (pfile, node)
          else if ((CPP_OPTION (pfile, lang) != CLK_ASM)
                && (!CPP_OPTION(pfile, allow_naked_hash)))
            {
-             ok = 0;
-             cpp_error (pfile, "'#' is not followed by a macro parameter");
-             goto cleanup1;
+             cpp_error (pfile, DL_ERROR,
+                        "'#' is not followed by a macro parameter");
+             return false;
            }
        }
 
@@ -1414,10 +1516,9 @@ _cpp_create_definition (pfile, node)
 
          if (macro->count == 0 || token->type == CPP_EOF)
            {
-             ok = 0;
-             cpp_error (pfile,
+             cpp_error (pfile, DL_ERROR,
                         "'##' cannot appear at either end of a macro expansion");
-             goto cleanup1;
+             return false;
            }
 
          token[-1].flags |= PASTE_LEFT;
@@ -1426,62 +1527,96 @@ _cpp_create_definition (pfile, node)
       token = lex_expansion_token (pfile, macro);
     }
 
-  macro->expansion = (cpp_token *) BUFF_FRONT (pfile->a_buff);
+  macro->exp.tokens = (cpp_token *) BUFF_FRONT (pfile->a_buff);
 
   /* Don't count the CPP_EOF.  */
   macro->count--;
 
   /* Clear whitespace on first token for warn_of_redefinition().  */
   if (macro->count)
-    macro->expansion[0].flags &= ~PREV_WHITE;
+    macro->exp.tokens[0].flags &= ~PREV_WHITE;
 
   /* Commit the memory.  */
-  BUFF_FRONT (pfile->a_buff) = (U_CHAR *) &macro->expansion[macro->count];
+  BUFF_FRONT (pfile->a_buff) = (uchar *) &macro->exp.tokens[macro->count];
 
-  /* Implement the macro-defined-to-itself optimisation.  */
-  if (macro->count == 1 && !macro->fun_like
-      && macro->expansion[0].type == CPP_NAME
-      && macro->expansion[0].val.node == node)
-    node->flags |= NODE_DISABLED;
+  return true;
+}
+
+/* Parse a macro and save its expansion.  Returns nonzero on success.  */
+bool
+_cpp_create_definition (pfile, node)
+     cpp_reader *pfile;
+     cpp_hashnode *node;
+{
+  cpp_macro *macro;
+  unsigned int i;
+  bool ok;
 
+  macro = (cpp_macro *) _cpp_aligned_alloc (pfile, sizeof (cpp_macro));
+  macro->line = pfile->directive_line;
+  macro->params = 0;
+  macro->paramc = 0;
+  macro->variadic = 0;
+  macro->used = 0;
+  macro->count = 0;
+  macro->fun_like = 0;
   /* To suppress some diagnostics.  */
   macro->syshdr = pfile->map->sysp != 0;
 
-  if (node->type != NT_VOID)
+  if (CPP_OPTION (pfile, traditional))
+    ok = _cpp_create_trad_definition (pfile, macro);
+  else
+    {
+      cpp_token *saved_cur_token = pfile->cur_token;
+
+      ok = create_iso_definition (pfile, macro);
+
+      /* Restore lexer position because of games lex_expansion_token()
+        plays lexing the macro.  We set the type for SEEN_EOL() in
+        cpplib.c.
+
+        Longer term we should lex the whole line before coming here,
+        and just copy the expansion.  */
+      saved_cur_token[-1].type = pfile->cur_token[-1].type;
+      pfile->cur_token = saved_cur_token;
+
+      /* Stop the lexer accepting __VA_ARGS__.  */
+      pfile->state.va_args_ok = 0;
+    }
+
+  /* Clear the fast argument lookup indices.  */
+  for (i = macro->paramc; i-- > 0; )
+    macro->params[i]->arg_index = 0;
+
+  if (!ok)
+    return ok;
+
+  if (node->type == NT_MACRO)
     {
-      if (warn_of_redefinition (node, macro))
+      if (CPP_OPTION (pfile, warn_unused_macros))
+       _cpp_warn_if_unused_macro (pfile, node, NULL);
+
+      if (warn_of_redefinition (pfile, node, macro))
        {
-         cpp_pedwarn_with_line (pfile, pfile->directive_line, 0,
-                                "\"%s\" redefined", NODE_NAME (node));
+         cpp_error_with_line (pfile, DL_PEDWARN, pfile->directive_line, 0,
+                              "\"%s\" redefined", NODE_NAME (node));
 
          if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN))
-           cpp_pedwarn_with_line (pfile, node->value.macro->line, 0,
-                           "this is the location of the previous definition");
+           cpp_error_with_line (pfile, DL_PEDWARN,
+                                node->value.macro->line, 0,
+                        "this is the location of the previous definition");
        }
-      _cpp_free_definition (node);
     }
 
+  if (node->type != NT_VOID)
+    _cpp_free_definition (node);
+
   /* Enter definition in hash table.  */
   node->type = NT_MACRO;
   node->value.macro = macro;
   if (! ustrncmp (NODE_NAME (node), DSC ("__STDC_")))
     node->flags |= NODE_WARN;
 
- cleanup1:
-
-  /* Set type for SEEN_EOL() in cpplib.c, restore the lexer position.  */
-  saved_cur_token[-1].type = pfile->cur_token[-1].type;
-  pfile->cur_token = saved_cur_token;
-
- cleanup2:
-
-  /* Stop the lexer accepting __VA_ARGS__.  */
-  pfile->state.va_args_ok = 0;
-
-  /* Clear the fast argument lookup indices.  */
-  for (i = macro->paramc; i-- > 0; )
-    macro->params[i]->arg_index = 0;
-
   return ok;
 }
 
@@ -1494,8 +1629,8 @@ check_trad_stringification (pfile, macro, string)
      const cpp_string *string;
 {
   unsigned int i, len;
-  const U_CHAR *p, *q, *limit = string->text + string->len;
-  
+  const uchar *p, *q, *limit = string->text + string->len;
+
   /* Loop over the string.  */
   for (p = string->text; p < limit; p = q)
     {
@@ -1519,9 +1654,9 @@ check_trad_stringification (pfile, macro, string)
          if (NODE_LEN (node) == len
              && !memcmp (p, NODE_NAME (node), len))
            {
-             cpp_warning (pfile,
-          "macro argument \"%s\" would be stringified with -traditional",
-                          NODE_NAME (node));
+             cpp_error (pfile, DL_WARNING,
+          "macro argument \"%s\" would be stringified in traditional C",
+                        NODE_NAME (node));
              break;
            }
        }
@@ -1544,7 +1679,8 @@ cpp_macro_definition (pfile, node)
 
   if (node->type != NT_MACRO || (node->flags & NODE_BUILTIN))
     {
-      cpp_ice (pfile, "invalid hash type %d in cpp_macro_definition", node->type);
+      cpp_error (pfile, DL_ICE,
+                "invalid hash type %d in cpp_macro_definition", node->type);
       return 0;
     }
 
@@ -1558,23 +1694,28 @@ cpp_macro_definition (pfile, node)
        len += NODE_LEN (macro->params[i]) + 1; /* "," */
     }
 
-  for (i = 0; i < macro->count; i++)
+  if (CPP_OPTION (pfile, traditional))
+    len += _cpp_replacement_text_len (macro);
+  else
     {
-      cpp_token *token = &macro->expansion[i];
+      for (i = 0; i < macro->count; i++)
+       {
+         cpp_token *token = &macro->exp.tokens[i];
 
-      if (token->type == CPP_MACRO_ARG)
-       len += NODE_LEN (macro->params[token->val.arg_no - 1]);
-      else
-       len += cpp_token_len (token); /* Includes room for ' '.  */
-      if (token->flags & STRINGIFY_ARG)
-       len++;                  /* "#" */
-      if (token->flags & PASTE_LEFT)
-       len += 3;               /* " ##" */
+         if (token->type == CPP_MACRO_ARG)
+           len += NODE_LEN (macro->params[token->val.arg_no - 1]);
+         else
+           len += cpp_token_len (token); /* Includes room for ' '.  */
+         if (token->flags & STRINGIFY_ARG)
+           len++;                      /* "#" */
+         if (token->flags & PASTE_LEFT)
+           len += 3;           /* " ##" */
+       }
     }
 
   if (len > pfile->macro_buffer_len)
     {
-      pfile->macro_buffer = (U_CHAR *) xrealloc (pfile->macro_buffer, len);
+      pfile->macro_buffer = (uchar *) xrealloc (pfile->macro_buffer, len);
       pfile->macro_buffer_len = len;
     }
 
@@ -1598,9 +1739,9 @@ cpp_macro_definition (pfile, node)
            }
 
          if (i + 1 < macro->paramc)
-            /* Don't emit a space after the comma here; we're trying
-               to emit a Dwarf-friendly definition, and the Dwarf spec
-               forbids spaces in the argument list.  */
+           /* Don't emit a space after the comma here; we're trying
+              to emit a Dwarf-friendly definition, and the Dwarf spec
+              forbids spaces in the argument list.  */
            *buffer++ = ',';
          else if (macro->variadic)
            *buffer++ = '.', *buffer++ = '.', *buffer++ = '.';
@@ -1612,12 +1753,14 @@ cpp_macro_definition (pfile, node)
      definition is the empty string.  */
   *buffer++ = ' ';
 
+  if (CPP_OPTION (pfile, traditional))
+    buffer = _cpp_copy_replacement_text (macro, buffer);
+  else if (macro->count)
   /* Expansion tokens.  */
-  if (macro->count)
     {
       for (i = 0; i < macro->count; i++)
        {
-         cpp_token *token = &macro->expansion[i];
+         cpp_token *token = &macro->exp.tokens[i];
 
          if (token->flags & PREV_WHITE)
            *buffer++ = ' ';
index 950130262b4a4f651014ab89a4aecfe79e34ac9b..d7afa05db7190d7e34ea97f490ef3bbe7186fac4 100644 (file)
@@ -1,5 +1,5 @@
-/* CPP main program, using CPP Library.
-   Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001, 2002
+/* Preprocess only, using cpplib.
+   Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003
    Free Software Foundation, Inc.
    Written by Per Bothner, 1994-95.
 
@@ -24,33 +24,21 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 #include "config.h"
 #include "system.h"
 #include "cpplib.h"
-#include "intl.h"
+#include "cpphash.h"
 
-/* Encapsulates state used to convert the stream of tokens coming from
-   cpp_get_token back into a text file.  */
-struct printer
-{
-  FILE *outf;                  /* Stream to write to.  */
-  const struct line_map *map;  /* Logical to physical line mappings.  */
-  const cpp_token *prev;       /* Previous token.  */
-  const cpp_token *source;     /* Source token for spacing.  */
-  unsigned int line;           /* Line currently being written.  */
-  unsigned char printed;       /* Nonzero if something output at line.  */
-};
-
-int main               PARAMS ((int, char **));
-static void general_init PARAMS ((const char *));
-static void do_preprocessing PARAMS ((int, char **));
-static void setup_callbacks PARAMS ((void));
+static void setup_callbacks PARAMS ((cpp_reader *));
 
 /* General output routines.  */
 static void scan_translation_unit PARAMS ((cpp_reader *));
-static void check_multiline_token PARAMS ((const cpp_string *));
+static void scan_translation_unit_trad PARAMS ((cpp_reader *));
+static void account_for_newlines PARAMS ((cpp_reader *, const uchar *,
+                                         size_t));
 static int dump_macro PARAMS ((cpp_reader *, cpp_hashnode *, void *));
 
-static void print_line PARAMS ((const struct line_map *, unsigned int,
-                               const char *));
-static void maybe_print_line PARAMS ((const struct line_map *, unsigned int));
+static void print_line PARAMS ((cpp_reader *, const struct line_map *,
+                               unsigned int, const char *));
+static void maybe_print_line PARAMS ((cpp_reader *, const struct line_map *,
+                                     unsigned int));
 
 /* Callback routines for the parser.   Most of these are active only
    in specific modes.  */
@@ -64,130 +52,59 @@ static void cb_ident         PARAMS ((cpp_reader *, unsigned int,
 static void cb_file_change PARAMS ((cpp_reader *, const struct line_map *));
 static void cb_def_pragma PARAMS ((cpp_reader *, unsigned int));
 
-const char *progname;          /* Needs to be global.  */
-static cpp_reader *pfile;      /* An opaque handle.  */
-static cpp_options *options;   /* Options of pfile.  */
-static struct printer print;
-
-int
-main (argc, argv)
-     int argc;
-     char **argv;
-{
-  general_init (argv[0]);
-
-  /* Construct a reader with default language GNU C89.  */
-  pfile = cpp_create_reader (CLK_GNUC89);
-  options = cpp_get_options (pfile);
-
-  do_preprocessing (argc, argv);
-
-  if (cpp_destroy (pfile))
-    return FATAL_EXIT_CODE;
-
-  return SUCCESS_EXIT_CODE;
-}
-
-/* Store the program name, and set the locale.  */
-static void
-general_init (argv0)
-     const char *argv0;
-{
-  progname = argv0 + strlen (argv0);
-
-  while (progname != argv0 && ! IS_DIR_SEPARATOR (progname[-1]))
-    --progname;
-
-  xmalloc_set_program_name (progname);
-
-  hex_init ();
-  gcc_init_libintl ();
-}
-
-/* Handle switches, preprocess and output.  */
-static void
-do_preprocessing (argc, argv)
-     int argc;
-     char **argv;
+/* Preprocess and output.  */
+void
+cpp_preprocess_file (pfile, in_fname, out_stream)
+     cpp_reader *pfile;
+     const char *in_fname;
+     FILE *out_stream;
 {
-  int argi = 1;  /* Next argument to handle.  */
-
-  argi += cpp_handle_options (pfile, argc - argi , argv + argi);
-  if (CPP_FATAL_ERRORS (pfile))
-    return;
-
-  if (argi < argc)
-    {
-      cpp_fatal (pfile, "invalid option %s", argv[argi]);
-      return;
-    }
-
-  cpp_post_options (pfile);
-  if (CPP_FATAL_ERRORS (pfile))
-    return;
-
-  /* If cpp_handle_options saw --help or --version on the command
-     line, it will have set pfile->help_only to indicate this.  Exit
-     successfully.  [The library does not exit itself, because
-     e.g. cc1 needs to print its own --help message at this point.]  */
-  if (options->help_only)
-    return;
-
   /* Initialize the printer structure.  Setting print.line to -1 here
      is a trick to guarantee that the first token of the file will
      cause a linemarker to be output by maybe_print_line.  */
-  print.line = (unsigned int) -1;
-  print.printed = 0;
-  print.prev = 0;
-  print.map = 0;
-
-  /* Open the output now.  We must do so even if no_output is on,
-     because there may be other output than from the actual
-     preprocessing (e.g. from -dM).  */
-  if (options->out_fname[0] == '\0')
-    print.outf = stdout;
-  else
-    {
-      print.outf = fopen (options->out_fname, "w");
-      if (print.outf == NULL)
-       {
-         cpp_notice_from_errno (pfile, options->out_fname);
-         return;
-       }
-    }
+  pfile->print.line = (unsigned int) -1;
+  pfile->print.printed = 0;
+  pfile->print.prev = 0;
+  pfile->print.map = 0;
+  pfile->print.outf = out_stream;
 
-  setup_callbacks ();
+  setup_callbacks (pfile);
 
-  if (cpp_read_main_file (pfile, options->in_fname, NULL))
+  if (cpp_read_main_file (pfile, in_fname, NULL))
     {
+      cpp_options *options = &pfile->opts;
       cpp_finish_options (pfile);
 
       /* A successful cpp_read_main_file guarantees that we can call
         cpp_scan_nooutput or cpp_get_token next.  */
       if (options->no_output)
-       cpp_scan_nooutput (pfile);
+       {
+         /* Scan -included buffers, then the main file.  */
+         while (pfile->buffer->prev)
+           cpp_scan_nooutput (pfile);
+         cpp_scan_nooutput (pfile);
+       }
+      else if (options->traditional)
+       scan_translation_unit_trad (pfile);
       else
        scan_translation_unit (pfile);
 
       /* -dM command line option.  Should this be in cpp_finish?  */
       if (options->dump_macros == dump_only)
        cpp_forall_identifiers (pfile, dump_macro, NULL);
-
-      cpp_finish (pfile);
     }
 
   /* Flush any pending output.  */
-  if (print.printed)
-    putc ('\n', print.outf);
-
-  if (ferror (print.outf) || fclose (print.outf))
-    cpp_notice_from_errno (pfile, options->out_fname);
+  if (pfile->print.printed)
+    putc ('\n', pfile->print.outf);
 }
 
 /* Set up the callbacks as appropriate.  */
 static void
-setup_callbacks ()
+setup_callbacks (pfile)
+     cpp_reader *pfile;
 {
+  cpp_options *options = &pfile->opts;
   cpp_callbacks *cb = cpp_get_callbacks (pfile);
 
   if (! options->no_output)
@@ -223,7 +140,7 @@ scan_translation_unit (pfile)
 {
   bool avoid_paste = false;
 
-  print.source = NULL;
+  pfile->print.source = NULL;
   for (;;)
     {
       const cpp_token *token = cpp_get_token (pfile);
@@ -231,10 +148,10 @@ scan_translation_unit (pfile)
       if (token->type == CPP_PADDING)
        {
          avoid_paste = true;
-         if (print.source == NULL
-             || (!(print.source->flags & PREV_WHITE)
+         if (pfile->print.source == NULL
+             || (!(pfile->print.source->flags & PREV_WHITE)
                  && token->val.source == NULL))
-           print.source = token->val.source;
+           pfile->print.source = token->val.source;
          continue;
        }
 
@@ -244,84 +161,102 @@ scan_translation_unit (pfile)
       /* Subtle logic to output a space if and only if necessary.  */
       if (avoid_paste)
        {
-         if (print.source == NULL)
-           print.source = token;
-         if (print.source->flags & PREV_WHITE
-             || (print.prev && cpp_avoid_paste (pfile, print.prev, token))
-             || (print.prev == NULL && token->type == CPP_HASH))
-           putc (' ', print.outf);
+         if (pfile->print.source == NULL)
+           pfile->print.source = token;
+         if (pfile->print.source->flags & PREV_WHITE
+             || (pfile->print.prev
+                 && cpp_avoid_paste (pfile, pfile->print.prev, token))
+             || (pfile->print.prev == NULL && token->type == CPP_HASH))
+           putc (' ', pfile->print.outf);
        }
       else if (token->flags & PREV_WHITE)
-       putc (' ', print.outf);
+       putc (' ', pfile->print.outf);
 
       avoid_paste = false;
-      print.source = NULL;
-      print.prev = token;
-      cpp_output_token (token, print.outf);
+      pfile->print.source = NULL;
+      pfile->print.prev = token;
+      cpp_output_token (token, pfile->print.outf);
 
-      if (token->type == CPP_STRING || token->type == CPP_WSTRING
-         || token->type == CPP_COMMENT
+      if (token->type == CPP_COMMENT
          /* SDCC _asm specific */
          || token->type == CPP_ASM)
-       check_multiline_token (&token->val.str);
+       account_for_newlines (pfile, token->val.str.text, token->val.str.len);
     }
 }
 
-/* Adjust print.line for newlines embedded in tokens.  */
+/* Adjust pfile->print.line for newlines embedded in output.  */
 static void
-check_multiline_token (str)
-     const cpp_string *str;
+account_for_newlines (pfile, str, len)
+     cpp_reader *pfile;
+     const uchar *str;
+     size_t len;
 {
-  unsigned int i;
+  while (len--)
+    if (*str++ == '\n')
+      pfile->print.line++;
+}
 
-  for (i = 0; i < str->len; i++)
-    if (str->text[i] == '\n')
-      print.line++;
+/* Writes out a traditionally preprocessed file.  */
+static void
+scan_translation_unit_trad (pfile)
+     cpp_reader *pfile;
+{
+  while (_cpp_read_logical_line_trad (pfile))
+    {
+      size_t len = pfile->out.cur - pfile->out.base;
+      maybe_print_line (pfile, pfile->print.map, pfile->out.first_line);
+      fwrite (pfile->out.base, 1, len, pfile->print.outf);
+      pfile->print.printed = 1;
+      if (!CPP_OPTION (pfile, discard_comments))
+       account_for_newlines (pfile, pfile->out.base, len);
+    }
 }
 
 /* If the token read on logical line LINE needs to be output on a
    different line to the current one, output the required newlines or
    a line marker, and return 1.  Otherwise return 0.  */
 static void
-maybe_print_line (map, line)
+maybe_print_line (pfile, map, line)
+     cpp_reader *pfile;
      const struct line_map *map;
      unsigned int line;
 {
   /* End the previous line of text.  */
-  if (print.printed)
+  if (pfile->print.printed)
     {
-      putc ('\n', print.outf);
-      print.line++;
-      print.printed = 0;
+      putc ('\n', pfile->print.outf);
+      pfile->print.line++;
+      pfile->print.printed = 0;
     }
 
-  if (line >= print.line && line < print.line + 8)
+  if (line >= pfile->print.line && line < pfile->print.line + 8)
     {
-      while (line > print.line)
+      while (line > pfile->print.line)
        {
-         putc ('\n', print.outf);
-         print.line++;
+         putc ('\n', pfile->print.outf);
+         pfile->print.line++;
        }
     }
   else
-    print_line (map, line, "");
+    print_line (pfile, map, line, "");
 }
 
 /* Output a line marker for logical line LINE.  Special flags are "1"
    or "2" indicating entering or leaving a file.  */
 static void
-print_line (map, line, special_flags)
+print_line (pfile, map, line, special_flags)
+     cpp_reader *pfile;
      const struct line_map *map;
      unsigned int line;
      const char *special_flags;
 {
   /* End any previous line of text.  */
-  if (print.printed)
-    putc ('\n', print.outf);
-  print.printed = 0;
+  if (pfile->print.printed)
+    putc ('\n', pfile->print.outf);
+  pfile->print.printed = 0;
 
-  print.line = line;
-  if (! options->no_line_commands)
+  pfile->print.line = line;
+  if (! CPP_OPTION (pfile, no_line_commands))
     {
       size_t to_file_len = strlen (map->to_file);
       unsigned char *to_file_quoted = alloca (to_file_len * 4 + 1);
@@ -332,15 +267,16 @@ print_line (map, line, special_flags)
       p = cpp_quote_string (to_file_quoted,
                            (unsigned char *)map->to_file, to_file_len);
       *p = '\0';
-      fprintf (print.outf, "# %u \"%s\"%s",
-              SOURCE_LINE (map, print.line), to_file_quoted, special_flags);
+      fprintf (pfile->print.outf, "# %u \"%s\"%s",
+              SOURCE_LINE (map, pfile->print.line),
+              to_file_quoted, special_flags);
 
       if (map->sysp == 2)
-       fputs (" 3 4", print.outf);
+       fputs (" 3 4", pfile->print.outf);
       else if (map->sysp == 1)
-       fputs (" 3", print.outf);
+       fputs (" 3", pfile->print.outf);
 
-      putc ('\n', print.outf);
+      putc ('\n', pfile->print.outf);
     }
 }
 
@@ -348,41 +284,44 @@ print_line (map, line, special_flags)
    of the line, and at end of file will be CPP_EOF.  */
 static void
 cb_line_change (pfile, token, parsing_args)
-     cpp_reader *pfile ATTRIBUTE_UNUSED;
+     cpp_reader *pfile;
      const cpp_token *token;
      int parsing_args;
 {
   if (token->type == CPP_EOF || parsing_args)
     return;
 
-  maybe_print_line (print.map, token->line);
-  print.printed = 1;
-  print.prev = 0;
-  print.source = 0;
+  maybe_print_line (pfile, pfile->print.map, token->line);
+  pfile->print.prev = 0;
+  pfile->print.source = 0;
 
   /* Supply enough spaces to put this token in its original column,
      one space per column greater than 2, since scan_translation_unit
      will provide a space if PREV_WHITE.  Don't bother trying to
      reconstruct tabs; we can't get it right in general, and nothing
      ought to care.  Some things do care; the fault lies with them.  */
-  if (token->col > 2)
+  if (!CPP_OPTION (pfile, traditional))
     {
-      unsigned int spaces = token->col - 2;
+      pfile->print.printed = 1;
+      if (token->col > 2)
+       {
+         unsigned int spaces = token->col - 2;
 
-      while (spaces--)
-       putc (' ', print.outf);
+         while (spaces--)
+           putc (' ', pfile->print.outf);
+       }
     }
 }
 
 static void
 cb_ident (pfile, line, str)
-     cpp_reader *pfile ATTRIBUTE_UNUSED;
+     cpp_reader *pfile;
      unsigned int line;
      const cpp_string * str;
 {
-  maybe_print_line (print.map, line);
-  fprintf (print.outf, "#ident \"%s\"\n", str->text);
-  print.line++;
+  maybe_print_line (pfile, pfile->print.map, line);
+  fprintf (pfile->print.outf, "#ident \"%s\"\n", str->text);
+  pfile->print.line++;
 }
 
 static void
@@ -391,28 +330,29 @@ cb_define (pfile, line, node)
      unsigned int line;
      cpp_hashnode *node;
 {
-  maybe_print_line (print.map, line);
-  fputs ("#define ", print.outf);
+  maybe_print_line (pfile, pfile->print.map, line);
+  fputs ("#define ", pfile->print.outf);
 
   /* -dD command line option.  */
-  if (options->dump_macros == dump_definitions)
-    fputs ((const char *) cpp_macro_definition (pfile, node), print.outf);
+  if (CPP_OPTION (pfile, dump_macros) == dump_definitions)
+    fputs ((const char *) cpp_macro_definition (pfile, node),
+          pfile->print.outf);
   else
-    fputs ((const char *) NODE_NAME (node), print.outf);
+    fputs ((const char *) NODE_NAME (node), pfile->print.outf);
 
-  putc ('\n', print.outf);
-  print.line++;
+  putc ('\n', pfile->print.outf);
+  pfile->print.line++;
 }
 
 static void
 cb_undef (pfile, line, node)
-     cpp_reader *pfile ATTRIBUTE_UNUSED;
+     cpp_reader *pfile;
      unsigned int line;
      cpp_hashnode *node;
 {
-  maybe_print_line (print.map, line);
-  fprintf (print.outf, "#undef %s\n", NODE_NAME (node));
-  print.line++;
+  maybe_print_line (pfile, pfile->print.map, line);
+  fprintf (pfile->print.outf, "#undef %s\n", NODE_NAME (node));
+  pfile->print.line++;
 }
 
 static void
@@ -422,43 +362,44 @@ cb_include (pfile, line, dir, header)
      const unsigned char *dir;
      const cpp_token *header;
 {
-  maybe_print_line (print.map, line);
-  fprintf (print.outf, "#%s %s\n", dir, cpp_token_as_text (pfile, header));
-  print.line++;
+  maybe_print_line (pfile, pfile->print.map, line);
+  fprintf (pfile->print.outf, "#%s %s\n", dir,
+          cpp_token_as_text (pfile, header));
+  pfile->print.line++;
 }
 
 /* The file name, line number or system header flags have changed, as
-   described in MAP.  From this point on, the old print.map might be
+   described in MAP.  From this point on, the old pfile->print.map might be
    pointing to freed memory, and so must not be dereferenced.  */
 
 static void
 cb_file_change (pfile, map)
-     cpp_reader *pfile ATTRIBUTE_UNUSED;
+     cpp_reader *pfile;
      const struct line_map *map;
 {
   const char *flags = "";
 
   /* First time?  */
-  if (print.map == NULL)
+  if (pfile->print.map == NULL)
     {
       /* Avoid printing foo.i when the main file is foo.c.  */
-      if (!options->preprocessed)
-       print_line (map, map->from_line, flags);
+      if (!CPP_OPTION (pfile, preprocessed))
+       print_line (pfile, map, map->from_line, flags);
     }
   else
     {
       /* Bring current file to correct line when entering a new file.  */
       if (map->reason == LC_ENTER)
-       maybe_print_line (map - 1, map->from_line - 1);
+       maybe_print_line (pfile, map - 1, map->from_line - 1);
 
       if (map->reason == LC_ENTER)
        flags = " 1";
       else if (map->reason == LC_LEAVE)
        flags = " 2";
-      print_line (map, map->from_line, flags);
+      print_line (pfile, map, map->from_line, flags);
     }
 
-  print.map = map;
+  pfile->print.map = map;
 }
 
 /* Copy a #pragma directive to the preprocessed output.  */
@@ -467,15 +408,10 @@ cb_def_pragma (pfile, line)
      cpp_reader *pfile;
      unsigned int line;
 {
-  maybe_print_line (print.map, line);
-  fputs ("#pragma ", print.outf);
-  cpp_output_line (pfile, print.outf);
-  print.line++;
-}
-
-void
-cpp_output_string (const char *s) {
-  fputs (s, print.outf);
+  maybe_print_line (pfile, pfile->print.map, line);
+  fputs ("#pragma ", pfile->print.outf);
+  cpp_output_line (pfile, pfile->print.outf);
+  pfile->print.line++;
 }
 
 /* Dump out the hash table.  */
@@ -487,10 +423,11 @@ dump_macro (pfile, node, v)
 {
   if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN))
     {
-      fputs ("#define ", print.outf);
-      fputs ((const char *) cpp_macro_definition (pfile, node), print.outf);
-      putc ('\n', print.outf);
-      print.line++;
+      fputs ("#define ", pfile->print.outf);
+      fputs ((const char *) cpp_macro_definition (pfile, node),
+            pfile->print.outf);
+      putc ('\n', pfile->print.outf);
+      pfile->print.line++;
     }
 
   return 1;
index 883a2b1865a08ff97a7d6780aa8fe2b354b04a6b..320552c5b7c5251dd9df4f0eee3cb210339b3c06 100644 (file)
@@ -83,18 +83,9 @@ extern void expand_eh_region_end_throw               PARAMS ((tree));
    destroying an object twice.  */
 extern void expand_eh_region_end_fixup         PARAMS ((tree));
 
-/* Begin a region that will contain entries created with
-   add_partial_entry.  */
-extern void begin_protect_partials              PARAMS ((void));
-
-/* Create a new exception region and add the handler for the region
-   onto a list. These regions will be ended (and their handlers emitted)
-   when end_protect_partials is invoked.  */
-extern void add_partial_entry                  PARAMS ((tree));
-
-/* End all of the pending exception regions that have handlers added with
-   add_partial_entry.  */
-extern void end_protect_partials               PARAMS ((void));
+/* Note that the current EH region (if any) may contain a throw, or a
+   call to a function which itself may contain a throw.  */
+extern void note_eh_region_may_contain_throw    PARAMS ((void));
 
 /* Invokes CALLBACK for every exception handler label.  Only used by old
    loop hackery; should not be used by new code.  */
@@ -104,8 +95,8 @@ extern void for_each_eh_label                        PARAMS ((void (*) (rtx)));
 extern bool can_throw_internal                 PARAMS ((rtx));
 extern bool can_throw_external                 PARAMS ((rtx));
 
-/* Return nonzero if nothing in this function can throw.  */
-extern bool nothrow_function_p                 PARAMS ((void));
+/* Set current_function_nothrow and cfun->all_throwers_are_sibcalls.  */
+extern void set_nothrow_function_flags         PARAMS ((void));
 
 /* After initial rtl generation, call back to finish generating
    exception support code.  */
@@ -128,7 +119,7 @@ extern rtx expand_builtin_eh_return_data_regno      PARAMS ((tree));
 extern rtx expand_builtin_extract_return_addr  PARAMS ((tree));
 extern void expand_builtin_init_dwarf_reg_sizes PARAMS ((tree));
 extern rtx expand_builtin_frob_return_addr     PARAMS ((tree));
-extern rtx expand_builtin_dwarf_fp_regnum      PARAMS ((void));
+extern rtx expand_builtin_dwarf_sp_column      PARAMS ((void));
 extern void expand_builtin_eh_return           PARAMS ((tree, tree));
 extern void expand_eh_return                   PARAMS ((void));
 extern rtx get_exception_pointer               PARAMS ((struct function *));
@@ -164,7 +155,6 @@ extern tree (*lang_eh_runtime_type) PARAMS ((tree));
 #if ! (defined (EH_RETURN_DATA_REGNO)                  \
        && (defined (IA64_UNWIND_INFO)                  \
           || (DWARF2_UNWIND_INFO                       \
-              && defined (EH_RETURN_STACKADJ_RTX)      \
               && (defined (EH_RETURN_HANDLER_RTX)      \
                   || defined (HAVE_eh_return)))))
 #define MUST_USE_SJLJ_EXCEPTIONS       1
@@ -181,9 +171,6 @@ extern tree (*lang_eh_runtime_type) PARAMS ((tree));
 #  ifndef EH_RETURN_DATA_REGNO
     #error "EH_RETURN_DATA_REGNO required"
 #  endif
-#  ifndef EH_RETURN_STACKADJ_RTX
-    #error "EH_RETURN_STACKADJ_RTX required"
-#  endif
 #  if !defined(EH_RETURN_HANDLER_RTX) && !defined(HAVE_eh_return)
     #error "EH_RETURN_HANDLER_RTX or eh_return required"
 #  endif
index 665b3bcf49accb74b487f5917c602d0625d08e92..b1d5b2d06c7657c29231153b0c15048a35f83316 100644 (file)
@@ -45,7 +45,7 @@ static void ht_expand PARAMS ((hash_table *));
 #define OBSTACK_CHUNK_FREE free
 #endif
 
-/* Initialise an obstack.  */
+/* Initialize an obstack.  */
 void
 gcc_obstack_init (obstack)
      struct obstack *obstack;
@@ -141,7 +141,8 @@ ht_lookup (table, str, len, insert)
       if (node == NULL)
        break;
 
-      if (HT_LEN (node) == len && !memcmp (HT_STR (node), str, len))
+      if (node->hash_value == hash && HT_LEN (node) == len
+          && !memcmp (HT_STR (node), str, len))
        {
          if (insert == HT_ALLOCED)
            /* The string we search for was placed at the end of the
@@ -161,6 +162,7 @@ ht_lookup (table, str, len, insert)
   table->entries[index] = node;
 
   HT_LEN (node) = len;
+  node->hash_value = hash;
   if (insert == HT_ALLOC)
     HT_STR (node) = obstack_copy0 (&table->stack, str, len);
   else
@@ -193,7 +195,7 @@ ht_expand (table)
       {
        unsigned int index, hash, hash2;
 
-       hash = calc_hash (HT_STR (*p), HT_LEN (*p));
+       hash = (*p)->hash_value;
        hash2 = ((hash * 17) & sizemask) | 1;
        index = hash & sizemask;
 
index f4708983cca3ad79620cd7e568e5f0020b967913..c3e0d1ee10aeae7f683aa0f1af261f0cf8ad1a7e 100644 (file)
@@ -27,10 +27,11 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 /* This is what each hash table entry points to.  It may be embedded
    deeply within another object.  */
 typedef struct ht_identifier ht_identifier;
-struct ht_identifier
+struct ht_identifier GTY(())
 {
-  unsigned int len;
   const unsigned char *str;
+  unsigned int len;
+  unsigned int hash_value;
 };
 
 #define HT_LEN(NODE) ((NODE)->len)
@@ -69,7 +70,7 @@ struct ht
 
 extern void gcc_obstack_init PARAMS ((struct obstack *));
 
-/* Initialise the hashtable with 2 ^ order entries.  */
+/* Initialize the hashtable with 2 ^ order entries.  */
 extern hash_table *ht_create PARAMS ((unsigned int order));
 
 /* Frees all memory associated with a hash table.  */
index 57d7edfadf59f79cfb5e5a531da13d9c39f3f7a2..6d645a00ea7c9cfa6009603fd47d1d851c07c900 100644 (file)
@@ -1,5 +1,5 @@
 /* HOST_WIDE_INT definitions for the GNU compiler.
-   Copyright (C) 1998 Free Software Foundation, Inc.
+   Copyright (C) 1998, 2002 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
 #ifndef HOST_WIDE_INT_PRINT_DEC
 # if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
 #  define HOST_WIDE_INT_PRINT_DEC "%d"
+#  define HOST_WIDE_INT_PRINT_DEC_C "%d"
+#  define HOST_WIDE_INT_PRINT_DEC_SPACE "% *d"
 # else
 #  if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
 #   define HOST_WIDE_INT_PRINT_DEC "%ld"
+#   define HOST_WIDE_INT_PRINT_DEC_C "%ldL"
+#   define HOST_WIDE_INT_PRINT_DEC_SPACE "% *ld"
 #  else
 #   define HOST_WIDE_INT_PRINT_DEC "%lld"
+#   define HOST_WIDE_INT_PRINT_DEC_C "%lldLL"
+#   define HOST_WIDE_INT_PRINT_DEC_SPACE "% *lld"
 #  endif
 # endif
 #endif /* ! HOST_WIDE_INT_PRINT_DEC */
 #ifndef HOST_WIDE_INT_PRINT_UNSIGNED
 # if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
 #  define HOST_WIDE_INT_PRINT_UNSIGNED "%u"
+#  define HOST_WIDE_INT_PRINT_UNSIGNED_SPACE "% *u"
 # else
 #  if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
 #   define HOST_WIDE_INT_PRINT_UNSIGNED "%lu"
+#   define HOST_WIDE_INT_PRINT_UNSIGNED_SPACE "% *lu"
 #  else
 #   define HOST_WIDE_INT_PRINT_UNSIGNED "%llu"
+#   define HOST_WIDE_INT_PRINT_UNSIGNED_SPACE "% *llu"
 #  endif
 # endif
 #endif /* ! HOST_WIDE_INT_PRINT_UNSIGNED */
 #   define HOST_BITS_PER_WIDEST_INT HOST_BITS_PER_LONGLONG
 #   define HOST_WIDEST_INT long long
 #   define HOST_WIDEST_INT_PRINT_DEC "%lld"
+#   define HOST_WIDEST_INT_PRINT_DEC_SPACE "% *lld"
 #   define HOST_WIDEST_INT_PRINT_UNSIGNED "%llu"
+#   define HOST_WIDEST_INT_PRINT_UNSIGNED_SPACE "% *llu"
 #   define HOST_WIDEST_INT_PRINT_HEX "0x%llx"
 #  else
 #   define HOST_BITS_PER_WIDEST_INT HOST_BITS_PER_LONG
 #   define HOST_WIDEST_INT long
 #   define HOST_WIDEST_INT_PRINT_DEC "%ld"
+#   define HOST_WIDEST_INT_PRINT_DEC_SPACE "% *ld"
 #   define HOST_WIDEST_INT_PRINT_UNSIGNED "%lu"
+#   define HOST_WIDEST_INT_PRINT_UNSIGNED_SPACE "% *lu"
 #   define HOST_WIDEST_INT_PRINT_HEX "0x%lx"
 # endif /* long long wider than long */
 #endif /* ! HOST_WIDEST_INT */
index 835cb3177531f459d5a30026a49a32d72b026c53..60201887f491fd9826c5e4733ed909e22a81d0ce 100644 (file)
@@ -109,7 +109,7 @@ extern void print_containing_files
 /* Returns the map a given map was included from.  */
 #define INCLUDED_FROM(SET, MAP) (&(SET)->maps[(MAP)->included_from])
 
-/* Non-zero if the map is at the bottom of the include stack.  */
+/* Nonzero if the map is at the bottom of the include stack.  */
 #define MAIN_FILE_P(MAP) ((MAP)->included_from < 0)
 
 /* The current line map.  Saves a call to lookup_line if the caller is
index 5c86dbf86988cc90399c51d31f855256f269e891..42517369d706caafd75e93ccdf022f2302b17712 100644 (file)
@@ -51,7 +51,7 @@ typedef enum {COPYA, COPYJ, COPYJ2, MAKE_A, MAKE_J, NOOP,
    Thus, maximum returned length is:
      2 (switch to JIS) + 2 (JIS characters) + 2 (switch back to ASCII) = 6.  */
 
-static JIS_STATE JIS_state_table[JIS_S_NUM][JIS_C_NUM] = {
+static const JIS_STATE JIS_state_table[JIS_S_NUM][JIS_C_NUM] = {
 /*            ESCAPE DOLLAR   BRACKET   AT     B      J     NUL JIS_CHAR OTH*/
 /*ASCII*/   { A_ESC, ASCII,   ASCII,    ASCII, ASCII, ASCII, ASCII,ASCII,ASCII},
 /*A_ESC*/   { ASCII, A_ESC_DL,ASCII,    ASCII, ASCII, ASCII, ASCII,ASCII,ASCII},
@@ -65,7 +65,7 @@ static JIS_STATE JIS_state_table[JIS_S_NUM][JIS_C_NUM] = {
 /*J2_ESC_BR*/{INV,   INV,     INV,      INV,   ASCII, ASCII, INV,  INV,  INV },
 };
 
-static JIS_ACTION JIS_action_table[JIS_S_NUM][JIS_C_NUM] = {
+static const JIS_ACTION JIS_action_table[JIS_S_NUM][JIS_C_NUM] = {
 /*            ESCAPE DOLLAR BRACKET AT     B       J      NUL  JIS_CHAR OTH */
 /*ASCII */   {NOOP,  COPYA, COPYA, COPYA,  COPYA,  COPYA, EMPTY, COPYA, COPYA},
 /*A_ESC */   {COPYA, NOOP,  COPYA, COPYA,  COPYA,  COPYA, COPYA, COPYA, COPYA},
index fb76670ad1a837f6267ec3647ddf961483418ad5..d533b889605b20227ee73fc5485b623d464ccea8 100644 (file)
@@ -47,7 +47,7 @@ static const char *munge      PARAMS ((const char *));
    not properly handled.  It isn't possible to get this right in any
    current version of Make.  (??? Still true?  Old comment referred to
    3.76.1.)  */
-
+   
 static const char *
 munge (filename)
      const char *filename;
@@ -215,12 +215,12 @@ deps_add_default_target (pfile, tgt)
       o = (char *) alloca (strlen (start) + strlen (obj_ext) + 1);
 
       strcpy (o, start);
-
+      
       suffix = strrchr (o, '.');
       if (!suffix)
         suffix = o + strlen (o);
       strcpy (suffix, obj_ext);
-
+      
       deps_add_target (d, o, 1);
     }
 }
@@ -292,7 +292,7 @@ deps_write (d, fp, colmax)
     }
   putc ('\n', fp);
 }
-
+  
 void
 deps_phony_targets (d, fp)
      const struct deps *d;
index 0e11df3c833f5c7a6d0a161d93fd3a4f5bcb73fa..0f089719082198b56c2a631620cb0799507e166c 100644 (file)
@@ -46,7 +46,6 @@ extern int dbr_sequence_length        PARAMS ((void));
 /* Indicate that branch shortening hasn't yet been done.  */
 extern void init_insn_lengths  PARAMS ((void));
 
-#ifdef RTX_CODE
 /* Obtain the current length of an insn.  If branch shortening has been done,
    get its actual length.  Otherwise, get its maximum length.  */
 extern int get_attr_length     PARAMS ((rtx));
@@ -119,7 +118,7 @@ extern void split_double    PARAMS ((rtx, rtx *, rtx *));
 /* Return nonzero if this function has no function calls.  */
 extern int leaf_function_p     PARAMS ((void));
 
-/* Return 1 if branch is an forward branch.
+/* Return 1 if branch is a forward branch.
    Uses insn_shuid array, so it works only in the final pass.  May be used by
    output templates to add branch prediction hints, for example.  */
 extern int final_forward_branch_p PARAMS ((rtx));
@@ -137,7 +136,7 @@ extern const char *get_insn_template PARAMS ((int, rtx));
 
 /* Add function NAME to the weak symbols list.  VALUE is a weak alias
    associated with NAME.  */
-extern int add_weak PARAMS ((const char *, const char *));
+extern int add_weak PARAMS ((tree, const char *, const char *));
 
 /* Functions in flow.c */
 extern void allocate_for_life_analysis PARAMS ((void));
@@ -145,8 +144,8 @@ extern int regno_uninitialized              PARAMS ((unsigned int));
 extern int regno_clobbered_at_setjmp   PARAMS ((int));
 extern void find_basic_blocks          PARAMS ((rtx, int, FILE *));
 extern bool cleanup_cfg                        PARAMS ((int));
+extern bool delete_unreachable_blocks  PARAMS ((void));
 extern void check_function_return_warnings PARAMS ((void));
-#endif
 
 /* Functions in varasm.c.  */
 
@@ -210,7 +209,6 @@ extern void sdata_section PARAMS ((void));
 extern void rdata_section PARAMS ((void));
 #endif
 
-#ifdef TREE_CODE
 /* Tell assembler to change to section NAME for DECL.
    If DECL is NULL, just switch to section NAME.
    If NAME is NULL, get the name from DECL.
@@ -233,7 +231,6 @@ extern void mergeable_constant_section      PARAMS ((enum machine_mode,
 extern void declare_weak               PARAMS ((tree));
 /* Merge weak status.  */
 extern void merge_weak                 PARAMS ((tree, tree));
-#endif /* TREE_CODE */
 
 /* Emit any pending weak declarations.  */
 extern void weak_finish                        PARAMS ((void));
@@ -247,7 +244,6 @@ extern void weak_finish                     PARAMS ((void));
    Prefixes such as % are optional.  */
 extern int decode_reg_name             PARAMS ((const char *));
 
-#ifdef TREE_CODE
 /* Make the rtl for variable VAR be volatile.
    Use this only for static variables.  */
 extern void make_var_volatile          PARAMS ((tree));
@@ -257,6 +253,8 @@ extern void assemble_constant_align PARAMS ((tree));
 
 extern void assemble_alias             PARAMS ((tree, tree));
 
+extern void default_assemble_visibility        PARAMS ((tree, int));
+
 /* Output a string of literal assembler code
    for an `asm' keyword used between functions.  */
 extern void assemble_asm               PARAMS ((tree));
@@ -286,7 +284,6 @@ extern void assemble_variable               PARAMS ((tree, int, int, int));
    (Most assemblers don't need this, so we normally output nothing.)
    Do nothing if DECL is not external.  */
 extern void assemble_external          PARAMS ((tree));
-#endif /* TREE_CODE */
 
 /* Assemble code to leave SIZE bytes of zeros.  */
 extern void assemble_zeros             PARAMS ((int));
@@ -298,13 +295,8 @@ extern void assemble_eh_align              PARAMS ((int));
 /* Assemble a string constant with the specified C string as contents.  */
 extern void assemble_string            PARAMS ((const char *, int));
 
-#ifdef RTX_CODE
 /* Similar, for calling a library function FUN.  */
 extern void assemble_external_libcall  PARAMS ((rtx));
-#endif
-
-/* Declare the label NAME global.  */
-extern void assemble_global            PARAMS ((const char *));
 
 /* Assemble a label named NAME.  */
 extern void assemble_label             PARAMS ((const char *));
@@ -326,7 +318,6 @@ extern void assemble_name           PARAMS ((FILE *, const char *));
    be followed immediately by the object's initial value.  */
 extern const char *integer_asm_op      PARAMS ((int, int));
 
-#ifdef RTX_CODE
 /* Use directive OP to assemble an integer object X.  Print OP at the
    start of the line, followed immediately by the value of X.  */
 extern void assemble_integer_with_op   PARAMS ((const char *, rtx));
@@ -336,7 +327,7 @@ extern bool default_assemble_integer        PARAMS ((rtx, unsigned int, int));
 
 /* Assemble the integer constant X into an object of SIZE bytes.  ALIGN is
    the alignment of the integer in bits.  Return 1 if we were able to output
-   the constant, otherwise 0.  If FORCE is non-zero, abort if we can't output
+   the constant, otherwise 0.  If FORCE is nonzero, abort if we can't output
    the constant.  */
 extern bool assemble_integer           PARAMS ((rtx, unsigned, unsigned, int));
 
@@ -346,18 +337,12 @@ extern bool assemble_integer              PARAMS ((rtx, unsigned, unsigned, int));
 #define assemble_aligned_integer(SIZE, VALUE) \
   assemble_integer (VALUE, SIZE, (SIZE) * BITS_PER_UNIT, 1)
 
-#ifdef REAL_VALUE_TYPE
+#ifdef REAL_VALUE_TYPE_SIZE
 /* Assemble the floating-point constant D into an object of size MODE.  */
 extern void assemble_real              PARAMS ((REAL_VALUE_TYPE,
                                                 enum machine_mode,
                                                 unsigned));
 #endif
-#endif
-
-/* At the end of a function, forget the memory-constants
-   previously made for CONST_DOUBLEs.  Mark them as not on real_constant_chain.
-   Also clear out real_constant_chain and clear out all the chain-pointers.  */
-extern void clear_const_double_mem     PARAMS ((void));
 
 /* Start deferring output of subconstants.  */
 extern void defer_addressed_constants  PARAMS ((void));
@@ -373,7 +358,6 @@ extern int get_pool_size            PARAMS ((void));
 extern rtx peephole                    PARAMS ((rtx));
 #endif
 
-#ifdef TREE_CODE
 /* Write all the constants in the constant pool.  */
 extern void output_constant_pool       PARAMS ((const char *, tree));
 
@@ -398,9 +382,7 @@ extern tree initializer_constant_valid_p    PARAMS ((tree, tree));
    ALIGN is the alignment in bits that may be assumed for the data.  */
 extern void output_constant            PARAMS ((tree, HOST_WIDE_INT,
                                                 unsigned int));
-#endif
 
-#ifdef RTX_CODE
 /* When outputting delayed branch sequences, this rtx holds the
    sequence being output.  It is null when no delayed branch
    sequence is being output, so it can be used as a test in the
@@ -408,7 +390,6 @@ extern void output_constant         PARAMS ((tree, HOST_WIDE_INT,
 
    This variable is defined  in final.c.  */
 extern rtx final_sequence;
-#endif
 
 /* The line number of the beginning of the current function.  Various
    md code needs this so that it can output relative linenumbers.  */
@@ -465,28 +446,19 @@ extern struct rtx_def *current_insn_predicate;
 /* Last insn processed by final_scan_insn.  */
 extern struct rtx_def *current_output_insn;
 
-/* Decide whether DECL needs to be in a writable section.  RELOC is the same
-   as for SELECT_SECTION.  */
+/* Nonzero while outputting an `asm' with operands.
+   This means that inconsistencies are the user's fault, so don't abort.
+   The precise value is the insn being output, to pass to error_for_asm.  */
+extern rtx this_is_asm_operands;
 
-#define DECL_READONLY_SECTION(DECL,RELOC)              \
-  (TREE_READONLY (DECL)                                        \
-   && ! TREE_THIS_VOLATILE (DECL)                      \
-   && DECL_INITIAL (DECL)                              \
-   && (DECL_INITIAL (DECL) == error_mark_node          \
-       || TREE_CONSTANT (DECL_INITIAL (DECL)))         \
-   && ! (RELOC && (flag_pic || DECL_ONE_ONLY (DECL))))
+/* Decide whether DECL needs to be in a writable section.
+   RELOC is the same as for SELECT_SECTION.  */
+extern bool decl_readonly_section PARAMS ((tree, int));
+extern bool decl_readonly_section_1 PARAMS ((tree, int, int));
 
 /* User label prefix in effect for this compilation.  */
 extern const char *user_label_prefix;
 
-/* This macro gets just the user-specified name
-   out of the string in a SYMBOL_REF.  On most machines,
-   we discard the * if any and that's all.  */
-#ifndef STRIP_NAME_ENCODING
-#define STRIP_NAME_ENCODING(VAR,SYMBOL_NAME) \
-  (VAR) = ((SYMBOL_NAME) + ((SYMBOL_NAME)[0] == '*'))
-#endif
-
 /* Default target function prologue and epilogue assembler output.  */
 extern void default_function_pro_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
 
@@ -512,7 +484,9 @@ extern void no_asm_to_stream PARAMS ((FILE *));
 #define SECTION_STRINGS  0x10000       /* contains zero terminated strings without
                                           embedded zeros */
 #define SECTION_OVERRIDE 0x20000       /* allow override of default flags */
-#define SECTION_MACH_DEP 0x40000       /* subsequent bits reserved for target */
+#define SECTION_TLS     0x40000        /* contains thread-local storage */
+#define SECTION_NOTYPE  0x80000        /* don't output @progbits */
+#define SECTION_MACH_DEP 0x100000      /* subsequent bits reserved for target */
 
 extern unsigned int get_named_section_flags PARAMS ((const char *));
 extern bool set_named_section_flags    PARAMS ((const char *, unsigned int));
@@ -522,6 +496,9 @@ extern bool named_section_first_declaration PARAMS((const char *));
 union tree_node;
 extern unsigned int default_section_type_flags PARAMS ((union tree_node *,
                                                        const char *, int));
+extern unsigned int default_section_type_flags_1 PARAMS ((union tree_node *,
+                                                         const char *,
+                                                         int, int));
 
 extern void default_no_named_section PARAMS ((const char *, unsigned int));
 extern void default_elf_asm_named_section PARAMS ((const char *, unsigned int));
@@ -540,6 +517,23 @@ extern void default_named_section_asm_out_constructor PARAMS ((struct rtx_def *,
 extern void default_ctor_section_asm_out_constructor PARAMS ((struct rtx_def *,
                                                              int));
 
+extern void default_select_section PARAMS ((tree, int,
+                                           unsigned HOST_WIDE_INT));
+extern void default_elf_select_section PARAMS ((tree, int,
+                                               unsigned HOST_WIDE_INT));
+extern void default_elf_select_section_1 PARAMS ((tree, int,
+                                                 unsigned HOST_WIDE_INT, int));
+extern void default_unique_section PARAMS ((tree, int));
+extern void default_unique_section_1 PARAMS ((tree, int, int));
+extern void default_select_rtx_section PARAMS ((enum machine_mode, rtx,
+                                               unsigned HOST_WIDE_INT));
+extern void default_elf_select_rtx_section PARAMS ((enum machine_mode, rtx,
+                                                   unsigned HOST_WIDE_INT));
+extern const char *default_strip_name_encoding PARAMS ((const char *));
+extern bool default_binds_local_p PARAMS ((tree));
+extern bool default_binds_local_p_1 PARAMS ((tree, int));
+extern void default_globalize_label PARAMS ((FILE *, const char *));
+
 /* Emit data for vtable gc for GNU binutils.  */
 extern void assemble_vtable_entry PARAMS ((struct rtx_def *, HOST_WIDE_INT));
 extern void assemble_vtable_inherit PARAMS ((struct rtx_def *,
index 09ff45b89f9d17b367e11010d1dc052e4f1c62b7..06930fee2ab1bfdc35c3f2aa4bf815758020e524 100644 (file)
@@ -1,5 +1,6 @@
 /* Utility to update paths from internal to external forms.
-   Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -77,7 +78,6 @@ static const char *get_key_value      PARAMS ((char *));
 static char *translate_name            PARAMS ((char *));
 static char *save_string               PARAMS ((const char *, int));
 static void tr                         PARAMS ((char *, int, int));
-char *concat                           VPARAMS ((const char *first, ...));
 
 #if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
 static char *lookup_key                PARAMS ((char *));
@@ -150,10 +150,10 @@ lookup_key (key)
                             KEY_READ, &reg_key);
 
       if (res != ERROR_SUCCESS)
-        {
-          reg_key = (HKEY) INVALID_HANDLE_VALUE;
-          return 0;
-        }
+       {
+         reg_key = (HKEY) INVALID_HANDLE_VALUE;
+         return 0;
+       }
     }
 
   size = 32;
@@ -252,7 +252,7 @@ update_path (path, key)
   const char *path;
   const char *key;
 {
-  char *result;
+  char *result, *p;
 
   if (! strncmp (path, std_prefix, strlen (std_prefix)) && key != 0)
     {
@@ -272,9 +272,66 @@ update_path (path, key)
   else
     result = xstrdup (path);
 
+#ifndef ALWAYS_STRIP_DOTDOT
+#define ALWAYS_STRIP_DOTDOT 0
+#endif
+
+  p = result;
+  while (1)
+    {
+      char *src, *dest;
+
+      p = strchr (p, '.');
+      if (p == NULL)
+       break;
+      /* Look for `/../'  */
+      if (p[1] == '.'
+         && IS_DIR_SEPARATOR (p[2])
+         && (p != result && IS_DIR_SEPARATOR (p[-1])))
+       {
+         *p = 0;
+         if (!ALWAYS_STRIP_DOTDOT && access (result, X_OK) == 0)
+           {
+             *p = '.';
+             break;
+           }
+         else
+           {
+             /* We can't access the dir, so we won't be able to
+                access dir/.. either.  Strip out `dir/../'.  If `dir'
+                turns out to be `.', strip one more path component.  */
+             dest = p;
+             do
+               {
+                 --dest;
+                 while (dest != result && IS_DIR_SEPARATOR (*dest))
+                   --dest;
+                 while (dest != result && !IS_DIR_SEPARATOR (dest[-1]))
+                   --dest;
+               }
+             while (dest != result && *dest == '.');
+             /* If we have something like `./..' or `/..', don't
+                strip anything more.  */
+             if (*dest == '.' || IS_DIR_SEPARATOR (*dest))
+               {
+                 *p = '.';
+                 break;
+               }
+             src = p + 3;
+             while (IS_DIR_SEPARATOR (*src))
+               ++src;
+             p = dest;
+             while ((*dest++ = *src++) != 0)
+               ;
+           }
+       }
+      else
+       ++p;
+    }
+
 #ifdef UPDATE_PATH_HOST_CANONICALIZE
   /* Perform host dependent canonicalization when needed.  */
-  UPDATE_PATH_HOST_CANONICALIZE (path);
+  UPDATE_PATH_HOST_CANONICALIZE (result);
 #endif
 
 #ifdef DIR_SEPARATOR_2
index ec18269db98066c922f828ce249e4c8616849e58..c405e7661fb197467cd9827bfdf0667923960a3d 100644 (file)
 /*
  * From defaults.h
  */
+#ifndef GET_ENVIRONMENT
+#define GET_ENVIRONMENT(VALUE, NAME) do { (VALUE) = getenv (NAME); } while (0)
+#endif
+
 /* Define results of standard character escape sequences.  */
 #define TARGET_BELL    007
 #define TARGET_BS      010
 #ifdef _WIN32
 #define HAVE_DOS_BASED_FILE_SYSTEM
 #endif
+
+/*
+ * From hashtab.h
+ */
+#ifndef GTY
+#define GTY(X)
+#endif
index bd4ea1462bf05a9254ad229dc50bafa12515e0e0..faa2465015ed76cb9cf6a7146cc5bcea5a8afe3c 100644 (file)
@@ -117,10 +117,6 @@ SOURCE=.\cpphash.c
 # End Source File\r
 # Begin Source File\r
 \r
-SOURCE=.\cppinit.c\r
-# End Source File\r
-# Begin Source File\r
-\r
 SOURCE=.\cpplex.c\r
 # End Source File\r
 # Begin Source File\r
@@ -137,6 +133,10 @@ SOURCE=.\cppmain.c
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\cpptrad.c\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\hashtable.c\r
 # End Source File\r
 # Begin Source File\r
@@ -173,6 +173,14 @@ SOURCE=".\libiberty\safe-ctype.c"
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\sdcppinit.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\sdcppmain.c\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=".\libiberty\splay-tree.c"\r
 # End Source File\r
 # Begin Source File\r
diff --git a/support/cpp2/sdcppinit.c b/support/cpp2/sdcppinit.c
new file mode 100644 (file)
index 0000000..95a1925
--- /dev/null
@@ -0,0 +1,1960 @@
+/* CPP Library.
+   Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   Contributed by Per Bothner, 1994-95.
+   Based on CCCP program by Paul Rubin, June 1986
+   Adapted to ANSI C, Richard Stallman, Jan 1987
+
+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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "cpplib.h"
+#include "cpphash.h"
+#include "prefix.h"
+#include "version.h"
+#include "intl.h"
+#include "mkdeps.h"
+#include "cppdefault.h"
+
+/* Windows does not natively support inodes, and neither does MSDOS.
+   Cygwin's emulation can generate non-unique inodes, so don't use it.
+   VMS has non-numeric inodes.  */
+#ifdef VMS
+# define INO_T_EQ(A, B) (!memcmp (&(A), &(B), sizeof (A)))
+# define INO_T_COPY(DEST, SRC) memcpy(&(DEST), &(SRC), sizeof (SRC))
+#else
+# if (defined _WIN32 && ! defined (_UWIN)) || defined __MSDOS__
+#  define INO_T_EQ(A, B) 0
+# else
+#  define INO_T_EQ(A, B) ((A) == (B))
+# endif
+# define INO_T_COPY(DEST, SRC) (DEST) = (SRC)
+#endif
+
+/* Internal structures and prototypes.  */
+
+/* A `struct pending_option' remembers one -D, -A, -U, -include, or
+   -imacros switch.  */
+typedef void (* cl_directive_handler) PARAMS ((cpp_reader *, const char *));
+struct pending_option
+{
+  struct pending_option *next;
+  const char *arg;
+  cl_directive_handler handler;
+};
+
+/* The `pending' structure accumulates all the options that are not
+   actually processed until we hit cpp_read_main_file.  It consists of
+   several lists, one for each type of option.  We keep both head and
+   tail pointers for quick insertion.  */
+struct cpp_pending
+{
+  struct pending_option *directive_head, *directive_tail;
+
+  struct search_path *quote_head, *quote_tail;
+  struct search_path *brack_head, *brack_tail;
+  struct search_path *systm_head, *systm_tail;
+  struct search_path *after_head, *after_tail;
+
+  struct pending_option *imacros_head, *imacros_tail;
+  struct pending_option *include_head, *include_tail;
+};
+
+#ifdef __STDC__
+#define APPEND(pend, list, elt) \
+  do {  if (!(pend)->list##_head) (pend)->list##_head = (elt); \
+       else (pend)->list##_tail->next = (elt); \
+       (pend)->list##_tail = (elt); \
+  } while (0)
+#else
+#define APPEND(pend, list, elt) \
+  do {  if (!(pend)->list/**/_head) (pend)->list/**/_head = (elt); \
+       else (pend)->list/**/_tail->next = (elt); \
+       (pend)->list/**/_tail = (elt); \
+  } while (0)
+#endif
+
+static void print_help                  PARAMS ((void));
+static void path_include               PARAMS ((cpp_reader *,
+                                                char *, int));
+static void init_library               PARAMS ((void));
+static void init_builtins              PARAMS ((cpp_reader *));
+static void mark_named_operators       PARAMS ((cpp_reader *));
+static void append_include_chain       PARAMS ((cpp_reader *,
+                                                char *, int, int));
+static struct search_path * remove_dup_dir     PARAMS ((cpp_reader *,
+                                                struct search_path *,
+                                                struct search_path **));
+static struct search_path * remove_dup_nonsys_dirs PARAMS ((cpp_reader *,
+                                                struct search_path **,
+                                                struct search_path *));
+static struct search_path * remove_dup_dirs PARAMS ((cpp_reader *,
+                                                struct search_path **));
+static void merge_include_chains       PARAMS ((cpp_reader *));
+static bool push_include               PARAMS ((cpp_reader *,
+                                                struct pending_option *));
+static void free_chain                 PARAMS ((struct pending_option *));
+static void init_standard_includes     PARAMS ((cpp_reader *));
+static void read_original_filename     PARAMS ((cpp_reader *));
+static void new_pending_directive      PARAMS ((struct cpp_pending *,
+                                                const char *,
+                                                cl_directive_handler));
+static int parse_option                        PARAMS ((const char *));
+static void post_options               PARAMS ((cpp_reader *));
+
+/* Fourth argument to append_include_chain: chain to use.
+   Note it's never asked to append to the quote chain.  */
+enum { BRACKET = 0, SYSTEM, AFTER };
+
+/* If we have designated initializers (GCC >2.7) these tables can be
+   initialized, constant data.  Otherwise, they have to be filled in at
+   runtime.  */
+#if HAVE_DESIGNATED_INITIALIZERS
+
+#define init_trigraph_map()  /* Nothing.  */
+#define TRIGRAPH_MAP \
+__extension__ const uchar _cpp_trigraph_map[UCHAR_MAX + 1] = {
+
+#define END };
+#define s(p, v) [p] = v,
+
+#else
+
+#define TRIGRAPH_MAP uchar _cpp_trigraph_map[UCHAR_MAX + 1] = { 0 }; \
+ static void init_trigraph_map PARAMS ((void)) { \
+ unsigned char *x = _cpp_trigraph_map;
+
+#define END }
+#define s(p, v) x[p] = v;
+
+#endif
+
+TRIGRAPH_MAP
+  s('=', '#')  s(')', ']')     s('!', '|')
+  s('(', '[')  s('\'', '^')    s('>', '}')
+  s('/', '\\') s('<', '{')     s('-', '~')
+END
+
+#undef s
+#undef END
+#undef TRIGRAPH_MAP
+
+/* Given a colon-separated list of file names PATH,
+   add all the names to the search path for include files.  */
+static void
+path_include (pfile, list, path)
+     cpp_reader *pfile;
+     char *list;
+     int path;
+{
+  char *p, *q, *name;
+
+  p = list;
+
+  do
+    {
+      /* Find the end of this name.  */
+      q = p;
+      while (*q != 0 && *q != PATH_SEPARATOR) q++;
+      if (q == p)
+       {
+         /* An empty name in the path stands for the current directory.  */
+         name = (char *) xmalloc (2);
+         name[0] = '.';
+         name[1] = 0;
+       }
+      else
+       {
+         /* Otherwise use the directory that is named.  */
+         name = (char *) xmalloc (q - p + 1);
+         memcpy (name, p, q - p);
+         name[q - p] = 0;
+       }
+
+      append_include_chain (pfile, name, path, path == SYSTEM);
+
+      /* Advance past this name.  */
+      if (*q == 0)
+       break;
+      p = q + 1;
+    }
+  while (1);
+}
+
+/* Append DIR to include path PATH.  DIR must be allocated on the
+   heap; this routine takes responsibility for freeing it.  CXX_AWARE
+   is nonzero if the header contains extern "C" guards for C++,
+   otherwise it is zero.  */
+static void
+append_include_chain (pfile, dir, path, cxx_aware)
+     cpp_reader *pfile;
+     char *dir;
+     int path;
+     int cxx_aware;
+{
+  struct cpp_pending *pend = CPP_OPTION (pfile, pending);
+  struct search_path *new;
+  struct stat st;
+  unsigned int len;
+
+  if (*dir == '\0')
+    {
+      free (dir);
+      dir = xstrdup (".");
+    }
+  _cpp_simplify_pathname (dir);
+
+  if (stat (dir, &st))
+    {
+      /* Dirs that don't exist are silently ignored.  */
+      if (errno != ENOENT)
+       cpp_errno (pfile, DL_ERROR, dir);
+      else if (CPP_OPTION (pfile, verbose))
+       fprintf (stderr, _("ignoring nonexistent directory \"%s\"\n"), dir);
+      free (dir);
+      return;
+    }
+
+  if (!S_ISDIR (st.st_mode))
+    {
+      cpp_error_with_line (pfile, DL_ERROR, 0, 0, "%s: Not a directory", dir);
+      free (dir);
+      return;
+    }
+
+  len = strlen (dir);
+  if (len > pfile->max_include_len)
+    pfile->max_include_len = len;
+
+  new = (struct search_path *) xmalloc (sizeof (struct search_path));
+  new->name = dir;
+  new->len = len;
+  INO_T_COPY (new->ino, st.st_ino);
+  new->dev  = st.st_dev;
+  /* Both systm and after include file lists should be treated as system
+     include files since these two lists are really just a concatenation
+     of one "system" list.  */
+  if (path == SYSTEM || path == AFTER)
+    new->sysp = cxx_aware ? 1 : 2;
+  else
+    new->sysp = 0;
+  new->name_map = NULL;
+  new->next = NULL;
+
+  switch (path)
+    {
+    case BRACKET:      APPEND (pend, brack, new); break;
+    case SYSTEM:       APPEND (pend, systm, new); break;
+    case AFTER:                APPEND (pend, after, new); break;
+    }
+}
+
+/* Handle a duplicated include path.  PREV is the link in the chain
+   before the duplicate, or NULL if the duplicate is at the head of
+   the chain.  The duplicate is removed from the chain and freed.
+   Returns PREV.  */
+static struct search_path *
+remove_dup_dir (pfile, prev, head_ptr)
+     cpp_reader *pfile;
+     struct search_path *prev;
+     struct search_path **head_ptr;
+{
+  struct search_path *cur;
+
+  if (prev != NULL)
+    {
+      cur = prev->next;
+      prev->next = cur->next;
+    }
+  else
+    {
+      cur = *head_ptr;
+      *head_ptr = cur->next;
+    }
+
+  if (CPP_OPTION (pfile, verbose))
+    fprintf (stderr, _("ignoring duplicate directory \"%s\"\n"), cur->name);
+
+  free ((PTR) cur->name);
+  free (cur);
+
+  return prev;
+}
+
+/* Remove duplicate non-system directories for which there is an equivalent
+   system directory latter in the chain.  The range for removal is between
+   *HEAD_PTR and END.  Returns the directory before END, or NULL if none.
+   This algorithm is quadratic in the number system directories, which is
+   acceptable since there aren't usually that many of them.  */
+static struct search_path *
+remove_dup_nonsys_dirs (pfile, head_ptr, end)
+     cpp_reader *pfile;
+     struct search_path **head_ptr;
+     struct search_path *end;
+{
+  int sysdir = 0;
+  struct search_path *prev = NULL, *cur, *other;
+
+  for (cur = *head_ptr; cur; cur = cur->next)
+    {
+      if (cur->sysp)
+       {
+         sysdir = 1;
+         for (other = *head_ptr, prev = NULL;
+              other != end;
+              other = other ? other->next : *head_ptr)
+           {
+             if (!other->sysp
+                 && INO_T_EQ (cur->ino, other->ino)
+                 && cur->dev == other->dev)
+               {
+                 other = remove_dup_dir (pfile, prev, head_ptr);
+                 if (CPP_OPTION (pfile, verbose))
+                   fprintf (stderr,
+  _("  as it is a non-system directory that duplicates a system directory\n"));
+               }
+             prev = other;
+           }
+       }
+    }
+
+  if (!sysdir)
+    for (cur = *head_ptr; cur != end; cur = cur->next)
+      prev = cur;
+
+  return prev;
+}
+
+/* Remove duplicate directories from a chain.  Returns the tail of the
+   chain, or NULL if the chain is empty.  This algorithm is quadratic
+   in the number of -I switches, which is acceptable since there
+   aren't usually that many of them.  */
+static struct search_path *
+remove_dup_dirs (pfile, head_ptr)
+     cpp_reader *pfile;
+     struct search_path **head_ptr;
+{
+  struct search_path *prev = NULL, *cur, *other;
+
+  for (cur = *head_ptr; cur; cur = cur->next)
+    {
+      for (other = *head_ptr; other != cur; other = other->next)
+       if (INO_T_EQ (cur->ino, other->ino) && cur->dev == other->dev)
+         {
+           cur = remove_dup_dir (pfile, prev, head_ptr);
+           break;
+         }
+      prev = cur;
+    }
+
+  return prev;
+}
+
+/* Merge the four include chains together in the order quote, bracket,
+   system, after.  Remove duplicate dirs (as determined by
+   INO_T_EQ()).  The system_include and after_include chains are never
+   referred to again after this function; all access is through the
+   bracket_include path.  */
+static void
+merge_include_chains (pfile)
+     cpp_reader *pfile;
+{
+  struct search_path *quote, *brack, *systm, *qtail;
+
+  struct cpp_pending *pend = CPP_OPTION (pfile, pending);
+
+  quote = pend->quote_head;
+  brack = pend->brack_head;
+  systm = pend->systm_head;
+  qtail = pend->quote_tail;
+
+  /* Paste together bracket, system, and after include chains.  */
+  if (systm)
+    pend->systm_tail->next = pend->after_head;
+  else
+    systm = pend->after_head;
+
+  if (brack)
+    pend->brack_tail->next = systm;
+  else
+    brack = systm;
+
+  /* This is a bit tricky.  First we drop non-system dupes of system
+     directories from the merged bracket-include list.  Next we drop
+     dupes from the bracket and quote include lists.  Then we drop
+     non-system dupes from the merged quote-include list.  Finally,
+     if qtail and brack are the same directory, we cut out brack and
+     move brack up to point to qtail.
+
+     We can't just merge the lists and then uniquify them because
+     then we may lose directories from the <> search path that should
+     be there; consider -Ifoo -Ibar -I- -Ifoo -Iquux.  It is however
+     safe to treat -Ibar -Ifoo -I- -Ifoo -Iquux as if written
+     -Ibar -I- -Ifoo -Iquux.  */
+
+  remove_dup_nonsys_dirs (pfile, &brack, systm);
+  remove_dup_dirs (pfile, &brack);
+
+  if (quote)
+    {
+      qtail = remove_dup_dirs (pfile, &quote);
+      qtail->next = brack;
+
+      qtail = remove_dup_nonsys_dirs (pfile, &quote, brack);
+
+      /* If brack == qtail, remove brack as it's simpler.  */
+      if (qtail && brack && INO_T_EQ (qtail->ino, brack->ino)
+         && qtail->dev == brack->dev)
+       brack = remove_dup_dir (pfile, qtail, &quote);
+    }
+  else
+    quote = brack;
+
+  CPP_OPTION (pfile, quote_include) = quote;
+  CPP_OPTION (pfile, bracket_include) = brack;
+}
+
+/* A set of booleans indicating what CPP features each source language
+   requires.  */
+struct lang_flags
+{
+  char c99;
+  char cplusplus;
+  char extended_numbers;
+  char std;
+  char dollars_in_ident;
+  char cplusplus_comments;
+  char digraphs;
+};
+
+/* ??? Enable $ in identifiers in assembly? */
+static const struct lang_flags lang_defaults[] =
+{ /*              c99 c++ xnum std dollar c++comm digr  */
+  /* GNUC89 */  { 0,  0,  1,   0,   1,     1,      1     },
+  /* GNUC99 */  { 1,  0,  1,   0,   1,     1,      1     },
+  /* STDC89 */  { 0,  0,  0,   1,   0,     0,      0     },
+  /* STDC94 */  { 0,  0,  0,   1,   0,     0,      1     },
+  /* STDC99 */  { 1,  0,  1,   1,   0,     1,      1     },
+  /* GNUCXX */  { 0,  1,  1,   0,   1,     1,      1     },
+  /* CXX98  */  { 0,  1,  1,   1,   0,     1,      1     },
+  /* ASM    */  { 0,  0,  1,   0,   0,     1,      0     }
+};
+
+/* Sets internal flags correctly for a given language.  */
+void
+cpp_set_lang (pfile, lang)
+     cpp_reader *pfile;
+     enum c_lang lang;
+{
+  const struct lang_flags *l = &lang_defaults[(int) lang];
+
+  CPP_OPTION (pfile, lang) = lang;
+
+  CPP_OPTION (pfile, c99)               = l->c99;
+  CPP_OPTION (pfile, cplusplus)                 = l->cplusplus;
+  CPP_OPTION (pfile, extended_numbers)  = l->extended_numbers;
+  CPP_OPTION (pfile, std)               = l->std;
+  CPP_OPTION (pfile, trigraphs)                 = l->std;
+  CPP_OPTION (pfile, dollars_in_ident)  = l->dollars_in_ident;
+  CPP_OPTION (pfile, cplusplus_comments) = l->cplusplus_comments;
+  CPP_OPTION (pfile, digraphs)          = l->digraphs;
+}
+
+#ifdef HOST_EBCDIC
+static int opt_comp PARAMS ((const void *, const void *));
+
+/* Run-time sorting of options array.  */
+static int
+opt_comp (p1, p2)
+     const void *p1, *p2;
+{
+  return strcmp (((struct cl_option *) p1)->opt_text,
+                ((struct cl_option *) p2)->opt_text);
+}
+#endif
+
+/* init initializes library global state.  It might not need to
+   do anything depending on the platform and compiler.  */
+static void
+init_library ()
+{
+  static int initialized = 0;
+
+  if (! initialized)
+    {
+      initialized = 1;
+
+#ifdef HOST_EBCDIC
+      /* For non-ASCII hosts, the cl_options array needs to be sorted at
+        runtime.  */
+      qsort (cl_options, N_OPTS, sizeof (struct cl_option), opt_comp);
+#endif
+
+      /* Set up the trigraph map.  This doesn't need to do anything if
+        we were compiled with a compiler that supports C99 designated
+        initializers.  */
+      init_trigraph_map ();
+    }
+}
+
+/* Initialize a cpp_reader structure.  */
+cpp_reader *
+cpp_create_reader (lang)
+     enum c_lang lang;
+{
+  cpp_reader *pfile;
+
+  /* Initialize this instance of the library if it hasn't been already.  */
+  init_library ();
+
+  pfile = (cpp_reader *) xcalloc (1, sizeof (cpp_reader));
+
+  cpp_set_lang (pfile, lang);
+  CPP_OPTION (pfile, warn_import) = 1;
+  CPP_OPTION (pfile, warn_multichar) = 1;
+  CPP_OPTION (pfile, discard_comments) = 1;
+  CPP_OPTION (pfile, discard_comments_in_macro_exp) = 1;
+  CPP_OPTION (pfile, show_column) = 1;
+  CPP_OPTION (pfile, tabstop) = 8;
+  CPP_OPTION (pfile, operator_names) = 1;
+  CPP_OPTION (pfile, warn_endif_labels) = 1;
+  CPP_OPTION (pfile, warn_long_long) = !CPP_OPTION (pfile, c99);
+  /* SDCC _asm specific */
+  CPP_OPTION (pfile, preproc_asm) = 1;
+
+  CPP_OPTION (pfile, pending) =
+    (struct cpp_pending *) xcalloc (1, sizeof (struct cpp_pending));
+
+  /* Default CPP arithmetic to something sensible for the host for the
+     benefit of dumb users like fix-header.  */
+  CPP_OPTION (pfile, precision) = CHAR_BIT * sizeof (long);
+  CPP_OPTION (pfile, char_precision) = CHAR_BIT;
+  CPP_OPTION (pfile, wchar_precision) = CHAR_BIT * sizeof (int);
+  CPP_OPTION (pfile, int_precision) = CHAR_BIT * sizeof (int);
+  CPP_OPTION (pfile, unsigned_char) = 0;
+  CPP_OPTION (pfile, unsigned_wchar) = 1;
+
+  /* Initialize the line map.  Start at logical line 1, so we can use
+     a line number of zero for special states.  */
+  init_line_maps (&pfile->line_maps);
+  pfile->line = 1;
+
+  /* Initialize lexer state.  */
+  pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);
+
+  /* Set up static tokens.  */
+  pfile->avoid_paste.type = CPP_PADDING;
+  pfile->avoid_paste.val.source = NULL;
+  pfile->eof.type = CPP_EOF;
+  pfile->eof.flags = 0;
+
+  /* Create a token buffer for the lexer.  */
+  _cpp_init_tokenrun (&pfile->base_run, 250);
+  pfile->cur_run = &pfile->base_run;
+  pfile->cur_token = pfile->base_run.base;
+
+  /* Initialize the base context.  */
+  pfile->context = &pfile->base_context;
+  pfile->base_context.macro = 0;
+  pfile->base_context.prev = pfile->base_context.next = 0;
+
+  /* Aligned and unaligned storage.  */
+  pfile->a_buff = _cpp_get_buff (pfile, 0);
+  pfile->u_buff = _cpp_get_buff (pfile, 0);
+
+  /* The expression parser stack.  */
+  _cpp_expand_op_stack (pfile);
+
+  /* Initialize the buffer obstack.  */
+  gcc_obstack_init (&pfile->buffer_ob);
+
+  _cpp_init_includes (pfile);
+
+  return pfile;
+}
+
+/* Free resources used by PFILE.  Accessing PFILE after this function
+   returns leads to undefined behavior.  Returns the error count.  */
+void
+cpp_destroy (pfile)
+     cpp_reader *pfile;
+{
+  struct search_path *dir, *dirn;
+  cpp_context *context, *contextn;
+  tokenrun *run, *runn;
+
+  free_chain (CPP_OPTION (pfile, pending)->include_head);
+  free (CPP_OPTION (pfile, pending));
+  free (pfile->op_stack);
+
+  while (CPP_BUFFER (pfile) != NULL)
+    _cpp_pop_buffer (pfile);
+
+  if (pfile->out.base)
+    free (pfile->out.base);
+
+  if (pfile->macro_buffer)
+    {
+      free ((PTR) pfile->macro_buffer);
+      pfile->macro_buffer = NULL;
+      pfile->macro_buffer_len = 0;
+    }
+
+  if (pfile->deps)
+    deps_free (pfile->deps);
+  obstack_free (&pfile->buffer_ob, 0);
+
+  _cpp_destroy_hashtable (pfile);
+  _cpp_cleanup_includes (pfile);
+
+  _cpp_free_buff (pfile->a_buff);
+  _cpp_free_buff (pfile->u_buff);
+  _cpp_free_buff (pfile->free_buffs);
+
+  for (run = &pfile->base_run; run; run = runn)
+    {
+      runn = run->next;
+      free (run->base);
+      if (run != &pfile->base_run)
+       free (run);
+    }
+
+  for (dir = CPP_OPTION (pfile, quote_include); dir; dir = dirn)
+    {
+      dirn = dir->next;
+      free ((PTR) dir->name);
+      free (dir);
+    }
+
+  for (context = pfile->base_context.next; context; context = contextn)
+    {
+      contextn = context->next;
+      free (context);
+    }
+
+  free_line_maps (&pfile->line_maps);
+  free (pfile);
+}
+
+/* This structure defines one built-in identifier.  A node will be
+   entered in the hash table under the name NAME, with value VALUE.
+
+   There are two tables of these.  builtin_array holds all the
+   "builtin" macros: these are handled by builtin_macro() in
+   cppmacro.c.  Builtin is somewhat of a misnomer -- the property of
+   interest is that these macros require special code to compute their
+   expansions.  The value is a "builtin_type" enumerator.
+
+   operator_array holds the C++ named operators.  These are keywords
+   which act as aliases for punctuators.  In C++, they cannot be
+   altered through #define, and #if recognizes them as operators.  In
+   C, these are not entered into the hash table at all (but see
+   <iso646.h>).  The value is a token-type enumerator.  */
+struct builtin
+{
+  const uchar *name;
+  unsigned short len;
+  unsigned short value;
+};
+
+#define B(n, t)    { DSC(n), t }
+static const struct builtin builtin_array[] =
+{
+  B("__TIME__",                 BT_TIME),
+  B("__DATE__",                 BT_DATE),
+  B("__FILE__",                 BT_FILE),
+  B("__BASE_FILE__",    BT_BASE_FILE),
+  B("__LINE__",                 BT_SPECLINE),
+  B("__INCLUDE_LEVEL__", BT_INCLUDE_LEVEL),
+  /* Keep builtins not used for -traditional-cpp at the end, and
+     update init_builtins() if any more are added.  */
+  B("_Pragma",          BT_PRAGMA),
+  B("__STDC__",                 BT_STDC),
+};
+
+static const struct builtin operator_array[] =
+{
+  B("and",     CPP_AND_AND),
+  B("and_eq",  CPP_AND_EQ),
+  B("bitand",  CPP_AND),
+  B("bitor",   CPP_OR),
+  B("compl",   CPP_COMPL),
+  B("not",     CPP_NOT),
+  B("not_eq",  CPP_NOT_EQ),
+  B("or",      CPP_OR_OR),
+  B("or_eq",   CPP_OR_EQ),
+  B("xor",     CPP_XOR),
+  B("xor_eq",  CPP_XOR_EQ)
+};
+#undef B
+
+/* Mark the C++ named operators in the hash table.  */
+static void
+mark_named_operators (pfile)
+     cpp_reader *pfile;
+{
+  const struct builtin *b;
+
+  for (b = operator_array;
+       b < (operator_array + ARRAY_SIZE (operator_array));
+       b++)
+    {
+      cpp_hashnode *hp = cpp_lookup (pfile, b->name, b->len);
+      hp->flags |= NODE_OPERATOR;
+      hp->value.operator = b->value;
+    }
+}
+
+/* Subroutine of cpp_read_main_file; reads the builtins table above and
+   enters them, and language-specific macros, into the hash table.  */
+static void
+init_builtins (pfile)
+     cpp_reader *pfile;
+{
+  const struct builtin *b;
+  size_t n = ARRAY_SIZE (builtin_array);
+
+  if (CPP_OPTION (pfile, traditional))
+    n -= 2;
+
+  for(b = builtin_array; b < builtin_array + n; b++)
+    {
+      cpp_hashnode *hp = cpp_lookup (pfile, b->name, b->len);
+      hp->type = NT_MACRO;
+      hp->flags |= NODE_BUILTIN | NODE_WARN;
+      hp->value.builtin = b->value;
+    }
+
+  if (CPP_OPTION (pfile, cplusplus))
+    _cpp_define_builtin (pfile, "__cplusplus 1");
+  else if (CPP_OPTION (pfile, lang) == CLK_ASM)
+    _cpp_define_builtin (pfile, "__ASSEMBLER__ 1");
+  else if (CPP_OPTION (pfile, lang) == CLK_STDC94)
+    _cpp_define_builtin (pfile, "__STDC_VERSION__ 199409L");
+  else if (CPP_OPTION (pfile, c99))
+    _cpp_define_builtin (pfile, "__STDC_VERSION__ 199901L");
+
+  if (CPP_OPTION (pfile, objc))
+    _cpp_define_builtin (pfile, "__OBJC__ 1");
+
+  if (pfile->cb.register_builtins)
+    (*pfile->cb.register_builtins) (pfile);
+}
+
+/* And another subroutine.  This one sets up the standard include path.  */
+static void
+init_standard_includes (pfile)
+     cpp_reader *pfile;
+{
+  char *path;
+  const struct default_include *p;
+  const char *specd_prefix = CPP_OPTION (pfile, include_prefix);
+
+  /* Several environment variables may add to the include search path.
+     CPATH specifies an additional list of directories to be searched
+     as if specified with -I, while C_INCLUDE_PATH, CPLUS_INCLUDE_PATH,
+     etc. specify an additional list of directories to be searched as
+     if specified with -isystem, for the language indicated.  */
+
+  GET_ENVIRONMENT (path, "CPATH");
+  if (path != 0 && *path != 0)
+    path_include (pfile, path, BRACKET);
+
+  switch ((CPP_OPTION (pfile, objc) << 1) + CPP_OPTION (pfile, cplusplus))
+    {
+    case 0:
+      GET_ENVIRONMENT (path, "C_INCLUDE_PATH");
+      break;
+    case 1:
+      GET_ENVIRONMENT (path, "CPLUS_INCLUDE_PATH");
+      break;
+    case 2:
+      GET_ENVIRONMENT (path, "OBJC_INCLUDE_PATH");
+      break;
+    case 3:
+      GET_ENVIRONMENT (path, "OBJCPLUS_INCLUDE_PATH");
+      break;
+    }
+  if (path != 0 && *path != 0)
+    path_include (pfile, path, SYSTEM);
+
+  /* Search "translated" versions of GNU directories.
+     These have /usr/local/lib/gcc... replaced by specd_prefix.  */
+  if (specd_prefix != 0 && cpp_GCC_INCLUDE_DIR_len)
+    {
+      /* Remove the `include' from /usr/local/lib/gcc.../include.
+        GCC_INCLUDE_DIR will always end in /include.  */
+      int default_len = cpp_GCC_INCLUDE_DIR_len;
+      char *default_prefix = (char *) alloca (default_len + 1);
+      int specd_len = strlen (specd_prefix);
+
+      memcpy (default_prefix, cpp_GCC_INCLUDE_DIR, default_len);
+      default_prefix[default_len] = '\0';
+
+      for (p = cpp_include_defaults; p->fname; p++)
+       {
+         /* Some standard dirs are only for C++.  */
+         if (!p->cplusplus
+             || (CPP_OPTION (pfile, cplusplus)
+                 && !CPP_OPTION (pfile, no_standard_cplusplus_includes)))
+           {
+             /* Does this dir start with the prefix?  */
+             if (!strncmp (p->fname, default_prefix, default_len))
+               {
+                 /* Yes; change prefix and add to search list.  */
+                 int flen = strlen (p->fname);
+                 int this_len = specd_len + flen - default_len;
+                 char *str = (char *) xmalloc (this_len + 1);
+                 memcpy (str, specd_prefix, specd_len);
+                 memcpy (str + specd_len,
+                         p->fname + default_len,
+                         flen - default_len + 1);
+
+                 append_include_chain (pfile, str, SYSTEM, p->cxx_aware);
+               }
+           }
+       }
+    }
+
+  /* Search ordinary names for GNU include directories.  */
+  for (p = cpp_include_defaults; p->fname; p++)
+    {
+      /* Some standard dirs are only for C++.  */
+      if (!p->cplusplus
+         || (CPP_OPTION (pfile, cplusplus)
+             && !CPP_OPTION (pfile, no_standard_cplusplus_includes)))
+       {
+         char *str = update_path (p->fname, p->component);
+         append_include_chain (pfile, str, SYSTEM, p->cxx_aware);
+       }
+    }
+}
+
+/* Pushes a command line -imacro and -include file indicated by P onto
+   the buffer stack.  Returns nonzero if successful.  */
+static bool
+push_include (pfile, p)
+     cpp_reader *pfile;
+     struct pending_option *p;
+{
+  cpp_token header;
+
+  /* Later: maybe update this to use the #include "" search path
+     if cpp_read_file fails.  */
+  header.type = CPP_STRING;
+  header.val.str.text = (const unsigned char *) p->arg;
+  header.val.str.len = strlen (p->arg);
+  /* Make the command line directive take up a line.  */
+  pfile->line++;
+
+  return _cpp_execute_include (pfile, &header, IT_CMDLINE);
+}
+
+/* Frees a pending_option chain.  */
+static void
+free_chain (head)
+     struct pending_option *head;
+{
+  struct pending_option *next;
+
+  while (head)
+    {
+      next = head->next;
+      free (head);
+      head = next;
+    }
+}
+
+/* Sanity-checks are dependent on command-line options, so it is
+   called as a subroutine of cpp_read_main_file ().  */
+#if ENABLE_CHECKING
+static void sanity_checks PARAMS ((cpp_reader *));
+static void sanity_checks (pfile)
+     cpp_reader *pfile;
+{
+  cppchar_t test = 0;
+  size_t max_precision = 2 * CHAR_BIT * sizeof (cpp_num_part);
+
+  /* Sanity checks for assumptions about CPP arithmetic and target
+     type precisions made by cpplib.  */
+  test--;
+  if (test < 1)
+    cpp_error (pfile, DL_ICE, "cppchar_t must be an unsigned type");
+
+  if (CPP_OPTION (pfile, precision) > max_precision)
+    cpp_error (pfile, DL_ICE,
+              "preprocessor arithmetic has maximum precision of %lu bits; target requires %lu bits",
+              (unsigned long) max_precision,
+              (unsigned long) CPP_OPTION (pfile, precision));
+
+  if (CPP_OPTION (pfile, precision) < CPP_OPTION (pfile, int_precision))
+    cpp_error (pfile, DL_ICE,
+              "CPP arithmetic must be at least as precise as a target int");
+
+  if (CPP_OPTION (pfile, char_precision) < 8)
+    cpp_error (pfile, DL_ICE, "target char is less than 8 bits wide");
+
+  if (CPP_OPTION (pfile, wchar_precision) < CPP_OPTION (pfile, char_precision))
+    cpp_error (pfile, DL_ICE,
+              "target wchar_t is narrower than target char");
+
+  if (CPP_OPTION (pfile, int_precision) < CPP_OPTION (pfile, char_precision))
+    cpp_error (pfile, DL_ICE,
+              "target int is narrower than target char");
+
+  /* This is assumed in eval_token() and could be fixed if necessary.  */
+  if (sizeof (cppchar_t) > sizeof (cpp_num_part))
+    cpp_error (pfile, DL_ICE, "CPP half-integer narrower than CPP character");
+
+  if (CPP_OPTION (pfile, wchar_precision) > BITS_PER_CPPCHAR_T)
+    cpp_error (pfile, DL_ICE,
+              "CPP on this host cannot handle wide character constants over %lu bits, but the target requires %lu bits",
+              (unsigned long) BITS_PER_CPPCHAR_T,
+              (unsigned long) CPP_OPTION (pfile, wchar_precision));
+}
+#else
+# define sanity_checks(PFILE)
+#endif
+
+/* Add a dependency target.  Can be called any number of times before
+   cpp_read_main_file().  If no targets have been added before
+   cpp_read_main_file(), then the default target is used.  */
+void
+cpp_add_dependency_target (pfile, target, quote)
+     cpp_reader *pfile;
+     const char *target;
+     int quote;
+{
+  if (!pfile->deps)
+    pfile->deps = deps_init ();
+
+  deps_add_target (pfile->deps, target, quote);
+}
+
+/* This is called after options have been parsed, and partially
+   processed.  Setup for processing input from the file named FNAME,
+   or stdin if it is the empty string.  Return the original filename
+   on success (e.g. foo.i->foo.c), or NULL on failure.  */
+const char *
+cpp_read_main_file (pfile, fname, table)
+     cpp_reader *pfile;
+     const char *fname;
+     hash_table *table;
+{
+  sanity_checks (pfile);
+
+  post_options (pfile);
+
+  /* The front ends don't set up the hash table until they have
+     finished processing the command line options, so initializing the
+     hashtable is deferred until now.  */
+  _cpp_init_hashtable (pfile, table);
+
+  /* Set up the include search path now.  */
+  if (! CPP_OPTION (pfile, no_standard_includes))
+    init_standard_includes (pfile);
+
+  merge_include_chains (pfile);
+
+  /* With -v, print the list of dirs to search.  */
+  if (CPP_OPTION (pfile, verbose))
+    {
+      struct search_path *l;
+      fprintf (stderr, _("#include \"...\" search starts here:\n"));
+      for (l = CPP_OPTION (pfile, quote_include); l; l = l->next)
+       {
+         if (l == CPP_OPTION (pfile, bracket_include))
+           fprintf (stderr, _("#include <...> search starts here:\n"));
+         fprintf (stderr, " %s\n", l->name);
+       }
+      fprintf (stderr, _("End of search list.\n"));
+    }
+
+  if (CPP_OPTION (pfile, deps.style) != DEPS_NONE)
+    {
+      if (!pfile->deps)
+       pfile->deps = deps_init ();
+
+      /* Set the default target (if there is none already).  */
+      deps_add_default_target (pfile, fname);
+    }
+
+  /* Open the main input file.  */
+  if (!_cpp_read_file (pfile, fname))
+    return NULL;
+
+  /* Set this here so the client can change the option if it wishes,
+     and after stacking the main file so we don't trace the main
+     file.  */
+  pfile->line_maps.trace_includes = CPP_OPTION (pfile, print_include_names);
+
+  /* For foo.i, read the original filename foo.c now, for the benefit
+     of the front ends.  */
+  if (CPP_OPTION (pfile, preprocessed))
+    read_original_filename (pfile);
+
+  return pfile->map->to_file;
+}
+
+/* For preprocessed files, if the first tokens are of the form # NUM.
+   handle the directive so we know the original file name.  This will
+   generate file_change callbacks, which the front ends must handle
+   appropriately given their state of initialization.  */
+static void
+read_original_filename (pfile)
+     cpp_reader *pfile;
+{
+  const cpp_token *token, *token1;
+
+  /* Lex ahead; if the first tokens are of the form # NUM, then
+     process the directive, otherwise back up.  */
+  token = _cpp_lex_direct (pfile);
+  if (token->type == CPP_HASH)
+    {
+      token1 = _cpp_lex_direct (pfile);
+      _cpp_backup_tokens (pfile, 1);
+
+      /* If it's a #line directive, handle it.  */
+      if (token1->type == CPP_NUMBER)
+       {
+         _cpp_handle_directive (pfile, token->flags & PREV_WHITE);
+         return;
+       }
+    }
+
+  /* Backup as if nothing happened.  */
+  _cpp_backup_tokens (pfile, 1);
+}
+
+/* Handle pending command line options: -D, -U, -A, -imacros and
+   -include.  This should be called after debugging has been properly
+   set up in the front ends.  */
+void
+cpp_finish_options (pfile)
+     cpp_reader *pfile;
+{
+  /* Mark named operators before handling command line macros.  */
+  if (CPP_OPTION (pfile, cplusplus) && CPP_OPTION (pfile, operator_names))
+    mark_named_operators (pfile);
+
+  /* Install builtins and process command line macros etc. in the order
+     they appeared, but only if not already preprocessed.  */
+  if (! CPP_OPTION (pfile, preprocessed))
+    {
+      struct pending_option *p;
+
+      /* Prevent -Wunused-macros with command-line redefinitions.  */
+      pfile->first_unused_line = (unsigned int) -1;
+      _cpp_do_file_change (pfile, LC_RENAME, _("<built-in>"), 1, 0);
+      init_builtins (pfile);
+      _cpp_do_file_change (pfile, LC_RENAME, _("<command line>"), 1, 0);
+      for (p = CPP_OPTION (pfile, pending)->directive_head; p; p = p->next)
+       (*p->handler) (pfile, p->arg);
+
+      /* Scan -imacros files after -D, -U, but before -include.
+        pfile->next_include_file is NULL, so _cpp_pop_buffer does not
+        push -include files.  */
+      for (p = CPP_OPTION (pfile, pending)->imacros_head; p; p = p->next)
+       if (push_include (pfile, p))
+         cpp_scan_nooutput (pfile);
+
+      pfile->next_include_file = &CPP_OPTION (pfile, pending)->include_head;
+      _cpp_maybe_push_include_file (pfile);
+    }
+
+  pfile->first_unused_line = pfile->line;
+
+  free_chain (CPP_OPTION (pfile, pending)->imacros_head);
+  free_chain (CPP_OPTION (pfile, pending)->directive_head);
+}
+
+/* Use mkdeps.c to output dependency information.  */
+static void
+output_deps (cpp_reader *pfile)
+{
+  /* Stream on which to print the dependency information.  */
+  FILE *deps_stream = 0;
+  const char *const deps_mode =
+    CPP_OPTION (pfile, deps.append) ? "a" : "w";
+
+  if (CPP_OPTION (pfile, deps.file)[0] == '\0')
+    deps_stream = stdout;
+  else
+    {
+      deps_stream = fopen (CPP_OPTION (pfile, deps.file), deps_mode);
+      if (deps_stream == 0)
+       {
+         cpp_errno (pfile, DL_ERROR, CPP_OPTION (pfile, deps.file));
+         return;
+       }
+    }
+
+  deps_write (pfile->deps, deps_stream, 72);
+
+  if (CPP_OPTION (pfile, deps.phony_targets))
+    deps_phony_targets (pfile->deps, deps_stream);
+
+  /* Don't close stdout.  */
+  if (deps_stream != stdout)
+    {
+      if (ferror (deps_stream) || fclose (deps_stream) != 0)
+       cpp_error (pfile, DL_ERROR, "I/O error on output");
+    }
+}
+
+/* This is called at the end of preprocessing.  It pops the
+   last buffer and writes dependency output.  It should also
+   clear macro definitions, such that you could call cpp_start_read
+   with a new filename to restart processing.  */
+void
+sdcpp_finish (cpp_reader *pfile)
+{
+  /* Warn about unused macros before popping the final buffer.  */
+  if (CPP_OPTION (pfile, warn_unused_macros))
+    cpp_forall_identifiers (pfile, _cpp_warn_if_unused_macro, NULL);
+
+  /* cpplex.c leaves the final buffer on the stack.  This it so that
+     it returns an unending stream of CPP_EOFs to the client.  If we
+     popped the buffer, we'd dereference a NULL buffer pointer and
+     segfault.  It's nice to allow the client to do worry-free excess
+     cpp_get_token calls.  */
+  while (pfile->buffer)
+    _cpp_pop_buffer (pfile);
+
+  /* Don't write the deps file if preprocessing has failed.  */
+  if (CPP_OPTION (pfile, deps.style) && pfile->errors == 0)
+    output_deps (pfile);
+
+  /* Report on headers that could use multiple include guards.  */
+  if (CPP_OPTION (pfile, print_include_names))
+    _cpp_report_missing_guards (pfile);
+}
+
+/* Push the next buffer on the stack given by -include, if any.  */
+void
+_cpp_maybe_push_include_file (pfile)
+     cpp_reader *pfile;
+{
+  if (pfile->next_include_file)
+    {
+      struct pending_option *head = *pfile->next_include_file;
+
+      while (head && !push_include (pfile, head))
+       head = head->next;
+
+      if (head)
+       pfile->next_include_file = &head->next;
+      else
+       {
+         /* All done; restore the line map from <command line>.  */
+         _cpp_do_file_change (pfile, LC_RENAME,
+                              pfile->line_maps.maps[0].to_file, 1, 0);
+         /* Don't come back here again.  */
+         pfile->next_include_file = NULL;
+       }
+    }
+}
+
+/* This is called at the end of preprocessing.  It pops the last
+   buffer and writes dependency output, and returns the number of
+   errors.
+
+   Maybe it should also reset state, such that you could call
+   cpp_start_read with a new filename to restart processing.  */
+int
+cpp_finish (pfile, deps_stream)
+     cpp_reader *pfile;
+     FILE *deps_stream;
+{
+  /* Warn about unused macros before popping the final buffer.  */
+  if (CPP_OPTION (pfile, warn_unused_macros))
+    cpp_forall_identifiers (pfile, _cpp_warn_if_unused_macro, NULL);
+
+  /* cpplex.c leaves the final buffer on the stack.  This it so that
+     it returns an unending stream of CPP_EOFs to the client.  If we
+     popped the buffer, we'd dereference a NULL buffer pointer and
+     segfault.  It's nice to allow the client to do worry-free excess
+     cpp_get_token calls.  */
+  while (pfile->buffer)
+    _cpp_pop_buffer (pfile);
+
+  /* Don't write the deps file if there are errors.  */
+  if (CPP_OPTION (pfile, deps.style) != DEPS_NONE
+      && deps_stream && pfile->errors == 0)
+    {
+      deps_write (pfile->deps, deps_stream, 72);
+
+      if (CPP_OPTION (pfile, deps.phony_targets))
+       deps_phony_targets (pfile->deps, deps_stream);
+    }
+
+  /* Report on headers that could use multiple include guards.  */
+  if (CPP_OPTION (pfile, print_include_names))
+    _cpp_report_missing_guards (pfile);
+
+  return pfile->errors;
+}
+
+/* Add a directive to be handled later in the initialization phase.  */
+static void
+new_pending_directive (pend, text, handler)
+     struct cpp_pending *pend;
+     const char *text;
+     cl_directive_handler handler;
+{
+  struct pending_option *o = (struct pending_option *)
+    xmalloc (sizeof (struct pending_option));
+
+  o->arg = text;
+  o->next = NULL;
+  o->handler = handler;
+  APPEND (pend, directive, o);
+}
+
+/* Irix6 "cc -n32" and OSF4 cc have problems with char foo[] = ("string");
+   I.e. a const string initializer with parens around it.  That is
+   what N_("string") resolves to, so we make no_* be macros instead.  */
+#define no_arg N_("argument missing after %s")
+#define no_ass N_("assertion missing after %s")
+#define no_dir N_("directory name missing after %s")
+#define no_fil N_("file name missing after %s")
+#define no_mac N_("macro name missing after %s")
+#define no_pth N_("path name missing after %s")
+#define no_num N_("number missing after %s")
+#define no_tgt N_("target missing after %s")
+
+/* This is the list of all command line options, with the leading
+   "-" removed.  It must be sorted in ASCII collating order.  */
+#define COMMAND_LINE_OPTIONS                                                  \
+  DEF_OPT("$",                        0,      OPT_dollar)                     \
+  DEF_OPT("+",                        0,      OPT_plus)                       \
+  DEF_OPT("-help",                    0,      OPT__help)                      \
+  DEF_OPT("-target-help",             0,      OPT_target__help)               \
+  DEF_OPT("-version",                 0,      OPT__version)                   \
+  DEF_OPT("A",                        no_ass, OPT_A)                          \
+  DEF_OPT("C",                        0,      OPT_C)                          \
+  DEF_OPT("D",                        no_mac, OPT_D)                          \
+  DEF_OPT("H",                        0,      OPT_H)                          \
+  DEF_OPT("I",                        no_dir, OPT_I)                          \
+  DEF_OPT("M",                        0,      OPT_M)                          \
+  DEF_OPT("MD",                       no_fil, OPT_MD)                         \
+  DEF_OPT("MF",                       no_fil, OPT_MF)                         \
+  DEF_OPT("MG",                       0,      OPT_MG)                         \
+  DEF_OPT("MM",                       0,      OPT_MM)                         \
+  DEF_OPT("MMD",                      no_fil, OPT_MMD)                        \
+  DEF_OPT("MP",                       0,      OPT_MP)                         \
+  DEF_OPT("MQ",                       no_tgt, OPT_MQ)                         \
+  DEF_OPT("MT",                       no_tgt, OPT_MT)                         \
+  DEF_OPT("P",                        0,      OPT_P)                          \
+  DEF_OPT("U",                        no_mac, OPT_U)                          \
+  DEF_OPT("W",                        no_arg, OPT_W)  /* arg optional */      \
+  DEF_OPT("d",                        no_arg, OPT_d)                          \
+  DEF_OPT("fno-operator-names",       0,      OPT_fno_operator_names)         \
+  DEF_OPT("fno-preprocessed",         0,      OPT_fno_preprocessed)           \
+  DEF_OPT("fno-show-column",          0,      OPT_fno_show_column)            \
+  DEF_OPT("fpreprocessed",            0,      OPT_fpreprocessed)              \
+  DEF_OPT("fshow-column",             0,      OPT_fshow_column)               \
+  DEF_OPT("ftabstop=",                no_num, OPT_ftabstop)                   \
+  DEF_OPT("funsigned-char",           0,      OPT_funsigned_char)             \
+  DEF_OPT("h",                        0,      OPT_h)                          \
+  DEF_OPT("idirafter",                no_dir, OPT_idirafter)                  \
+  DEF_OPT("imacros",                  no_fil, OPT_imacros)                    \
+  DEF_OPT("include",                  no_fil, OPT_include)                    \
+  DEF_OPT("iprefix",                  no_pth, OPT_iprefix)                    \
+  DEF_OPT("isystem",                  no_dir, OPT_isystem)                    \
+  DEF_OPT("iwithprefix",              no_dir, OPT_iwithprefix)                \
+  DEF_OPT("iwithprefixbefore",        no_dir, OPT_iwithprefixbefore)          \
+  DEF_OPT("lang-asm",                 0,      OPT_lang_asm)                   \
+  DEF_OPT("lang-c",                   0,      OPT_lang_c)                     \
+  DEF_OPT("lang-c++",                 0,      OPT_lang_cplusplus)             \
+  DEF_OPT("lang-c89",                 0,      OPT_lang_c89)                   \
+  DEF_OPT("nostdinc",                 0,      OPT_nostdinc)                   \
+  DEF_OPT("nostdinc++",               0,      OPT_nostdincplusplus)           \
+  DEF_OPT("o",                        no_fil, OPT_o)                          \
+  /* SDCC specific */                                                         \
+  DEF_OPT("obj-ext=",                 no_arg, OPT_obj_ext)                    \
+  DEF_OPT("pedantic",                 0,      OPT_pedantic)                   \
+  DEF_OPT("pedantic-errors",          0,      OPT_pedantic_errors)            \
+  DEF_OPT("remap",                    0,      OPT_remap)                      \
+  DEF_OPT("std=c++98",                0,      OPT_std_cplusplus98)            \
+  DEF_OPT("std=c89",                  0,      OPT_std_c89)                    \
+  DEF_OPT("std=c99",                  0,      OPT_std_c99)                    \
+  DEF_OPT("std=c9x",                  0,      OPT_std_c9x)                    \
+  DEF_OPT("std=gnu89",                0,      OPT_std_gnu89)                  \
+  DEF_OPT("std=gnu99",                0,      OPT_std_gnu99)                  \
+  DEF_OPT("std=gnu9x",                0,      OPT_std_gnu9x)                  \
+  DEF_OPT("std=iso9899:1990",         0,      OPT_std_iso9899_1990)           \
+  DEF_OPT("std=iso9899:199409",       0,      OPT_std_iso9899_199409)         \
+  DEF_OPT("std=iso9899:1999",         0,      OPT_std_iso9899_1999)           \
+  DEF_OPT("std=iso9899:199x",         0,      OPT_std_iso9899_199x)           \
+  DEF_OPT("trigraphs",                0,      OPT_trigraphs)                  \
+  DEF_OPT("v",                        0,      OPT_v)                          \
+  DEF_OPT("version",                  0,      OPT_version)                    \
+  DEF_OPT("w",                        0,      OPT_w)
+
+#define DEF_OPT(text, msg, code) code,
+enum opt_code
+{
+  COMMAND_LINE_OPTIONS
+  N_OPTS
+};
+#undef DEF_OPT
+
+struct cl_option
+{
+  const char *opt_text;
+  const char *msg;
+  size_t opt_len;
+  enum opt_code opt_code;
+};
+
+#define DEF_OPT(text, msg, code) { text, msg, sizeof(text) - 1, code },
+#ifdef HOST_EBCDIC
+static struct cl_option cl_options[] =
+#else
+static const struct cl_option cl_options[] =
+#endif
+{
+  COMMAND_LINE_OPTIONS
+};
+#undef DEF_OPT
+#undef COMMAND_LINE_OPTIONS
+
+/* Perform a binary search to find which, if any, option the given
+   command-line matches.  Returns its index in the option array,
+   negative on failure.  Complications arise since some options can be
+   suffixed with an argument, and multiple complete matches can occur,
+   e.g. -pedantic and -pedantic-errors.  */
+static int
+parse_option (input)
+     const char *input;
+{
+  unsigned int md, mn, mx;
+  size_t opt_len;
+  int comp;
+
+  mn = 0;
+  mx = N_OPTS;
+
+  while (mx > mn)
+    {
+      md = (mn + mx) / 2;
+
+      opt_len = cl_options[md].opt_len;
+      comp = strncmp (input, cl_options[md].opt_text, opt_len);
+
+      if (comp > 0)
+       mn = md + 1;
+      else if (comp < 0)
+       mx = md;
+      else
+       {
+         if (input[opt_len] == '\0')
+           return md;
+         /* We were passed more text.  If the option takes an argument,
+            we may match a later option or we may have been passed the
+            argument.  The longest possible option match succeeds.
+            If the option takes no arguments we have not matched and
+            continue the search (e.g. input="stdc++" match was "stdc").  */
+         mn = md + 1;
+         if (cl_options[md].msg)
+           {
+             /* Scan forwards.  If we get an exact match, return it.
+                Otherwise, return the longest option-accepting match.
+                This loops no more than twice with current options.  */
+             mx = md;
+             for (; mn < (unsigned int) N_OPTS; mn++)
+               {
+                 opt_len = cl_options[mn].opt_len;
+                 if (strncmp (input, cl_options[mn].opt_text, opt_len))
+                   break;
+                 if (input[opt_len] == '\0')
+                   return mn;
+                 if (cl_options[mn].msg)
+                   mx = mn;
+               }
+             return mx;
+           }
+       }
+    }
+
+  return -1;
+}
+
+/* Handle one command-line option in (argc, argv).
+   Can be called multiple times, to handle multiple sets of options.
+   Returns number of strings consumed.  */
+int
+cpp_handle_option (pfile, argc, argv)
+     cpp_reader *pfile;
+     int argc;
+     char **argv;
+{
+  int i = 0;
+  struct cpp_pending *pend = CPP_OPTION (pfile, pending);
+
+  /* Interpret "-" or a non-option as a file name.  */
+  if (argv[i][0] != '-' || argv[i][1] == '\0')
+    {
+      if (CPP_OPTION (pfile, in_fname) == NULL)
+       CPP_OPTION (pfile, in_fname) = argv[i];
+      else if (CPP_OPTION (pfile, out_fname) == NULL)
+       CPP_OPTION (pfile, out_fname) = argv[i];
+      else
+       cpp_error (pfile, DL_ERROR, "too many filenames. Type %s --help for usage info",
+                  progname);
+    }
+  else
+    {
+      enum opt_code opt_code;
+      int opt_index;
+      const char *arg = 0;
+
+      /* Skip over '-'.  */
+      opt_index = parse_option (&argv[i][1]);
+      if (opt_index < 0)
+       return i;
+
+      opt_code = cl_options[opt_index].opt_code;
+      if (cl_options[opt_index].msg)
+       {
+         arg = &argv[i][cl_options[opt_index].opt_len + 1];
+         /* Yuk. Special case for -W as it must not swallow
+            up any following argument.  If this becomes common, add
+            another field to the cl_options table.  */
+         if (arg[0] == '\0' && opt_code != OPT_W)
+           {
+             arg = argv[++i];
+             if (!arg)
+               {
+                 cpp_error (pfile, DL_ERROR,
+                            cl_options[opt_index].msg, argv[i - 1]);
+                 return argc;
+               }
+           }
+       }
+
+      switch (opt_code)
+       {
+       case N_OPTS: /* Shut GCC up.  */
+         break;
+       case OPT_fno_operator_names:
+         CPP_OPTION (pfile, operator_names) = 0;
+         break;
+       case OPT_fpreprocessed:
+         CPP_OPTION (pfile, preprocessed) = 1;
+         break;
+       case OPT_fno_preprocessed:
+         CPP_OPTION (pfile, preprocessed) = 0;
+         break;
+       case OPT_fshow_column:
+         CPP_OPTION (pfile, show_column) = 1;
+         break;
+       case OPT_fno_show_column:
+         CPP_OPTION (pfile, show_column) = 0;
+         break;
+       case OPT_ftabstop:
+         /* Silently ignore empty string, non-longs and silly values.  */
+         if (arg[0] != '\0')
+           {
+             char *endptr;
+             long tabstop = strtol (arg, &endptr, 10);
+             if (*endptr == '\0' && tabstop >= 1 && tabstop <= 100)
+               CPP_OPTION (pfile, tabstop) = tabstop;
+           }
+         break;
+       case OPT_w:
+         CPP_OPTION (pfile, inhibit_warnings) = 1;
+         break;
+       case OPT_h:
+       case OPT__help:
+         print_help ();
+         CPP_OPTION (pfile, help_only) = 1;
+         break;
+       case OPT_target__help:
+          /* Print if any target specific options. cpplib has none, but
+            make sure help_only gets set.  */
+         CPP_OPTION (pfile, help_only) = 1;
+          break;
+
+         /* --version inhibits compilation, -version doesn't. -v means
+            verbose and -version.  Historical reasons, don't ask.  */
+       case OPT__version:
+         CPP_OPTION (pfile, help_only) = 1;
+         pfile->print_version = 1;
+         break;
+       case OPT_v:
+         CPP_OPTION (pfile, verbose) = 1;
+         pfile->print_version = 1;
+         break;
+       case OPT_version:
+         pfile->print_version = 1;
+         break;
+
+       case OPT_C:
+         CPP_OPTION (pfile, discard_comments) = 0;
+         break;
+       case OPT_P:
+         CPP_OPTION (pfile, no_line_commands) = 1;
+         break;
+       case OPT_dollar:        /* Don't include $ in identifiers.  */
+         CPP_OPTION (pfile, dollars_in_ident) = 0;
+         break;
+       case OPT_H:
+         CPP_OPTION (pfile, print_include_names) = 1;
+         break;
+       case OPT_D:
+         new_pending_directive (pend, arg, cpp_define);
+         break;
+       case OPT_pedantic_errors:
+         CPP_OPTION (pfile, pedantic_errors) = 1;
+         /* fall through */
+       case OPT_pedantic:
+         CPP_OPTION (pfile, pedantic) = 1;
+         break;
+       case OPT_trigraphs:
+         CPP_OPTION (pfile, trigraphs) = 1;
+         break;
+       case OPT_plus:
+         CPP_OPTION (pfile, cplusplus) = 1;
+         CPP_OPTION (pfile, cplusplus_comments) = 1;
+         break;
+       case OPT_remap:
+         CPP_OPTION (pfile, remap) = 1;
+         break;
+       case OPT_iprefix:
+         CPP_OPTION (pfile, include_prefix) = arg;
+         CPP_OPTION (pfile, include_prefix_len) = strlen (arg);
+         break;
+       case OPT_lang_c:
+         cpp_set_lang (pfile, CLK_GNUC89);
+         break;
+       case OPT_lang_cplusplus:
+         cpp_set_lang (pfile, CLK_GNUCXX);
+         break;
+       case OPT_lang_asm:
+         cpp_set_lang (pfile, CLK_ASM);
+         break;
+       case OPT_std_cplusplus98:
+         cpp_set_lang (pfile, CLK_CXX98);
+         break;
+       case OPT_std_gnu89:
+         cpp_set_lang (pfile, CLK_GNUC89);
+         break;
+       case OPT_std_gnu9x:
+       case OPT_std_gnu99:
+         cpp_set_lang (pfile, CLK_GNUC99);
+         break;
+       case OPT_std_iso9899_199409:
+         cpp_set_lang (pfile, CLK_STDC94);
+         break;
+       case OPT_std_iso9899_1990:
+       case OPT_std_c89:
+       case OPT_lang_c89:
+         cpp_set_lang (pfile, CLK_STDC89);
+         break;
+       case OPT_std_iso9899_199x:
+       case OPT_std_iso9899_1999:
+       case OPT_std_c9x:
+       case OPT_std_c99:
+         cpp_set_lang (pfile, CLK_STDC99);
+         break;
+       case OPT_nostdinc:
+         /* -nostdinc causes no default include directories.
+            You must specify all include-file directories with -I.  */
+         CPP_OPTION (pfile, no_standard_includes) = 1;
+         break;
+       case OPT_nostdincplusplus:
+         /* -nostdinc++ causes no default C++-specific include directories.  */
+         CPP_OPTION (pfile, no_standard_cplusplus_includes) = 1;
+         break;
+       case OPT_o:
+         if (CPP_OPTION (pfile, out_fname) == NULL)
+           CPP_OPTION (pfile, out_fname) = arg;
+         else
+           {
+             cpp_error (pfile, DL_ERROR, "output filename specified twice");
+             return argc;
+           }
+         break;
+       case OPT_d:
+         /* Args to -d specify what parts of macros to dump.
+            Silently ignore unrecognised options; they may
+            be aimed at the compiler proper.  */
+         {
+           char c;
+
+           while ((c = *arg++) != '\0')
+             switch (c)
+               {
+               case 'M':
+                 CPP_OPTION (pfile, dump_macros) = dump_only;
+                 break;
+               case 'N':
+                 CPP_OPTION (pfile, dump_macros) = dump_names;
+                 break;
+               case 'D':
+                 CPP_OPTION (pfile, dump_macros) = dump_definitions;
+                 break;
+               case 'I':
+                 CPP_OPTION (pfile, dump_includes) = 1;
+                 break;
+               }
+         }
+         break;
+
+       case OPT_MG:
+         CPP_OPTION (pfile, deps.missing_files) = 1;
+         break;
+       case OPT_M:
+         /* When doing dependencies with -M or -MM, suppress normal
+            preprocessed output, but still do -dM etc. as software
+            depends on this.  Preprocessed output occurs if -MD, -MMD
+            or environment var dependency generation is used.  */
+         CPP_OPTION (pfile, deps.style) = 2;
+         CPP_OPTION (pfile, no_output) = 1;
+         break;
+       case OPT_MM:
+         CPP_OPTION (pfile, deps.style) = 1;
+         CPP_OPTION (pfile, no_output) = 1;
+         break;
+       case OPT_MF:
+         CPP_OPTION (pfile, deps.file) = arg;
+         break;
+       case OPT_MP:
+         CPP_OPTION (pfile, deps.phony_targets) = 1;
+         break;
+       case OPT_MQ:
+       case OPT_MT:
+         /* Add a target.  -MQ quotes for Make.  */
+         deps_add_target (pfile->deps, arg, opt_code == OPT_MQ);
+         break;
+
+       case OPT_MD:
+         CPP_OPTION (pfile, deps.style) = 2;
+         CPP_OPTION (pfile, deps.file) = arg;
+         break;
+       case OPT_MMD:
+         CPP_OPTION (pfile, deps.style) = 1;
+         CPP_OPTION (pfile, deps.file) = arg;
+         break;
+
+       case OPT_A:
+         if (arg[0] == '-')
+           {
+             /* -A with an argument beginning with '-' acts as
+                #unassert on whatever immediately follows the '-'.
+                If "-" is the whole argument, we eliminate all
+                predefined macros and assertions, including those
+                that were specified earlier on the command line.
+                That way we can get rid of any that were passed
+                automatically in from GCC.  */
+
+             if (arg[1] == '\0')
+               {
+                 free_chain (pend->directive_head);
+                 pend->directive_head = NULL;
+                 pend->directive_tail = NULL;
+               }
+             else
+               new_pending_directive (pend, arg + 1, cpp_unassert);
+           }
+         else
+           new_pending_directive (pend, arg, cpp_assert);
+         break;
+       case OPT_U:
+         new_pending_directive (pend, arg, cpp_undef);
+         break;
+       case OPT_I:           /* Add directory to path for includes.  */
+         if (!strcmp (arg, "-"))
+           {
+             /* -I- means:
+                Use the preceding -I directories for #include "..."
+                but not #include <...>.
+                Don't search the directory of the present file
+                for #include "...".  (Note that -I. -I- is not the same as
+                the default setup; -I. uses the compiler's working dir.)  */
+             if (! CPP_OPTION (pfile, ignore_srcdir))
+               {
+                 pend->quote_head = pend->brack_head;
+                 pend->quote_tail = pend->brack_tail;
+                 pend->brack_head = 0;
+                 pend->brack_tail = 0;
+                 CPP_OPTION (pfile, ignore_srcdir) = 1;
+               }
+             else
+               {
+                 cpp_error (pfile, DL_ERROR, "-I- specified twice");
+                 return argc;
+               }
+           }
+         else
+           append_include_chain (pfile, (char *)xstrdup (arg), BRACKET, 0);
+         break;
+       case OPT_isystem:
+         /* Add directory to beginning of system include path, as a system
+            include directory.  */
+         append_include_chain (pfile, (char *)xstrdup (arg), SYSTEM, 0);
+         break;
+       case OPT_include:
+       case OPT_imacros:
+         {
+           struct pending_option *o = (struct pending_option *)
+             xmalloc (sizeof (struct pending_option));
+           o->arg = arg;
+           o->next = NULL;
+
+           if (opt_code == OPT_include)
+             APPEND (pend, include, o);
+           else
+             APPEND (pend, imacros, o);
+         }
+         break;
+       case OPT_iwithprefix:
+         /* Add directory to end of path for includes,
+            with the default prefix at the front of its name.  */
+         /* fall through */
+       case OPT_iwithprefixbefore:
+         /* Add directory to main path for includes,
+            with the default prefix at the front of its name.  */
+         {
+           char *fname;
+           int len;
+
+           len = strlen (arg);
+
+           if (CPP_OPTION (pfile, include_prefix) != 0)
+             {
+               size_t ipl = CPP_OPTION (pfile, include_prefix_len);
+               fname = xmalloc (ipl + len + 1);
+               memcpy (fname, CPP_OPTION (pfile, include_prefix), ipl);
+               memcpy (fname + ipl, arg, len + 1);
+             }
+           else if (cpp_GCC_INCLUDE_DIR_len)
+             {
+               fname = xmalloc (cpp_GCC_INCLUDE_DIR_len + len + 1);
+               memcpy (fname, cpp_GCC_INCLUDE_DIR, cpp_GCC_INCLUDE_DIR_len);
+               memcpy (fname + cpp_GCC_INCLUDE_DIR_len, arg, len + 1);
+             }
+           else
+             fname = xstrdup (arg);
+
+           append_include_chain (pfile, fname,
+                         opt_code == OPT_iwithprefix ? SYSTEM: BRACKET, 0);
+         }
+         break;
+       case OPT_idirafter:
+         /* Add directory to end of path for includes.  */
+         append_include_chain (pfile, (char *)xstrdup (arg), AFTER, 0);
+         break;
+       case OPT_W:
+         /* Silently ignore unrecognised options.  */
+         if (!strcmp (argv[i], "-Wall"))
+           {
+             CPP_OPTION (pfile, warn_trigraphs) = 1;
+             CPP_OPTION (pfile, warn_comments) = 1;
+           }
+         else if (!strcmp (argv[i], "-Wtraditional"))
+           CPP_OPTION (pfile, warn_traditional) = 1;
+         else if (!strcmp (argv[i], "-Wtrigraphs"))
+           CPP_OPTION (pfile, warn_trigraphs) = 1;
+         else if (!strcmp (argv[i], "-Wcomment"))
+           CPP_OPTION (pfile, warn_comments) = 1;
+         else if (!strcmp (argv[i], "-Wcomments"))
+           CPP_OPTION (pfile, warn_comments) = 1;
+         else if (!strcmp (argv[i], "-Wundef"))
+           CPP_OPTION (pfile, warn_undef) = 1;
+         else if (!strcmp (argv[i], "-Wimport"))
+           CPP_OPTION (pfile, warn_import) = 1;
+         else if (!strcmp (argv[i], "-Werror"))
+           CPP_OPTION (pfile, warnings_are_errors) = 1;
+         else if (!strcmp (argv[i], "-Wsystem-headers"))
+           CPP_OPTION (pfile, warn_system_headers) = 1;
+         else if (!strcmp (argv[i], "-Wno-traditional"))
+           CPP_OPTION (pfile, warn_traditional) = 0;
+         else if (!strcmp (argv[i], "-Wno-trigraphs"))
+           CPP_OPTION (pfile, warn_trigraphs) = 0;
+         else if (!strcmp (argv[i], "-Wno-comment"))
+           CPP_OPTION (pfile, warn_comments) = 0;
+         else if (!strcmp (argv[i], "-Wno-comments"))
+           CPP_OPTION (pfile, warn_comments) = 0;
+         else if (!strcmp (argv[i], "-Wno-undef"))
+           CPP_OPTION (pfile, warn_undef) = 0;
+         else if (!strcmp (argv[i], "-Wno-import"))
+           CPP_OPTION (pfile, warn_import) = 0;
+         else if (!strcmp (argv[i], "-Wno-error"))
+           CPP_OPTION (pfile, warnings_are_errors) = 0;
+         else if (!strcmp (argv[i], "-Wno-system-headers"))
+           CPP_OPTION (pfile, warn_system_headers) = 0;
+         break;
+       /* SDCC specific */
+       case OPT_obj_ext:
+         CPP_OPTION (pfile, obj_ext) = arg;
+         break;
+       }
+    }
+  return i + 1;
+}
+
+/* Handle command-line options in (argc, argv).
+   Can be called multiple times, to handle multiple sets of options.
+   Returns if an unrecognized option is seen.
+   Returns number of strings consumed.  */
+int
+cpp_handle_options (pfile, argc, argv)
+     cpp_reader *pfile;
+     int argc;
+     char **argv;
+{
+  int i;
+  int strings_processed;
+
+  for (i = 0; i < argc; i += strings_processed)
+    {
+      strings_processed = cpp_handle_option (pfile, argc - i, argv + i);
+      if (strings_processed == 0)
+       break;
+    }
+
+  return i;
+}
+
+static void
+post_options (pfile)
+     cpp_reader *pfile;
+{
+  /* -Wtraditional is not useful in C++ mode.  */
+  if (CPP_OPTION (pfile, cplusplus))
+    CPP_OPTION (pfile, warn_traditional) = 0;
+
+  /* Permanently disable macro expansion if we are rescanning
+     preprocessed text.  Read preprocesed source in ISO mode.  */
+  if (CPP_OPTION (pfile, preprocessed))
+    {
+      pfile->state.prevent_expansion = 1;
+      CPP_OPTION (pfile, traditional) = 0;
+    }
+
+  /* Traditional CPP does not accurately track column information.  */
+  if (CPP_OPTION (pfile, traditional))
+    CPP_OPTION (pfile, show_column) = 0;
+}
+
+/* Handle --help output.  */
+static void
+print_help ()
+{
+  /* To keep the lines from getting too long for some compilers, limit
+     to about 500 characters (6 lines) per chunk.  */
+  fputs (_("\
+Switches:\n\
+  -include <file>           Include the contents of <file> before other files\n\
+  -imacros <file>           Accept definition of macros in <file>\n\
+  -iprefix <path>           Specify <path> as a prefix for next two options\n\
+  -iwithprefix <dir>        Add <dir> to the end of the system include path\n\
+  -iwithprefixbefore <dir>  Add <dir> to the end of the main include path\n\
+  -isystem <dir>            Add <dir> to the start of the system include path\n\
+"), stdout);
+  fputs (_("\
+  -idirafter <dir>          Add <dir> to the end of the system include path\n\
+  -I <dir>                  Add <dir> to the end of the main include path\n\
+  -I-                       Fine-grained include path control; see info docs\n\
+  -nostdinc                 Do not search system include directories\n\
+                             (dirs specified with -isystem will still be used)\n\
+  -nostdinc++               Do not search system include directories for C++\n\
+  -o <file>                 Put output into <file>\n\
+"), stdout);
+  fputs (_("\
+  -pedantic                 Issue all warnings demanded by strict ISO C\n\
+  -pedantic-errors          Issue -pedantic warnings as errors instead\n\
+  -trigraphs                Support ISO C trigraphs\n\
+  -lang-c                   Assume that the input sources are in C\n\
+  -lang-c89                 Assume that the input sources are in C89\n\
+"), stdout);
+  fputs (_("\
+  -lang-c++                 Assume that the input sources are in C++\n\
+  -lang-asm                 Assume that the input sources are in assembler\n\
+"), stdout);
+  fputs (_("\
+  -std=<std name>           Specify the conformance standard; one of:\n\
+                            gnu89, gnu99, c89, c99, iso9899:1990,\n\
+                            iso9899:199409, iso9899:1999\n\
+  -+                        Allow parsing of C++ style features\n\
+  -w                        Inhibit warning messages\n\
+  -Wtrigraphs               Warn if trigraphs are encountered\n\
+  -Wno-trigraphs            Do not warn about trigraphs\n\
+  -Wcomment{s}              Warn if one comment starts inside another\n\
+"), stdout);
+  fputs (_("\
+  -Wno-comment{s}           Do not warn about comments\n\
+  -Wtraditional             Warn about features not present in traditional C\n\
+  -Wno-traditional          Do not warn about traditional C\n\
+  -Wundef                   Warn if an undefined macro is used by #if\n\
+  -Wno-undef                Do not warn about testing undefined macros\n\
+  -Wimport                  Warn about the use of the #import directive\n\
+"), stdout);
+  fputs (_("\
+  -Wno-import               Do not warn about the use of #import\n\
+  -Werror                   Treat all warnings as errors\n\
+  -Wno-error                Do not treat warnings as errors\n\
+  -Wsystem-headers          Do not suppress warnings from system headers\n\
+  -Wno-system-headers       Suppress warnings from system headers\n\
+  -Wall                     Enable all preprocessor warnings\n\
+"), stdout);
+  fputs (_("\
+  -M                        Generate make dependencies\n\
+  -MM                       As -M, but ignore system header files\n\
+  -MD                       Generate make dependencies and compile\n\
+  -MMD                      As -MD, but ignore system header files\n\
+  -MF <file>                Write dependency output to the given file\n\
+  -MG                       Treat missing header file as generated files\n\
+"), stdout);
+  fputs (_("\
+  -MP                      Generate phony targets for all headers\n\
+  -MQ <target>              Add a MAKE-quoted target\n\
+  -MT <target>              Add an unquoted target\n\
+"), stdout);
+  /* SDCC specific */
+  fputs (_("\
+  -obj-ext=<extension>      Define object file extension, used for generation\n\
+                            of make dependencies\n\
+"), stdout);
+  fputs (_("\
+  -D<macro>                 Define a <macro> with string '1' as its value\n\
+  -D<macro>=<val>           Define a <macro> with <val> as its value\n\
+  -A<question>=<answer>     Assert the <answer> to <question>\n\
+  -A-<question>=<answer>    Disable the <answer> to <question>\n\
+  -U<macro>                 Undefine <macro> \n\
+  -v                        Display the version number\n\
+"), stdout);
+  fputs (_("\
+  -H                        Print the name of header files as they are used\n\
+  -C                        Do not discard comments\n\
+  -dM                       Display a list of macro definitions active at end\n\
+  -dD                       Preserve macro definitions in output\n\
+  -dN                       As -dD except that only the names are preserved\n\
+  -dI                       Include #include directives in the output\n\
+"), stdout);
+  fputs (_("\
+  -fpreprocessed            Treat the input file as already preprocessed\n\
+  -ftabstop=<number>        Distance between tab stops for column reporting\n\
+  -P                        Do not generate #line directives\n\
+  -$                        Do not allow '$' in identifiers\n\
+  -remap                    Remap file names when including files\n\
+  --version                 Display version information\n\
+  -h or --help              Display this information\n\
+"), stdout);
+}
diff --git a/support/cpp2/sdcppmain.c b/support/cpp2/sdcppmain.c
new file mode 100644 (file)
index 0000000..1ac1a9e
--- /dev/null
@@ -0,0 +1,219 @@
+/*-------------------------------------------------------------------------
+    sdcppmain.c - sdcpp: SDCC preprocessor main file, using cpplib.
+
+    Written by Borut Razem, 2006.
+
+    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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 "cpplib.h"
+#include "cpphash.h"
+#include "version.h"
+#include "mkdeps.h"
+
+#define _
+
+#define CPP_FATAL_LIMIT 1000
+/* True if we have seen a "fatal" error.  */
+#define CPP_FATAL_ERRORS(PFILE) (cpp_errors (PFILE) >= CPP_FATAL_LIMIT)
+
+const char *progname;          /* Needs to be global.  */
+
+
+/* Set up dependency-file output.  On exit, if deps.style is non-zero
+   then deps.file is not NULL; stdout is the empty string.  */
+static void
+init_dependency_output (cpp_reader *pfile)
+{
+  char *spec, *s, *output_file;
+
+  /* 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 (CPP_OPTION (pfile, deps.style) == 0)
+    {
+      spec = getenv ("DEPENDENCIES_OUTPUT");
+      if (spec)
+       CPP_OPTION (pfile, deps.style) = 1;
+      else
+       {
+         spec = getenv ("SUNPRO_DEPENDENCIES");
+         if (spec)
+           {
+             CPP_OPTION (pfile, deps.style) = 2;
+             CPP_OPTION (pfile, deps.ignore_main_file) = 1;
+           }
+         else
+           return;
+       }
+
+      /* Find the space before the DEPS_TARGET, if there is one.  */
+      s = strchr (spec, ' ');
+      if (s)
+       {
+         /* Let the caller perform MAKE quoting.  */
+         deps_add_target (pfile->deps, s + 1, 0);
+         output_file = (char *) xmalloc (s - spec + 1);
+         memcpy (output_file, spec, s - spec);
+         output_file[s - spec] = 0;
+       }
+      else
+       output_file = spec;
+
+      /* Command line -MF overrides environment variables and default.  */
+      if (CPP_OPTION (pfile, deps.file) == 0)
+       CPP_OPTION (pfile, deps.file) = output_file;
+
+      CPP_OPTION (pfile, deps.append) = 1;
+    }
+  else if (CPP_OPTION (pfile, deps.file) == 0)
+    /* If -M or -MM was seen without -MF, default output to wherever
+       was specified with -o.  out_fname is non-NULL here.  */
+    CPP_OPTION (pfile, deps.file) = CPP_OPTION (pfile, out_fname);
+}
+
+static void
+sdcpp_post_options (cpp_reader *pfile)
+{
+  if (pfile->print_version)
+    {
+      fprintf (stderr, _("GNU CPP version %s (cpplib)"), version_string);
+#ifdef TARGET_VERSION
+      TARGET_VERSION;
+#endif
+      fputc ('\n', stderr);
+    }
+
+  /* Canonicalize in_fname and out_fname.  We guarantee they are not
+     NULL, and that the empty string represents stdin / stdout.  */
+  if (CPP_OPTION (pfile, in_fname) == NULL
+      || !strcmp (CPP_OPTION (pfile, in_fname), "-"))
+    CPP_OPTION (pfile, in_fname) = "";
+
+  if (CPP_OPTION (pfile, out_fname) == NULL
+      || !strcmp (CPP_OPTION (pfile, out_fname), "-"))
+    CPP_OPTION (pfile, out_fname) = "";
+
+  /* -dM makes no normal output.  This is set here so that -dM -dD
+     works as expected.  */
+  if (CPP_OPTION (pfile, dump_macros) == dump_only)
+    CPP_OPTION (pfile, no_output) = 1;
+
+  /* Disable -dD, -dN and -dI if we should make no normal output
+     (such as with -M). Allow -M -dM since some software relies on
+     this.  */
+  if (CPP_OPTION (pfile, no_output))
+    {
+      if (CPP_OPTION (pfile, dump_macros) != dump_only)
+       CPP_OPTION (pfile, dump_macros) = dump_none;
+      CPP_OPTION (pfile, dump_includes) = 0;
+    }
+
+  /* We need to do this after option processing and before
+     cpp_start_read, as cppmain.c relies on the options->no_output to
+     set its callbacks correctly before calling cpp_start_read.  */
+  init_dependency_output (pfile);
+
+  /* After checking the environment variables, check if -M or -MM has
+     not been specified, but other -M options have.  */
+  if (CPP_OPTION (pfile, deps.style) == 0 &&
+      (CPP_OPTION (pfile, deps.missing_files)
+       || CPP_OPTION (pfile, deps.file)
+       || CPP_OPTION (pfile, deps.phony_targets)))
+    cpp_error (pfile, DL_ERROR, "you must additionally specify either -M or -MM");
+}
+
+/* Store the program name, and set the locale.  */
+static void
+general_init (const char *argv0)
+{
+  progname = argv0 + strlen (argv0);
+
+  while (progname != argv0 && ! IS_DIR_SEPARATOR (progname[-1]))
+    --progname;
+
+  hex_init ();
+}
+
+/* Handle switches, preprocess and output.  */
+static void
+do_preprocessing (cpp_reader *pfile, int argc, char **argv)
+{
+  FILE *outf;
+  int argi = 1;  /* Next argument to handle.  */
+
+  argi += cpp_handle_options (pfile, argc - argi , argv + argi);
+  if (CPP_FATAL_ERRORS (pfile))
+    return;
+
+  if (argi < argc)
+    {
+      cpp_error (pfile, DL_ERROR, "invalid option %s", argv[argi]);
+      return;
+    }
+
+  sdcpp_post_options (pfile);
+  if (CPP_FATAL_ERRORS (pfile))
+    return;
+
+  /* If cpp_handle_options saw --help or --version on the command
+     line, it will have set pfile->help_only to indicate this.  Exit
+     successfully.  [The library does not exit itself, because
+     e.g. cc1 needs to print its own --help message at this point.]  */
+  if (pfile->opts.help_only)
+    return;
+
+  /* Open the output now.  We must do so even if no_output is on,
+     because there may be other output than from the actual
+     preprocessing (e.g. from -dM).  */
+  if (CPP_OPTION(pfile, out_fname)[0] == '\0')
+    outf = stdout;
+  else
+    {
+      outf = fopen (CPP_OPTION(pfile, out_fname), "w");
+      if (outf == NULL)
+       {
+         cpp_errno (pfile, DL_ERROR, CPP_OPTION(pfile, out_fname));
+         return;
+       }
+    }
+
+  cpp_preprocess_file (pfile, pfile->opts.in_fname, outf);
+}
+
+int
+main (int argc, char **argv)
+{
+  cpp_reader *pfile;
+
+  general_init (argv[0]);
+
+  /* Construct a reader with default language GNU C89.  */
+  pfile = cpp_create_reader (CLK_GNUC89);
+
+  do_preprocessing (pfile, argc, argv);
+
+  cpp_destroy (pfile);
+
+  return SUCCESS_EXIT_CODE;
+}
index e9cefaf8b12d6bb14957ea50ba0ef41043318649..07b188ae1998702d929680884af401128860114a 100644 (file)
@@ -23,11 +23,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #ifndef GCC_SYSTEM_H
 #define GCC_SYSTEM_H
 
-/* This is the location of the online document giving information how
-   to report bugs. If you change this string, also check for strings
-   not under control of the preprocessor.  */
-#define GCCBUGURL "<URL:http://sdcc.sourceforge.net>"
-
 #include "ansidecl.h"
 
 /* We must include stdarg.h/varargs.h before stdio.h.  */
@@ -493,11 +488,19 @@ typedef char _Bool;
    compiling gcc, so that the autoconf declaration tests for malloc
    etc don't spuriously fail.  */
 #ifdef IN_GCC
-#undef malloc
-#undef realloc
 #undef calloc
 #undef strdup
- #pragma GCC poison malloc realloc calloc strdup
+ #pragma GCC poison calloc strdup
+
+#if defined(FLEX_SCANNER) || defined (YYBISON) || defined(YYBYACC)
+/* Flex and bison use malloc and realloc.  Yuk.  */
+#define malloc xmalloc
+#define realloc xrealloc
+#else
+#undef malloc
+#undef realloc
+ #pragma GCC poison malloc realloc
+#endif
 
 /* Old target macros that have moved to the target hooks structure.  */
  #pragma GCC poison ASM_OPEN_PAREN ASM_CLOSE_PAREN                     \
@@ -508,9 +511,12 @@ typedef char _Bool;
        SET_DEFAULT_TYPE_ATTRIBUTES SET_DEFAULT_DECL_ATTRIBUTES         \
        MERGE_MACHINE_TYPE_ATTRIBUTES MERGE_MACHINE_DECL_ATTRIBUTES     \
        MD_INIT_BUILTINS MD_EXPAND_BUILTIN ASM_OUTPUT_CONSTRUCTOR       \
-       ASM_OUTPUT_DESTRUCTOR SIGNED_CHAR_SPEC
+       ASM_OUTPUT_DESTRUCTOR SIGNED_CHAR_SPEC MAX_CHAR_TYPE_SIZE       \
+       WCHAR_UNSIGNED UNIQUE_SECTION SELECT_SECTION SELECT_RTX_SECTION \
+       ENCODE_SECTION_INFO STRIP_NAME_ENCODING ASM_GLOBALIZE_LABEL     \
+       ASM_OUTPUT_MI_THUNK
 
-/* And other obsolete target macros, or macros that used to be in target
+/* Other obsolete target macros, or macros that used to be in target
    headers and were not used, and may be obsolete or may never have
    been used.  */
  #pragma GCC poison INT_ASM_OP ASM_OUTPUT_EH_REGION_BEG                           \
@@ -520,9 +526,16 @@ typedef char _Bool;
        LONGJMP_RESTORE_FROM_STACK MAX_INT_TYPE_SIZE ASM_IDENTIFY_GCC      \
        STDC_VALUE TRAMPOLINE_ALIGN ASM_IDENTIFY_GCC_AFTER_SOURCE          \
        SLOW_ZERO_EXTEND SUBREG_REGNO_OFFSET DWARF_LINE_MIN_INSTR_LENGTH   \
-       BLOCK_PROFILER BLOCK_PROFILER_CODE FUNCTION_BLOCK_PROFILER         \
-       FUNCTION_BLOCK_PROFILER_EXIT MACHINE_STATE_SAVE                    \
-       MACHINE_STATE_RESTORE
+       TRADITIONAL_RETURN_FLOAT NO_BUILTIN_SIZE_TYPE                      \
+       NO_BUILTIN_PTRDIFF_TYPE NO_BUILTIN_WCHAR_TYPE NO_BUILTIN_WINT_TYPE \
+       BLOCK_PROFILER BLOCK_PROFILER_CODE FUNCTION_BLOCK_PROFILER         \
+       FUNCTION_BLOCK_PROFILER_EXIT MACHINE_STATE_SAVE                    \
+       MACHINE_STATE_RESTORE SCCS_DIRECTIVE SECTION_ASM_OP                \
+       ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
+
+/* Hooks that are no longer used.  */
+ #pragma GCC poison LANG_HOOKS_FUNCTION_MARK LANG_HOOKS_FUNCTION_FREE  \
+       LANG_HOOKS_MARK_TREE
 
 #endif /* IN_GCC */
 
index 18a2df8ad659e5dd07b1d5f43302abefccd6b40f..582349b0b049b09b93e275cea6cd84a89d6929f5 100644 (file)
@@ -1,4 +1,18 @@
 #include "ansidecl.h"
 #include "version.h"
 
-const char *const version_string = "3.2.3 + SDCC";
+/* This is the string reported as the version number by all components
+   of the compiler.  If you distribute a modified version of GCC,
+   please modify this string to indicate that, e.g. by putting your
+   organization's name in parentheses at the end of the string.  */
+
+const char version_string[] = "3.3.6 + SDCC";
+
+/* This is the location of the online document giving instructions for
+   reporting bugs.  If you distribute a modified version of GCC,
+   please change this to refer to a document giving instructions for
+   reporting bugs to you, not us.  (You are of course welcome to
+   forward us bugs reported to you, if you determine that they are
+   not bugs in your modifications.)  */
+
+const char bug_report_url[] = "<URL:http://sdcc.sourceforge.net>";
index 99416495a4f180adade0c3b13581c9830603c238..8e944ccdef60232e611394d5939a1eb485541d22 100644 (file)
@@ -1,4 +1,5 @@
 #ifndef GCC_VERSION_H
 #define GCC_VERSION_H
-extern const char *const version_string;
+extern const char version_string[];
+extern const char bug_report_url[];
 #endif /* ! GCC_VERSION_H */