OSDN Git Service

Update comment for last commit.
[pf3gnuchains/gcc-fork.git] / libcpp / lex.c
index 2eb66bd..f299982 100644 (file)
@@ -1,5 +1,6 @@
 /* CPP Library - lexical analysis.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
+   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
@@ -7,7 +8,7 @@
 
 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
+Free Software Foundation; either version 3, or (at your option) any
 later version.
 
 This program is distributed in the hope that it will be useful,
@@ -16,8 +17,8 @@ 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+along with this program; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -55,6 +56,7 @@ static int skip_line_comment (cpp_reader *);
 static void skip_whitespace (cpp_reader *, cppchar_t);
 static void lex_string (cpp_reader *, cpp_token *, const uchar *);
 static void save_comment (cpp_reader *, cpp_token *, const uchar *, cppchar_t);
+static void store_comment (cpp_reader *, cpp_token *);
 static void create_literal (cpp_reader *, cpp_token *, const uchar *,
                            unsigned int, enum cpp_ttype);
 static bool warn_in_comment (cpp_reader *, _cpp_line_note *);
@@ -74,7 +76,7 @@ cpp_ideq (const cpp_token *token, const char *string)
   if (token->type != CPP_NAME)
     return 0;
 
-  return !ustrcmp (NODE_NAME (token->val.node), (const uchar *) string);
+  return !ustrcmp (NODE_NAME (token->val.node.node), (const uchar *) string);
 }
 
 /* Record a note TYPE at byte POS into the current cleaned logical
@@ -312,6 +314,8 @@ _cpp_process_line_notes (cpp_reader *pfile, int in_comment)
                }
            }
        }
+      else if (note->type == 0)
+       /* Already processed in lex_raw_string.  */;
       else
        abort ();
     }
@@ -502,6 +506,63 @@ forms_identifier_p (cpp_reader *pfile, int first,
   return false;
 }
 
+/* Helper function to get the cpp_hashnode of the identifier BASE.  */
+static cpp_hashnode *
+lex_identifier_intern (cpp_reader *pfile, const uchar *base)
+{
+  cpp_hashnode *result;
+  const uchar *cur;
+  unsigned int len;
+  unsigned int hash = HT_HASHSTEP (0, *base);
+
+  cur = base + 1;
+  while (ISIDNUM (*cur))
+    {
+      hash = HT_HASHSTEP (hash, *cur);
+      cur++;
+    }
+  len = cur - base;
+  hash = HT_HASHFINISH (hash, len);
+  result = CPP_HASHNODE (ht_lookup_with_hash (pfile->hash_table,
+                                             base, len, hash, HT_ALLOC));
+
+  /* Rarely, identifiers require diagnostics when lexed.  */
+  if (__builtin_expect ((result->flags & NODE_DIAGNOSTIC)
+                       && !pfile->state.skipping, 0))
+    {
+      /* It is allowed to poison the same identifier twice.  */
+      if ((result->flags & NODE_POISONED) && !pfile->state.poisoned_ok)
+       cpp_error (pfile, CPP_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_error (pfile, CPP_DL_PEDWARN,
+                  "__VA_ARGS__ can only appear in the expansion"
+                  " of a C99 variadic macro");
+
+      /* For -Wc++-compat, warn about use of C++ named operators.  */
+      if (result->flags & NODE_WARN_OPERATOR)
+       cpp_error (pfile, CPP_DL_WARNING,
+                  "identifier \"%s\" is a special operator name in C++",
+                  NODE_NAME (result));
+    }
+
+  return result;
+}
+
+/* Get the cpp_hashnode of an identifier specified by NAME in
+   the current cpp_reader object.  If none is found, NULL is returned.  */
+cpp_hashnode *
+_cpp_lex_identifier (cpp_reader *pfile, const char *name)
+{
+  cpp_hashnode *result;
+  result = lex_identifier_intern (pfile, (uchar *) name);
+  return result;
+}
+
 /* Lex an identifier starting at BUFFER->CUR - 1.  */
 static cpp_hashnode *
 lex_identifier (cpp_reader *pfile, const uchar *base, bool starts_ucn,
@@ -558,6 +619,12 @@ lex_identifier (cpp_reader *pfile, const uchar *base, bool starts_ucn,
        cpp_error (pfile, CPP_DL_PEDWARN,
                   "__VA_ARGS__ can only appear in the expansion"
                   " of a C99 variadic macro");
+
+      /* For -Wc++-compat, warn about use of C++ named operators.  */
+      if (result->flags & NODE_WARN_OPERATOR)
+       cpp_error (pfile, CPP_DL_WARNING,
+                  "identifier \"%s\" is a special operator name in C++",
+                  NODE_NAME (result));
     }
 
   return result;
@@ -609,10 +676,291 @@ create_literal (cpp_reader *pfile, cpp_token *token, const uchar *base,
   token->val.str.text = dest;
 }
 
+/* Subroutine of lex_raw_string: Append LEN chars from BASE to the buffer
+   sequence from *FIRST_BUFF_P to LAST_BUFF_P.  */
+
+static void
+bufring_append (cpp_reader *pfile, const uchar *base, size_t len,
+               _cpp_buff **first_buff_p, _cpp_buff **last_buff_p)
+{
+  _cpp_buff *first_buff = *first_buff_p;
+  _cpp_buff *last_buff = *last_buff_p;
+
+  if (first_buff == NULL)
+    first_buff = last_buff = _cpp_get_buff (pfile, len);
+  else if (len > BUFF_ROOM (last_buff))
+    {
+      size_t room = BUFF_ROOM (last_buff);
+      memcpy (BUFF_FRONT (last_buff), base, room);
+      BUFF_FRONT (last_buff) += room;
+      base += room;
+      len -= room;
+      last_buff = _cpp_append_extend_buff (pfile, last_buff, len);
+    }
+
+  memcpy (BUFF_FRONT (last_buff), base, len);
+  BUFF_FRONT (last_buff) += len;
+
+  *first_buff_p = first_buff;
+  *last_buff_p = last_buff;
+}
+
+/* Lexes a raw string.  The stored string contains the spelling, including
+   double quotes, delimiter string, '(' and ')', any leading
+   'L', 'u', 'U' or 'u8' and 'R' modifier.  It returns the type of the
+   literal, or CPP_OTHER if it was not properly terminated.
+
+   The spelling is NUL-terminated, but it is not guaranteed that this
+   is the first NUL since embedded NULs are preserved.  */
+
+static void
+lex_raw_string (cpp_reader *pfile, cpp_token *token, const uchar *base,
+               const uchar *cur)
+{
+  source_location saw_NUL = 0;
+  const uchar *raw_prefix;
+  unsigned int raw_prefix_len = 0;
+  enum cpp_ttype type;
+  size_t total_len = 0;
+  _cpp_buff *first_buff = NULL, *last_buff = NULL;
+  _cpp_line_note *note = &pfile->buffer->notes[pfile->buffer->cur_note];
+
+  type = (*base == 'L' ? CPP_WSTRING :
+         *base == 'U' ? CPP_STRING32 :
+         *base == 'u' ? (base[1] == '8' ? CPP_UTF8STRING : CPP_STRING16)
+         : CPP_STRING);
+
+  raw_prefix = cur + 1;
+  while (raw_prefix_len < 16)
+    {
+      switch (raw_prefix[raw_prefix_len])
+       {
+       case ' ': case '(': case ')': case '\\': case '\t':
+       case '\v': case '\f': case '\n': default:
+         break;
+       /* Basic source charset except the above chars.  */
+       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':
+       case '0': case '1': case '2': case '3': case '4': case '5':
+       case '6': case '7': case '8': case '9':
+       case '_': case '{': case '}': case '#': case '[': case ']':
+       case '<': case '>': case '%': case ':': case ';': case '.':
+       case '?': case '*': case '+': case '-': case '/': case '^':
+       case '&': case '|': case '~': case '!': case '=': case ',':
+       case '"': case '\'':
+         raw_prefix_len++;
+         continue;
+       }
+      break;
+    }
+
+  if (raw_prefix[raw_prefix_len] != '(')
+    {
+      int col = CPP_BUF_COLUMN (pfile->buffer, raw_prefix + raw_prefix_len)
+               + 1;
+      if (raw_prefix_len == 16)
+       cpp_error_with_line (pfile, CPP_DL_ERROR, token->src_loc, col,
+                            "raw string delimiter longer than 16 characters");
+      else
+       cpp_error_with_line (pfile, CPP_DL_ERROR, token->src_loc, col,
+                            "invalid character '%c' in raw string delimiter",
+                            (int) raw_prefix[raw_prefix_len]);
+      pfile->buffer->cur = raw_prefix - 1;
+      create_literal (pfile, token, base, raw_prefix - 1 - base, CPP_OTHER);
+      return;
+    }
+
+  cur = raw_prefix + raw_prefix_len + 1;
+  for (;;)
+    {
+#define BUF_APPEND(STR,LEN)                                    \
+      do {                                                     \
+       bufring_append (pfile, (const uchar *)(STR), (LEN),     \
+                       &first_buff, &last_buff);               \
+       total_len += (LEN);                                     \
+      } while (0);
+
+      cppchar_t c;
+
+      /* If we previously performed any trigraph or line splicing
+        transformations, undo them within the body of the raw string.  */
+      while (note->pos < cur)
+       ++note;
+      for (; note->pos == cur; ++note)
+       {
+         switch (note->type)
+           {
+           case '\\':
+           case ' ':
+             /* Restore backslash followed by newline.  */
+             BUF_APPEND (base, cur - base);
+             base = cur;
+             BUF_APPEND ("\\", 1);
+           after_backslash:
+             if (note->type == ' ')
+               {
+                 /* GNU backslash whitespace newline extension.  FIXME
+                    could be any sequence of non-vertical space.  When we
+                    can properly restore any such sequence, we should mark
+                    this note as handled so _cpp_process_line_notes
+                    doesn't warn.  */
+                 BUF_APPEND (" ", 1);
+               }
+
+             BUF_APPEND ("\n", 1);
+             break;
+
+           case 0:
+             /* Already handled.  */
+             break;
+
+           default:
+             if (_cpp_trigraph_map[note->type])
+               {
+                 /* Don't warn about this trigraph in
+                    _cpp_process_line_notes, since trigraphs show up as
+                    trigraphs in raw strings.  */
+                 uchar type = note->type;
+                 note->type = 0;
+
+                 if (!CPP_OPTION (pfile, trigraphs))
+                   /* If we didn't convert the trigraph in the first
+                      place, don't do anything now either.  */
+                   break;
+
+                 BUF_APPEND (base, cur - base);
+                 base = cur;
+                 BUF_APPEND ("??", 2);
+
+                 /* ??/ followed by newline gets two line notes, one for
+                    the trigraph and one for the backslash/newline.  */
+                 if (type == '/' && note[1].pos == cur)
+                   {
+                     if (note[1].type != '\\'
+                         && note[1].type != ' ')
+                       abort ();
+                     BUF_APPEND ("/", 1);
+                     ++note;
+                     goto after_backslash;
+                   }
+                 /* The ) from ??) could be part of the suffix.  */
+                 else if (type == ')'
+                          && strncmp ((const char *) cur+1,
+                                      (const char *) raw_prefix,
+                                      raw_prefix_len) == 0
+                          && cur[raw_prefix_len+1] == '"')
+                   {
+                     cur += raw_prefix_len+2;
+                     goto break_outer_loop;
+                   }
+                 else
+                   {
+                     /* Skip the replacement character.  */
+                     base = ++cur;
+                     BUF_APPEND (&type, 1);
+                   }
+               }
+             else
+               abort ();
+             break;
+           }
+       }
+      c = *cur++;
+
+      if (c == ')'
+         && strncmp ((const char *) cur, (const char *) raw_prefix,
+                     raw_prefix_len) == 0
+         && cur[raw_prefix_len] == '"')
+       {
+         cur += raw_prefix_len + 1;
+         break;
+       }
+      else if (c == '\n')
+       {
+         if (pfile->state.in_directive
+             || pfile->state.parsing_args
+             || pfile->state.in_deferred_pragma)
+           {
+             cur--;
+             type = CPP_OTHER;
+             cpp_error_with_line (pfile, CPP_DL_ERROR, token->src_loc, 0,
+                                  "unterminated raw string");
+             break;
+           }
+
+         BUF_APPEND (base, cur - base);
+
+         if (pfile->buffer->cur < pfile->buffer->rlimit)
+           CPP_INCREMENT_LINE (pfile, 0);
+         pfile->buffer->need_line = true;
+
+         pfile->buffer->cur = cur-1;
+         _cpp_process_line_notes (pfile, false);
+         if (!_cpp_get_fresh_line (pfile))
+           {
+             source_location src_loc = token->src_loc;
+             token->type = CPP_EOF;
+             /* Tell the compiler the line number of the EOF token.  */
+             token->src_loc = pfile->line_table->highest_line;
+             token->flags = BOL;
+             if (first_buff != NULL)
+               _cpp_release_buff (pfile, first_buff);
+             cpp_error_with_line (pfile, CPP_DL_ERROR, src_loc, 0,
+                                  "unterminated raw string");
+             return;
+           }
+
+         cur = base = pfile->buffer->cur;
+         note = &pfile->buffer->notes[pfile->buffer->cur_note];
+       }
+      else if (c == '\0' && !saw_NUL)
+       LINEMAP_POSITION_FOR_COLUMN (saw_NUL, pfile->line_table,
+                                    CPP_BUF_COLUMN (pfile->buffer, cur));
+    }
+ break_outer_loop:
+
+  if (saw_NUL && !pfile->state.skipping)
+    cpp_error_with_line (pfile, CPP_DL_WARNING, saw_NUL, 0,
+              "null character(s) preserved in literal");
+
+  pfile->buffer->cur = cur;
+  if (first_buff == NULL)
+    create_literal (pfile, token, base, cur - base, type);
+  else
+    {
+      uchar *dest = _cpp_unaligned_alloc (pfile, total_len + (cur - base) + 1);
+
+      token->type = type;
+      token->val.str.len = total_len + (cur - base);
+      token->val.str.text = dest;
+      last_buff = first_buff;
+      while (last_buff != NULL)
+       {
+         memcpy (dest, last_buff->base,
+                 BUFF_FRONT (last_buff) - last_buff->base);
+         dest += BUFF_FRONT (last_buff) - last_buff->base;
+         last_buff = last_buff->next;
+       }
+      _cpp_release_buff (pfile, first_buff);
+      memcpy (dest, base, cur - base);
+      dest[cur - base] = '\0';
+    }
+}
+
 /* Lexes a string, character constant, or angle-bracketed header file
    name.  The stored string contains the spelling, including opening
-   quote and leading any leading 'L', 'u' or 'U'.  It returns the type
-   of the literal, or CPP_OTHER if it was not properly terminated.
+   quote and any leading 'L', 'u', 'U' or 'u8' and optional
+   'R' modifier.  It returns the type of the literal, or CPP_OTHER
+   if it was not properly terminated, or CPP_LESS for an unterminated
+   header name which must be relexed as normal tokens.
 
    The spelling is NUL-terminated, but it is not guaranteed that this
    is the first NUL since embedded NULs are preserved.  */
@@ -626,12 +974,24 @@ lex_string (cpp_reader *pfile, cpp_token *token, const uchar *base)
 
   cur = base;
   terminator = *cur++;
-  if (terminator == 'L' || terminator == 'u' || terminator == 'U')
+  if (terminator == 'L' || terminator == 'U')
     terminator = *cur++;
-  if (terminator == '\"')
+  else if (terminator == 'u')
+    {
+      terminator = *cur++;
+      if (terminator == '8')
+       terminator = *cur++;
+    }
+  if (terminator == 'R')
+    {
+      lex_raw_string (pfile, token, base, cur);
+      return;
+    }
+  if (terminator == '"')
     type = (*base == 'L' ? CPP_WSTRING :
            *base == 'U' ? CPP_STRING32 :
-           *base == 'u' ? CPP_STRING16 : CPP_STRING);
+           *base == 'u' ? (base[1] == '8' ? CPP_UTF8STRING : CPP_STRING16)
+                        : CPP_STRING);
   else if (terminator == '\'')
     type = (*base == 'L' ? CPP_WCHAR :
            *base == 'U' ? CPP_CHAR32 :
@@ -651,6 +1011,14 @@ lex_string (cpp_reader *pfile, cpp_token *token, const uchar *base)
       else if (c == '\n')
        {
          cur--;
+         /* Unmatched quotes always yield undefined behavior, but
+            greedy lexing means that what appears to be an unterminated
+            header name may actually be a legitimate sequence of tokens.  */
+         if (terminator == '>')
+           {
+             token->type = CPP_LESS;
+             return;
+           }
          type = CPP_OTHER;
          break;
        }
@@ -670,6 +1038,51 @@ lex_string (cpp_reader *pfile, cpp_token *token, const uchar *base)
   create_literal (pfile, token, base, cur - base, type);
 }
 
+/* Return the comment table. The client may not make any assumption
+   about the ordering of the table.  */
+cpp_comment_table *
+cpp_get_comments (cpp_reader *pfile)
+{
+  return &pfile->comments;
+}
+
+/* Append a comment to the end of the comment table. */
+static void 
+store_comment (cpp_reader *pfile, cpp_token *token) 
+{
+  int len;
+
+  if (pfile->comments.allocated == 0)
+    {
+      pfile->comments.allocated = 256; 
+      pfile->comments.entries = (cpp_comment *) xmalloc
+       (pfile->comments.allocated * sizeof (cpp_comment));
+    }
+
+  if (pfile->comments.count == pfile->comments.allocated)
+    {
+      pfile->comments.allocated *= 2;
+      pfile->comments.entries = (cpp_comment *) xrealloc
+       (pfile->comments.entries,
+        pfile->comments.allocated * sizeof (cpp_comment));
+    }
+
+  len = token->val.str.len;
+
+  /* Copy comment. Note, token may not be NULL terminated. */
+  pfile->comments.entries[pfile->comments.count].comment = 
+    (char *) xmalloc (sizeof (char) * (len + 1));
+  memcpy (pfile->comments.entries[pfile->comments.count].comment,
+         token->val.str.text, len);
+  pfile->comments.entries[pfile->comments.count].comment[len] = '\0';
+
+  /* Set source location. */
+  pfile->comments.entries[pfile->comments.count].sloc = token->src_loc;
+
+  /* Increment the count of entries in the comment table. */
+  pfile->comments.count++;
+}
+
 /* The stored comment includes the comment start and any terminator.  */
 static void
 save_comment (cpp_reader *pfile, cpp_token *token, const unsigned char *from,
@@ -709,6 +1122,9 @@ save_comment (cpp_reader *pfile, cpp_token *token, const unsigned char *from,
       buffer[clen - 2] = '*';
       buffer[clen - 1] = '/';
     }
+
+  /* Finally store this comment for use by clients of libcpp. */
+  store_comment (pfile, token);
 }
 
 /* Allocate COUNT tokens for RUN.  */
@@ -1035,10 +1451,21 @@ _cpp_lex_direct (cpp_reader *pfile)
     case 'L':
     case 'u':
     case 'U':
-      /* 'L', 'u' or 'U' may introduce wide characters or strings.  */
+    case 'R':
+      /* 'L', 'u', 'U', 'u8' or 'R' may introduce wide characters,
+        wide strings or raw strings.  */
       if (c == 'L' || CPP_OPTION (pfile, uliterals))
        {
-         if (*buffer->cur == '\'' || *buffer->cur == '"')
+         if ((*buffer->cur == '\'' && c != 'R')
+             || *buffer->cur == '"'
+             || (*buffer->cur == 'R'
+                 && c != 'R'
+                 && buffer->cur[1] == '"'
+                 && CPP_OPTION (pfile, uliterals))
+             || (*buffer->cur == '8'
+                 && c == 'u'
+                 && (buffer->cur[1] == '"'
+                     || (buffer->cur[1] == 'R' && buffer->cur[2] == '"'))))
            {
              lex_string (pfile, result, buffer->cur - 1);
              break;
@@ -1054,22 +1481,22 @@ _cpp_lex_direct (cpp_reader *pfile)
     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 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+    case 'M': case 'N': case 'O': case 'P': case 'Q':
     case 'S': case 'T':           case 'V': case 'W': case 'X':
     case 'Y': case 'Z':
       result->type = CPP_NAME;
       {
        struct normalize_state nst = INITIAL_NORMALIZE_STATE;
-       result->val.node = lex_identifier (pfile, buffer->cur - 1, false,
-                                          &nst);
+       result->val.node.node = lex_identifier (pfile, buffer->cur - 1, false,
+                                               &nst);
        warn_about_normalization (pfile, result, &nst);
       }
 
       /* Convert named operators to their proper types.  */
-      if (result->val.node->flags & NODE_OPERATOR)
+      if (result->val.node.node->flags & NODE_OPERATOR)
        {
          result->flags |= NAMED_OP;
-         result->type = (enum cpp_ttype) result->val.node->directive_index;
+         result->type = (enum cpp_ttype) result->val.node.node->directive_index;
        }
       break;
 
@@ -1132,7 +1559,8 @@ _cpp_lex_direct (cpp_reader *pfile)
       if (pfile->state.angled_headers)
        {
          lex_string (pfile, result, buffer->cur - 1);
-         break;
+         if (result->type != CPP_LESS)
+           break;
        }
 
       result->type = CPP_LESS;
@@ -1183,7 +1611,7 @@ _cpp_lex_direct (cpp_reader *pfile)
              result->flags |= DIGRAPH;
              result->type = CPP_HASH;
              if (*buffer->cur == '%' && buffer->cur[1] == ':')
-               buffer->cur += 2, result->type = CPP_PASTE;
+               buffer->cur += 2, result->type = CPP_PASTE, result->val.token_no = 0;
            }
          else if (*buffer->cur == '>')
            {
@@ -1264,7 +1692,7 @@ _cpp_lex_direct (cpp_reader *pfile)
     case '=': IF_NEXT_IS ('=', CPP_EQ_EQ, CPP_EQ); break;
     case '!': IF_NEXT_IS ('=', CPP_NOT_EQ, CPP_NOT); break;
     case '^': IF_NEXT_IS ('=', CPP_XOR_EQ, CPP_XOR); break;
-    case '#': IF_NEXT_IS ('#', CPP_PASTE, CPP_HASH); break;
+    case '#': IF_NEXT_IS ('#', CPP_PASTE, CPP_HASH); result->val.token_no = 0; break;
 
     case '?': result->type = CPP_QUERY; break;
     case '~': result->type = CPP_COMPL; break;
@@ -1289,7 +1717,7 @@ _cpp_lex_direct (cpp_reader *pfile)
        if (forms_identifier_p (pfile, true, &nst))
          {
            result->type = CPP_NAME;
-           result->val.node = lex_identifier (pfile, base, true, &nst);
+           result->val.node.node = lex_identifier (pfile, base, true, &nst);
            warn_about_normalization (pfile, result, &nst);
            break;
          }
@@ -1313,9 +1741,9 @@ cpp_token_len (const cpp_token *token)
 
   switch (TOKEN_SPELL (token))
     {
-    default:           len = 4;                                break;
+    default:           len = 6;                                break;
     case SPELL_LITERAL:        len = token->val.str.len;               break;
-    case SPELL_IDENT:  len = NODE_LEN (token->val.node) * 10;  break;
+    case SPELL_IDENT:  len = NODE_LEN (token->val.node.node) * 10;     break;
     }
 
   return len;
@@ -1355,6 +1783,13 @@ utf8_to_ucn (unsigned char *buffer, const unsigned char *name)
   return ucn_len;
 }
 
+/* Given a token TYPE corresponding to a digraph, return a pointer to
+   the spelling of the digraph.  */
+static const unsigned char *
+cpp_digraph2name (enum cpp_ttype type)
+{
+  return digraph_spellings[(int) type - (int) CPP_FIRST_DIGRAPH];
+}
 
 /* Write the spelling of a token TOKEN to BUFFER.  The buffer must
    already contain the enough space to hold the token's spelling.
@@ -1374,8 +1809,7 @@ cpp_spell_token (cpp_reader *pfile, const cpp_token *token,
        unsigned char c;
 
        if (token->flags & DIGRAPH)
-         spelling
-           = digraph_spellings[(int) token->type - (int) CPP_FIRST_DIGRAPH];
+         spelling = cpp_digraph2name (token->type);
        else if (token->flags & NAMED_OP)
          goto spell_ident;
        else
@@ -1390,23 +1824,23 @@ cpp_spell_token (cpp_reader *pfile, const cpp_token *token,
     case SPELL_IDENT:
       if (forstring)
        {
-         memcpy (buffer, NODE_NAME (token->val.node),
-                 NODE_LEN (token->val.node));
-         buffer += NODE_LEN (token->val.node);
+         memcpy (buffer, NODE_NAME (token->val.node.node),
+                 NODE_LEN (token->val.node.node));
+         buffer += NODE_LEN (token->val.node.node);
        }
       else
        {
          size_t i;
-         const unsigned char * name = NODE_NAME (token->val.node);
+         const unsigned char * name = NODE_NAME (token->val.node.node);
          
-         for (i = 0; i < NODE_LEN (token->val.node); i++)
+         for (i = 0; i < NODE_LEN (token->val.node.node); i++)
            if (name[i] & ~0x7F)
              {
                i += utf8_to_ucn (buffer, name + i) - 1;
                buffer += 10;
              }
            else
-             *buffer++ = NODE_NAME (token->val.node)[i];
+             *buffer++ = NODE_NAME (token->val.node.node)[i];
        }
       break;
 
@@ -1438,11 +1872,17 @@ cpp_token_as_text (cpp_reader *pfile, const cpp_token *token)
   return start;
 }
 
-/* Used by C front ends, which really should move to using
-   cpp_token_as_text.  */
+/* Returns a pointer to a string which spells the token defined by
+   TYPE and FLAGS.  Used by C front ends, which really should move to
+   using cpp_token_as_text.  */
 const char *
-cpp_type2name (enum cpp_ttype type)
+cpp_type2name (enum cpp_ttype type, unsigned char flags)
 {
+  if (flags & DIGRAPH)
+    return (const char *) cpp_digraph2name (type);
+  else if (flags & NAMED_OP)
+    return cpp_named_operator2name (type);
+
   return (const char *) token_spellings[type].name;
 }
 
@@ -1460,8 +1900,7 @@ cpp_output_token (const cpp_token *token, FILE *fp)
        int c;
 
        if (token->flags & DIGRAPH)
-         spelling
-           = digraph_spellings[(int) token->type - (int) CPP_FIRST_DIGRAPH];
+         spelling = cpp_digraph2name (token->type);
        else if (token->flags & NAMED_OP)
          goto spell_ident;
        else
@@ -1478,9 +1917,9 @@ cpp_output_token (const cpp_token *token, FILE *fp)
     case SPELL_IDENT:
       {
        size_t i;
-       const unsigned char * name = NODE_NAME (token->val.node);
+       const unsigned char * name = NODE_NAME (token->val.node.node);
        
-       for (i = 0; i < NODE_LEN (token->val.node); i++)
+       for (i = 0; i < NODE_LEN (token->val.node.node); i++)
          if (name[i] & ~0x7F)
            {
              unsigned char buffer[10];
@@ -1488,7 +1927,7 @@ cpp_output_token (const cpp_token *token, FILE *fp)
              fwrite (buffer, 1, 10, fp);
            }
          else
-           fputc (NODE_NAME (token->val.node)[i], fp);
+           fputc (NODE_NAME (token->val.node.node)[i], fp);
       }
       break;
 
@@ -1511,11 +1950,14 @@ _cpp_equiv_tokens (const cpp_token *a, const cpp_token *b)
       {
       default:                 /* Keep compiler happy.  */
       case SPELL_OPERATOR:
-       return 1;
+       /* token_no is used to track where multiple consecutive ##
+          tokens were originally located.  */
+       return (a->type != CPP_PASTE || a->val.token_no == b->val.token_no);
       case SPELL_NONE:
-       return (a->type != CPP_MACRO_ARG || a->val.arg_no == b->val.arg_no);
+       return (a->type != CPP_MACRO_ARG
+               || a->val.macro_arg.arg_no == b->val.macro_arg.arg_no);
       case SPELL_IDENT:
-       return a->val.node == b->val.node;
+       return a->val.node.node == b->val.node.node;
       case SPELL_LITERAL:
        return (a->val.str.len == b->val.str.len
                && !memcmp (a->val.str.text, b->val.str.text,
@@ -1825,6 +2267,11 @@ cpp_token_val_index (cpp_token *tok)
       return CPP_TOKEN_FLD_NODE;
     case SPELL_LITERAL:
       return CPP_TOKEN_FLD_STR;
+    case SPELL_OPERATOR:
+      if (tok->type == CPP_PASTE)
+       return CPP_TOKEN_FLD_TOKEN_NO;
+      else
+       return CPP_TOKEN_FLD_NONE;
     case SPELL_NONE:
       if (tok->type == CPP_MACRO_ARG)
        return CPP_TOKEN_FLD_ARG_NO;