Automatic date update in version.in
[deliverable/binutils-gdb.git] / gdb / macroexp.c
index 8102bc081f00b366a9e12e4a1487a6f73a755b71..1ece8d5d5be580a797029a09e36f2161154cfe0f 100644 (file)
@@ -1,5 +1,5 @@
 /* C preprocessor macro expansion for GDB.
-   Copyright (C) 2002, 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2002-2021 Free Software Foundation, Inc.
    Contributed by Red Hat, Inc.
 
    This file is part of GDB.
 
 #include "defs.h"
 #include "gdb_obstack.h"
-#include "bcache.h"
 #include "macrotab.h"
 #include "macroexp.h"
-#include "gdb_assert.h"
+#include "macroscope.h"
+#include "c-lang.h"
 
 
 \f
-/* A resizeable, substringable string type.  */
 
+/* A string type that we can use to refer to substrings of other
+   strings.  */
 
-/* A string type that we can resize, quickly append to, and use to
-   refer to substrings of other strings.  */
-struct macro_buffer
+struct shared_macro_buffer
 {
-  /* An array of characters.  The first LEN bytes are the real text,
-     but there are SIZE bytes allocated to the array.  If SIZE is
-     zero, then this doesn't point to a malloc'ed block.  If SHARED is
-     non-zero, then this buffer is actually a pointer into some larger
-     string, and we shouldn't append characters to it, etc.  Because
-     of sharing, we can't assume in general that the text is
+  /* An array of characters.  This buffer is a pointer into some
+     larger string and thus we can't assume in that the text is
      null-terminated.  */
-  char *text;
+  const char *text;
 
   /* The number of characters in the string.  */
   int len;
 
-  /* The number of characters allocated to the string.  If SHARED is
-     non-zero, this is meaningless; in this case, we set it to zero so
-     that any "do we have room to append something?" tests will fail,
-     so we don't always have to check SHARED before using this field.  */
-  int size;
-
-  /* Zero if TEXT can be safely realloc'ed (i.e., it's its own malloc
-     block).  Non-zero if TEXT is actually pointing into the middle of
-     some other block, and we shouldn't reallocate it.  */
-  int shared;
-
   /* For detecting token splicing. 
 
      This is the index in TEXT of the first character of the token
@@ -64,107 +48,124 @@ struct macro_buffer
      no token abutting the end of TEXT (it's just whitespace), and
      again, we set this equal to LEN.  We set this to -1 if we don't
      know the nature of TEXT.  */
-  int last_token;
+  int last_token = -1;
 
   /* If this buffer is holding the result from get_token, then this 
      is non-zero if it is an identifier token, zero otherwise.  */
-  int is_identifier;
-};
+  int is_identifier = 0;
 
+  shared_macro_buffer ()
+    : text (NULL),
+      len (0)
+  {
+  }
 
-/* Set the macro buffer *B to the empty string, guessing that its
-   final contents will fit in N bytes.  (It'll get resized if it
-   doesn't, so the guess doesn't have to be right.)  Allocate the
-   initial storage with xmalloc.  */
-static void
-init_buffer (struct macro_buffer *b, int n)
-{
-  b->size = n;
-  if (n > 0)
-    b->text = (char *) xmalloc (n);
-  else
-    b->text = NULL;
-  b->len = 0;
-  b->shared = 0;
-  b->last_token = -1;
-}
+  /* Set the macro buffer to refer to the LEN bytes at ADDR, as a
+     shared substring.  */
+  shared_macro_buffer (const char *addr, int len)
+  {
+    set_shared (addr, len);
+  }
 
+  /* Set the macro buffer to refer to the LEN bytes at ADDR, as a
+     shared substring.  */
+  void set_shared (const char *addr, int len_)
+  {
+    text = addr;
+    len = len_;
+  }
+};
 
-/* Set the macro buffer *BUF to refer to the LEN bytes at ADDR, as a
-   shared substring.  */
-static void
-init_shared_buffer (struct macro_buffer *buf, char *addr, int len)
+/* A string type that we can resize and quickly append to.  */
+
+struct growable_macro_buffer
 {
-  buf->text = addr;
-  buf->len = len;
-  buf->shared = 1;
-  buf->size = 0;
-  buf->last_token = -1;
-}
+  /* An array of characters.  The first LEN bytes are the real text,
+     but there are SIZE bytes allocated to the array.  */
+  char *text;
 
+  /* The number of characters in the string.  */
+  int len;
 
-/* Free the text of the buffer B.  Raise an error if B is shared.  */
-static void
-free_buffer (struct macro_buffer *b)
-{
-  gdb_assert (! b->shared);
-  if (b->size)
-    xfree (b->text);
-}
+  /* The number of characters allocated to the string.  */
+  int size;
 
+  /* For detecting token splicing.
 
-/* A cleanup function for macro buffers.  */
-static void
-cleanup_macro_buffer (void *untyped_buf)
-{
-  free_buffer ((struct macro_buffer *) untyped_buf);
-}
+     This is the index in TEXT of the first character of the token
+     that abuts the end of TEXT.  If TEXT contains no tokens, then we
+     set this equal to LEN.  If TEXT ends in whitespace, then there is
+     no token abutting the end of TEXT (it's just whitespace), and
+     again, we set this equal to LEN.  We set this to -1 if we don't
+     know the nature of TEXT.  */
+  int last_token = -1;
+
+  /* Set the macro buffer to the empty string, guessing that its
+     final contents will fit in N bytes.  (It'll get resized if it
+     doesn't, so the guess doesn't have to be right.)  Allocate the
+     initial storage with xmalloc.  */
+  explicit growable_macro_buffer (int n)
+    : len (0),
+      size (n)
+  {
+    if (n > 0)
+      text = (char *) xmalloc (n);
+    else
+      text = NULL;
+  }
 
+  DISABLE_COPY_AND_ASSIGN (growable_macro_buffer);
 
-/* Resize the buffer B to be at least N bytes long.  Raise an error if
-   B shouldn't be resized.  */
-static void
-resize_buffer (struct macro_buffer *b, int n)
-{
-  /* We shouldn't be trying to resize shared strings.  */
-  gdb_assert (! b->shared);
-  
-  if (b->size == 0)
-    b->size = n;
-  else
-    while (b->size <= n)
-      b->size *= 2;
+  ~growable_macro_buffer ()
+  {
+    xfree (text);
+  }
 
-  b->text = xrealloc (b->text, b->size);
-}
+  /* Release the text of the buffer to the caller.  */
+  gdb::unique_xmalloc_ptr<char> release ()
+  {
+    gdb_assert (size);
+    char *result = text;
+    text = NULL;
+    return gdb::unique_xmalloc_ptr<char> (result);
+  }
 
+  /* Resize the buffer to be at least N bytes long.  */
+  void resize_buffer (int n)
+  {
+    if (size == 0)
+      size = n;
+    else
+      while (size <= n)
+       size *= 2;
 
-/* Append the character C to the buffer B.  */
-static void
-appendc (struct macro_buffer *b, int c)
-{
-  int new_len = b->len + 1;
+    text = (char *) xrealloc (text, size);
+  }
 
-  if (new_len > b->size)
-    resize_buffer (b, new_len);
+  /* Append the character C to the buffer.  */
+  void appendc (int c)
+  {
+    int new_len = len + 1;
 
-  b->text[b->len] = c;
-  b->len = new_len;
-}
+    if (new_len > size)
+      resize_buffer (new_len);
 
+    text[len] = c;
+    len = new_len;
+  }
 
-/* Append the LEN bytes at ADDR to the buffer B.  */
-static void
-appendmem (struct macro_buffer *b, char *addr, int len)
-{
-  int new_len = b->len + len;
+  /* Append the COUNT bytes at ADDR to the buffer.  */
+  void appendmem (const char *addr, int count)
+  {
+    int new_len = len + count;
 
-  if (new_len > b->size)
-    resize_buffer (b, new_len);
+    if (new_len > size)
+      resize_buffer (new_len);
 
-  memcpy (b->text + b->len, addr, len);
-  b->len = new_len;
-}
+    memcpy (text + len, addr, count);
+    len = new_len;
+  }
+};
 
 
 \f
@@ -175,10 +176,10 @@ int
 macro_is_whitespace (int c)
 {
   return (c == ' '
-          || c == '\t'
-          || c == '\n'
-          || c == '\v'
-          || c == '\f');
+         || c == '\t'
+         || c == '\n'
+         || c == '\v'
+         || c == '\f');
 }
 
 
@@ -193,55 +194,55 @@ int
 macro_is_identifier_nondigit (int c)
 {
   return (c == '_'
-          || ('a' <= c && c <= 'z')
-          || ('A' <= c && c <= 'Z'));
+         || ('a' <= c && c <= 'z')
+         || ('A' <= c && c <= 'Z'));
 }
 
 
 static void
-set_token (struct macro_buffer *tok, char *start, char *end)
+set_token (shared_macro_buffer *tok, const char *start, const char *end)
 {
-  init_shared_buffer (tok, start, end - start);
+  tok->set_shared (start, end - start);
   tok->last_token = 0;
 
-  /* Presumed; get_identifier may overwrite this. */
+  /* Presumed; get_identifier may overwrite this.  */
   tok->is_identifier = 0;
 }
 
 
 static int
-get_comment (struct macro_buffer *tok, char *p, char *end)
+get_comment (shared_macro_buffer *tok, const char *p, const char *end)
 {
   if (p + 2 > end)
     return 0;
   else if (p[0] == '/'
-           && p[1] == '*')
+          && p[1] == '*')
     {
-      char *tok_start = p;
+      const char *tok_start = p;
 
       p += 2;
 
       for (; p < end; p++)
-        if (p + 2 <= end
-            && p[0] == '*'
-            && p[1] == '/')
-          {
-            p += 2;
-            set_token (tok, tok_start, p);
-            return 1;
-          }
+       if (p + 2 <= end
+           && p[0] == '*'
+           && p[1] == '/')
+         {
+           p += 2;
+           set_token (tok, tok_start, p);
+           return 1;
+         }
 
       error (_("Unterminated comment in macro expansion."));
     }
   else if (p[0] == '/'
-           && p[1] == '/')
+          && p[1] == '/')
     {
-      char *tok_start = p;
+      const char *tok_start = p;
 
       p += 2;
       for (; p < end; p++)
-        if (*p == '\n')
-          break;
+       if (*p == '\n')
+         break;
 
       set_token (tok, tok_start, p);
       return 1;
@@ -252,17 +253,17 @@ get_comment (struct macro_buffer *tok, char *p, char *end)
 
 
 static int
-get_identifier (struct macro_buffer *tok, char *p, char *end)
+get_identifier (shared_macro_buffer *tok, const char *p, const char *end)
 {
   if (p < end
       && macro_is_identifier_nondigit (*p))
     {
-      char *tok_start = p;
+      const char *tok_start = p;
 
       while (p < end
-             && (macro_is_identifier_nondigit (*p)
-                 || macro_is_digit (*p)))
-        p++;
+            && (macro_is_identifier_nondigit (*p)
+                || macro_is_digit (*p)))
+       p++;
 
       set_token (tok, tok_start, p);
       tok->is_identifier = 1;
@@ -274,27 +275,29 @@ get_identifier (struct macro_buffer *tok, char *p, char *end)
 
 
 static int
-get_pp_number (struct macro_buffer *tok, char *p, char *end)
+get_pp_number (shared_macro_buffer *tok, const char *p, const char *end)
 {
   if (p < end
       && (macro_is_digit (*p)
-          || *p == '.'))
+         || (*p == '.'
+             && p + 2 <= end
+             && macro_is_digit (p[1]))))
     {
-      char *tok_start = p;
+      const char *tok_start = p;
 
       while (p < end)
-        {
-          if (macro_is_digit (*p)
-              || macro_is_identifier_nondigit (*p)
-              || *p == '.')
-            p++;
-          else if (p + 2 <= end
-                   && strchr ("eEpP.", *p)
-                   && (p[1] == '+' || p[1] == '-'))
-            p += 2;
-          else
-            break;
-        }
+       {
+         if (p + 2 <= end
+             && strchr ("eEpP", *p)
+             && (p[1] == '+' || p[1] == '-'))
+           p += 2;
+         else if (macro_is_digit (*p)
+                  || macro_is_identifier_nondigit (*p)
+                  || *p == '.')
+           p++;
+         else
+           break;
+       }
 
       set_token (tok, tok_start, p);
       return 1;
@@ -311,46 +314,54 @@ get_pp_number (struct macro_buffer *tok, char *p, char *end)
    Signal an error if it contains a malformed or incomplete character
    constant.  */
 static int
-get_character_constant (struct macro_buffer *tok, char *p, char *end)
+get_character_constant (shared_macro_buffer *tok,
+                       const char *p, const char *end)
 {
   /* ISO/IEC 9899:1999 (E)  Section 6.4.4.4  paragraph 1 
      But of course, what really matters is that we handle it the same
      way GDB's C/C++ lexer does.  So we call parse_escape in utils.c
      to handle escape sequences.  */
   if ((p + 1 <= end && *p == '\'')
-      || (p + 2 <= end && p[0] == 'L' && p[1] == '\''))
+      || (p + 2 <= end
+         && (p[0] == 'L' || p[0] == 'u' || p[0] == 'U')
+         && p[1] == '\''))
     {
-      char *tok_start = p;
-      char *body_start;
+      const char *tok_start = p;
+      int char_count = 0;
 
       if (*p == '\'')
-        p++;
-      else if (*p == 'L')
-        p += 2;
+       p++;
+      else if (*p == 'L' || *p == 'u' || *p == 'U')
+       p += 2;
       else
-        gdb_assert (0);
+       gdb_assert_not_reached ("unexpected character constant");
 
-      body_start = p;
       for (;;)
-        {
-          if (p >= end)
-            error (_("Unmatched single quote."));
-          else if (*p == '\'')
-            {
-              if (p == body_start)
-                error (_("A character constant must contain at least one "
-                       "character."));
-              p++;
-              break;
-            }
-          else if (*p == '\\')
-            {
-              p++;
-              parse_escape (&p);
-            }
-          else
-            p++;
-        }
+       {
+         if (p >= end)
+           error (_("Unmatched single quote."));
+         else if (*p == '\'')
+           {
+             if (!char_count)
+               error (_("A character constant must contain at least one "
+                      "character."));
+             p++;
+             break;
+           }
+         else if (*p == '\\')
+           {
+             const char *s, *o;
+
+             s = o = ++p;
+             char_count += c_parse_escape (&s, NULL);
+             p += s - o;
+           }
+         else
+           {
+             p++;
+             char_count++;
+           }
+       }
 
       set_token (tok, tok_start, p);
       return 1;
@@ -365,43 +376,46 @@ get_character_constant (struct macro_buffer *tok, char *p, char *end)
    literal, and return 1.  Otherwise, return zero.  Signal an error if
    it contains a malformed or incomplete string literal.  */
 static int
-get_string_literal (struct macro_buffer *tok, char *p, char *end)
+get_string_literal (shared_macro_buffer *tok, const char *p, const char *end)
 {
   if ((p + 1 <= end
-       && *p == '\"')
+       && *p == '"')
       || (p + 2 <= end
-          && p[0] == 'L'
-          && p[1] == '\"'))
+         && (p[0] == 'L' || p[0] == 'u' || p[0] == 'U')
+         && p[1] == '"'))
     {
-      char *tok_start = p;
+      const char *tok_start = p;
 
-      if (*p == '\"')
-        p++;
-      else if (*p == 'L')
-        p += 2;
+      if (*p == '"')
+       p++;
+      else if (*p == 'L' || *p == 'u' || *p == 'U')
+       p += 2;
       else
-        gdb_assert (0);
+       gdb_assert_not_reached ("unexpected string literal");
 
       for (;;)
-        {
-          if (p >= end)
-            error (_("Unterminated string in expression."));
-          else if (*p == '\"')
-            {
-              p++;
-              break;
-            }
-          else if (*p == '\n')
-            error (_("Newline characters may not appear in string "
-                   "constants."));
-          else if (*p == '\\')
-            {
-              p++;
-              parse_escape (&p);
-            }
-          else
-            p++;
-        }
+       {
+         if (p >= end)
+           error (_("Unterminated string in expression."));
+         else if (*p == '"')
+           {
+             p++;
+             break;
+           }
+         else if (*p == '\n')
+           error (_("Newline characters may not appear in string "
+                  "constants."));
+         else if (*p == '\\')
+           {
+             const char *s, *o;
+
+             s = o = ++p;
+             c_parse_escape (&s, NULL);
+             p += s - o;
+           }
+         else
+           p++;
+       }
 
       set_token (tok, tok_start, p);
       return 1;
@@ -412,7 +426,7 @@ get_string_literal (struct macro_buffer *tok, char *p, char *end)
 
 
 static int
-get_punctuator (struct macro_buffer *tok, char *p, char *end)
+get_punctuator (shared_macro_buffer *tok, const char *p, const char *end)
 {
   /* Here, speed is much less important than correctness and clarity.  */
 
@@ -445,21 +459,21 @@ get_punctuator (struct macro_buffer *tok, char *p, char *end)
   if (p + 1 <= end)
     {
       for (i = 0; punctuators[i]; i++)
-        {
-          const char *punctuator = punctuators[i];
-
-          if (p[0] == punctuator[0])
-            {
-              int len = strlen (punctuator);
-
-              if (p + len <= end
-                  && ! memcmp (p, punctuator, len))
-                {
-                  set_token (tok, p, p + len);
-                  return 1;
-                }
-            }
-        }
+       {
+         const char *punctuator = punctuators[i];
+
+         if (p[0] == punctuator[0])
+           {
+             int len = strlen (punctuator);
+
+             if (p + len <= end
+                 && ! memcmp (p, punctuator, len))
+               {
+                 set_token (tok, p, p + len);
+                 return 1;
+               }
+           }
+       }
     }
 
   return 0;
@@ -468,29 +482,27 @@ get_punctuator (struct macro_buffer *tok, char *p, char *end)
 
 /* Peel the next preprocessor token off of SRC, and put it in TOK.
    Mutate TOK to refer to the first token in SRC, and mutate SRC to
-   refer to the text after that token.  SRC must be a shared buffer;
-   the resulting TOK will be shared, pointing into the same string SRC
-   does.  Initialize TOK's last_token field.  Return non-zero if we
-   succeed, or 0 if we didn't find any more tokens in SRC.  */
+   refer to the text after that token.  The resulting TOK will point
+   into the same string SRC does.  Initialize TOK's last_token field.
+   Return non-zero if we succeed, or 0 if we didn't find any more
+   tokens in SRC.  */
+
 static int
-get_token (struct macro_buffer *tok,
-           struct macro_buffer *src)
+get_token (shared_macro_buffer *tok, shared_macro_buffer *src)
 {
-  char *p = src->text;
-  char *end = p + src->len;
-
-  gdb_assert (src->shared);
+  const char *p = src->text;
+  const char *end = p + src->len;
 
   /* From the ISO C standard, ISO/IEC 9899:1999 (E), section 6.4:
 
      preprocessing-token: 
-         header-name
-         identifier
-         pp-number
-         character-constant
-         string-literal
-         punctuator
-         each non-white-space character that cannot be one of the above
+        header-name
+        identifier
+        pp-number
+        character-constant
+        string-literal
+        punctuator
+        each non-white-space character that cannot be one of the above
 
      We don't have to deal with header-name tokens, since those can
      only occur after a #include, which we will never see.  */
@@ -501,36 +513,37 @@ get_token (struct macro_buffer *tok,
     else if (get_comment (tok, p, end))
       p += tok->len;
     else if (get_pp_number (tok, p, end)
-             || get_character_constant (tok, p, end)
-             || get_string_literal (tok, p, end)
-             /* Note: the grammar in the standard seems to be
-                ambiguous: L'x' can be either a wide character
-                constant, or an identifier followed by a normal
-                character constant.  By trying `get_identifier' after
-                we try get_character_constant and get_string_literal,
-                we give the wide character syntax precedence.  Now,
-                since GDB doesn't handle wide character constants
-                anyway, is this the right thing to do?  */
-             || get_identifier (tok, p, end)
-             || get_punctuator (tok, p, end))
+            || get_character_constant (tok, p, end)
+            || get_string_literal (tok, p, end)
+            /* Note: the grammar in the standard seems to be
+               ambiguous: L'x' can be either a wide character
+               constant, or an identifier followed by a normal
+               character constant.  By trying `get_identifier' after
+               we try get_character_constant and get_string_literal,
+               we give the wide character syntax precedence.  Now,
+               since GDB doesn't handle wide character constants
+               anyway, is this the right thing to do?  */
+            || get_identifier (tok, p, end)
+            || get_punctuator (tok, p, end))
       {
-        /* How many characters did we consume, including whitespace?  */
-        int consumed = p - src->text + tok->len;
-        src->text += consumed;
-        src->len -= consumed;
-        return 1;
+       /* How many characters did we consume, including whitespace?  */
+       int consumed = p - src->text + tok->len;
+
+       src->text += consumed;
+       src->len -= consumed;
+       return 1;
       }
     else 
       {
-        /* We have found a "non-whitespace character that cannot be
-           one of the above."  Make a token out of it.  */
-        int consumed;
-
-        set_token (tok, p, p + 1);
-        consumed = p - src->text + tok->len;
-        src->text += consumed;
-        src->len -= consumed;
-        return 1;
+       /* We have found a "non-whitespace character that cannot be
+          one of the above."  Make a token out of it.  */
+       int consumed;
+
+       set_token (tok, p, p + 1);
+       consumed = p - src->text + tok->len;
+       src->text += consumed;
+       src->len -= consumed;
+       return 1;
       }
 
   return 0;
@@ -557,18 +570,18 @@ get_token (struct macro_buffer *tok,
    fine to return with DEST set to "x y".  Similarly, "<" and "<" must
    yield "< <", not "<<", etc.  */
 static void
-append_tokens_without_splicing (struct macro_buffer *dest,
-                                struct macro_buffer *src)
+append_tokens_without_splicing (growable_macro_buffer *dest,
+                                shared_macro_buffer *src)
 {
   int original_dest_len = dest->len;
-  struct macro_buffer dest_tail, new_token;
+  shared_macro_buffer dest_tail, new_token;
 
   gdb_assert (src->last_token != -1);
   gdb_assert (dest->last_token != -1);
   
   /* First, just try appending the two, and call get_token to see if
      we got a splice.  */
-  appendmem (dest, src->text, src->len);
+  dest->appendmem (src->text, src->len);
 
   /* If DEST originally had no token abutting its end, then we can't
      have spliced anything, so we're done.  */
@@ -580,9 +593,8 @@ append_tokens_without_splicing (struct macro_buffer *dest,
 
   /* Set DEST_TAIL to point to the last token in DEST, followed by
      all the stuff we just appended.  */
-  init_shared_buffer (&dest_tail,
-                      dest->text + dest->last_token,
-                      dest->len - dest->last_token);
+  dest_tail.set_shared (dest->text + dest->last_token,
+                       dest->len - dest->last_token);
 
   /* Re-parse DEST's last token.  We know that DEST used to contain
      at least one token, so if it doesn't contain any after the
@@ -591,7 +603,7 @@ append_tokens_without_splicing (struct macro_buffer *dest,
      the first time.  This is not a bug fix.)  */
   if (get_token (&new_token, &dest_tail)
       && (new_token.text + new_token.len
-          == dest->text + original_dest_len))
+         == dest->text + original_dest_len))
     {
       /* No splice, so we're done.  */
       dest->last_token = original_dest_len + src->last_token;
@@ -602,17 +614,16 @@ append_tokens_without_splicing (struct macro_buffer *dest,
      its original length and try again, but separate the texts with a
      space.  */
   dest->len = original_dest_len;
-  appendc (dest, ' ');
-  appendmem (dest, src->text, src->len);
+  dest->appendc (' ');
+  dest->appendmem (src->text, src->len);
 
-  init_shared_buffer (&dest_tail,
-                      dest->text + dest->last_token,
-                      dest->len - dest->last_token);
+  dest_tail.set_shared (dest->text + dest->last_token,
+                       dest->len - dest->last_token);
 
   /* Try to re-parse DEST's last token, as above.  */
   if (get_token (&new_token, &dest_tail)
       && (new_token.text + new_token.len
-          == dest->text + original_dest_len))
+         == dest->text + original_dest_len))
     {
       /* No splice, so we're done.  */
       dest->last_token = original_dest_len + 1 + src->last_token;
@@ -622,9 +633,69 @@ append_tokens_without_splicing (struct macro_buffer *dest,
   /* As far as I know, there's no case where inserting a space isn't
      enough to prevent a splice.  */
   internal_error (__FILE__, __LINE__,
-                  _("unable to avoid splicing tokens during macro expansion"));
+                 _("unable to avoid splicing tokens during macro expansion"));
+}
+
+/* Stringify an argument, and insert it into DEST.  ARG is the text to
+   stringify; it is LEN bytes long.  */
+
+static void
+stringify (growable_macro_buffer *dest, const char *arg, int len)
+{
+  /* Trim initial whitespace from ARG.  */
+  while (len > 0 && macro_is_whitespace (*arg))
+    {
+      ++arg;
+      --len;
+    }
+
+  /* Trim trailing whitespace from ARG.  */
+  while (len > 0 && macro_is_whitespace (arg[len - 1]))
+    --len;
+
+  /* Insert the string.  */
+  dest->appendc ('"');
+  while (len > 0)
+    {
+      /* We could try to handle strange cases here, like control
+        characters, but there doesn't seem to be much point.  */
+      if (macro_is_whitespace (*arg))
+       {
+         /* Replace a sequence of whitespace with a single space.  */
+         dest->appendc (' ');
+         while (len > 1 && macro_is_whitespace (arg[1]))
+           {
+             ++arg;
+             --len;
+           }
+       }
+      else if (*arg == '\\' || *arg == '"')
+       {
+         dest->appendc ('\\');
+         dest->appendc (*arg);
+       }
+      else
+       dest->appendc (*arg);
+      ++arg;
+      --len;
+    }
+  dest->appendc ('"');
+  dest->last_token = dest->len;
 }
 
+/* See macroexp.h.  */
+
+gdb::unique_xmalloc_ptr<char>
+macro_stringify (const char *str)
+{
+  int len = strlen (str);
+  growable_macro_buffer buffer (len);
+
+  stringify (&buffer, str, len);
+  buffer.appendc ('\0');
+
+  return buffer.release ();
+}
 
 \f
 /* Expanding macros!  */
@@ -647,7 +718,7 @@ struct macro_name_list {
    particular macro, and otherwise delegates the decision to another
    function/baton pair.  But that makes the linked list of excluded
    macros chained through untyped baton pointers, which will make it
-   harder to debug.  :( */
+   harder to debug.  :(  */
 static int
 currently_rescanning (struct macro_name_list *list, const char *name)
 {
@@ -670,17 +741,19 @@ currently_rescanning (struct macro_name_list *list, const char *name)
    baz).
 
    If SRC doesn't start with an open paren ( token at all, return
-   zero, leave SRC unchanged, and don't set *ARGC_P to anything.
+   false, leave SRC unchanged, and don't set *ARGS_PTR to anything.
 
    If SRC doesn't contain a properly terminated argument list, then
    raise an error.
 
-   Otherwise, return a pointer to the first element of an array of
-   macro buffers referring to the argument texts, and set *ARGC_P to
-   the number of arguments we found --- the number of elements in the
-   array.  The macro buffers share their text with SRC, and their
-   last_token fields are initialized.  The array is allocated with
-   xmalloc, and the caller is responsible for freeing it.
+   For a variadic macro, NARGS holds the number of formal arguments to
+   the macro.  For a GNU-style variadic macro, this should be the
+   number of named arguments.  For a non-variadic macro, NARGS should
+   be -1.
+
+   Otherwise, return true and set *ARGS_PTR to a vector of macro
+   buffers referring to the argument texts.  The macro buffers share
+   their text with SRC, and their last_token fields are initialized.
 
    NOTE WELL: if SRC starts with a open paren ( token followed
    immediately by a close paren ) token (e.g., the invocation looks
@@ -693,201 +766,430 @@ currently_rescanning (struct macro_name_list *list, const char *name)
    Consume the tokens from SRC; after this call, SRC contains the text
    following the invocation.  */
 
-static struct macro_buffer *
-gather_arguments (const char *name, struct macro_buffer *src, int *argc_p)
+static bool
+gather_arguments (const char *name, shared_macro_buffer *src, int nargs,
+                 std::vector<shared_macro_buffer> *args_ptr)
 {
-  struct macro_buffer tok;
-  int args_len, args_size;
-  struct macro_buffer *args = NULL;
-  struct cleanup *back_to = make_cleanup (free_current_contents, &args);
+  shared_macro_buffer tok;
+  std::vector<shared_macro_buffer> args;
 
   /* Does SRC start with an opening paren token?  Read from a copy of
      SRC, so SRC itself is unaffected if we don't find an opening
      paren.  */
   {
-    struct macro_buffer temp;
-    init_shared_buffer (&temp, src->text, src->len);
+    shared_macro_buffer temp (src->text, src->len);
 
     if (! get_token (&tok, &temp)
-        || tok.len != 1
-        || tok.text[0] != '(')
-      {
-        discard_cleanups (back_to);
-        return 0;
-      }
+       || tok.len != 1
+       || tok.text[0] != '(')
+      return false;
   }
 
   /* Consume SRC's opening paren.  */
   get_token (&tok, src);
 
-  args_len = 0;
-  args_size = 6;
-  args = (struct macro_buffer *) xmalloc (sizeof (*args) * args_size);
-
   for (;;)
     {
-      struct macro_buffer *arg;
+      shared_macro_buffer *arg;
       int depth;
 
-      /* Make sure we have room for the next argument.  */
-      if (args_len >= args_size)
-        {
-          args_size *= 2;
-          args = xrealloc (args, sizeof (*args) * args_size);
-        }
-
       /* Initialize the next argument.  */
-      arg = &args[args_len++];
+      args.emplace_back ();
+      arg = &args.back ();
       set_token (arg, src->text, src->text);
 
       /* Gather the argument's tokens.  */
       depth = 0;
       for (;;)
-        {
-          char *start = src->text;
-
-          if (! get_token (&tok, src))
-            error (_("Malformed argument list for macro `%s'."), name);
-      
-          /* Is tok an opening paren?  */
-          if (tok.len == 1 && tok.text[0] == '(')
-            depth++;
-
-          /* Is tok is a closing paren?  */
-          else if (tok.len == 1 && tok.text[0] == ')')
-            {
-              /* If it's a closing paren at the top level, then that's
-                 the end of the argument list.  */
-              if (depth == 0)
-                {
-                  discard_cleanups (back_to);
-                  *argc_p = args_len;
-                  return args;
-                }
-
-              depth--;
-            }
-
-          /* If tok is a comma at top level, then that's the end of
-             the current argument.  */
-          else if (tok.len == 1 && tok.text[0] == ',' && depth == 0)
-            break;
-
-          /* Extend the current argument to enclose this token.  If
-             this is the current argument's first token, leave out any
-             leading whitespace, just for aesthetics.  */
-          if (arg->len == 0)
-            {
-              arg->text = tok.text;
-              arg->len = tok.len;
-              arg->last_token = 0;
-            }
-          else
-            {
-              arg->len = (tok.text + tok.len) - arg->text;
-              arg->last_token = tok.text - arg->text;
-            }
-        }
+       {
+         if (! get_token (&tok, src))
+           error (_("Malformed argument list for macro `%s'."), name);
+
+         /* Is tok an opening paren?  */
+         if (tok.len == 1 && tok.text[0] == '(')
+           depth++;
+
+         /* Is tok is a closing paren?  */
+         else if (tok.len == 1 && tok.text[0] == ')')
+           {
+             /* If it's a closing paren at the top level, then that's
+                the end of the argument list.  */
+             if (depth == 0)
+               {
+                 /* In the varargs case, the last argument may be
+                    missing.  Add an empty argument in this case.  */
+                 if (nargs != -1 && args.size () == nargs - 1)
+                   {
+                     args.emplace_back ();
+                     arg = &args.back ();
+                     set_token (arg, src->text, src->text);
+                   }
+
+                 *args_ptr = std::move (args);
+                 return true;
+               }
+
+             depth--;
+           }
+
+         /* If tok is a comma at top level, then that's the end of
+            the current argument.  However, if we are handling a
+            variadic macro and we are computing the last argument, we
+            want to include the comma and remaining tokens.  */
+         else if (tok.len == 1 && tok.text[0] == ',' && depth == 0
+                  && (nargs == -1 || args.size () < nargs))
+           break;
+
+         /* Extend the current argument to enclose this token.  If
+            this is the current argument's first token, leave out any
+            leading whitespace, just for aesthetics.  */
+         if (arg->len == 0)
+           {
+             arg->text = tok.text;
+             arg->len = tok.len;
+             arg->last_token = 0;
+           }
+         else
+           {
+             arg->len = (tok.text + tok.len) - arg->text;
+             arg->last_token = tok.text - arg->text;
+           }
+       }
     }
 }
 
 
 /* The `expand' and `substitute_args' functions both invoke `scan'
    recursively, so we need a forward declaration somewhere.  */
-static void scan (struct macro_buffer *dest,
-                  struct macro_buffer *src,
-                  struct macro_name_list *no_loop,
-                  macro_lookup_ftype *lookup_func,
-                  void *lookup_baton);
+static void scan (growable_macro_buffer *dest,
+                 shared_macro_buffer *src,
+                 struct macro_name_list *no_loop,
+                 const macro_scope &scope);
+
+/* A helper function for substitute_args.
+   
+   ARGV is a vector of all the arguments; ARGC is the number of
+   arguments.  IS_VARARGS is true if the macro being substituted is a
+   varargs macro; in this case VA_ARG_NAME is the name of the
+   "variable" argument.  VA_ARG_NAME is ignored if IS_VARARGS is
+   false.
+
+   If the token TOK is the name of a parameter, return the parameter's
+   index.  If TOK is not an argument, return -1.  */
+
+static int
+find_parameter (const shared_macro_buffer *tok,
+               int is_varargs, const shared_macro_buffer *va_arg_name,
+               int argc, const char * const *argv)
+{
+  int i;
+
+  if (! tok->is_identifier)
+    return -1;
 
+  for (i = 0; i < argc; ++i)
+    if (tok->len == strlen (argv[i]) 
+       && !memcmp (tok->text, argv[i], tok->len))
+      return i;
+
+  if (is_varargs && tok->len == va_arg_name->len
+      && ! memcmp (tok->text, va_arg_name->text, tok->len))
+    return argc - 1;
+
+  return -1;
+}
+/* Helper function for substitute_args that gets the next token and
+   updates the passed-in state variables.  */
+
+static void
+get_next_token_for_substitution (shared_macro_buffer *replacement_list,
+                                shared_macro_buffer *token,
+                                const char **start,
+                                shared_macro_buffer *lookahead,
+                                const char **lookahead_start,
+                                int *lookahead_valid,
+                                bool *keep_going)
+{
+  if (!*lookahead_valid)
+    *keep_going = false;
+  else
+    {
+      *keep_going = true;
+      *token = *lookahead;
+      *start = *lookahead_start;
+      *lookahead_start = replacement_list->text;
+      *lookahead_valid = get_token (lookahead, replacement_list);
+    }
+}
 
 /* Given the macro definition DEF, being invoked with the actual
-   arguments given by ARGC and ARGV, substitute the arguments into the
+   arguments given by ARGV, substitute the arguments into the
    replacement list, and store the result in DEST.
 
+   IS_VARARGS should be true if DEF is a varargs macro.  In this case,
+   VA_ARG_NAME should be the name of the "variable" argument -- either
+   __VA_ARGS__ for c99-style varargs, or the final argument name, for
+   GNU-style varargs.  If IS_VARARGS is false, this parameter is
+   ignored.
+
    If it is necessary to expand macro invocations in one of the
    arguments, use LOOKUP_FUNC and LOOKUP_BATON to find the macro
    definitions, and don't expand invocations of the macros listed in
    NO_LOOP.  */
+
 static void
-substitute_args (struct macro_buffer *dest, 
-                 struct macro_definition *def,
-                 int argc, struct macro_buffer *argv,
-                 struct macro_name_list *no_loop,
-                 macro_lookup_ftype *lookup_func,
-                 void *lookup_baton)
+substitute_args (growable_macro_buffer *dest,
+                struct macro_definition *def,
+                int is_varargs, const shared_macro_buffer *va_arg_name,
+                const std::vector<shared_macro_buffer> &argv,
+                struct macro_name_list *no_loop,
+                const macro_scope &scope)
 {
-  /* A macro buffer for the macro's replacement list.  */
-  struct macro_buffer replacement_list;
+  /* The token we are currently considering.  */
+  shared_macro_buffer tok;
+  /* The replacement list's pointer from just before TOK was lexed.  */
+  const char *original_rl_start;
+  /* We have a single lookahead token to handle token splicing.  */
+  shared_macro_buffer lookahead;
+  /* The lookahead token might not be valid.  */
+  int lookahead_valid;
+  /* The replacement list's pointer from just before LOOKAHEAD was
+     lexed.  */
+  const char *lookahead_rl_start;
 
-  init_shared_buffer (&replacement_list, (char *) def->replacement,
-                      strlen (def->replacement));
+  /* A macro buffer for the macro's replacement list.  */
+  shared_macro_buffer replacement_list (def->replacement,
+                                       strlen (def->replacement));
 
   gdb_assert (dest->len == 0);
   dest->last_token = 0;
 
-  for (;;)
+  original_rl_start = replacement_list.text;
+  if (! get_token (&tok, &replacement_list))
+    return;
+  lookahead_rl_start = replacement_list.text;
+  lookahead_valid = get_token (&lookahead, &replacement_list);
+
+  /* __VA_OPT__ state variable.  The states are:
+     0 - nothing happening
+     1 - saw __VA_OPT__
+     >= 2 in __VA_OPT__, the value encodes the parenthesis depth.  */
+  unsigned vaopt_state = 0;
+
+  for (bool keep_going = true;
+       keep_going;
+       get_next_token_for_substitution (&replacement_list,
+                                       &tok,
+                                       &original_rl_start,
+                                       &lookahead,
+                                       &lookahead_rl_start,
+                                       &lookahead_valid,
+                                       &keep_going))
     {
-      struct macro_buffer tok;
-      char *original_rl_start = replacement_list.text;
-      int substituted = 0;
-      
-      /* Find the next token in the replacement list.  */
-      if (! get_token (&tok, &replacement_list))
-        break;
+      bool token_is_vaopt = (tok.len == 10
+                            && startswith (tok.text, "__VA_OPT__"));
+
+      if (vaopt_state > 0)
+       {
+         if (token_is_vaopt)
+           error (_("__VA_OPT__ cannot appear inside __VA_OPT__"));
+         else if (tok.len == 1 && tok.text[0] == '(')
+           {
+             ++vaopt_state;
+             /* We just entered __VA_OPT__, so don't emit this
+                token.  */
+             continue;
+           }
+         else if (vaopt_state == 1)
+           error (_("__VA_OPT__ must be followed by an open parenthesis"));
+         else if (tok.len == 1 && tok.text[0] == ')')
+           {
+             --vaopt_state;
+             if (vaopt_state == 1)
+               {
+                 /* Done with __VA_OPT__.  */
+                 vaopt_state = 0;
+                 /* Don't emit.  */
+                 continue;
+               }
+           }
+
+         /* If __VA_ARGS__ is empty, then drop the contents of
+            __VA_OPT__.  */
+         if (argv.back ().len == 0)
+           continue;
+       }
+      else if (token_is_vaopt)
+       {
+         if (!is_varargs)
+           error (_("__VA_OPT__ is only valid in a variadic macro"));
+         vaopt_state = 1;
+         /* Don't emit this token.  */
+         continue;
+       }
 
       /* Just for aesthetics.  If we skipped some whitespace, copy
-         that to DEST.  */
+        that to DEST.  */
       if (tok.text > original_rl_start)
-        {
-          appendmem (dest, original_rl_start, tok.text - original_rl_start);
-          dest->last_token = dest->len;
-        }
+       {
+         dest->appendmem (original_rl_start, tok.text - original_rl_start);
+         dest->last_token = dest->len;
+       }
 
       /* Is this token the stringification operator?  */
       if (tok.len == 1
-          && tok.text[0] == '#')
-        error (_("Stringification is not implemented yet."));
-
+         && tok.text[0] == '#')
+       {
+         int arg;
+
+         if (!lookahead_valid)
+           error (_("Stringification operator requires an argument."));
+
+         arg = find_parameter (&lookahead, is_varargs, va_arg_name,
+                               def->argc, def->argv);
+         if (arg == -1)
+           error (_("Argument to stringification operator must name "
+                    "a macro parameter."));
+
+         stringify (dest, argv[arg].text, argv[arg].len);
+
+         /* Read one token and let the loop iteration code handle the
+            rest.  */
+         lookahead_rl_start = replacement_list.text;
+         lookahead_valid = get_token (&lookahead, &replacement_list);
+       }
       /* Is this token the splicing operator?  */
-      if (tok.len == 2
-          && tok.text[0] == '#'
-          && tok.text[1] == '#')
-        error (_("Token splicing is not implemented yet."));
-
-      /* Is this token an identifier?  */
-      if (tok.is_identifier)
-        {
-          int i;
-
-          /* Is it the magic varargs parameter?  */
-          if (tok.len == 11
-              && ! memcmp (tok.text, "__VA_ARGS__", 11))
-            error (_("Variable-arity macros not implemented yet."));
-
-          /* Is it one of the parameters?  */
-          for (i = 0; i < def->argc; i++)
-            if (tok.len == strlen (def->argv[i])
-                && ! memcmp (tok.text, def->argv[i], tok.len))
-              {
-                struct macro_buffer arg_src;
-
-                /* Expand any macro invocations in the argument text,
-                   and append the result to dest.  Remember that scan
-                   mutates its source, so we need to scan a new buffer
-                   referring to the argument's text, not the argument
-                   itself.  */
-                init_shared_buffer (&arg_src, argv[i].text, argv[i].len);
-                scan (dest, &arg_src, no_loop, lookup_func, lookup_baton);
-                substituted = 1;
-                break;
-              }
-        }
-
-      /* If it wasn't a parameter, then just copy it across.  */
-      if (! substituted)
-        append_tokens_without_splicing (dest, &tok);
+      else if (tok.len == 2
+              && tok.text[0] == '#'
+              && tok.text[1] == '#')
+       error (_("Stray splicing operator"));
+      /* Is the next token the splicing operator?  */
+      else if (lookahead_valid
+              && lookahead.len == 2
+              && lookahead.text[0] == '#'
+              && lookahead.text[1] == '#')
+       {
+         int finished = 0;
+         int prev_was_comma = 0;
+
+         /* Note that GCC warns if the result of splicing is not a
+            token.  In the debugger there doesn't seem to be much
+            benefit from doing this.  */
+
+         /* Insert the first token.  */
+         if (tok.len == 1 && tok.text[0] == ',')
+           prev_was_comma = 1;
+         else
+           {
+             int arg = find_parameter (&tok, is_varargs, va_arg_name,
+                                       def->argc, def->argv);
+
+             if (arg != -1)
+               dest->appendmem (argv[arg].text, argv[arg].len);
+             else
+               dest->appendmem (tok.text, tok.len);
+           }
+
+         /* Apply a possible sequence of ## operators.  */
+         for (;;)
+           {
+             if (! get_token (&tok, &replacement_list))
+               error (_("Splicing operator at end of macro"));
+
+             /* Handle a comma before a ##.  If we are handling
+                varargs, and the token on the right hand side is the
+                varargs marker, and the final argument is empty or
+                missing, then drop the comma.  This is a GNU
+                extension.  There is one ambiguous case here,
+                involving pedantic behavior with an empty argument,
+                but we settle that in favor of GNU-style (GCC uses an
+                option).  If we aren't dealing with varargs, we
+                simply insert the comma.  */
+             if (prev_was_comma)
+               {
+                 if (! (is_varargs
+                        && tok.len == va_arg_name->len
+                        && !memcmp (tok.text, va_arg_name->text, tok.len)
+                        && argv.back ().len == 0))
+                   dest->appendmem (",", 1);
+                 prev_was_comma = 0;
+               }
+
+             /* Insert the token.  If it is a parameter, insert the
+                argument.  If it is a comma, treat it specially.  */
+             if (tok.len == 1 && tok.text[0] == ',')
+               prev_was_comma = 1;
+             else
+               {
+                 int arg = find_parameter (&tok, is_varargs, va_arg_name,
+                                           def->argc, def->argv);
+
+                 if (arg != -1)
+                   dest->appendmem (argv[arg].text, argv[arg].len);
+                 else
+                   dest->appendmem (tok.text, tok.len);
+               }
+
+             /* Now read another token.  If it is another splice, we
+                loop.  */
+             original_rl_start = replacement_list.text;
+             if (! get_token (&tok, &replacement_list))
+               {
+                 finished = 1;
+                 break;
+               }
+
+             if (! (tok.len == 2
+                    && tok.text[0] == '#'
+                    && tok.text[1] == '#'))
+               break;
+           }
+
+         if (prev_was_comma)
+           {
+             /* We saw a comma.  Insert it now.  */
+             dest->appendmem (",", 1);
+           }
+
+         dest->last_token = dest->len;
+         if (finished)
+           lookahead_valid = 0;
+         else
+           {
+             /* Set up for the loop iterator.  */
+             lookahead = tok;
+             lookahead_rl_start = original_rl_start;
+             lookahead_valid = 1;
+           }
+       }
+      else
+       {
+         /* Is this token an identifier?  */
+         int substituted = 0;
+         int arg = find_parameter (&tok, is_varargs, va_arg_name,
+                                   def->argc, def->argv);
+
+         if (arg != -1)
+           {
+             /* Expand any macro invocations in the argument text,
+                and append the result to dest.  Remember that scan
+                mutates its source, so we need to scan a new buffer
+                referring to the argument's text, not the argument
+                itself.  */
+             shared_macro_buffer arg_src (argv[arg].text, argv[arg].len);
+             scan (dest, &arg_src, no_loop, scope);
+             substituted = 1;
+           }
+
+         /* If it wasn't a parameter, then just copy it across.  */
+         if (! substituted)
+           append_tokens_without_splicing (dest, &tok);
+       }
     }
+
+  if (vaopt_state > 0)
+    error (_("Unterminated __VA_OPT__"));
 }
 
 
@@ -895,19 +1197,18 @@ substitute_args (struct macro_buffer *dest,
    its expansion to DEST.  SRC is the input text following the ID
    token.  We are currently rescanning the expansions of the macros
    named in NO_LOOP; don't re-expand them.  Use LOOKUP_FUNC and
-   LOOKUP_BATON to find definitions for any nested macro references.  
+   LOOKUP_BATON to find definitions for any nested macro references.
 
    Return 1 if we decided to expand it, zero otherwise.  (If it's a
    function-like macro name that isn't followed by an argument list,
    we don't expand it.)  If we return zero, leave SRC unchanged.  */
 static int
 expand (const char *id,
-        struct macro_definition *def, 
-        struct macro_buffer *dest,
-        struct macro_buffer *src,
-        struct macro_name_list *no_loop,
-        macro_lookup_ftype *lookup_func,
-        void *lookup_baton)
+       struct macro_definition *def,
+       growable_macro_buffer *dest,
+       shared_macro_buffer *src,
+       struct macro_name_list *no_loop,
+       const macro_scope &scope)
 {
   struct macro_name_list new_no_loop;
 
@@ -922,77 +1223,90 @@ expand (const char *id,
   /* What kind of macro are we expanding?  */
   if (def->kind == macro_object_like)
     {
-      struct macro_buffer replacement_list;
-
-      init_shared_buffer (&replacement_list, (char *) def->replacement,
-                          strlen (def->replacement));
+      shared_macro_buffer replacement_list (def->replacement,
+                                           strlen (def->replacement));
 
-      scan (dest, &replacement_list, &new_no_loop, lookup_func, lookup_baton);
+      scan (dest, &replacement_list, &new_no_loop, scope);
       return 1;
     }
   else if (def->kind == macro_function_like)
     {
-      struct cleanup *back_to = make_cleanup (null_cleanup, 0);
-      int argc = 0;
-      struct macro_buffer *argv = NULL;
-      struct macro_buffer substituted;
-      struct macro_buffer substituted_src;
-
-      if (def->argc >= 1
-          && strcmp (def->argv[def->argc - 1], "...") == 0)
-        error (_("Varargs macros not implemented yet."));
-
-      make_cleanup (free_current_contents, &argv);
-      argv = gather_arguments (id, src, &argc);
-
+      shared_macro_buffer va_arg_name;
+      int is_varargs = 0;
+
+      if (def->argc >= 1)
+       {
+         if (strcmp (def->argv[def->argc - 1], "...") == 0)
+           {
+             /* In C99-style varargs, substitution is done using
+                __VA_ARGS__.  */
+             va_arg_name.set_shared ("__VA_ARGS__", strlen ("__VA_ARGS__"));
+             is_varargs = 1;
+           }
+         else
+           {
+             int len = strlen (def->argv[def->argc - 1]);
+
+             if (len > 3
+                 && strcmp (def->argv[def->argc - 1] + len - 3, "...") == 0)
+               {
+                 /* In GNU-style varargs, the name of the
+                    substitution parameter is the name of the formal
+                    argument without the "...".  */
+                 va_arg_name.set_shared (def->argv[def->argc - 1], len - 3);
+                 is_varargs = 1;
+               }
+           }
+       }
+
+      std::vector<shared_macro_buffer> argv;
       /* If we couldn't find any argument list, then we don't expand
-         this macro.  */
-      if (! argv)
-        {
-          do_cleanups (back_to);
-          return 0;
-        }
+        this macro.  */
+      if (!gather_arguments (id, src, is_varargs ? def->argc : -1,
+                            &argv))
+       return 0;
 
       /* Check that we're passing an acceptable number of arguments for
-         this macro.  */
-      if (argc != def->argc)
-        {
-          /* Remember that a sequence of tokens like "foo()" is a
-             valid invocation of a macro expecting either zero or one
-             arguments.  */
-          if (! (argc == 1
-                 && argv[0].len == 0
-                 && def->argc == 0))
-            error (_("Wrong number of arguments to macro `%s' "
-                   "(expected %d, got %d)."),
-                   id, def->argc, argc);
-        }
+        this macro.  */
+      if (argv.size () != def->argc)
+       {
+         if (is_varargs && argv.size () >= def->argc - 1)
+           {
+             /* Ok.  */
+           }
+         /* Remember that a sequence of tokens like "foo()" is a
+            valid invocation of a macro expecting either zero or one
+            arguments.  */
+         else if (! (argv.size () == 1
+                     && argv[0].len == 0
+                     && def->argc == 0))
+           error (_("Wrong number of arguments to macro `%s' "
+                  "(expected %d, got %d)."),
+                  id, def->argc, int (argv.size ()));
+       }
 
       /* Note that we don't expand macro invocations in the arguments
-         yet --- we let subst_args take care of that.  Parameters that
-         appear as operands of the stringifying operator "#" or the
-         splicing operator "##" don't get macro references expanded,
-         so we can't really tell whether it's appropriate to macro-
-         expand an argument until we see how it's being used.  */
-      init_buffer (&substituted, 0);
-      make_cleanup (cleanup_macro_buffer, &substituted);
-      substitute_args (&substituted, def, argc, argv, no_loop,
-                       lookup_func, lookup_baton);
+        yet --- we let subst_args take care of that.  Parameters that
+        appear as operands of the stringifying operator "#" or the
+        splicing operator "##" don't get macro references expanded,
+        so we can't really tell whether it's appropriate to macro-
+        expand an argument until we see how it's being used.  */
+      growable_macro_buffer substituted (0);
+      substitute_args (&substituted, def, is_varargs, &va_arg_name,
+                      argv, no_loop, scope);
 
       /* Now `substituted' is the macro's replacement list, with all
-         argument values substituted into it properly.  Re-scan it for
-         macro references, but don't expand invocations of this macro.
-
-         We create a new buffer, `substituted_src', which points into
-         `substituted', and scan that.  We can't scan `substituted'
-         itself, since the tokenization process moves the buffer's
-         text pointer around, and we still need to be able to find
-         `substituted's original text buffer after scanning it so we
-         can free it.  */
-      init_shared_buffer (&substituted_src, substituted.text, substituted.len);
-      scan (dest, &substituted_src, &new_no_loop, lookup_func, lookup_baton);
-
-      do_cleanups (back_to);
+        argument values substituted into it properly.  Re-scan it for
+        macro references, but don't expand invocations of this macro.
+
+        We create a new buffer, `substituted_src', which points into
+        `substituted', and scan that.  We can't scan `substituted'
+        itself, since the tokenization process moves the buffer's
+        text pointer around, and we still need to be able to find
+        `substituted's original text buffer after scanning it so we
+        can free it.  */
+      shared_macro_buffer substituted_src (substituted.text, substituted.len);
+      scan (dest, &substituted_src, &new_no_loop, scope);
 
       return 1;
     }
@@ -1002,50 +1316,35 @@ expand (const char *id,
 
 
 /* If the single token in SRC_FIRST followed by the tokens in SRC_REST
-   constitute a macro invokation not forbidden in NO_LOOP, append its
+   constitute a macro invocation not forbidden in NO_LOOP, append its
    expansion to DEST and return non-zero.  Otherwise, return zero, and
    leave DEST unchanged.
 
-   SRC_FIRST and SRC_REST must be shared buffers; DEST must not be one.
    SRC_FIRST must be a string built by get_token.  */
 static int
-maybe_expand (struct macro_buffer *dest,
-              struct macro_buffer *src_first,
-              struct macro_buffer *src_rest,
-              struct macro_name_list *no_loop,
-              macro_lookup_ftype *lookup_func,
-              void *lookup_baton)
+maybe_expand (growable_macro_buffer *dest,
+             shared_macro_buffer *src_first,
+             shared_macro_buffer *src_rest,
+             struct macro_name_list *no_loop,
+             const macro_scope &scope)
 {
-  gdb_assert (src_first->shared);
-  gdb_assert (src_rest->shared);
-  gdb_assert (! dest->shared);
-
   /* Is this token an identifier?  */
   if (src_first->is_identifier)
     {
       /* Make a null-terminated copy of it, since that's what our
-         lookup function expects.  */
-      char *id = xmalloc (src_first->len + 1);
-      struct cleanup *back_to = make_cleanup (xfree, id);
-      memcpy (id, src_first->text, src_first->len);
-      id[src_first->len] = 0;
-          
+        lookup function expects.  */
+      std::string id (src_first->text, src_first->len);
+
       /* If we're currently re-scanning the result of expanding
-         this macro, don't expand it again.  */
-      if (! currently_rescanning (no_loop, id))
-        {
-          /* Does this identifier have a macro definition in scope?  */
-          struct macro_definition *def = lookup_func (id, lookup_baton);
-
-          if (def && expand (id, def, dest, src_rest, no_loop,
-                             lookup_func, lookup_baton))
-            {
-              do_cleanups (back_to);
-              return 1;
-            }
-        }
-
-      do_cleanups (back_to);
+        this macro, don't expand it again.  */
+      if (! currently_rescanning (no_loop, id.c_str ()))
+       {
+         /* Does this identifier have a macro definition in scope?  */
+         macro_definition *def = standard_macro_lookup (id.c_str (), scope);
+
+         if (def && expand (id.c_str (), def, dest, src_rest, no_loop, scope))
+           return 1;
+       }
     }
 
   return 0;
@@ -1054,122 +1353,99 @@ maybe_expand (struct macro_buffer *dest,
 
 /* Expand macro references in SRC, appending the results to DEST.
    Assume we are re-scanning the result of expanding the macros named
-   in NO_LOOP, and don't try to re-expand references to them.
+   in NO_LOOP, and don't try to re-expand references to them.  */
 
-   SRC must be a shared buffer; DEST must not be one.  */
 static void
-scan (struct macro_buffer *dest,
-      struct macro_buffer *src,
+scan (growable_macro_buffer *dest,
+      shared_macro_buffer *src,
       struct macro_name_list *no_loop,
-      macro_lookup_ftype *lookup_func,
-      void *lookup_baton)
+      const macro_scope &scope)
 {
-  gdb_assert (src->shared);
-  gdb_assert (! dest->shared);
 
   for (;;)
     {
-      struct macro_buffer tok;
-      char *original_src_start = src->text;
+      shared_macro_buffer tok;
+      const char *original_src_start = src->text;
 
       /* Find the next token in SRC.  */
       if (! get_token (&tok, src))
-        break;
+       break;
 
       /* Just for aesthetics.  If we skipped some whitespace, copy
-         that to DEST.  */
+        that to DEST.  */
       if (tok.text > original_src_start)
-        {
-          appendmem (dest, original_src_start, tok.text - original_src_start);
-          dest->last_token = dest->len;
-        }
-
-      if (! maybe_expand (dest, &tok, src, no_loop, lookup_func, lookup_baton))
-        /* We didn't end up expanding tok as a macro reference, so
-           simply append it to dest.  */
-        append_tokens_without_splicing (dest, &tok);
+       {
+         dest->appendmem (original_src_start, tok.text - original_src_start);
+         dest->last_token = dest->len;
+       }
+
+      if (! maybe_expand (dest, &tok, src, no_loop, scope))
+       /* We didn't end up expanding tok as a macro reference, so
+          simply append it to dest.  */
+       append_tokens_without_splicing (dest, &tok);
     }
 
   /* Just for aesthetics.  If there was any trailing whitespace in
      src, copy it to dest.  */
   if (src->len)
     {
-      appendmem (dest, src->text, src->len);
+      dest->appendmem (src->text, src->len);
       dest->last_token = dest->len;
     }
 }
 
 
-char *
-macro_expand (const char *source,
-              macro_lookup_ftype *lookup_func,
-              void *lookup_func_baton)
+gdb::unique_xmalloc_ptr<char>
+macro_expand (const char *source, const macro_scope &scope)
 {
-  struct macro_buffer src, dest;
-  struct cleanup *back_to;
-
-  init_shared_buffer (&src, (char *) source, strlen (source));
+  shared_macro_buffer src (source, strlen (source));
 
-  init_buffer (&dest, 0);
+  growable_macro_buffer dest (0);
   dest.last_token = 0;
-  back_to = make_cleanup (cleanup_macro_buffer, &dest);
 
-  scan (&dest, &src, 0, lookup_func, lookup_func_baton);
+  scan (&dest, &src, 0, scope);
 
-  appendc (&dest, '\0');
+  dest.appendc ('\0');
 
-  discard_cleanups (back_to);
-  return dest.text;
+  return dest.release ();
 }
 
 
-char *
-macro_expand_once (const char *source,
-                   macro_lookup_ftype *lookup_func,
-                   void *lookup_func_baton)
+gdb::unique_xmalloc_ptr<char>
+macro_expand_once (const char *source, const macro_scope &scope)
 {
   error (_("Expand-once not implemented yet."));
 }
 
-
-char *
-macro_expand_next (char **lexptr,
-                   macro_lookup_ftype *lookup_func,
-                   void *lookup_baton)
+gdb::unique_xmalloc_ptr<char>
+macro_expand_next (const char **lexptr, const macro_scope &scope)
 {
-  struct macro_buffer src, dest, tok;
-  struct cleanup *back_to;
+  shared_macro_buffer tok;
 
   /* Set up SRC to refer to the input text, pointed to by *lexptr.  */
-  init_shared_buffer (&src, *lexptr, strlen (*lexptr));
+  shared_macro_buffer src (*lexptr, strlen (*lexptr));
 
   /* Set up DEST to receive the expansion, if there is one.  */
-  init_buffer (&dest, 0);
+  growable_macro_buffer dest (0);
   dest.last_token = 0;
-  back_to = make_cleanup (cleanup_macro_buffer, &dest);
 
   /* Get the text's first preprocessing token.  */
   if (! get_token (&tok, &src))
-    {
-      do_cleanups (back_to);
-      return 0;
-    }
+    return nullptr;
 
   /* If it's a macro invocation, expand it.  */
-  if (maybe_expand (&dest, &tok, &src, 0, lookup_func, lookup_baton))
+  if (maybe_expand (&dest, &tok, &src, 0, scope))
     {
       /* It was a macro invocation!  Package up the expansion as a
-         null-terminated string and return it.  Set *lexptr to the
-         start of the next token in the input.  */
-      appendc (&dest, '\0');
-      discard_cleanups (back_to);
+        null-terminated string and return it.  Set *lexptr to the
+        start of the next token in the input.  */
+      dest.appendc ('\0');
       *lexptr = src.text;
-      return dest.text;
+      return dest.release ();
     }
   else
     {
       /* It wasn't a macro invocation.  */
-      do_cleanups (back_to);
-      return 0;
+      return nullptr;
     }
 }
This page took 0.047608 seconds and 4 git commands to generate.