OSDN Git Service

PR driver/40144
[pf3gnuchains/gcc-fork.git] / libcpp / lex.c
index 2eaf610..ca2f2ca 100644 (file)
@@ -1,5 +1,6 @@
 /* CPP Library - lexical analysis.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007 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"
@@ -39,10 +40,10 @@ struct token_spelling
 };
 
 static const unsigned char *const digraph_spellings[] =
-{ U"%:", U"%:%:", U"<:", U":>", U"<%", U"%>" };
+{ UC"%:", UC"%:%:", UC"<:", UC":>", UC"<%", UC"%>" };
 
-#define OP(e, s) { SPELL_OPERATOR, U s  },
-#define TK(e, s) { SPELL_ ## s,    U #e },
+#define OP(e, s) { SPELL_OPERATOR, UC s  },
+#define TK(e, s) { SPELL_ ## s,    UC #e },
 static const struct token_spelling token_spellings[N_TTYPES] = { TTYPE_TABLE };
 #undef OP
 #undef TK
@@ -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
@@ -384,7 +386,7 @@ static int
 skip_line_comment (cpp_reader *pfile)
 {
   cpp_buffer *buffer = pfile->buffer;
-  unsigned int orig_line = pfile->line_table->highest_line;
+  source_location orig_line = pfile->line_table->highest_line;
 
   while (*buffer->cur != '\n')
     buffer->cur++;
@@ -611,8 +613,10 @@ create_literal (cpp_reader *pfile, cpp_token *token, const uchar *base,
 
 /* 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'.  It returns the type of the
-   literal, or CPP_OTHER if it was not properly terminated.
+   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, 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 +630,16 @@ lex_string (cpp_reader *pfile, cpp_token *token, const uchar *base)
 
   cur = base;
   terminator = *cur++;
-  if (terminator == 'L')
+  if (terminator == 'L' || terminator == 'u' || terminator == 'U')
     terminator = *cur++;
   if (terminator == '\"')
-    type = *base == 'L' ? CPP_WSTRING: CPP_STRING;
+    type = (*base == 'L' ? CPP_WSTRING :
+           *base == 'U' ? CPP_STRING32 :
+           *base == 'u' ? CPP_STRING16 : CPP_STRING);
   else if (terminator == '\'')
-    type = *base == 'L' ? CPP_WCHAR: CPP_CHAR;
+    type = (*base == 'L' ? CPP_WCHAR :
+           *base == 'U' ? CPP_CHAR32 :
+           *base == 'u' ? CPP_CHAR16 : CPP_CHAR);
   else
     terminator = '>', type = CPP_HEADER_NAME;
 
@@ -647,6 +655,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;
        }
@@ -666,6 +682,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,
@@ -705,6 +766,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.  */
@@ -730,6 +794,49 @@ next_tokenrun (tokenrun *run)
   return run->next;
 }
 
+/* Look ahead in the input stream.  */
+const cpp_token *
+cpp_peek_token (cpp_reader *pfile, int index)
+{
+  cpp_context *context = pfile->context;
+  const cpp_token *peektok;
+  int count;
+
+  /* First, scan through any pending cpp_context objects.  */
+  while (context->prev)
+    {
+      ptrdiff_t sz = (context->direct_p
+                      ? LAST (context).token - FIRST (context).token
+                      : LAST (context).ptoken - FIRST (context).ptoken);
+
+      if (index < (int) sz)
+        return (context->direct_p
+                ? FIRST (context).token + index
+                : *(FIRST (context).ptoken + index));
+
+      index -= (int) sz;
+      context = context->prev;
+    }
+
+  /* We will have to read some new tokens after all (and do so
+     without invalidating preceding tokens).  */
+  count = index;
+  pfile->keep_tokens++;
+
+  do
+    {
+      peektok = _cpp_lex_token (pfile);
+      if (peektok->type == CPP_EOF)
+       return peektok;
+    }
+  while (index--);
+
+  _cpp_backup_tokens_direct (pfile, count + 1);
+  pfile->keep_tokens--;
+
+  return peektok;
+}
+
 /* Allocate a single token that is invalidated at the same time as the
    rest of the tokens on the line.  Has its line and col set to the
    same as the last lexed token, so that diagnostics appear in the
@@ -738,9 +845,30 @@ cpp_token *
 _cpp_temp_token (cpp_reader *pfile)
 {
   cpp_token *old, *result;
+  ptrdiff_t sz = pfile->cur_run->limit - pfile->cur_token;
+  ptrdiff_t la = (ptrdiff_t) pfile->lookaheads;
 
   old = pfile->cur_token - 1;
-  if (pfile->cur_token == pfile->cur_run->limit)
+  /* Any pre-existing lookaheads must not be clobbered.  */
+  if (la)
+    {
+      if (sz <= la)
+        {
+          tokenrun *next = next_tokenrun (pfile->cur_run);
+
+          if (sz < la)
+            memmove (next->base + 1, next->base,
+                     (la - sz) * sizeof (cpp_token));
+
+          next->base[0] = pfile->cur_run->limit[-1];
+        }
+
+      if (sz > 1)
+        memmove (pfile->cur_token + 1, pfile->cur_token,
+                 MIN (la, sz - 1) * sizeof (cpp_token));
+    }
+
+  if (!sz && pfile->cur_token == pfile->cur_run->limit)
     {
       pfile->cur_run = next_tokenrun (pfile->cur_run);
       pfile->cur_token = pfile->cur_run->base;
@@ -965,11 +1093,16 @@ _cpp_lex_direct (cpp_reader *pfile)
       }
 
     case 'L':
-      /* 'L' may introduce wide characters or strings.  */
-      if (*buffer->cur == '\'' || *buffer->cur == '"')
+    case 'u':
+    case 'U':
+      /* 'L', 'u' or 'U' may introduce wide characters or strings.  */
+      if (c == 'L' || CPP_OPTION (pfile, uliterals))
        {
-         lex_string (pfile, result, buffer->cur - 1);
-         break;
+         if (*buffer->cur == '\'' || *buffer->cur == '"')
+           {
+             lex_string (pfile, result, buffer->cur - 1);
+             break;
+           }
        }
       /* Fall through.  */
 
@@ -977,26 +1110,26 @@ _cpp_lex_direct (cpp_reader *pfile)
     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 's': case 't':           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 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
-    case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+    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;
 
@@ -1059,7 +1192,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;
@@ -1110,7 +1244,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 == '>')
            {
@@ -1191,7 +1325,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;
@@ -1216,7 +1350,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;
          }
@@ -1240,9 +1374,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;
@@ -1282,6 +1416,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.
@@ -1301,8 +1442,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
@@ -1317,23 +1457,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;
 
@@ -1365,11 +1505,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;
 }
 
@@ -1387,8 +1533,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
@@ -1405,9 +1550,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];
@@ -1415,7 +1560,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;
 
@@ -1438,11 +1583,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,
@@ -1530,6 +1678,51 @@ cpp_output_line (cpp_reader *pfile, FILE *fp)
   putc ('\n', fp);
 }
 
+/* Return a string representation of all the remaining tokens on the
+   current line.  The result is allocated using xmalloc and must be
+   freed by the caller.  */
+unsigned char *
+cpp_output_line_to_string (cpp_reader *pfile, const unsigned char *dir_name)
+{
+  const cpp_token *token;
+  unsigned int out = dir_name ? ustrlen (dir_name) : 0;
+  unsigned int alloced = 120 + out;
+  unsigned char *result = (unsigned char *) xmalloc (alloced);
+
+  /* If DIR_NAME is empty, there are no initial contents.  */
+  if (dir_name)
+    {
+      sprintf ((char *) result, "#%s ", dir_name);
+      out += 2;
+    }
+
+  token = cpp_get_token (pfile);
+  while (token->type != CPP_EOF)
+    {
+      unsigned char *last;
+      /* Include room for a possible space and the terminating nul.  */
+      unsigned int len = cpp_token_len (token) + 2;
+
+      if (out + len > alloced)
+       {
+         alloced *= 2;
+         if (out + len > alloced)
+           alloced = out + len;
+         result = (unsigned char *) xrealloc (result, alloced);
+       }
+
+      last = cpp_spell_token (pfile, token, &result[out], 0);
+      out = last - result;
+
+      token = cpp_get_token (pfile);
+      if (token->flags & PREV_WHITE)
+       result[out++] = ' ';
+    }
+
+  result[out] = '\0';
+  return result;
+}
+
 /* Memory buffers.  Changing these three constants can have a dramatic
    effect on performance.  The values here are reasonable defaults,
    but might be tuned.  If you adjust them, be sure to test across a
@@ -1707,6 +1900,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;