cppfiles.c (read_and_prescan): Map backslash-newline to '\r' (which cannot otherwise...
authorZack Weinberg <zack@rabi.columbia.edu>
Tue, 16 Mar 1999 13:10:15 +0000 (13:10 +0000)
committerDave Brolley <brolley@gcc.gnu.org>
Tue, 16 Mar 1999 13:10:15 +0000 (08:10 -0500)
1999-03-16 16:06 -0500  Zack Weinberg  <zack@rabi.columbia.edu>
* cppfiles.c (read_and_prescan): Map backslash-newline to '\r'
(which cannot otherwise appear in the processed buffer) and
move it out of tokens that it appears in the middle of.
Improve performance.
(find_position): New function.
* cpplib.c: \r (one character) indicates backslash
newline, not \\\n (two characters).  It cannot appear in the
middle of a token.  Call CPP_BUMP_LINE (pfile) whenever
parsing moves past \n or \r.  Increment pfile->lineno whenever
a \n is placed into token_buffer.  Only one mark can exist at
a time, and CPP_BUMP_LINE must not be used while it is
active.  It is automatically cleared by cpp_pop_buffer and
parse_goto_mark.  \r is not in is_hor_space or is_space.
(NEWLINE_FIX, NEWLINE_FIX1, adjust_position,
update_position, count_newlines, parse_move_mark): Removed.
(parse_string, copy_comment): New functions.
(parse_name): Returns void.
(parse_set_mark, parse_clear_mark, parse_goto_mark): Take only
one argument, a cpp_reader *.  Change for new marking scheme.
(skip_comment): Handle CHILL line comments too.  Second
argument is now first character of comment marker; all callers
changed.  Issue error for unterminated block comment here.
(cpp_skip_hspace): Recognize CHILL comments.
(copy_rest_of_line): Likewise.  Call skip_comment and
parse_string directly, don't go through cpp_get_token.  Emit
"/**/" for block comments if -traditional (create_definition
needs this).
(do_define): Don't play with put_out_comments.
(cpp_push_buffer): Initialize ->mark to -1.
(cpp_buf_line_and_col): Just read out the values in the buffer
structure.
(output_line_command): Use cpp_buf_line_and_col.  Fix
formatting.  Remove stale code.
(cpp_get_token): Break out string parsing code to
parse_string.  Use skip_comment for CHILL comments too.  Use
copy_comment for put_out_comments instead of dinking with
marks.  Remove stale code.  Don't call output_line_command
unless it's necessary.
* cpplib.h (parse_marker): Removed.
(struct cpp_buffer): line_base is now a unsigned char *; add
`mark' [long], remove `marks' [struct parse_marker *].
(parse_set_mark, parse_clear_mark, parse_goto_mark): Update
prototypes.
(CPP_BUMP_LINE, CPP_BUMP_BUFFER_LINE): New macros.
* cppinit.c (is_hor_space, is_space): '\r' is not considered
whitespace.
* cppexp.c (cpp_parse_expression): Use cpp_skip_hspace, not
SKIP_WHITE_SPACE.
* cpphash.c (macarg): Disable line commands while expanding.

From-SVN: r25802

gcc/ChangeLog
gcc/cppexp.c
gcc/cppfiles.c
gcc/cpphash.c
gcc/cppinit.c
gcc/cpplib.c
gcc/cpplib.h

index 398ab23e7390e37a20e78f5411866d89780932d1..f697c1ce4615f19cfe1c2d5a5da755c6389b2f7e 100644 (file)
@@ -1,3 +1,58 @@
+1999-03-16 16:06 -0500  Zack Weinberg  <zack@rabi.columbia.edu>
+
+       * cppfiles.c (read_and_prescan): Map backslash-newline to '\r'
+       (which cannot otherwise appear in the processed buffer) and
+       move it out of tokens that it appears in the middle of.
+       Improve performance.
+       (find_position): New function.
+
+       * cpplib.c: \r (one character) indicates backslash
+       newline, not \\\n (two characters).  It cannot appear in the
+       middle of a token.  Call CPP_BUMP_LINE (pfile) whenever
+       parsing moves past \n or \r.  Increment pfile->lineno whenever
+       a \n is placed into token_buffer.  Only one mark can exist at
+       a time, and CPP_BUMP_LINE must not be used while it is
+       active.  It is automatically cleared by cpp_pop_buffer and
+       parse_goto_mark.  \r is not in is_hor_space or is_space.
+
+       (NEWLINE_FIX, NEWLINE_FIX1, adjust_position,
+       update_position, count_newlines, parse_move_mark): Removed.
+       (parse_string, copy_comment): New functions.
+       (parse_name): Returns void.
+       (parse_set_mark, parse_clear_mark, parse_goto_mark): Take only
+       one argument, a cpp_reader *.  Change for new marking scheme.
+       (skip_comment): Handle CHILL line comments too.  Second
+       argument is now first character of comment marker; all callers
+       changed.  Issue error for unterminated block comment here.
+       (cpp_skip_hspace): Recognize CHILL comments.
+       (copy_rest_of_line): Likewise.  Call skip_comment and
+       parse_string directly, don't go through cpp_get_token.  Emit
+       "/**/" for block comments if -traditional (create_definition
+       needs this).
+       (do_define): Don't play with put_out_comments.
+       (cpp_push_buffer): Initialize ->mark to -1.
+       (cpp_buf_line_and_col): Just read out the values in the buffer
+       structure.
+       (output_line_command): Use cpp_buf_line_and_col.  Fix
+       formatting.  Remove stale code.
+       (cpp_get_token): Break out string parsing code to
+       parse_string.  Use skip_comment for CHILL comments too.  Use
+       copy_comment for put_out_comments instead of dinking with
+       marks.  Remove stale code.  Don't call output_line_command
+       unless it's necessary.
+
+       * cpplib.h (parse_marker): Removed.
+       (struct cpp_buffer): line_base is now a unsigned char *; add
+       `mark' [long], remove `marks' [struct parse_marker *].
+       (parse_set_mark, parse_clear_mark, parse_goto_mark): Update
+       prototypes.
+       (CPP_BUMP_LINE, CPP_BUMP_BUFFER_LINE): New macros.
+       * cppinit.c (is_hor_space, is_space): '\r' is not considered
+       whitespace.
+       * cppexp.c (cpp_parse_expression): Use cpp_skip_hspace, not
+       SKIP_WHITE_SPACE.
+       * cpphash.c (macarg): Disable line commands while expanding.
+
 Tue Mar 16 11:30:19 1999  Gavin Romig-Koch  <gavin@cygnus.com>
 
        * c-lex.c (yylex) : Remove warning for integer literals being
index 8b59630af03639f7729577221a3131728bd695ac..eaec4686d7590ad84eed8ddf76adf83147558456 100644 (file)
@@ -101,8 +101,6 @@ static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT, int,
 #define SKIP_OPERAND 8
 /*#define UNSIGNEDP 16*/
 
-#define SKIP_WHITE_SPACE(p) do { while (is_hor_space[*p]) p++; } while (0)
-
 struct operation {
     short op;
     char rprio; /* Priority of op (relative to it right operand).  */
@@ -444,12 +442,12 @@ cpp_lex (pfile, skip_evaluation)
          cpp_buffer *ip = CPP_BUFFER (pfile);
          U_CHAR *tok;
 
-         SKIP_WHITE_SPACE (ip->cur);
+         cpp_skip_hspace (pfile);
          if (*ip->cur == '(')
            {
              paren++;
              ip->cur++;                        /* Skip over the paren */
-             SKIP_WHITE_SPACE (ip->cur);
+             cpp_skip_hspace (pfile);
            }
 
          if (!is_idstart[*ip->cur])
@@ -460,7 +458,7 @@ cpp_lex (pfile, skip_evaluation)
          while (is_idchar[*ip->cur])
            ++ip->cur;
          len = ip->cur - tok;
-         SKIP_WHITE_SPACE (ip->cur);
+         cpp_skip_hspace (pfile);
          if (paren)
            {
              if (*ip->cur != ')')
index ef78ee34320724cc9af0c53f72d7df5e17b1b8d4..7828569c0dd233f4d38f478fcb5992c023c4f060 100644 (file)
@@ -757,15 +757,51 @@ actual_directory (pfile, fname)
   return x;
 }
 
-/* Read the entire contents of file DESC into buffer BUF, convert end-of-line
-   markers to canonical form, and convert trigraphs if enabled.  Also, make
-   sure there is a newline at the end of the file.  LEN is how much room we
-   have to start with (this can be expanded if necessary).
-   Returns -1 on failure, or the actual length of the data to be scanned.
+/* Almost but not quite the same as adjust_position in cpplib.c.
+   Used only by read_and_prescan. */
+static void
+find_position (start, limit, linep, colp)
+     U_CHAR *start;
+     U_CHAR *limit;
+     long *linep;
+     long *colp;
+{
+  long line = *linep, col = 0;
+  while (start < limit)
+    {
+      U_CHAR ch = *start++;
+      if (ch == '\n' || ch == '\r')
+       line++, col = 1;
+      else
+       col++;
+    }
+  *linep = line, *colp = col;
+}
 
-   N.B. This function has been rearranged to out-of-line the uncommon cases
-   as much as possible; this is important to prevent it from being a
-   performance bottleneck.  */
+/* Read the entire contents of file DESC into buffer BUF.  LEN is how
+   much memory to allocate initially; more will be allocated if
+   necessary.  Convert end-of-line markers (\n, \r, \r\n, \n\r) to
+   canonical form (\n).  If enabled, convert and/or warn about
+   trigraphs.  Convert backslash-newline to a one-character escape
+   (\r) and remove it from "embarrassing" places (i.e. the middle of a
+   token).  If there is no newline at the end of the file, add one and
+   warn.  Returns -1 on failure, or the actual length of the data to
+   be scanned.
+
+   This function does a lot of work, and can be a serious performance
+   bottleneck.  It has been tuned heavily; make sure you understand it
+   before hacking.  The common case - no trigraphs, Unix style line
+   breaks, backslash-newline set off by whitespace, newline at EOF -
+   has been optimized at the expense of the others.  The performance
+   penalty for DOS style line breaks (\r\n) is about 15%.
+   
+   Warnings lose particularly heavily since we have to determine the
+   line number, which involves scanning from the beginning of the file
+   or from the last warning.  The penalty for the absence of a newline
+   at the end of reload1.c is about 60%.  (reload1.c is 329k.)
+
+   If your file has more than one kind of end-of-line marker, you
+   will get messed-up line numbering.  */
 
 static long
 read_and_prescan (pfile, fp, desc, len)
@@ -774,29 +810,47 @@ read_and_prescan (pfile, fp, desc, len)
      int desc;
      size_t len;
 {
-  U_CHAR *buf = (U_CHAR *) xmalloc (len);
+  U_CHAR *buf = xmalloc (len);
   U_CHAR *ip, *op, *line_base;
   U_CHAR *ibase;
-  unsigned int line;
+  unsigned int line, deferred_newlines;
   int count;
   size_t offset;
-  /* 4096 bytes of buffer proper, 2 to detect running off the end without
-     address arithmetic all the time, and 2 for pushback in the case there's
-     a potential trigraph or end-of-line digraph at the end of a block. */
-#define INTERMED_BUFFER_SIZE 4096
-  U_CHAR intermed[INTERMED_BUFFER_SIZE + 2 + 2];
+  /* PIPE_BUF bytes of buffer proper, 2 to detect running off the end
+     without address arithmetic all the time, and 2 for pushback in
+     the case there's a potential trigraph or end-of-line digraph at
+     the end of a block. */
+  U_CHAR intermed[PIPE_BUF + 2 + 2];
+
+  /* Table of characters that can't be handled in the inner loop.
+     Keep these contiguous to optimize the performance of the code generated
+     for the switch that uses them.  */
+  #define SPECCASE_EMPTY     0
+  #define SPECCASE_NUL       1
+  #define SPECCASE_CR        2
+  #define SPECCASE_BACKSLASH 3
+  #define SPECCASE_QUESTION  4
+  U_CHAR speccase[256];
 
   offset = 0;
   op = buf;
   line_base = buf;
   line = 1;
   ibase = intermed + 2;
+  deferred_newlines = 0;
+
+  memset (speccase, SPECCASE_EMPTY, sizeof (speccase));
+  speccase['\0'] = SPECCASE_NUL;
+  speccase['\r'] = SPECCASE_CR;
+  speccase['\\'] = SPECCASE_BACKSLASH;
+  if (CPP_OPTIONS (pfile)->trigraphs || CPP_OPTIONS (pfile)->warn_trigraphs)
+    speccase['?'] = SPECCASE_QUESTION;
 
   for (;;)
     {
     read_next:
 
-      count = read (desc, intermed + 2, INTERMED_BUFFER_SIZE);
+      count = read (desc, intermed + 2, PIPE_BUF);
       if (count < 0)
        goto error;
       else if (count == 0)
@@ -806,16 +860,16 @@ read_and_prescan (pfile, fp, desc, len)
       ip = ibase;
       ibase = intermed + 2;
       ibase[count] = ibase[count+1] = '\0';
-      
+
       if (offset > len)
        {
          size_t delta_op;
          size_t delta_line_base;
          len *= 2;
          if (offset > len)
-             /* len overflowed.
-                This could happen if the file is larger than half the
-                maximum address space of the machine. */
+           /* len overflowed.
+              This could happen if the file is larger than half the
+              maximum address space of the machine. */
            goto too_big;
 
          delta_op = op - buf;
@@ -827,93 +881,155 @@ read_and_prescan (pfile, fp, desc, len)
 
       for (;;)
        {
-         unsigned int c;
-         c = *ip++;
-         switch (c)
+         unsigned int span = 0;
+
+         /* Deal with \-newline in the middle of a token. */
+         if (deferred_newlines)
            {
-             /* The default case is at the top so gcc will realize
-                it's the common case, and leave c in a register.
-                Also, cache utilization is a little better this way. */
-           default:
-             *op++ = c;
-             break;
-             
-           case '\0':
+             while (speccase[ip[span]] == SPECCASE_EMPTY
+                    && ip[span] != '\n'
+                    && ip[span] != '\t'
+                    && ip[span] != ' ')
+               span++;
+             memcpy (op, ip, span);
+             op += span;
+             ip += span;
+             if (*ip == '\n' || *ip == '\t'
+                 || *ip == ' ' || *ip == ' ')
+               while (deferred_newlines)
+                 deferred_newlines--, *op++ = '\r';
+             span = 0;
+           }
+
+         /* Copy as much as we can without special treatment. */
+         while (speccase[ip[span]] == SPECCASE_EMPTY) span++;
+         memcpy (op, ip, span);
+         op += span;
+         ip += span;
+
+         switch (speccase[*ip++])
+           {
+           case SPECCASE_NUL:  /* \0 */
+             ibase[-1] = op[-1];
              goto read_next;
-           case '\r':
-             if (*ip == '\n') ip++;
+
+           case SPECCASE_CR:  /* \r */
+             if (*ip == '\n')
+               ip++;
              else if (*ip == '\0')
                {
                  --ibase;
                  intermed[1] = '\r';
                  goto read_next;
                }
+             else if (ip[-2] == '\n')
+               continue;
              *op++ = '\n';
-             line++;
-             line_base = op;
              break;
 
-           case '\n':
-             if (*ip == '\r') ip++;
-             else if (*ip == '\0')
+           case SPECCASE_BACKSLASH:  /* \ */
+           backslash:
+           {
+             /* If we're at the end of the intermediate buffer,
+                we have to shift the backslash down to the start
+                and come back next pass. */
+             if (*ip == '\0')
                {
                  --ibase;
-                 intermed[1] = '\n';
+                 intermed[1] = '\\';
                  goto read_next;
                }
-             *op++ = '\n';
-             line++;
-             line_base = op;
-             break;
-
-           case '?':
-             if (CPP_OPTIONS (pfile)->trigraphs
-                 || CPP_OPTIONS (pfile)->warn_trigraphs)
+             else if (*ip == '\n')
                {
-                 unsigned int d;
-                 /* If we're at the end of the intermediate buffer,
-                    we have to shift the ?'s down to the start and
-                    come back next pass. */
-                 d = ip[0];
-                 if (d == '\0')
-                   {
-                     --ibase;
-                     intermed[1] = '?';
-                     goto read_next;
-                   }
-                 if (d != '?')
-                   {
-                     *op++ = '?';
-                     break;
-                   }
-                 d = ip[1];
-                 if (d == '\0')
+                 ip++;
+                 if (*ip == '\r') ip++;
+                 if (*ip == '\n' || *ip == '\t' || *ip == ' ')
+                   *op++ = '\r';
+                 else if (op[-1] == '\t' || op[-1] == ' '
+                          || op[-1] == '\r' || op[-1] == '\n')
+                   *op++ = '\r';
+                 else
+                   deferred_newlines++;
+                 line++;
+                 line_base = op;
+               }
+             else if (*ip == '\r')
+               {
+                 ip++;
+                 if (*ip == '\n') ip++;
+                 else if (*ip == '\0')
                    {
                      ibase -= 2;
-                     intermed[0] = intermed[1] = '?';
+                     intermed[0] = '\\';
+                     intermed[1] = '\r';
                      goto read_next;
                    }
-                 if (!trigraph_table[d])
-                   {
-                     *op++ = '?';
-                     break;
-                   }
-
-                 if (CPP_OPTIONS (pfile)->warn_trigraphs)
-                   cpp_warning_with_line (pfile, line, op-line_base,
-                                          "trigraph ??%c encountered", d);
-                 if (CPP_OPTIONS (pfile)->trigraphs)
-                   *op++ = trigraph_table[d];
+                 else if (*ip == '\r' || *ip == '\t' || *ip == ' ')
+                   *op++ = '\r';
                  else
-                   {
-                     *op++ = '?';
-                     *op++ = '?';
-                     *op++ = d;
-                   }
-                 ip += 2;
+                   deferred_newlines++;
+                 line++;
+                 line_base = op;
                }
              else
-               *op++ = c;
+               *op++ = '\\';
+           }
+           break;
+
+           case SPECCASE_QUESTION: /* ? */
+             {
+               unsigned int d;
+               /* If we're at the end of the intermediate buffer,
+                  we have to shift the ?'s down to the start and
+                  come back next pass. */
+               d = ip[0];
+               if (d == '\0')
+                 {
+                   --ibase;
+                   intermed[1] = '?';
+                   goto read_next;
+                 }
+               if (d != '?')
+                 {
+                   *op++ = '?';
+                   break;
+                 }
+               d = ip[1];
+               if (d == '\0')
+                 {
+                   ibase -= 2;
+                   intermed[0] = intermed[1] = '?';
+                   goto read_next;
+                 }
+               if (!trigraph_table[d])
+                 {
+                   *op++ = '?';
+                   break;
+                 }
+
+               if (CPP_OPTIONS (pfile)->warn_trigraphs)
+                 {
+                   long col;
+                   find_position (line_base, op, &line, &col);
+                   line_base = op - col;
+                   cpp_warning_with_line (pfile, line, col,
+                                          "trigraph ??%c encountered", d);
+                 }
+               if (CPP_OPTIONS (pfile)->trigraphs)
+                 {
+                   if (trigraph_table[d] == '\\')
+                     goto backslash;
+                   else
+                     *op++ = trigraph_table[d];
+                 }
+               else
+                 {
+                   *op++ = '?';
+                   *op++ = '?';
+                   *op++ = d;
+                 }
+               ip += 2;
+             }
            }
        }
     }
@@ -922,47 +1038,48 @@ read_and_prescan (pfile, fp, desc, len)
     return 0;
 
   /* Deal with pushed-back chars at true EOF.
-     If two chars were pushed back, they must both be ?'s.
-     If one was, it might be ?, \r, or \n, and \r needs to
-     become \n.
+     This may be any of:  ?? ? \ \r \n \\r \\n.
+     \r must become \n, \\r or \\n must become \r.
      We know we have space already. */
   if (ibase == intermed)
     {
-      *op++ = '?';
-      *op++ = '?';
+      if (*ibase == '?')
+       {
+         *op++ = '?';
+         *op++ = '?';
+       }
+      else
+       *op++ = '\r';
     }
   else if (ibase == intermed + 1)
     {
-      if (*ibase == '?')
-       *op++ = '?';
-      else
+      if (*ibase == '\r')
        *op++ = '\n';
+      else
+       *op++ = *ibase;
     }
 
-  if (op[-1] != '\n' || op[-2] == '\\')
+  if (op[-1] != '\n')
     {
-      if (CPP_PEDANTIC (pfile))
-       cpp_pedwarn_with_line (pfile, line, op - line_base,
-                              "no newline at end of file");
-      if (offset + 2 > len)
+      long col;
+      find_position (line_base, op, &line, &col);
+      cpp_warning_with_line (pfile, line, col, "no newline at end of file\n");
+      if (offset + 1 > len)
        {
-         len += 2;
-         if (offset + 2 > len)
+         len += 1;
+         if (offset + 1 > len)
            goto too_big;
          buf = (U_CHAR *) xrealloc (buf, len);
          op = buf + offset;
        }
-      if (op[-1] == '\\')
-       *op++ = '\n';
       *op++ = '\n';
     }
 
-  fp->buf =
-    (U_CHAR *) ((len - offset < 20) ? (PTR) buf : xrealloc (buf, op - buf));
+  fp->buf = ((len - offset < 20) ? buf : (U_CHAR *)xrealloc (buf, op - buf));
   return op - buf;
 
  too_big:
-  cpp_error (pfile, "file is too large");
+  cpp_error (pfile, "file is too large (>%lu bytes)\n", (unsigned long)offset);
   free (buf);
   return -1;
 
index 0f95d8ad3078bccf61cdd590a84dca4e41138b40..ff63bd816811b1955d330b18ecb47e342983d458 100644 (file)
@@ -787,6 +787,7 @@ macarg (pfile, rest_args)
   /* Try to parse as much of the argument as exists at this
      input stack level.  */
   pfile->no_macro_expand++;
+  CPP_OPTIONS (pfile)->no_line_commands++;
   for (;;)
     {
       token = cpp_get_token (pfile);
@@ -824,6 +825,7 @@ macarg (pfile, rest_args)
 
 done:
   CPP_OPTIONS (pfile)->put_out_comments = save_put_out_comments;
+  CPP_OPTIONS (pfile)->no_line_commands--;
   pfile->no_macro_expand--;
 
   return token;
index c3933080c1fa11f6b70425bb71e183de1c8a8516..08bbff410b3096df69ca73426a20ef4142ac793c 100644 (file)
@@ -255,15 +255,16 @@ U_CHAR is_idstart[256] =
   ['_']  = 1,
 };
 
-/* Table to tell if a character is horizontal space. */
+/* Table to tell if a character is horizontal space.
+   \r is magical, so it is not in here.  */
 U_CHAR is_hor_space[256] =
 {
-  [' '] = 1, ['\t'] = 1, ['\v'] = 1, ['\f'] = 1, ['\r'] = 1
+  [' '] = 1, ['\t'] = 1, ['\v'] = 1, ['\f'] = 1,
 };
 /* table to tell if a character is horizontal or vertical space.  */
 U_CHAR is_space[256] =
 {
-  [' '] = 1, ['\t'] = 1, ['\v'] = 1, ['\f'] = 1, ['\r'] = 1, ['\n'] = 1,
+  [' '] = 1, ['\t'] = 1, ['\v'] = 1, ['\f'] = 1, ['\n'] = 1,
 };
 /* Table to handle trigraph conversion, which occurs before all other
    processing, everywhere in the file.  (This is necessary since one
@@ -362,14 +363,12 @@ initialize_char_syntax (dollar_in_ident)
   is_hor_space['\t'] = 1;
   is_hor_space['\v'] = 1;
   is_hor_space['\f'] = 1;
-  is_hor_space['\r'] = 1;
 
   is_space[' '] = 1;
   is_space['\t'] = 1;
   is_space['\v'] = 1;
   is_space['\f'] = 1;
   is_space['\n'] = 1;
-  is_space['\r'] = 1;
 
   /* trigraph conversion */
   trigraph_table['='] = '#';  trigraph_table[')'] = ']';
index c55eafac03f27444f9579c0ae6db1e0ed6b3663f..8cbe54804811de556272684c69b9fb283f2b7ed0 100644 (file)
@@ -36,21 +36,6 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
    (Note that it is false while we're expanding macro *arguments*.) */
 #define CPP_IS_MACRO_BUFFER(PBUF) ((PBUF)->data != NULL)
 
-/* Move all backslash-newline pairs out of embarrassing places.
-   Exchange all such pairs following BP
-   with any potentially-embarrassing characters that follow them.
-   Potentially-embarrassing characters are / and *
-   (because a backslash-newline inside a comment delimiter
-   would cause it not to be recognized).  */
-
-#define NEWLINE_FIX \
-  do {while (PEEKC() == '\\' && PEEKN(1) == '\n') FORWARD(2); } while(0)
-
-/* Same, but assume we've already read the potential '\\' into C.  */
-#define NEWLINE_FIX1(C) do { \
-    while ((C) == '\\' && PEEKC() == '\n') { FORWARD(1); (C) = GETC(); }\
-  } while(0)
-
 /* Forward declarations.  */
 
 static char *my_strerror               PROTO ((int));
@@ -60,7 +45,10 @@ static HOST_WIDEST_INT eval_if_expression    PROTO ((cpp_reader *));
 static void conditional_skip           PROTO ((cpp_reader *, int,
                                                enum node_type, U_CHAR *));
 static void skip_if_group              PROTO ((cpp_reader *));
-static int parse_name                   PARAMS ((cpp_reader *, int));
+
+static void parse_name                 PARAMS ((cpp_reader *, int));
+static void parse_string               PARAMS ((cpp_reader *, int));
+static int parse_assertion             PARAMS ((cpp_reader *));
 
 /* External declarations.  */
 
@@ -245,71 +233,144 @@ null_cleanup (pbuf, pfile)
   return 0;
 }
 
-/* Assuming we have read '/'.
-   If this is the start of a comment (followed by '*' or '/'),
-   skip to the end of the comment, and return ' '.
-   Return EOF if we reached the end of file before the end of the comment.
-   If not the start of a comment, return '/'.  */
+/* Skip a comment - C, C++, or Chill style.  M is the first character
+   of the comment marker.  If this really is a comment, skip to its
+   end and return ' '.  If we hit end-of-file before end-of-comment,
+   return EOF.  If this is not a comment, return M (which will be
+   '/' or '-').  */
 
 static int
-skip_comment (pfile, linep)
+skip_comment (pfile, m)
      cpp_reader *pfile;
-     long *linep;
+     int m;
 {
-  int c = 0;
-  while (PEEKC() == '\\' && PEEKN(1) == '\n')
-    {
-      if (linep)
-       (*linep)++;
-      FORWARD(2);
-    }
-  if (PEEKC() == '*')
+  if (m == '/' && PEEKC() == '*')
     {
+      int c, prev_c = -1;
+      long line, col;
+      
       FORWARD(1);
+      cpp_buf_line_and_col (CPP_BUFFER (pfile), &line, &col);
       for (;;)
        {
-         int prev_c = c;
          c = GETC ();
          if (c == EOF)
-           return EOF;
-         while (c == '\\' && PEEKC() == '\n')
            {
-             if (linep)
-               (*linep)++;
-             FORWARD(1), c = GETC();
+             cpp_error_with_line (pfile, line, col, "unterminated comment");
+             return EOF;
            }
-         if (prev_c == '*' && c == '/')
+         else if (c == '\n' || c == '\r')
+           CPP_BUMP_LINE (pfile);
+         else if (c == '/' && prev_c == '*')
            return ' ';
-         if (c == '\n' && linep)
-           (*linep)++;
+         else if (c == '*' && prev_c == '/'
+                  && CPP_OPTIONS (pfile)->warn_comments)
+           cpp_warning (pfile, "`/*' within comment");
+
+         prev_c = c;
        }
     }
-  else if (PEEKC() == '/' && CPP_OPTIONS (pfile)->cplusplus_comments)
+  else if ((m == '/' && PEEKC() == '/'
+           && CPP_OPTIONS (pfile)->cplusplus_comments)
+          || (m == '-' && PEEKC() == '-'
+              && CPP_OPTIONS (pfile)->chill))
     {
       FORWARD(1);
       for (;;)
        {
-         c = GETC ();
+         int c = GETC ();
          if (c == EOF)
            return ' '; /* Allow // to be terminated by EOF.  */
-         while (c == '\\' && PEEKC() == '\n')
+             if (c == '\n')
+               {
+                 /* Don't consider final '\n' to be part of comment.  */
+                 FORWARD(-1);
+                 return ' ';
+               }
+             else if (c == '\r')
+               CPP_BUMP_LINE (pfile);
+       }
+    }
+  else
+    return m;
+}
+
+/* Identical to skip_comment except that it copies the comment into the
+   token_buffer.  This is used if put_out_comments.  */
+static int
+copy_comment (pfile, m)
+     cpp_reader *pfile;
+     int m;
+{
+  if (m == '/' && PEEKC() == '*')
+    {
+      int c, prev_c = -1;
+      long line, col;
+
+      CPP_PUTC (pfile, '/');
+      CPP_PUTC (pfile, '*');
+      FORWARD(1);
+      cpp_buf_line_and_col (CPP_BUFFER (pfile), &line, &col);
+      for (;;)
+       {
+         c = GETC ();
+         if (c == EOF)
            {
-             FORWARD(1);
-             c = GETC();
-             if (linep)
-               (*linep)++;
+             cpp_error_with_line (pfile, line, col, "unterminated comment");
+             /* We must pretend this was a legitimate comment, so that the
+                output in token_buffer is not passed back tagged CPP_POP. */
+             return ' ';
            }
+         else if (c == '\r')
+           {
+             CPP_BUMP_LINE (pfile);
+             continue;
+           }
+
+         CPP_PUTC (pfile, c);
          if (c == '\n')
+           {
+             pfile->lineno++;
+             CPP_BUMP_LINE (pfile);
+           }
+         else if (c == '/' && prev_c == '*')
+           return ' ';
+         else if (c == '*' && prev_c == '/'
+                  && CPP_OPTIONS (pfile)->warn_comments)
+           cpp_warning (pfile, "`/*' within comment");
+
+         prev_c = c;
+       }
+    }
+  else if ((m == '/' && PEEKC() == '/'
+           && CPP_OPTIONS (pfile)->cplusplus_comments)
+          || (m == '-' && PEEKC() == '-'
+              && CPP_OPTIONS (pfile)->chill))
+    {
+      CPP_PUTC (pfile, m);
+      CPP_PUTC (pfile, m);
+      FORWARD(1);
+      for (;;)
+       {
+         int c = GETC ();
+         if (c == EOF)
+           return ' '; /* Allow line comments to be terminated by EOF. */
+         else if (c == '\n')
            {
              /* Don't consider final '\n' to be part of comment.  */
              FORWARD(-1);
              return ' ';
            }
+         else if (c == '\r')
+           CPP_BUMP_LINE (pfile);
+
+         CPP_PUTC (pfile, c);
        }
     }
   else
-    return '/';
-}     
+    return m;
+}
+
 
 /* Skip whitespace \-newline and comments.  Does not macro-expand.  */
 
@@ -317,34 +378,43 @@ void
 cpp_skip_hspace (pfile)
      cpp_reader *pfile;
 {
+  int c;
   while (1)
     {
-      int c = PEEKC();
+      c = GETC();
       if (c == EOF)
-       return; /* FIXME */
-      if (is_hor_space[c])
+       return;
+      else if (is_hor_space[c])
        {
          if ((c == '\f' || c == '\v') && CPP_PEDANTIC (pfile))
            cpp_pedwarn (pfile, "%s in preprocessing directive",
                         c == '\f' ? "formfeed" : "vertical tab");
-         FORWARD(1);
        }
-      else if (c == '/')
+      else if (c == '\r')
        {
-         FORWARD (1);
-         c = skip_comment (pfile, NULL);
-         if (c == '/')
-           FORWARD(-1);
-         if (c == EOF || c == '/')
+         CPP_BUFFER (pfile)->lineno++;
+       }
+      else if (c == '/' || c == '-')
+       {
+         c = skip_comment (pfile, c);
+         if (c == EOF)
            return;
+         else if (c != ' ')
+           {
+             FORWARD(-1);
+             return;
+           }
        }
-      else if (c == '\\' && PEEKN(1) == '\n') {
-       FORWARD(2);
-      }
       else if (c == '@' && CPP_BUFFER (pfile)->has_escapes
-              && is_hor_space[PEEKN(1)])
-       FORWARD(2);
-      else return;
+              && PEEKC() == ' ')
+       {
+         FORWARD(1);
+       }
+      else
+       {
+         FORWARD(-1);
+         return;
+       }
     }
 }
 
@@ -355,30 +425,36 @@ static void
 copy_rest_of_line (pfile)
      cpp_reader *pfile;
 {
-  struct cpp_options *opts = CPP_OPTIONS (pfile);
   for (;;)
     {
       int c = GETC();
-      int nextc;
       switch (c)
        {
+       case '\n':
+         FORWARD(-1);
        case EOF:
-         goto end_directive;
-       case '\\':
-         if (PEEKC() == '\n')
-           {
-             FORWARD (1);
-             continue;
-           }
+         CPP_NUL_TERMINATE (pfile);
+         return;
+
+       case '\r':
+         CPP_BUFFER (pfile)->lineno++;
+         continue;
        case '\'':
        case '\"':
-         goto scan_directive_token;
-         break;
+         parse_string (pfile, c);
+         continue;
        case '/':
-         nextc = PEEKC();
-         if (nextc == '*' || (opts->cplusplus_comments && nextc == '/'))
-           goto scan_directive_token;
+         if (PEEKC() == '*' && CPP_TRADITIONAL (pfile))
+           {
+             CPP_PUTS (pfile, "/**/", 4);
+             skip_comment (pfile, c);
+             continue;
+           }
+         /* else fall through */
+       case '-':
+         c = skip_comment (pfile, c);
          break;
+
        case '\f':
        case '\v':
          if (CPP_PEDANTIC (pfile))
@@ -386,20 +462,15 @@ copy_rest_of_line (pfile)
                         c == '\f' ? "formfeed" : "vertical tab");
          break;
 
-       case '\n':
-         FORWARD(-1);
-         goto end_directive;
-       scan_directive_token:
-         FORWARD(-1);
-         cpp_get_token (pfile);
-         continue;
        }
       CPP_PUTC (pfile, c);
     }
- end_directive: ;
-  CPP_NUL_TERMINATE (pfile);
 }
 
+/* FIXME: It is almost definitely a performance win to make this do
+   the scan itself.  >75% of calls to copy_r_o_l are from here or
+   skip_if_group, which means the common case is to copy stuff into the
+   token_buffer only to discard it.  */
 void
 skip_rest_of_line (pfile)
      cpp_reader *pfile;
@@ -415,7 +486,8 @@ skip_rest_of_line (pfile)
 static int
 handle_directive (pfile)
      cpp_reader *pfile;
-{ int c;
+{
+  int c;
   register struct directive *kt;
   int ident_length;
   U_CHAR *ident;
@@ -590,16 +662,11 @@ do_define (pfile, keyword)
   int hashcode;
   MACRODEF mdef;
   HASHNODE *hp;
-  int save_put_out_comments;
   long here;
   U_CHAR *macro, *buf, *end;
 
   here = CPP_WRITTEN (pfile);
-  
-  save_put_out_comments = CPP_OPTIONS (pfile)->put_out_comments;
-  CPP_OPTIONS (pfile)->put_out_comments = CPP_TRADITIONAL (pfile);
   copy_rest_of_line (pfile);
-  CPP_OPTIONS (pfile)->put_out_comments = save_put_out_comments;
 
   /* Copy out the line so we can pop the token buffer. */
   buf = pfile->token_buffer + here;
@@ -696,6 +763,7 @@ cpp_push_buffer (pfile, buffer, length)
   new->buf = new->cur = buffer;
   new->alimit = new->rlimit = buffer + length;
   new->prev = buf;
+  new->mark = -1;
 
   CPP_BUFFER (pfile) = new;
   return new;
@@ -781,59 +849,22 @@ cpp_expand_to_buffer (pfile, buf, length)
   CPP_NUL_TERMINATE (pfile);
 }
 
-static void
-adjust_position (buf, limit, linep, colp)
-     U_CHAR *buf;
-     U_CHAR *limit;
-     long *linep;
-     long *colp;
-{
-  while (buf < limit)
-    {
-      U_CHAR ch = *buf++;
-      if (ch == '\n')
-       (*linep)++, (*colp) = 1;
-      else
-       (*colp)++;
-    }
-}
-
-/* Move line_base forward, updating lineno and colno.  */
-
-static void
-update_position (pbuf)
-     register cpp_buffer *pbuf;
-{
-  unsigned char *old_pos = pbuf->buf + pbuf->line_base;
-  unsigned char *new_pos = pbuf->cur;
-  register struct parse_marker *mark;
-  for (mark = pbuf->marks;  mark != NULL; mark = mark->next)
-    {
-      if (pbuf->buf + mark->position < new_pos)
-       new_pos = pbuf->buf + mark->position;
-    }
-  pbuf->line_base += new_pos - old_pos;
-  adjust_position (old_pos, new_pos, &pbuf->lineno, &pbuf->colno);
-}
-
 void
 cpp_buf_line_and_col (pbuf, linep, colp)
      register cpp_buffer *pbuf;
      long *linep, *colp;
 {
-  long dummy;
-  if (colp == NULL)
-    colp = &dummy;
   if (pbuf)
     {
       *linep = pbuf->lineno;
-      *colp = pbuf->colno;
-      adjust_position (pbuf->buf + pbuf->line_base, pbuf->cur, linep, colp);
+      if (colp)
+       *colp = pbuf->cur - pbuf->line_base;
     }
   else
     {
       *linep = 0;
-      *colp = 0;
+      if (colp)
+       *colp = 0;
     }
 }
 
@@ -851,21 +882,6 @@ cpp_file_buffer (pfile)
   return NULL;
 }
 
-static long
-count_newlines (buf, limit)
-     register U_CHAR *buf;
-     register U_CHAR *limit;
-{
-  register long count = 0;
-  while (buf < limit)
-    {
-      U_CHAR ch = *buf++;
-      if (ch == '\n')
-       count++;
-    }
-  return count;
-}
-
 /*
  * write out a #line command, for instance, after an #include file.
  * If CONDITIONAL is nonzero, we can omit the #line if it would
@@ -886,73 +902,56 @@ output_line_command (pfile, conditional, file_change)
   if (ip->fname == NULL)
     return;
 
-  update_position (ip);
-
   if (CPP_OPTIONS (pfile)->no_line_commands
       || CPP_OPTIONS (pfile)->no_output)
     return;
 
-  line = CPP_BUFFER (pfile)->lineno;
-  col = CPP_BUFFER (pfile)->colno;
-  adjust_position (CPP_LINE_BASE (ip), ip->cur, &line, &col);
+  cpp_buf_line_and_col (CPP_BUFFER (pfile), &line, &col);
 
-  if (CPP_OPTIONS (pfile)->no_line_commands)
-    return;
+  if (conditional)
+    {
+      if (line == pfile->lineno)
+       return;
 
-  if (conditional) {
-    if (line == pfile->lineno)
-      return;
-
-    /* If the inherited line number is a little too small,
-       output some newlines instead of a #line command.  */
-    if (line > pfile->lineno && line < pfile->lineno + 8) {
-      CPP_RESERVE (pfile, 20);
-      while (line > pfile->lineno) {
-       CPP_PUTC_Q (pfile, '\n');
-       pfile->lineno++;
-      }
-      return;
+      /* If the inherited line number is a little too small,
+        output some newlines instead of a #line command.  */
+      if (line > pfile->lineno && line < pfile->lineno + 8)
+       {
+         CPP_RESERVE (pfile, 20);
+         while (line > pfile->lineno)
+           {
+             CPP_PUTC_Q (pfile, '\n');
+             pfile->lineno++;
+           }
+         return;
+       }
     }
-  }
-
-#if 0
-  /* Don't output a line number of 0 if we can help it.  */
-  if (ip->lineno == 0 && ip->bufp - ip->buf < ip->length
-      && *ip->bufp == '\n') {
-    ip->lineno++;
-    ip->bufp++;
-  }
-#endif
 
   CPP_RESERVE (pfile, 4 * strlen (ip->nominal_fname) + 50);
-  {
-#ifdef OUTPUT_LINE_COMMANDS
-    static char sharp_line[] = "#line ";
-#else
-    static char sharp_line[] = "# ";
-#endif
-    CPP_PUTS_Q (pfile, sharp_line, sizeof(sharp_line)-1);
-  }
+  CPP_PUTS_Q (pfile, "# ", 2);
 
   sprintf ((char *) CPP_PWRITTEN (pfile), "%ld ", line);
   CPP_ADJUST_WRITTEN (pfile, strlen (CPP_PWRITTEN (pfile)));
 
   quote_string (pfile, ip->nominal_fname); 
-  if (file_change != same_file) {
-    CPP_PUTC_Q (pfile, ' ');
-    CPP_PUTC_Q (pfile, file_change == enter_file ? '1' : '2');
-  }
+  if (file_change != same_file)
+    {
+      CPP_PUTC_Q (pfile, ' ');
+      CPP_PUTC_Q (pfile, file_change == enter_file ? '1' : '2');
+    }
   /* Tell cc1 if following text comes from a system header file.  */
-  if (ip->system_header_p) {
-    CPP_PUTC_Q (pfile, ' ');
-    CPP_PUTC_Q (pfile, '3');
-  }
+  if (ip->system_header_p)
+    {
+      CPP_PUTC_Q (pfile, ' ');
+      CPP_PUTC_Q (pfile, '3');
+    }
 #ifndef NO_IMPLICIT_EXTERN_C
   /* Tell cc1plus if following text should be treated as C.  */
-  if (ip->system_header_p == 2 && CPP_OPTIONS (pfile)->cplusplus) {
-    CPP_PUTC_Q (pfile, ' ');
-    CPP_PUTC_Q (pfile, '4');
-  }
+  if (ip->system_header_p == 2 && CPP_OPTIONS (pfile)->cplusplus)
+    {
+      CPP_PUTC_Q (pfile, ' ');
+      CPP_PUTC_Q (pfile, '4');
+    }
 #endif
   CPP_PUTC_Q (pfile, '\n');
   pfile->lineno = line;
@@ -1886,6 +1885,7 @@ skip_if_group (pfile)
        {
          if (CPP_OPTIONS (pfile)->output_conditionals)
            CPP_PUTC (pfile, c);
+         CPP_BUMP_LINE (pfile);
          continue;
        }
       else if (c == '#')
@@ -1915,7 +1915,11 @@ skip_if_group (pfile)
        {
          /* \n */
          if (CPP_OPTIONS (pfile)->output_conditionals)
-           CPP_PUTC (pfile, c);
+           {
+             CPP_PUTC (pfile, c);
+             pfile->lineno++;
+           }
+         CPP_BUMP_LINE (pfile);
        }
     }    
 
@@ -1998,10 +2002,9 @@ do_endif (pfile, keyword)
        {
          /* This #endif matched a #ifndef at the start of the file.
             See if it is at the end of the file.  */
-         struct parse_marker start_mark;
          int c;
 
-         parse_set_mark (&start_mark, pfile);
+         parse_set_mark (pfile);
 
          for (;;)
            {
@@ -2010,8 +2013,7 @@ do_endif (pfile, keyword)
              if (c != '\n')
                break;
            }
-         parse_goto_mark (&start_mark, pfile);
-         parse_clear_mark (&start_mark);
+         parse_goto_mark (pfile);
 
          if (c == EOF)
            {
@@ -2057,8 +2059,6 @@ cpp_get_token (pfile)
      cpp_reader *pfile;
 {
   register int c, c2, c3;
-  long old_written;
-  long start_line, start_column;
   enum cpp_token token;
   struct cpp_options *opts = CPP_OPTIONS (pfile);
 
@@ -2099,68 +2099,27 @@ cpp_get_token (pfile)
     {
       switch (c)
        {
-         long newlines;
-         struct parse_marker start_mark;
        case '/':
          if (PEEKC () == '=')
            goto op2;
+
+       comment:
          if (opts->put_out_comments)
-           parse_set_mark (&start_mark, pfile);
-         newlines = 0;
-         cpp_buf_line_and_col (cpp_file_buffer (pfile),
-                               &start_line, &start_column);
-         c = skip_comment (pfile, &newlines);
-         if (opts->put_out_comments && (c == '/' || c == EOF))
-           parse_clear_mark (&start_mark);
-         if (c == '/')
-           goto randomchar;
+           c = copy_comment (pfile, c);
+         else
+           c = skip_comment (pfile, c);
          if (c == EOF)
-           {
-             cpp_error_with_line (pfile, start_line, start_column,
-                                  "unterminated comment");
-             goto handle_eof;
-           }
-         c = '/';  /* Initial letter of comment.  */
-       return_comment:
+           goto handle_eof;
+         else if (c != ' ')
+           goto randomchar;
+         
          /* Comments are equivalent to spaces.
             For -traditional, a comment is equivalent to nothing.  */
-         if (opts->put_out_comments)
-           {
-             cpp_buffer *pbuf = CPP_BUFFER (pfile);
-             U_CHAR *start = pbuf->buf + start_mark.position;
-             int len = pbuf->cur - start;
-             CPP_RESERVE(pfile, 1 + len);
-             CPP_PUTC_Q (pfile, c);
-             CPP_PUTS_Q (pfile, start, len);
-             pfile->lineno += newlines;
-             parse_clear_mark (&start_mark);
-             return CPP_COMMENT;
-           }
-         else if (CPP_TRADITIONAL (pfile))
-           {
-             return CPP_COMMENT;
-           }
+         if (opts->traditional || opts->put_out_comments)
+           return CPP_COMMENT;
          else
            {
-#if 0
-             /* This may not work if cpp_get_token is called recursively,
-                since many places look for horizontal space.  */
-             if (newlines)
-               {
-                 /* Copy the newlines into the output buffer, in order to
-                    avoid the pain of a #line every time a multiline comment
-                    is seen.  */
-                 CPP_RESERVE(pfile, newlines);
-                 while (--newlines >= 0)
-                   {
-                     CPP_PUTC_Q (pfile, '\n');
-                     pfile->lineno++;
-                   }
-                 return CPP_VSPACE;
-               }
-#endif
-             CPP_RESERVE(pfile, 1);
-             CPP_PUTC_Q (pfile, ' ');
+             CPP_PUTC (pfile, c);
              return CPP_HSPACE;
            }
 #if 0
@@ -2218,91 +2177,7 @@ cpp_get_token (pfile)
        case '\"':
        case '\'':
        string:
-         /* A single quoted string is treated like a double -- some
-            programs (e.g., troff) are perverse this way */
-         cpp_buf_line_and_col (cpp_file_buffer (pfile),
-                               &start_line, &start_column);
-         old_written = CPP_WRITTEN (pfile);
-         CPP_PUTC (pfile, c);
-         while (1)
-           {
-             int cc = GETC();
-             if (cc == EOF)
-               {
-                 if (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
-                   {
-                     /* try harder: this string crosses a macro expansion
-                        boundary.  This can happen naturally if -traditional.
-                        Otherwise, only -D can make a macro with an unmatched
-                        quote.  */
-                       cpp_pop_buffer (pfile);
-                       continue;
-                   }
-                 if (!CPP_TRADITIONAL (pfile))
-                   {
-                     cpp_error_with_line (pfile, start_line, start_column,
-                             "unterminated string or character constant");
-                     if (pfile->multiline_string_line != start_line
-                         && pfile->multiline_string_line != 0)
-                       cpp_error_with_line (pfile,
-                                            pfile->multiline_string_line, -1,
-                              "possible real start of unterminated constant");
-                     pfile->multiline_string_line = 0;
-                   }
-                 break;
-               }
-             CPP_PUTC (pfile, cc);
-             switch (cc)
-               {
-               case '\n':
-                 /* Traditionally, end of line ends a string constant with
-                no error.  So exit the loop and record the new line.  */
-                 if (CPP_TRADITIONAL (pfile))
-                   goto while2end;
-                 if (c == '\'')
-                   {
-                     cpp_error_with_line (pfile, start_line, start_column,
-                                          "unterminated character constant");
-                     goto while2end;
-                   }
-                 if (CPP_PEDANTIC (pfile)
-                     && pfile->multiline_string_line == 0)
-                   {
-                     cpp_pedwarn_with_line (pfile, start_line, start_column,
-                              "string constant runs past end of line");
-                   }
-                 if (pfile->multiline_string_line == 0)
-                   pfile->multiline_string_line = start_line;
-                 break;
-               
-               case '\\':
-                 cc = GETC();
-                 if (cc == '\n')
-                   {
-                     /* Backslash newline is replaced by nothing at all.  */
-                     CPP_ADJUST_WRITTEN (pfile, -1);
-                     pfile->lineno++;
-                   }
-                 else
-                   {
-                     /* ANSI stupidly requires that in \\ the second \
-                        is *not* prevented from combining with a newline.  */
-                     NEWLINE_FIX1(cc);
-                     if (cc != EOF)
-                       CPP_PUTC (pfile, cc);
-                   }
-                 break;
-
-               case '\"':
-               case '\'':
-                 if (cc == c)
-                   goto while2end;
-                 break;
-               }
-           }
-       while2end:
-         pfile->lineno += count_newlines (pfile->token_buffer + old_written,
-                                          CPP_PWRITTEN (pfile));
+         parse_string (pfile, c);
          pfile->only_seen_white = 0;
          return c == '\'' ? CPP_CHAR : CPP_STRING;
 
@@ -2319,7 +2194,6 @@ cpp_get_token (pfile)
        case '&':
        case '+':
        case '|':
-         NEWLINE_FIX;
          c2 = PEEKC ();
          if (c2 == c || c2 == '=')
            goto op2;
@@ -2330,35 +2204,14 @@ cpp_get_token (pfile)
        case '%':
        case '=':
        case '^':
-         NEWLINE_FIX;
          if (PEEKC () == '=')
            goto op2;
          goto randomchar;
 
        case '-':
-         NEWLINE_FIX;
          c2 = PEEKC ();
          if (c2 == '-' && opts->chill)
-           {
-             /* Chill style comment */
-             if (opts->put_out_comments)
-               parse_set_mark (&start_mark, pfile);
-             FORWARD(1);  /* Skip second '-'.  */
-             for (;;)
-               {
-                 c = GETC ();
-                 if (c == EOF)
-                   break;
-                 if (c == '\n')
-                   {
-                     /* Don't consider final '\n' to be part of comment.  */
-                     FORWARD(-1);
-                     break;
-                   }
-               }
-             c = '-';
-             goto return_comment;
-           }
+           goto comment;  /* Chill style comment */
          if (c2 == '-' || c2 == '=' || c2 == '>')
            goto op2;
          goto randomchar;
@@ -2372,19 +2225,23 @@ cpp_get_token (pfile)
                  if (c == '>')
                    break;
                  c = GETC ();
-                 NEWLINE_FIX1 (c);
                  if (c == '\n' || c == EOF)
                    {
                      cpp_error (pfile,
                                 "missing '>' in `#include <FILENAME>'");
                      break;
                    }
+                 else if (c == '\r')
+                   {
+                     /* Backslash newline is replaced by nothing. */
+                     CPP_ADJUST_WRITTEN (pfile, -1);
+                     CPP_BUMP_LINE (pfile);
+                   }
                }
              return CPP_STRING;
            }
          /* else fall through */
        case '>':
-         NEWLINE_FIX;
          c2 = PEEKC ();
          if (c2 == '=')
            goto op2;
@@ -2394,7 +2251,6 @@ cpp_get_token (pfile)
          CPP_RESERVE (pfile, 4);
          CPP_PUTC (pfile, c);
          CPP_PUTC (pfile, c2);
-         NEWLINE_FIX;
          c3 = PEEKC ();
          if (c3 == '=')
            CPP_PUTC_Q (pfile, GETC ());
@@ -2413,7 +2269,7 @@ cpp_get_token (pfile)
                  parse_name (pfile, GETC ());
                  return CPP_NAME;
                }
-             else if (is_space [c])
+             else if (c == ' ')
                {
                  CPP_RESERVE (pfile, 2);
                  if (pfile->output_escapes)
@@ -2430,7 +2286,6 @@ cpp_get_token (pfile)
          goto randomchar;
 
        case '.':
-         NEWLINE_FIX;
          c2 = PEEKC ();
          if (ISDIGIT(c2))
            {
@@ -2439,7 +2294,6 @@ cpp_get_token (pfile)
              c = GETC ();
              goto number;
            }
-         /* FIXME - misses the case "..\\\n." */
          if (c2 == '.' && PEEKN(1) == '.')
            {
              CPP_RESERVE(pfile, 4);
@@ -2456,7 +2310,6 @@ cpp_get_token (pfile)
        op2:
          token = CPP_OTHER;
          pfile->only_seen_white = 0;
-        op2any:
          CPP_RESERVE(pfile, 3);
          CPP_PUTC_Q (pfile, c);
          CPP_PUTC_Q (pfile, GETC ());
@@ -2464,7 +2317,6 @@ cpp_get_token (pfile)
          return token;
 
        case 'L':
-         NEWLINE_FIX;
          c2 = PEEKC ();
          if ((c2 == '\'' || c2 == '\"') && !CPP_TRADITIONAL (pfile))
            {
@@ -2482,7 +2334,6 @@ cpp_get_token (pfile)
            {
              CPP_RESERVE (pfile, 2);
              CPP_PUTC_Q (pfile, c);
-             NEWLINE_FIX;
              c = PEEKC ();
              if (c == EOF)
                break;
@@ -2512,14 +2363,7 @@ cpp_get_token (pfile)
                  if (c == EOF)
                    goto chill_number_eof;
                  if (!is_idchar[c])
-                   {
-                     if (c == '\\' && PEEKC() == '\n')
-                       {
-                         FORWARD(2);
-                         continue;
-                       }
-                     break;
-                   }
+                   break;
                  CPP_PUTC (pfile, c);
                }
              if (c == '\'')
@@ -2584,10 +2428,9 @@ cpp_get_token (pfile)
               decide this is not a macro call and leave things that way.  */
            if (hp->type == T_MACRO && hp->value.defn->nargs >= 0)
            {
-             struct parse_marker macro_mark;
              int is_macro_call, macbuf_whitespace = 0;
 
-             parse_set_mark (&macro_mark, pfile);
+             parse_set_mark (pfile);
              for (;;)
                {
                  cpp_skip_hspace (pfile);
@@ -2603,14 +2446,15 @@ cpp_get_token (pfile)
                     {
                       if (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
                         {
-                          if (macro_mark.position !=
+                          if (CPP_BUFFER (pfile)->mark !=
                               (CPP_BUFFER (pfile)->cur
                                - CPP_BUFFER (pfile)->buf))
                              macbuf_whitespace = 1;
 
-                          parse_clear_mark (&macro_mark);
+                         /* The mark goes away automatically when
+                            the buffer is popped. */
                           cpp_pop_buffer (pfile);
-                          parse_set_mark (&macro_mark, pfile);
+                          parse_set_mark (pfile);
                         }
                       else
                         break;
@@ -2618,11 +2462,12 @@ cpp_get_token (pfile)
                }
              if (!is_macro_call)
                 {
-                  parse_goto_mark (&macro_mark, pfile);
+                  parse_goto_mark (pfile);
                   if (macbuf_whitespace)
                     CPP_PUTC (pfile, ' ');
                 }
-             parse_clear_mark (&macro_mark);
+             else
+               parse_clear_mark (pfile);
              if (!is_macro_call)
                return CPP_NAME;
            }
@@ -2634,7 +2479,7 @@ cpp_get_token (pfile)
          }
          goto get_next;
 
-       case ' ':  case '\t':  case '\v':  case '\r':
+       case ' ':  case '\t':  case '\v':
          for (;;)
            {
              CPP_PUTC (pfile, c);
@@ -2646,18 +2491,21 @@ cpp_get_token (pfile)
          return CPP_HSPACE;
 
         case '\\':
-         c2 = PEEKC ();
-         if (c2 != '\n')
-           goto randomchar;
-         token = CPP_HSPACE;
-         goto op2any;
+         goto randomchar;
+
+       case '\r':
+         /* Backslash newline is ignored. */
+         CPP_BUMP_LINE (pfile);
+         goto get_next;
 
        case '\n':
          CPP_PUTC (pfile, c);
          if (pfile->only_seen_white == 0)
            pfile->only_seen_white = 1;
+         CPP_BUMP_LINE (pfile);
          pfile->lineno++;
-         output_line_command (pfile, 1, same_file);
+         if (CPP_BUFFER (pfile)->lineno != pfile->lineno)
+           output_line_command (pfile, 1, same_file);
          return CPP_VSPACE;
 
        case '(': token = CPP_LPAREN;    goto char1;
@@ -2697,19 +2545,15 @@ cpp_get_non_space_token (pfile)
 
 /* Parse an identifier starting with C.  */
 
-static int
+static void
 parse_name (pfile, c)
-     cpp_reader *pfile; int c;
+     cpp_reader *pfile;
+     int c;
 {
   for (;;)
   {
       if (! is_idchar[c])
       {
-         if (c == '\\' && PEEKC() == '\n')
-         {
-             FORWARD(2);
-             continue;
-         }
          FORWARD (-1);
          break;
       }
@@ -2724,7 +2568,95 @@ parse_name (pfile, c)
        break;
   }
   CPP_NUL_TERMINATE_Q (pfile);
-  return 1;
+  return;
+}
+
+/* Parse a string starting with C.  A single quoted string is treated
+   like a double -- some programs (e.g., troff) are perverse this way.
+   (However, a single quoted string is not allowed to extend over
+   multiple lines.  */
+static void
+parse_string (pfile, c)
+     cpp_reader *pfile;
+     int c;
+{
+  long start_line, start_column;
+  
+  cpp_buf_line_and_col (cpp_file_buffer (pfile), &start_line, &start_column);
+
+  CPP_PUTC (pfile, c);
+  while (1)
+    {
+      int cc = GETC();
+      if (cc == EOF)
+       {
+         if (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
+           {
+             /* try harder: this string crosses a macro expansion
+                boundary.  This can happen naturally if -traditional.
+                Otherwise, only -D can make a macro with an unmatched
+                quote.  */
+             cpp_pop_buffer (pfile);
+             continue;
+           }
+         if (!CPP_TRADITIONAL (pfile))
+           {
+             cpp_error_with_line (pfile, start_line, start_column,
+                                "unterminated string or character constant");
+             if (pfile->multiline_string_line != start_line
+                 && pfile->multiline_string_line != 0)
+               cpp_error_with_line (pfile,
+                                    pfile->multiline_string_line, -1,
+                              "possible real start of unterminated constant");
+             pfile->multiline_string_line = 0;
+           }
+         break;
+       }
+      CPP_PUTC (pfile, cc);
+      switch (cc)
+       {
+       case '\n':
+         CPP_BUMP_LINE (pfile);
+         pfile->lineno++;
+         /* Traditionally, end of line ends a string constant with
+            no error.  */
+         if (CPP_TRADITIONAL (pfile))
+           return;
+         /* Character constants may not extend over multiple lines.  */
+         if (c == '\'')
+           {
+             cpp_error_with_line (pfile, start_line, start_column,
+                                  "unterminated character constant");
+             return;
+           }
+         if (CPP_PEDANTIC (pfile) && pfile->multiline_string_line == 0)
+           {
+             cpp_pedwarn_with_line (pfile, start_line, start_column,
+                                    "string constant runs past end of line");
+           }
+         if (pfile->multiline_string_line == 0)
+           pfile->multiline_string_line = start_line;
+         break;
+
+       case '\r':
+         /* Backslash newline is replaced by nothing at all.  */
+         CPP_ADJUST_WRITTEN (pfile, -1);
+         CPP_BUMP_LINE (pfile);
+         break;
+
+       case '\\':
+         cc = GETC();
+         if (cc != EOF)
+           CPP_PUTC (pfile, cc);
+         break;
+
+       case '\"':
+       case '\'':
+         if (cc == c)
+           return;
+         break;
+       }
+    }
 }
 
 /* Read an assertion into the token buffer, converting to
@@ -2752,7 +2684,7 @@ parse_assertion (pfile)
   c = PEEKC();
   if (c != '(')
     {
-      if (is_hor_space[c])
+      if (is_hor_space[c] || c == '\r')
        cpp_skip_hspace (pfile);
       c = PEEKC();
     }
@@ -2772,17 +2704,17 @@ parse_assertion (pfile)
              dropwhite = 1;
            }
        }
-      else if (c == '\\' && PEEKC() == '\n')
-       FORWARD(1);
       else if (c == '\n' || c == EOF)
        {
          if (c == '\n') FORWARD(-1);
          cpp_error (pfile, "un-terminated assertion answer");
          return 0;
        }
+      else if (c == '\r')
+       CPP_BUMP_LINE (pfile);
       else
        {
-         CPP_PUTC(pfile, c);
+         CPP_PUTC (pfile, c);
          dropwhite = 0;
        }
     }
@@ -2795,9 +2727,9 @@ parse_assertion (pfile)
       return 0;
     }
   else
-    CPP_PUTC(pfile, ')');
+    CPP_PUTC (pfile, ')');
 
-  CPP_NUL_TERMINATE(pfile);
+  CPP_NUL_TERMINATE (pfile);
   return 2;
 }
 
@@ -2971,62 +2903,50 @@ cpp_read_check_assertion (pfile)
   return result;
 }
 
-/* Initialize PMARK to remember the current position of PFILE.  */
+/* Remember the current position of PFILE.  */
 
 void
-parse_set_mark (pmark, pfile)
-     struct parse_marker *pmark;
+parse_set_mark (pfile)
      cpp_reader *pfile;
 {
-  cpp_buffer *pbuf = CPP_BUFFER (pfile);
-  pmark->next = pbuf->marks;
-  pbuf->marks = pmark;
-  pmark->buf = pbuf;
-  pmark->position = pbuf->cur - pbuf->buf;
-}
-
-/* Cleanup PMARK - we no longer need it.  */
+  cpp_buffer *ip = CPP_BUFFER (pfile);
+  if (ip->mark != -1)
+      cpp_fatal (pfile,
+                "cpp internal error: ip->mark != -1 in parse_set_mark");
 
-void
-parse_clear_mark (pmark)
-     struct parse_marker *pmark;
-{
-  struct parse_marker **pp = &pmark->buf->marks;
-  for (; ; pp = &(*pp)->next) {
-    if (*pp == NULL) abort ();
-    if (*pp == pmark) break;
-  }
-  *pp = pmark->next;
+  ip->mark = ip->cur - ip->buf;
 }
 
-/* Backup the current position of PFILE to that saved in PMARK.  */
+/* Clear the current mark - we no longer need it.  */
 
 void
-parse_goto_mark (pmark, pfile)
-     struct parse_marker *pmark;
+parse_clear_mark (pfile)
      cpp_reader *pfile;
 {
-  cpp_buffer *pbuf = CPP_BUFFER (pfile);
-  if (pbuf != pmark->buf)
-    cpp_fatal (pfile, "internal error %s", "parse_goto_mark");
-  pbuf->cur = pbuf->buf + pmark->position;
+  cpp_buffer *ip = CPP_BUFFER (pfile);
+  if (ip->mark == -1)
+      cpp_fatal (pfile,
+                "cpp internal error: ip->mark == -1 in parse_clear_mark");
+
+  ip->mark = -1;
 }
 
-/* Reset PMARK to point to the current position of PFILE.  (Same
-   as parse_clear_mark (PMARK), parse_set_mark (PMARK, PFILE) but faster.  */
+/* Backup the current position of PFILE to that saved in its mark,
+   and clear the mark.  */
 
 void
-parse_move_mark (pmark, pfile)
-     struct parse_marker *pmark;
+parse_goto_mark (pfile)
      cpp_reader *pfile;
 {
-  cpp_buffer *pbuf = CPP_BUFFER (pfile);
-  if (pbuf != pmark->buf)
-    cpp_fatal (pfile, "internal error %s", "parse_move_mark");
-  pmark->position = pbuf->cur - pbuf->buf;
+  cpp_buffer *ip = CPP_BUFFER (pfile);
+  if (ip->mark == -1)
+      cpp_fatal (pfile,
+                "cpp internal error: ip->mark == -1 in parse_goto_mark");
+
+  ip->cur = ip->buf + ip->mark;
+  ip->mark = -1;
 }
 
-\f
 void
 cpp_print_file_and_line (pfile)
      cpp_reader *pfile;
index e2bb414448757f5ac7646de3271455ece4b6df00..9af3b4b6343d337cd08d23b66f8d064d070ee2e2 100644 (file)
@@ -72,19 +72,9 @@ enum cpp_token {
 typedef enum cpp_token (*parse_underflow_t) PARAMS((cpp_reader *));
 typedef int (*parse_cleanup_t) PARAMS((cpp_buffer *, cpp_reader *));
 
-/* A parse_marker indicates a previous position,
-   which we can backtrack to. */
-
-struct parse_marker {
-  cpp_buffer *buf;
-  struct parse_marker *next;
-  int position;
-};
-
-extern void parse_set_mark PARAMS ((struct parse_marker *, cpp_reader *));
-extern void parse_clear_mark PARAMS ((struct parse_marker *));
-extern void parse_goto_mark PARAMS((struct parse_marker *, cpp_reader *));
-extern void parse_move_mark PARAMS((struct parse_marker *, cpp_reader *));
+extern void parse_set_mark     PARAMS ((cpp_reader *));
+extern void parse_clear_mark   PARAMS ((cpp_reader *));
+extern void parse_goto_mark    PARAMS ((cpp_reader *));
 
 extern int cpp_handle_option PARAMS ((cpp_reader *, int, char **));
 extern int cpp_handle_options PARAMS ((cpp_reader *, int, char **));
@@ -95,15 +85,13 @@ extern enum cpp_token cpp_get_non_space_token PARAMS ((cpp_reader *));
 /* This frees resources used by PFILE. */
 extern void cpp_cleanup PARAMS ((cpp_reader *PFILE));
 
-/* If we have a huge buffer, may need to cache more recent counts */
-#define CPP_LINE_BASE(BUF) ((BUF)->buf + (BUF)->line_base)
-
 struct cpp_buffer
 {
   unsigned char *cur;   /* current position */
   unsigned char *rlimit; /* end of valid data */
   unsigned char *buf;   /* entire buffer */
   unsigned char *alimit; /* end of allocated buffer */
+  unsigned char *line_base; /* start of current line */
 
   struct cpp_buffer *prev;
 
@@ -120,13 +108,13 @@ struct cpp_buffer
      to record control macros. */
   struct include_hash *ihash;
 
-  long line_base;
   long lineno; /* Line number at CPP_LINE_BASE. */
   long colno; /* Column number at CPP_LINE_BASE. */
+  long mark;  /* Saved position for lengthy backtrack. */
   parse_underflow_t underflow;
   parse_cleanup_t cleanup;
   void *data;
-  struct parse_marker *marks;
+  
   /* Value of if_stack at start of this file.
      Used to prohibit unmatched #endif (etc) in an include file.  */
   struct if_stack *if_stack;
@@ -289,8 +277,12 @@ struct cpp_reader
 #define CPP_ADJUST_WRITTEN(PFILE,DELTA) ((PFILE)->limit += (DELTA))
 #define CPP_SET_WRITTEN(PFILE,N) ((PFILE)->limit = (PFILE)->token_buffer + (N))
 
-#define CPP_OPTIONS(PFILE) ((PFILE)->opts)
+/* Advance the current line by one. */
+#define CPP_BUMP_BUFFER_LINE(PBUF) ((PBUF)->lineno++,\
+                                   (PBUF)->line_base = (PBUF)->cur)
+#define CPP_BUMP_LINE(PFILE) CPP_BUMP_BUFFER_LINE(CPP_BUFFER(PFILE))
 
+#define CPP_OPTIONS(PFILE) ((PFILE)->opts)
 #define CPP_BUFFER(PFILE) ((PFILE)->buffer)
 #define CPP_PREV_BUFFER(BUFFER) ((BUFFER)->prev)
 /* The bottom of the buffer stack. */