X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fmacroexp.c;h=84584d4a00e021d36581bc78dbe797981347033f;hb=40786782896deaf8f97f8dc62b85d9facb30fc8a;hp=e132a3bc26ca62f1e98236c94f13587aa337bfea;hpb=618f726fcb851883a0094aa7fa17003889b7189f;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/macroexp.c b/gdb/macroexp.c index e132a3bc26..84584d4a00 100644 --- a/gdb/macroexp.c +++ b/gdb/macroexp.c @@ -1,5 +1,5 @@ /* C preprocessor macro expansion for GDB. - Copyright (C) 2002-2016 Free Software Foundation, Inc. + Copyright (C) 2002-2021 Free Software Foundation, Inc. Contributed by Red Hat, Inc. This file is part of GDB. @@ -19,43 +19,27 @@ #include "defs.h" #include "gdb_obstack.h" -#include "bcache.h" #include "macrotab.h" #include "macroexp.h" +#include "macroscope.h" #include "c-lang.h" -/* 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,118 +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 *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) -{ - buf->text = addr; - buf->len = len; - buf->shared = 1; - buf->size = 0; - buf->last_token = -1; -} + /* 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_; + } +}; +/* A string type that we can resize and quickly append to. */ -/* Free the text of the buffer B. Raise an error if B is shared. */ -static void -free_buffer (struct macro_buffer *b) +struct growable_macro_buffer { - gdb_assert (! b->shared); - if (b->size) - xfree (b->text); -} + /* An array of characters. The first LEN bytes are the real text, + but there are SIZE bytes allocated to the array. */ + char *text; -/* Like free_buffer, but return the text as an xstrdup()d string. - This only exists to try to make the API relatively clean. */ + /* The number of characters in the string. */ + int len; -static char * -free_buffer_return_text (struct macro_buffer *b) -{ - gdb_assert (! b->shared); - gdb_assert (b->size); - /* Nothing to do. */ - return b->text; -} + /* The number of characters allocated to the string. */ + int size; -/* A cleanup function for macro buffers. */ -static void -cleanup_macro_buffer (void *untyped_buf) -{ - free_buffer ((struct macro_buffer *) untyped_buf); -} + /* For detecting token splicing. + 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; + } -/* 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; + DISABLE_COPY_AND_ASSIGN (growable_macro_buffer); - b->text = (char *) xrealloc (b->text, b->size); -} + ~growable_macro_buffer () + { + xfree (text); + } + /* Release the text of the buffer to the caller. */ + gdb::unique_xmalloc_ptr release () + { + gdb_assert (size); + char *result = text; + text = NULL; + return gdb::unique_xmalloc_ptr (result); + } -/* Append the character C to the buffer B. */ -static void -appendc (struct macro_buffer *b, int c) -{ - int new_len = b->len + 1; + /* 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; - if (new_len > b->size) - resize_buffer (b, new_len); + text = (char *) xrealloc (text, size); + } - b->text[b->len] = c; - b->len = new_len; -} + /* Append the character C to the buffer. */ + void appendc (int c) + { + int new_len = len + 1; + if (new_len > size) + resize_buffer (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; + text[len] = c; + len = new_len; + } - if (new_len > b->size) - resize_buffer (b, new_len); + /* Append the COUNT bytes at ADDR to the buffer. */ + void appendmem (const char *addr, int count) + { + int new_len = len + count; - memcpy (b->text + b->len, addr, len); - b->len = new_len; -} + if (new_len > size) + resize_buffer (new_len); + + memcpy (text + len, addr, count); + len = new_len; + } +}; @@ -186,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'); } @@ -204,15 +194,15 @@ 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. */ @@ -221,38 +211,38 @@ set_token (struct macro_buffer *tok, char *start, char *end) 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; @@ -263,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; @@ -285,29 +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 (p + 2 <= end && strchr ("eEpP", *p) && (p[1] == '+' || p[1] == '-')) - p += 2; - else if (macro_is_digit (*p) + p += 2; + else if (macro_is_digit (*p) || macro_is_identifier_nondigit (*p) || *p == '.') - p++; - else - break; - } + p++; + else + break; + } set_token (tok, tok_start, p); return 1; @@ -324,7 +314,8 @@ 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 @@ -335,42 +326,42 @@ get_character_constant (struct macro_buffer *tok, char *p, char *end) && (p[0] == 'L' || p[0] == 'u' || p[0] == 'U') && p[1] == '\'')) { - char *tok_start = p; + const char *tok_start = p; int char_count = 0; if (*p == '\'') - p++; + p++; else if (*p == 'L' || *p == 'u' || *p == 'U') - p += 2; + p += 2; else - gdb_assert_not_reached ("unexpected character constant"); + gdb_assert_not_reached ("unexpected character constant"); for (;;) - { - 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 == '\\') - { + { + 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 + } + else { p++; char_count++; } - } + } set_token (tok, tok_start, p); return 1; @@ -385,46 +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 + 2 <= end - && (p[0] == 'L' || p[0] == 'u' || p[0] == 'U') - && 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++; + p++; else if (*p == 'L' || *p == 'u' || *p == 'U') - p += 2; + p += 2; else - gdb_assert_not_reached ("unexpected string literal"); + 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 == '\\') - { + { + 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++; - } + } + else + p++; + } set_token (tok, tok_start, p); return 1; @@ -435,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. */ @@ -468,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; @@ -491,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. */ @@ -524,37 +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; + /* How many characters did we consume, including whitespace? */ + int consumed = p - src->text + tok->len; - src->text += consumed; - src->len -= consumed; - return 1; + 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; @@ -581,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. */ @@ -604,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 @@ -615,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; @@ -626,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; @@ -646,14 +633,14 @@ 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 (struct macro_buffer *dest, const char *arg, int len) +stringify (growable_macro_buffer *dest, const char *arg, int len) { /* Trim initial whitespace from ARG. */ while (len > 0 && macro_is_whitespace (*arg)) @@ -667,7 +654,7 @@ stringify (struct macro_buffer *dest, const char *arg, int len) --len; /* Insert the string. */ - appendc (dest, '"'); + dest->appendc ('"'); while (len > 0) { /* We could try to handle strange cases here, like control @@ -675,7 +662,7 @@ stringify (struct macro_buffer *dest, const char *arg, int len) if (macro_is_whitespace (*arg)) { /* Replace a sequence of whitespace with a single space. */ - appendc (dest, ' '); + dest->appendc (' '); while (len > 1 && macro_is_whitespace (arg[1])) { ++arg; @@ -684,31 +671,30 @@ stringify (struct macro_buffer *dest, const char *arg, int len) } else if (*arg == '\\' || *arg == '"') { - appendc (dest, '\\'); - appendc (dest, *arg); + dest->appendc ('\\'); + dest->appendc (*arg); } else - appendc (dest, *arg); + dest->appendc (*arg); ++arg; --len; } - appendc (dest, '"'); + dest->appendc ('"'); dest->last_token = dest->len; } /* See macroexp.h. */ -char * +gdb::unique_xmalloc_ptr macro_stringify (const char *str) { - struct macro_buffer buffer; int len = strlen (str); + growable_macro_buffer buffer (len); - init_buffer (&buffer, len); stringify (&buffer, str, len); - appendc (&buffer, '\0'); + buffer.appendc ('\0'); - return free_buffer_return_text (&buffer); + return buffer.release (); } @@ -755,22 +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. - + 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 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. + 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 @@ -783,131 +766,105 @@ 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 nargs, int *argc_p) +static bool +gather_arguments (const char *name, shared_macro_buffer *src, int nargs, + std::vector *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 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 = XNEWVEC (struct macro_buffer, 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 = XRESIZEVEC (struct macro_buffer, 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 (;;) - { - 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) - { + { + 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_len == nargs - 1) + if (nargs != -1 && args.size () == nargs - 1) { - /* Make sure we have room for the argument. */ - if (args_len >= args_size) - { - args_size++; - args = XRESIZEVEC (struct macro_buffer, args, - args_size); - } - arg = &args[args_len++]; + args.emplace_back (); + arg = &args.back (); set_token (arg, src->text, src->text); } - 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. 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_len < 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; - } - } + *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. @@ -921,8 +878,8 @@ static void scan (struct macro_buffer *dest, index. If TOK is not an argument, return -1. */ static int -find_parameter (const struct macro_buffer *tok, - int is_varargs, const struct macro_buffer *va_arg_name, +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; @@ -942,8 +899,32 @@ find_parameter (const struct macro_buffer *tok, 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, @@ -958,30 +939,28 @@ find_parameter (const struct macro_buffer *tok, NO_LOOP. */ static void -substitute_args (struct macro_buffer *dest, - struct macro_definition *def, - int is_varargs, const struct macro_buffer *va_arg_name, - 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 &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. */ - struct macro_buffer tok; + shared_macro_buffer tok; /* The replacement list's pointer from just before TOK was lexed. */ - char *original_rl_start; + const char *original_rl_start; /* We have a single lookahead token to handle token splicing. */ - struct macro_buffer lookahead; + 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. */ - char *lookahead_rl_start; + 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; @@ -992,19 +971,75 @@ substitute_args (struct macro_buffer *dest, lookahead_rl_start = replacement_list.text; lookahead_valid = get_token (&lookahead, &replacement_list); - for (;;) + /* __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)) { + bool token_is_vaopt = (tok.len == 10 + && strncmp (tok.text, "__VA_OPT__", 10) == 0); + + 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] == '#') + && tok.text[0] == '#') { int arg; @@ -1051,9 +1086,9 @@ substitute_args (struct macro_buffer *dest, def->argc, def->argv); if (arg != -1) - appendmem (dest, argv[arg].text, argv[arg].len); + dest->appendmem (argv[arg].text, argv[arg].len); else - appendmem (dest, tok.text, tok.len); + dest->appendmem (tok.text, tok.len); } /* Apply a possible sequence of ## operators. */ @@ -1076,8 +1111,8 @@ substitute_args (struct macro_buffer *dest, if (! (is_varargs && tok.len == va_arg_name->len && !memcmp (tok.text, va_arg_name->text, tok.len) - && argv[argc - 1].len == 0)) - appendmem (dest, ",", 1); + && argv.back ().len == 0)) + dest->appendmem (",", 1); prev_was_comma = 0; } @@ -1091,9 +1126,9 @@ substitute_args (struct macro_buffer *dest, def->argc, def->argv); if (arg != -1) - appendmem (dest, argv[arg].text, argv[arg].len); + dest->appendmem (argv[arg].text, argv[arg].len); else - appendmem (dest, tok.text, tok.len); + dest->appendmem (tok.text, tok.len); } /* Now read another token. If it is another splice, we @@ -1114,10 +1149,10 @@ substitute_args (struct macro_buffer *dest, if (prev_was_comma) { /* We saw a comma. Insert it now. */ - appendmem (dest, ",", 1); + dest->appendmem (",", 1); } - dest->last_token = dest->len; + dest->last_token = dest->len; if (finished) lookahead_valid = 0; else @@ -1137,15 +1172,13 @@ substitute_args (struct macro_buffer *dest, if (arg != -1) { - 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[arg].text, argv[arg].len); - scan (dest, &arg_src, no_loop, lookup_func, lookup_baton); + shared_macro_buffer arg_src (argv[arg].text, argv[arg].len); + scan (dest, &arg_src, no_loop, scope); substituted = 1; } @@ -1153,16 +1186,10 @@ substitute_args (struct macro_buffer *dest, if (! substituted) append_tokens_without_splicing (dest, &tok); } - - if (! lookahead_valid) - break; - - tok = lookahead; - original_rl_start = lookahead_rl_start; - - lookahead_rl_start = replacement_list.text; - lookahead_valid = get_token (&lookahead, &replacement_list); } + + if (vaopt_state > 0) + error (_("Unterminated __VA_OPT__")); } @@ -1177,12 +1204,11 @@ substitute_args (struct macro_buffer *dest, 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; @@ -1197,22 +1223,15 @@ 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; - struct macro_buffer va_arg_name = {0}; + shared_macro_buffer va_arg_name; int is_varargs = 0; if (def->argc >= 1) @@ -1221,8 +1240,7 @@ expand (const char *id, { /* In C99-style varargs, substitution is done using __VA_ARGS__. */ - init_shared_buffer (&va_arg_name, "__VA_ARGS__", - strlen ("__VA_ARGS__")); + va_arg_name.set_shared ("__VA_ARGS__", strlen ("__VA_ARGS__")); is_varargs = 1; } else @@ -1235,70 +1253,60 @@ expand (const char *id, /* In GNU-style varargs, the name of the substitution parameter is the name of the formal argument without the "...". */ - init_shared_buffer (&va_arg_name, - (char *) def->argv[def->argc - 1], - len - 3); + va_arg_name.set_shared (def->argv[def->argc - 1], len - 3); is_varargs = 1; } } } - make_cleanup (free_current_contents, &argv); - argv = gather_arguments (id, src, is_varargs ? def->argc : -1, - &argc); - + std::vector 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) - { - if (is_varargs && argc >= def->argc - 1) + 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 (! (argc == 1 + /* 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, argc); - } + 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); + 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, - argc, argv, no_loop, lookup_func, lookup_baton); + 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; } @@ -1308,51 +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 = (char *) xmalloc (src_first->len + 1); - struct cleanup *back_to = make_cleanup (xfree, id); + lookup function expects. */ + std::string id (src_first->text, src_first->len); - memcpy (id, src_first->text, src_first->len); - id[src_first->len] = 0; - /* 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; @@ -1361,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 +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 +macro_expand_once (const char *source, const macro_scope &scope) { error (_("Expand-once not implemented yet.")); } - -char * -macro_expand_next (const char **lexptr, - macro_lookup_ftype *lookup_func, - void *lookup_baton) +gdb::unique_xmalloc_ptr +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, (char *) *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; } }