/* C preprocessor macro expansion for GDB.
- Copyright (C) 2002, 2007, 2008, 2009, 2010, 2011
- Free Software Foundation, Inc.
+ Copyright (C) 2002-2017 Free Software Foundation, Inc.
Contributed by Red Hat, Inc.
This file is part of GDB.
#include "bcache.h"
#include "macrotab.h"
#include "macroexp.h"
-#include "gdb_assert.h"
#include "c-lang.h"
/* 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;
+ some other block, or to a string literal, and we shouldn't
+ reallocate it. */
+ bool shared;
/* For detecting token splicing.
else
b->text = NULL;
b->len = 0;
- b->shared = 0;
+ b->shared = false;
b->last_token = -1;
}
/* 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)
+init_shared_buffer (struct macro_buffer *buf, const char *addr, int len)
{
- buf->text = addr;
+ /* The function accept a "const char *" addr so that clients can
+ pass in string literals without casts. */
+ buf->text = (char *) addr;
buf->len = len;
- buf->shared = 1;
+ buf->shared = true;
buf->size = 0;
buf->last_token = -1;
}
xfree (b->text);
}
+/* Like free_buffer, but return the text as an xstrdup()d string.
+ This only exists to try to make the API relatively clean. */
+
+static char *
+free_buffer_return_text (struct macro_buffer *b)
+{
+ gdb_assert (! b->shared);
+ gdb_assert (b->size);
+ /* Nothing to do. */
+ return b->text;
+}
/* A cleanup function for macro buffers. */
static void
while (b->size <= n)
b->size *= 2;
- b->text = xrealloc (b->text, b->size);
+ b->text = (char *) xrealloc (b->text, b->size);
}
/* Append the LEN bytes at ADDR to the buffer B. */
static void
-appendmem (struct macro_buffer *b, char *addr, int len)
+appendmem (struct macro_buffer *b, const char *addr, int len)
{
int new_len = b->len + len;
init_shared_buffer (tok, start, end - start);
tok->last_token = 0;
- /* Presumed; get_identifier may overwrite this. */
+ /* Presumed; get_identifier may overwrite this. */
tok->is_identifier = 0;
}
&& p[1] == '\''))
{
char *tok_start = p;
- char *body_start;
int char_count = 0;
if (*p == '\'')
else
gdb_assert_not_reached ("unexpected character constant");
- body_start = p;
for (;;)
{
if (p >= end)
}
else if (*p == '\\')
{
- p++;
- char_count += c_parse_escape (&p, NULL);
+ const char *s, *o;
+
+ s = o = ++p;
+ char_count += c_parse_escape (&s, NULL);
+ p += s - o;
}
else
{
"constants."));
else if (*p == '\\')
{
- p++;
- c_parse_escape (&p, NULL);
+ const char *s, *o;
+
+ s = o = ++p;
+ c_parse_escape (&s, NULL);
+ p += s - o;
}
else
p++;
stringify; it is LEN bytes long. */
static void
-stringify (struct macro_buffer *dest, char *arg, int len)
+stringify (struct macro_buffer *dest, const char *arg, int len)
{
/* Trim initial whitespace from ARG. */
while (len > 0 && macro_is_whitespace (*arg))
dest->last_token = dest->len;
}
+/* See macroexp.h. */
+
+char *
+macro_stringify (const char *str)
+{
+ struct macro_buffer buffer;
+ int len = strlen (str);
+
+ init_buffer (&buffer, len);
+ stringify (&buffer, str, len);
+ appendc (&buffer, '\0');
+
+ return free_buffer_return_text (&buffer);
+}
+
\f
/* Expanding macros! */
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)
{
args_len = 0;
args_size = 6;
- args = (struct macro_buffer *) xmalloc (sizeof (*args) * args_size);
+ args = XNEWVEC (struct macro_buffer, args_size);
for (;;)
{
if (args_len >= args_size)
{
args_size *= 2;
- args = xrealloc (args, sizeof (*args) * args_size);
+ args = XRESIZEVEC (struct macro_buffer, args, args_size);
}
/* Initialize the next argument. */
if (args_len >= args_size)
{
args_size++;
- args = xrealloc (args, sizeof (*args) * args_size);
+ args = XRESIZEVEC (struct macro_buffer, args,
+ args_size);
}
arg = &args[args_len++];
set_token (arg, src->text, src->text);
return -1;
for (i = 0; i < argc; ++i)
- if (tok->len == strlen (argv[i]) && ! memcmp (tok->text, argv[i], tok->len))
+ if (tok->len == strlen (argv[i])
+ && !memcmp (tok->text, argv[i], tok->len))
return i;
if (is_varargs && tok->len == va_arg_name->len
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 (struct macro_buffer *replacement_list,
+ struct macro_buffer *token,
+ char **start,
+ struct macro_buffer *lookahead,
+ 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
replacement list, and store the result in DEST.
lexed. */
char *lookahead_rl_start;
- init_shared_buffer (&replacement_list, (char *) def->replacement,
+ init_shared_buffer (&replacement_list, def->replacement,
strlen (def->replacement));
gdb_assert (dest->len == 0);
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[argc - 1].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. */
if (tok.text > original_rl_start)
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__"));
}
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,
{
struct macro_buffer replacement_list;
- init_shared_buffer (&replacement_list, (char *) def->replacement,
+ init_shared_buffer (&replacement_list, def->replacement,
strlen (def->replacement));
scan (dest, &replacement_list, &new_no_loop, lookup_func, lookup_baton);
struct macro_buffer *argv = NULL;
struct macro_buffer substituted;
struct macro_buffer substituted_src;
- struct macro_buffer va_arg_name;
+ struct macro_buffer va_arg_name = {0};
int is_varargs = 0;
if (def->argc >= 1)
substitution parameter is the name of the formal
argument without the "...". */
init_shared_buffer (&va_arg_name,
- (char *) def->argv[def->argc - 1],
+ def->argv[def->argc - 1],
len - 3);
is_varargs = 1;
}
{
/* Make a null-terminated copy of it, since that's what our
lookup function expects. */
- char *id = xmalloc (src_first->len + 1);
+ char *id = (char *) xmalloc (src_first->len + 1);
struct cleanup *back_to = make_cleanup (xfree, id);
memcpy (id, src_first->text, src_first->len);
struct macro_buffer src, dest;
struct cleanup *back_to;
- init_shared_buffer (&src, (char *) source, strlen (source));
+ init_shared_buffer (&src, source, strlen (source));
init_buffer (&dest, 0);
dest.last_token = 0;
char *
-macro_expand_next (char **lexptr,
+macro_expand_next (const char **lexptr,
macro_lookup_ftype *lookup_func,
void *lookup_baton)
{