Makefile.in: Update for cpptrad.c.
authorNeil Booth <neil@daikokuya.demon.co.uk>
Fri, 17 May 2002 20:16:48 +0000 (20:16 +0000)
committerNeil Booth <neil@gcc.gnu.org>
Fri, 17 May 2002 20:16:48 +0000 (20:16 +0000)
* Makefile.in: Update for cpptrad.c.
* cpphash.h (struct cpp_buffer): New members for buffer
overlays.
(struct cpp_reader): New members for traditional output.
(_cpp_read_logical_line, _cpp_overlay_buffer): New.
* cppinit.c (cpp_create_reader): Set trad_line.
(cpp_destroy): Free trad_out_base if used.
(cpp_read_main_file): Overlay an empty buffer if traditional.
(cpp_finish_options): Don't do builtins.
(COMMAND_LINE_OPTIONS): Add -traditional-cpp.
(cpp_handle_option): Handle it.
* cpplex.c (continue_after_nul): New.
(_cpp_lex_direct): Use handle_nul.
* cpplib.h (struct cpp_options): New traditional option.
* cpptrad.c: New file.

From-SVN: r53568

gcc/ChangeLog
gcc/Makefile.in
gcc/cpphash.h
gcc/cppinit.c
gcc/cpplex.c
gcc/cpplib.h
gcc/cpptrad.c [new file with mode: 0644]

index 42c8f168d4c0766b575d526fb8b7232804a2033d..afadd9db08c95e3013f248868b3c3c01935d1156 100644 (file)
@@ -1,3 +1,21 @@
+2002-05-17  Neil Booth  <neil@daikokuya.demon.co.uk>
+
+       * Makefile.in: Update for cpptrad.c.
+       * cpphash.h (struct cpp_buffer): New members for buffer
+       overlays.
+       (struct cpp_reader): New members for traditional output.
+       (_cpp_read_logical_line, _cpp_overlay_buffer): New.
+       * cppinit.c (cpp_create_reader): Set trad_line.
+       (cpp_destroy): Free trad_out_base if used.
+       (cpp_read_main_file): Overlay an empty buffer if traditional.
+       (cpp_finish_options): Don't do builtins.
+       (COMMAND_LINE_OPTIONS): Add -traditional-cpp.
+       (cpp_handle_option): Handle it.
+       * cpplex.c (continue_after_nul): New.
+       (_cpp_lex_direct): Use handle_nul.
+       * cpplib.h (struct cpp_options): New traditional option.
+       * cpptrad.c: New file.
+
 2002-05-17  Neil Booth  <neil@daikokuya.demon.co.uk>
 
        * c-common.c (c_common_init_options): Use C89 for Objective-C,
index 72943faf224a20aad35bc24e7d2785e7b34d0c68..7c3f961dbf53096b72c7ae9d994c3598579be7f6 100644 (file)
@@ -1993,7 +1993,7 @@ 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 \
+LIBCPP_OBJS =  cpplib.o cpplex.o cppmacro.o cppexp.o cppfiles.o cpptrad.o \
                cpphash.o cpperror.o cppinit.o cppdefault.o cppmain.o \
                hashtable.o line-map.o mkdeps.o prefix.o version.o mbchar.o
 
@@ -2015,6 +2015,7 @@ cpplex.o:   cpplex.c   $(CONFIG_H) $(LIBCPP_DEPS) mbchar.h
 cppmacro.o: cppmacro.c $(CONFIG_H) $(LIBCPP_DEPS)
 cpplib.o:   cpplib.c   $(CONFIG_H) $(LIBCPP_DEPS)
 cpphash.o:  cpphash.c  $(CONFIG_H) $(LIBCPP_DEPS)
+cpptrad.o:  cpptrad.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 version.h
index 3d82316372a147a049cd6035d78383511c3072e5..dcbb4fc1ae622a66428983b43939e8b31c465755 100644 (file)
@@ -245,6 +245,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, *saved_line_base;
 };
 
 /* A cpp_reader encapsulates the "state" of a pre-processor run.
@@ -355,6 +358,11 @@ struct cpp_reader
 
   /* Whether cpplib owns the hashtable.  */
   unsigned char our_hashtable;
+
+  /* Traditional preprocessing output buffer.  */
+  uchar *trad_out_base, *trad_out_limit;
+  uchar *trad_out_cur;
+  unsigned int trad_line;
 };
 
 /* Character classes.  Based on the more primitive macros in safe-ctype.h.
@@ -447,6 +455,11 @@ 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));
+
 /* Utility routines and macros.  */
 #define DSC(str) (const uchar *)str, sizeof str - 1
 #define xnew(T)                (T *) xmalloc (sizeof(T))
index cb3f483d550381841ea9694c2553deaf499fbabc..c7d51b765e9ee4bd675afe6b7d1079fc6b112616 100644 (file)
@@ -510,7 +510,7 @@ cpp_create_reader (lang)
   /* Initialise 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;
+  pfile->trad_line = pfile->line = 1;
 
   /* Initialize lexer state.  */
   pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);
@@ -565,6 +565,9 @@ cpp_destroy (pfile)
   while (CPP_BUFFER (pfile) != NULL)
     _cpp_pop_buffer (pfile);
 
+  if (pfile->trad_out_base)
+    free (pfile->trad_out_base);
+
   if (pfile->macro_buffer)
     {
       free ((PTR) pfile->macro_buffer);
@@ -950,6 +953,9 @@ cpp_read_main_file (pfile, fname, table)
      of the front ends.  */
   if (CPP_OPTION (pfile, preprocessed))
     read_original_filename (pfile);
+  /* Overlay an empty buffer to seed traditional preprocessing.  */
+  else if (CPP_OPTION (pfile, traditional))
+    _cpp_overlay_buffer (pfile, U"", 0);
 
   return pfile->map->to_file;
 }
@@ -998,10 +1004,12 @@ cpp_finish_options (pfile)
       struct pending_option *p;
 
       _cpp_do_file_change (pfile, LC_RENAME, _("<built-in>"), 1, 0);
-      init_builtins (pfile);
+      if (!CPP_OPTION (pfile, traditional) /* REMOVEME */)
+       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);
+      if (!CPP_OPTION (pfile, traditional) /* REMOVEME */)
+       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
@@ -1195,6 +1203,7 @@ new_pending_directive (pend, text, handler)
   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("traditional-cpp",         0,      OPT_traditional_cpp)            \
   DEF_OPT("trigraphs",                0,      OPT_trigraphs)                  \
   DEF_OPT("v",                        0,      OPT_v)                          \
   DEF_OPT("version",                  0,      OPT_version)                    \
@@ -1444,6 +1453,9 @@ cpp_handle_option (pfile, argc, argv, ignore)
        case OPT_remap:
          CPP_OPTION (pfile, remap) = 1;
          break;
+       case OPT_traditional_cpp:
+         CPP_OPTION (pfile, traditional) = 1;
+         break;
        case OPT_iprefix:
          CPP_OPTION (pfile, include_prefix) = arg;
          CPP_OPTION (pfile, include_prefix_len) = strlen (arg);
index f2d07963f79dc305bafbc3eff29ba0d590b65b25..44ca1d869499ec51e0263de1e624f226bbe9d361 100644 (file)
@@ -78,6 +78,7 @@ static void parse_string PARAMS ((cpp_reader *, cpp_token *, cppchar_t));
 static bool trigraph_p PARAMS ((cpp_reader *));
 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 *, cppchar_t *));
@@ -877,6 +878,48 @@ _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))
+    more = _cpp_read_logical_line_trad (pfile);
+  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)    \
@@ -927,30 +970,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)
-       {
-         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);
-           }
-
-         /* Don't pop the last buffer.  */
-         if (!pfile->state.in_directive && 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;
 
index 378fa7e2e54cd7cd5f34f1e77106fb7ae1486112..982d0f14eae2affc2027554d15fe3b51a7d7c422 100644 (file)
@@ -387,6 +387,9 @@ struct cpp_options
      parsing; drivers might want to continue printing help.  */
   unsigned char help_only;
 
+  /* True for traditional preprocessing.  */
+  unsigned char traditional;
+
   /* Target-specific features set by the front end or client.  */
 
   /* Precision for target CPP arithmetic, target characters, target
diff --git a/gcc/cpptrad.c b/gcc/cpptrad.c
new file mode 100644 (file)
index 0000000..a6178e3
--- /dev/null
@@ -0,0 +1,315 @@
+/* CPP Library - traditional lexical analysis and macro expansion.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   Contributed by Neil Booth, May 2002
+
+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"
+
+/* Lexing TODO: Handle -Wcomment, -C, maybe -CC, and space in escaped
+   newlines.  Stop cpplex.c from recognizing comments, trigraphs and
+   directives during its lexing pass.  */
+
+static const uchar *handle_newline PARAMS ((cpp_reader *, const uchar *));
+static const uchar *skip_escaped_newlines PARAMS ((cpp_reader *,
+                                                  const uchar *));
+static cpp_hashnode *lex_identifier PARAMS ((cpp_reader *, const uchar *));
+static const uchar *skip_comment PARAMS ((cpp_reader *, const uchar *));
+static void scan_out_logical_line PARAMS ((cpp_reader *pfile));
+static void check_output_buffer PARAMS ((cpp_reader *, size_t));
+static void restore_buff PARAMS ((cpp_reader *));
+
+/* Ensures we have N bytes' space in the output buffer, and
+   reallocates it if not.  */
+static void
+check_output_buffer (pfile, n)
+     cpp_reader *pfile;
+     size_t n;
+{
+  if (n > (size_t) (pfile->trad_out_limit - pfile->trad_out_cur))
+    {
+      size_t size = pfile->trad_out_cur - pfile->trad_out_base;
+      size_t new_size = (size + n) * 3 / 2;
+
+      pfile->trad_out_base
+       = (uchar *) xrealloc (pfile->trad_out_base, new_size);
+      pfile->trad_out_limit = pfile->trad_out_base + new_size;
+      pfile->trad_out_cur = pfile->trad_out_base + size;
+    }
+}
+
+/* To be called whenever a newline character is encountered in the
+   input file, at CUR.  Handles DOS, MAC and Unix ends of line, and
+   returns the character after the newline sequence.  */
+static const uchar *
+handle_newline (pfile, cur)
+     cpp_reader *pfile;
+     const uchar *cur;
+{
+  pfile->line++;
+  if (cur[0] + cur[1] == '\r' + '\n')
+    cur++;
+  return cur + 1;
+}
+
+/* CUR points to any character in the buffer, not necessarily a
+   backslash.  Advances CUR until all escaped newlines are skipped,
+   and returns the new position.  */
+static const uchar *
+skip_escaped_newlines (pfile, cur)
+     cpp_reader *pfile;
+     const uchar *cur;
+{
+  while (*cur == '\\' && is_vspace (cur[1]))
+    cur = handle_newline (pfile, cur + 1);
+
+  return cur;
+}
+
+/* CUR points to the character after the asterisk introducing a
+   comment.  Returns the position after the comment.  */
+static const uchar *
+skip_comment (pfile, cur)
+     cpp_reader *pfile;
+     const uchar *cur;
+{
+  unsigned int from_line = pfile->line;
+
+  for (;;)
+    {
+      unsigned int c = *cur++;
+      if (c == '*')
+       {
+         cur = skip_escaped_newlines (pfile, cur);
+         if (*cur == '/')
+           {
+             cur++;
+             break;
+           }
+       }
+      else if (is_vspace (c))
+       cur = handle_newline (pfile, cur - 1);
+      else if (c == '\0' && cur - 1 == pfile->buffer->rlimit)
+       {
+         cur--;
+         cpp_error_with_line (pfile, DL_ERROR, from_line, 0,
+                              "unterminated comment");
+         break;
+       }
+    }
+
+  return cur;
+}
+
+/* Lexes and outputs an identifier starting at CUR, which is assumed
+   to point to a valid first character of an identifier.  Returns
+   the hashnode, and updates trad_out_cur.  */
+static cpp_hashnode *
+lex_identifier (pfile, cur)
+     cpp_reader *pfile;
+     const uchar *cur;
+{
+  size_t len;
+  uchar *out = pfile->trad_out_cur;
+
+  do
+    {
+      do
+       *out++ = *cur++;
+      while (ISIDNUM (*cur));
+      cur = skip_escaped_newlines (pfile, cur);
+    }
+  while (ISIDNUM (*cur));
+
+  pfile->buffer->cur = cur;
+  len = out - pfile->trad_out_cur;
+  pfile->trad_out_cur = out;
+  return (cpp_hashnode *) ht_lookup (pfile->hash_table, pfile->trad_out_cur,
+                                    len, HT_ALLOC);
+}
+
+/* Overlays the true file buffer temporarily with text of length LEN
+   starting at START.  The true buffer is restored upon calling
+   restore_buff().  */
+void
+_cpp_overlay_buffer (pfile, start, len)
+     cpp_reader *pfile;
+     const uchar *start;
+     size_t len;
+{
+  cpp_buffer *buffer = pfile->buffer;
+
+  buffer->saved_cur = buffer->cur;
+  buffer->saved_rlimit = buffer->rlimit;
+  buffer->saved_line_base = buffer->line_base;
+
+  buffer->cur = start;
+  buffer->line_base = start;
+  buffer->rlimit = start + len;
+}
+
+/* Restores a buffer overlaid by _cpp_overlay_buffer().  */
+static void
+restore_buff (pfile)
+     cpp_reader *pfile;
+{
+  cpp_buffer *buffer = pfile->buffer;
+
+  buffer->cur = buffer->saved_cur;
+  buffer->rlimit = buffer->saved_rlimit;
+  buffer->line_base = buffer->saved_line_base;
+}
+
+/* Reads a logical line into the output buffer.  Returns TRUE if there
+   is more text left in the buffer.  */
+bool
+_cpp_read_logical_line_trad (pfile)
+     cpp_reader *pfile;
+{
+  cpp_buffer *buffer;
+  unsigned int first_line;
+
+  restore_buff (pfile);
+
+  first_line = pfile->line = pfile->trad_line;
+
+  buffer = pfile->buffer;
+  if (buffer->cur == buffer->rlimit)
+    {
+      bool stop = true;
+
+      /* Don't pop the last buffer.  */
+      if (buffer->prev)
+       {
+         stop = buffer->return_at_eof;
+         _cpp_pop_buffer (pfile);
+       }
+
+      if (stop)
+       return false;
+    }
+
+  pfile->trad_out_cur = pfile->trad_out_base;
+  scan_out_logical_line (pfile);
+  pfile->trad_line = pfile->line;
+  pfile->line = first_line;
+  _cpp_overlay_buffer (pfile, pfile->trad_out_base,
+                      pfile->trad_out_cur - pfile->trad_out_base);
+  return true;
+}
+
+/* Copies the next logical line in the current buffer to the output
+   buffer.  The output is guaranteed to terminate with a NUL
+   character.  */
+static void
+scan_out_logical_line (pfile)
+     cpp_reader *pfile;
+{
+  cpp_buffer *buffer = pfile->buffer;
+  const uchar *cur = buffer->cur;
+  unsigned int c, quote = 0;
+  uchar *out;
+
+  check_output_buffer (pfile, buffer->rlimit - cur);
+  out = pfile->trad_out_cur;
+
+  for (;;)
+    {
+      c = *cur++;
+      *out++ = c;
+
+      /* There are only a few entities we need to catch: comments,
+        identifiers, newlines, escaped newlines, # and '\0'.  */
+      switch (c)
+       {
+       case '\0':
+         if (cur - 1 != buffer->rlimit)
+           break;
+         cur--;
+         if (!buffer->from_stage3)
+           cpp_error (pfile, DL_PEDWARN, "no newline at end of file");
+         pfile->line++;
+         if (0)
+           {
+           case '\r': case '\n':
+             cur = handle_newline (pfile, cur - 1);
+           }
+         out[-1] = '\n';
+         out[0] = '\0';
+         buffer->cur = cur;
+         pfile->trad_out_cur = out;
+         return;
+
+       case '"':
+       case '\'':
+         if (c == quote)
+           quote = 0;
+         else if (!quote)
+           quote = c;
+         break;
+
+       case '\\':
+         if (is_vspace (*cur))
+           out--, cur = skip_escaped_newlines (pfile, cur - 1);
+         else
+           {
+             /* Skip escaped quotes here, it's easier than above, but
+                take care to first skip escaped newlines.  */
+             cur = skip_escaped_newlines (pfile, cur);
+             if (*cur == '\\' || *cur == '"' || *cur == '\'')
+               *out++ = *cur++;
+           }
+         break;
+
+       case '/':
+         /* Traditional CPP does not recognize comments within
+            literals.  */
+         if (!quote)
+           {
+             cur = skip_escaped_newlines (pfile, cur);
+             if (*cur == '*')
+               out--, cur = skip_comment (pfile, cur + 1);
+           }
+         break;
+
+       case '_':
+       case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+       case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
+       case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
+       case 's': case 't': case 'u': case 'v': case 'w': case 'x':
+       case 'y': case 'z':
+       case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+       case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+       case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+       case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+       case 'Y': case 'Z':
+         {
+           cpp_hashnode *node;
+
+           pfile->trad_out_cur = --out;
+           node = lex_identifier (pfile, cur - 1);
+           out = pfile->trad_out_cur;
+           cur = buffer->cur;
+         }
+         break;
+
+       default:
+         break;
+       }
+    }
+}