/* Part of CPP library. (Macro and #define handling.)
Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998,
- 1999, 2000, 2001 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
Written by Per Bothner, 1994.
Based on CCCP program by Paul Rubin, June 1986
Adapted to ANSI C, Richard Stallman, Jan 1987
#include "config.h"
#include "system.h"
-#include "intl.h" /* for _("<command line>") below. */
#include "cpplib.h"
#include "cpphash.h"
struct cpp_macro
{
cpp_hashnode **params; /* Parameters, if any. */
- cpp_token *expansion; /* First token of replacement list. */
+ cpp_token *expansion; /* First token of replacement list. */
unsigned int line; /* Starting line number. */
unsigned int count; /* Number of tokens in expansion. */
unsigned short paramc; /* Number of parameters. */
unsigned int fun_like : 1; /* If a function-like macro. */
unsigned int variadic : 1; /* If a variadic macro. */
- unsigned int disabled : 1; /* If macro is disabled. */
unsigned int syshdr : 1; /* If macro defined in system header. */
};
struct macro_arg
{
const cpp_token **first; /* First token in unexpanded argument. */
- const cpp_token **expanded; /* Macro-expanded argument. */
+ const cpp_token **expanded; /* Macro-expanded argument. */
const cpp_token *stringified; /* Stringified argument. */
unsigned int count; /* # of tokens in argument. */
unsigned int expanded_count; /* # of tokens in expanded argument. */
/* Macro expansion. */
static int enter_macro_context PARAMS ((cpp_reader *, cpp_hashnode *));
-static const cpp_token *builtin_macro PARAMS ((cpp_reader *, cpp_hashnode *));
+static int builtin_macro PARAMS ((cpp_reader *, cpp_hashnode *));
static void push_token_context
- PARAMS ((cpp_reader *, cpp_macro *, const cpp_token *, unsigned int));
+ PARAMS ((cpp_reader *, cpp_hashnode *, const cpp_token *, unsigned int));
static void push_ptoken_context
- PARAMS ((cpp_reader *, cpp_macro *, _cpp_buff *,
+ PARAMS ((cpp_reader *, cpp_hashnode *, _cpp_buff *,
const cpp_token **, unsigned int));
static _cpp_buff *collect_args PARAMS ((cpp_reader *, const cpp_hashnode *));
static cpp_context *next_context PARAMS ((cpp_reader *));
unsigned int));
static const cpp_token *new_string_token PARAMS ((cpp_reader *, U_CHAR *,
unsigned int));
-static const cpp_token *new_number_token PARAMS ((cpp_reader *, int));
+static const cpp_token *new_number_token PARAMS ((cpp_reader *, unsigned int));
static const cpp_token *stringify_arg PARAMS ((cpp_reader *, macro_arg *));
static void paste_all_tokens PARAMS ((cpp_reader *, const cpp_token *));
-static int paste_tokens PARAMS ((cpp_reader *, cpp_token *,
- const cpp_token *));
-static int funlike_invocation_p PARAMS ((cpp_reader *, const cpp_hashnode *));
-static void replace_args PARAMS ((cpp_reader *, cpp_macro *, macro_arg *));
+static bool paste_tokens PARAMS ((cpp_reader *, const cpp_token **,
+ const cpp_token *));
+static void replace_args PARAMS ((cpp_reader *, cpp_hashnode *, macro_arg *));
+static _cpp_buff *funlike_invocation_p PARAMS ((cpp_reader *, cpp_hashnode *));
/* #define directive parsing and handling. */
static cpp_token *alloc_expansion_token PARAMS ((cpp_reader *, cpp_macro *));
static cpp_token *lex_expansion_token PARAMS ((cpp_reader *, cpp_macro *));
-static int warn_of_redefinition PARAMS ((cpp_reader *, const cpp_hashnode *,
+static int warn_of_redefinition PARAMS ((const cpp_hashnode *,
const cpp_macro *));
static int save_parameter PARAMS ((cpp_reader *, cpp_macro *, cpp_hashnode *));
static int parse_params PARAMS ((cpp_reader *, cpp_macro *));
static const cpp_token *
new_number_token (pfile, number)
cpp_reader *pfile;
- int number;
+ unsigned int number;
{
cpp_token *token = _cpp_temp_token (pfile);
- unsigned char *buf = _cpp_pool_alloc (&pfile->ident_pool, 20);
+ /* 21 bytes holds all NUL-terminated unsigned 64-bit numbers. */
+ unsigned char *buf = _cpp_unaligned_alloc (pfile, 21);
- sprintf ((char *) buf, "%d", number);
+ sprintf ((char *) buf, "%u", number);
token->type = CPP_NUMBER;
token->val.str.text = buf;
token->val.str.len = ustrlen (buf);
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
-/* Handle builtin macros like __FILE__. */
-static const cpp_token *
+/* Handle builtin macros like __FILE__, and push the resulting token
+ on the context stack. Also handles _Pragma, for which no new token
+ is created. Returns 1 if it generates a new token context, 0 to
+ return the token to the caller. */
+static int
builtin_macro (pfile, node)
cpp_reader *pfile;
cpp_hashnode *node;
{
+ const cpp_token *result;
+
switch (node->value.builtin)
{
default:
- cpp_ice (pfile, "invalid builtin macro \"%s\"", NODE_NAME (node));
- return new_number_token (pfile, 1);
+ cpp_ice (pfile, "invalid built-in macro \"%s\"", NODE_NAME (node));
+ return 0;
case BT_FILE:
case BT_BASE_FILE:
name = map->to_file;
len = strlen (name);
- buf = _cpp_pool_alloc (&pfile->ident_pool, len * 4 + 1);
+ buf = _cpp_unaligned_alloc (pfile, len * 4 + 1);
len = quote_string (buf, (const unsigned char *) name, len) - buf;
- return new_string_token (pfile, buf, len);
+ result = new_string_token (pfile, buf, len);
}
-
+ break;
+
case BT_INCLUDE_LEVEL:
/* The line map depth counts the primary source as level 1, but
historically __INCLUDE_DEPTH__ has called the primary source
level 0. */
- return new_number_token (pfile, pfile->line_maps.depth - 1);
+ result = new_number_token (pfile, pfile->line_maps.depth - 1);
+ break;
case BT_SPECLINE:
/* If __LINE__ is embedded in a macro, it must expand to the
line of the macro's invocation, not its definition.
Otherwise things like assert() will not work properly. */
- return new_number_token (pfile, SOURCE_LINE (pfile->map,
- pfile->cur_token[-1].line));
+ result = new_number_token (pfile,
+ SOURCE_LINE (pfile->map,
+ pfile->cur_token[-1].line));
+ break;
case BT_STDC:
{
int stdc = (!CPP_IN_SYSTEM_HEADER (pfile)
|| pfile->spec_nodes.n__STRICT_ANSI__->type != NT_VOID);
- return new_number_token (pfile, stdc);
+ result = new_number_token (pfile, stdc);
}
+ break;
case BT_DATE:
case BT_TIME:
struct tm *tb = localtime (&tt);
pfile->date.val.str.text =
- _cpp_pool_alloc (&pfile->ident_pool, sizeof ("Oct 11 1347"));
+ _cpp_unaligned_alloc (pfile, sizeof ("Oct 11 1347"));
pfile->date.val.str.len = sizeof ("Oct 11 1347") - 1;
pfile->date.type = CPP_STRING;
pfile->date.flags = 0;
monthnames[tb->tm_mon], tb->tm_mday, tb->tm_year + 1900);
pfile->time.val.str.text =
- _cpp_pool_alloc (&pfile->ident_pool, sizeof ("12:34:56"));
+ _cpp_unaligned_alloc (pfile, sizeof ("12:34:56"));
pfile->time.val.str.len = sizeof ("12:34:56") - 1;
pfile->time.type = CPP_STRING;
pfile->time.flags = 0;
tb->tm_hour, tb->tm_min, tb->tm_sec);
}
- return node->value.builtin == BT_DATE ? &pfile->date: &pfile->time;
+ if (node->value.builtin == BT_DATE)
+ result = &pfile->date;
+ else
+ result = &pfile->time;
+ break;
+
+ case BT_PRAGMA:
+ /* Don't interpret _Pragma within directives. The standard is
+ not clear on this, but to me this makes most sense. */
+ if (pfile->state.in_directive)
+ return 0;
+
+ _cpp_do__Pragma (pfile);
+ return 1;
}
+
+ push_token_context (pfile, NULL, result, 1);
+ return 1;
}
-/* Adds backslashes before all backslashes and double quotes appearing
- in strings. Non-printable characters are converted to octal. */
+/* Copies SRC, of length LEN, to DEST, adding backslashes before all
+ backslashes and double quotes. Non-printable characters are
+ converted to octal. DEST must be of sufficient size. */
static U_CHAR *
quote_string (dest, src, len)
U_CHAR *dest;
return dest;
}
-/* Convert a token sequence to a single string token according to the
- rules of the ISO C #-operator. */
+/* Convert a token sequence ARG to a single string token according to
+ the rules of the ISO C #-operator. */
static const cpp_token *
stringify_arg (pfile, arg)
cpp_reader *pfile;
macro_arg *arg;
{
- cpp_pool *pool = &pfile->ident_pool;
- unsigned char *start = POOL_FRONT (pool);
- unsigned int i, escape_it, total_len = 0, backslash_count = 0;
+ unsigned char *dest = BUFF_FRONT (pfile->u_buff);
+ unsigned int i, escape_it, backslash_count = 0;
const cpp_token *source = NULL;
+ size_t len;
/* Loop, reading in the argument's tokens. */
for (i = 0; i < arg->count; i++)
{
- unsigned char *dest;
const cpp_token *token = arg->first[i];
- unsigned int len;
if (token->type == CPP_PADDING)
{
escape_it = (token->type == CPP_STRING || token->type == CPP_WSTRING
|| token->type == CPP_CHAR || token->type == CPP_WCHAR);
+ /* Room for each char being written in octal, initial space and
+ final NUL. */
len = cpp_token_len (token);
if (escape_it)
- /* Worst case is each char is octal. */
len *= 4;
- len += 2; /* Room for initial space and final NUL. */
+ len += 2;
- dest = &start[total_len];
- if (dest + len > POOL_LIMIT (pool))
+ if ((size_t) (BUFF_LIMIT (pfile->u_buff) - dest) < len)
{
- _cpp_next_chunk (pool, len, (unsigned char **) &start);
- dest = &start[total_len];
+ size_t len_so_far = dest - BUFF_FRONT (pfile->u_buff);
+ _cpp_extend_buff (pfile, &pfile->u_buff, len);
+ dest = BUFF_FRONT (pfile->u_buff) + len_so_far;
}
/* Leading white space? */
- if (total_len)
+ if (dest != BUFF_FRONT (pfile->u_buff))
{
if (source == NULL)
source = token;
if (escape_it)
{
- unsigned char *buf = (unsigned char *) xmalloc (len);
-
+ _cpp_buff *buff = _cpp_get_buff (pfile, len);
+ unsigned char *buf = BUFF_FRONT (buff);
len = cpp_spell_token (pfile, token, buf) - buf;
dest = quote_string (dest, buf, len);
- free (buf);
+ _cpp_release_buff (pfile, buff);
}
else
dest = cpp_spell_token (pfile, token, dest);
- total_len = dest - start;
if (token->type == CPP_OTHER && token->val.c == '\\')
backslash_count++;
if (backslash_count & 1)
{
cpp_warning (pfile, "invalid string literal, ignoring final '\\'");
- total_len--;
+ dest--;
}
/* Commit the memory, including NUL, and return the token. */
- POOL_COMMIT (pool, total_len + 1);
- return new_string_token (pfile, start, total_len);
+ len = dest - BUFF_FRONT (pfile->u_buff);
+ BUFF_FRONT (pfile->u_buff) = dest + 1;
+ return new_string_token (pfile, dest - len, len);
}
-/* Try to paste two tokens. On success, the LHS becomes the pasted
- token, and 0 is returned. For failure, we update the flags of the
- RHS appropriately and return non-zero. */
-static int
-paste_tokens (pfile, lhs, rhs)
+/* Try to paste two tokens. On success, return non-zero. In any
+ case, PLHS is updated to point to the pasted token, which is
+ guaranteed to not have the PASTE_LEFT flag set. */
+static bool
+paste_tokens (pfile, plhs, rhs)
cpp_reader *pfile;
- cpp_token *lhs;
- const cpp_token *rhs;
+ const cpp_token **plhs, *rhs;
{
- unsigned char flags = 0;
- int digraph = 0;
- enum cpp_ttype type;
-
- type = cpp_can_paste (pfile, lhs, rhs, &digraph);
-
- if (type == CPP_EOF)
- {
- /* Mandatory warning for all apart from assembler. */
- if (CPP_OPTION (pfile, lang) != CLK_ASM)
- cpp_warning (pfile,
- "pasting \"%s\" and \"%s\" does not give a valid preprocessing token",
- cpp_token_as_text (pfile, lhs),
- cpp_token_as_text (pfile, rhs));
- return 1;
- }
-
- if (digraph)
- flags |= DIGRAPH;
-
- /* Identifiers and numbers need spellings to be pasted. */
- if (type == CPP_NAME || type == CPP_NUMBER)
- {
- unsigned int total_len = cpp_token_len (lhs) + cpp_token_len (rhs);
- unsigned char *result, *end;
-
- result = _cpp_pool_alloc (&pfile->ident_pool, total_len + 1);
-
- /* Paste the spellings and null terminate. */
- end = cpp_spell_token (pfile, rhs, cpp_spell_token (pfile, lhs, result));
- *end = '\0';
- total_len = end - result;
-
- if (type == CPP_NAME)
- {
- lhs->val.node = cpp_lookup (pfile, result, total_len);
- if (lhs->val.node->flags & NODE_OPERATOR)
- {
- flags |= NAMED_OP;
- lhs->type = lhs->val.node->value.operator;
- }
- }
- else
- {
- lhs->val.str.text = result;
- lhs->val.str.len = total_len;
- }
- }
- else if (type == CPP_WCHAR || type == CPP_WSTRING)
- lhs->val.str = rhs->val.str;
-
- /* Set type and flags after pasting spellings. */
- lhs->type = type;
- lhs->flags = flags;
-
- return 0;
+ unsigned char *buf, *end;
+ const cpp_token *lhs;
+ unsigned int len;
+ bool valid;
+
+ lhs = *plhs;
+ len = cpp_token_len (lhs) + cpp_token_len (rhs) + 1;
+ buf = (unsigned char *) alloca (len);
+ end = cpp_spell_token (pfile, lhs, buf);
+
+ /* Avoid comment headers, since they are still processed in stage 3.
+ It is simpler to insert a space here, rather than modifying the
+ lexer to ignore comments in some circumstances. Simply returning
+ false doesn't work, since we want to clear the PASTE_LEFT flag. */
+ if (lhs->type == CPP_DIV
+ && (rhs->type == CPP_MULT || rhs->type == CPP_DIV))
+ *end++ = ' ';
+ end = cpp_spell_token (pfile, rhs, end);
+ *end = '\0';
+
+ cpp_push_buffer (pfile, buf, end - buf, /* from_stage3 */ true, 1);
+
+ /* Tweak the column number the lexer will report. */
+ pfile->buffer->col_adjust = pfile->cur_token[-1].col - 1;
+
+ /* We don't want a leading # to be interpreted as a directive. */
+ pfile->buffer->saved_flags = 0;
+
+ /* Set pfile->cur_token as required by _cpp_lex_direct. */
+ pfile->cur_token = _cpp_temp_token (pfile);
+ *plhs = _cpp_lex_direct (pfile);
+ valid = pfile->buffer->cur == pfile->buffer->rlimit;
+ _cpp_pop_buffer (pfile);
+
+ return valid;
}
-/* Handles an arbitrarily long sequence of ## operators. This
- implementation is left-associative, non-recursive, and finishes a
- paste before handling succeeding ones. If the paste fails, we back
- up a token to just after the ## operator, with the effect that it
- appears in the output stream normally. */
+/* Handles an arbitrarily long sequence of ## operators, with initial
+ operand LHS. This implementation is left-associative,
+ non-recursive, and finishes a paste before handling succeeding
+ ones. If a paste fails, we back up to the RHS of the failing ##
+ operator before pushing the context containing the result of prior
+ successful pastes, with the effect that the RHS appears in the
+ output stream after the pasted LHS normally. */
static void
paste_all_tokens (pfile, lhs)
cpp_reader *pfile;
const cpp_token *lhs;
{
- cpp_token *pasted;
const cpp_token *rhs;
cpp_context *context = pfile->context;
- /* Copy lhs to pasted, but preserve original line and column. */
- pasted = _cpp_temp_token (pfile);
- pasted->type = lhs->type;
- pasted->flags = lhs->flags;
- pasted->val.str = lhs->val.str;
-
do
{
/* Take the token directly from the current context. We can do
if (rhs->type == CPP_PADDING)
abort ();
- if (paste_tokens (pfile, pasted, rhs))
+ if (!paste_tokens (pfile, &lhs, rhs))
{
_cpp_backup_tokens (pfile, 1);
+
+ /* Mandatory warning for all apart from assembler. */
+ if (CPP_OPTION (pfile, lang) != CLK_ASM)
+ cpp_warning (pfile,
+ "pasting \"%s\" and \"%s\" does not give a valid preprocessing token",
+ cpp_token_as_text (pfile, lhs),
+ cpp_token_as_text (pfile, rhs));
break;
}
}
while (rhs->flags & PASTE_LEFT);
- /* Clear PASTE_LEFT flag, put the token in its own context. */
- pasted->flags &= ~PASTE_LEFT;
- push_token_context (pfile, NULL, pasted, 1);
+ /* Put the resulting token in its own context. */
+ push_token_context (pfile, NULL, lhs, 1);
}
-/* Reads and returns the arguments to a function-like macro invocation.
- Assumes the opening parenthesis has been processed. If there is an
- error, emits an appropriate diagnostic and returns NULL. */
+/* Reads and returns the arguments to a function-like macro
+ invocation. Assumes the opening parenthesis has been processed.
+ If there is an error, emits an appropriate diagnostic and returns
+ NULL. Each argument is terminated by a CPP_EOF token, for the
+ future benefit of expand_arg(). */
static _cpp_buff *
collect_args (pfile, node)
cpp_reader *pfile;
base_buff = buff;
args = (macro_arg *) buff->base;
memset (args, 0, argc * sizeof (macro_arg));
- buff->cur = (char *) &args[argc];
+ buff->cur = (unsigned char *) &args[argc];
arg = args, argc = 0;
/* Collect the tokens making up each argument. We don't yet know
for (;;)
{
/* Require space for 2 new tokens (including a CPP_EOF). */
- if ((char *) &arg->first[ntokens + 2] > buff->limit)
+ if ((unsigned char *) &arg->first[ntokens + 2] > buff->limit)
{
- buff = _cpp_extend_buff (pfile, buff,
- 1000 * sizeof (cpp_token *));
+ buff = _cpp_append_extend_buff (pfile, buff,
+ 1000 * sizeof (cpp_token *));
arg->first = (const cpp_token **) buff->cur;
}
overwrite the final legitimate argument, before failing. */
if (argc <= macro->paramc)
{
- buff->cur = (char *) &arg->first[ntokens + 1];
+ buff->cur = (unsigned char *) &arg->first[ntokens + 1];
if (argc != macro->paramc)
arg++;
}
step_back = true;
}
else
- /* We still need the CPP_EOF to end directives, and to end
- pre-expansion of a macro argument. */
step_back = (pfile->context->prev || pfile->state.in_directive);
+ /* We still need the CPP_EOF to end directives, and to end
+ pre-expansion of a macro argument. Step back is not
+ unconditional, since we don't want to return a CPP_EOF to our
+ callers at the end of an -include-d file. */
if (step_back)
_cpp_backup_tokens (pfile, 1);
cpp_error (pfile, "unterminated argument list invoking macro \"%s\"",
return NULL;
}
-static int
+/* Search for an opening parenthesis to the macro of NODE, in such a
+ way that, if none is found, we don't lose the information in any
+ intervening padding tokens. If we find the parenthesis, collect
+ the arguments and return the buffer containing them. */
+static _cpp_buff *
funlike_invocation_p (pfile, node)
cpp_reader *pfile;
- const cpp_hashnode *node;
+ cpp_hashnode *node;
{
- const cpp_token *maybe_paren;
- _cpp_buff *buff = NULL;
-
- pfile->state.prevent_expansion++;
- pfile->keep_tokens++;
+ const cpp_token *token, *padding = NULL;
- pfile->state.parsing_args = 1;
- do
- maybe_paren = cpp_get_token (pfile);
- while (maybe_paren->type == CPP_PADDING);
- pfile->state.parsing_args = 2;
-
- if (maybe_paren->type == CPP_OPEN_PAREN)
- buff = collect_args (pfile, node);
- else
+ for (;;)
{
- _cpp_backup_tokens (pfile, 1);
- if (CPP_WTRADITIONAL (pfile) && ! node->value.macro->syshdr)
- cpp_warning (pfile,
- "function-like macro \"%s\" must be used with arguments in traditional C",
- NODE_NAME (node));
+ token = cpp_get_token (pfile);
+ if (token->type != CPP_PADDING)
+ break;
+ if (padding == NULL
+ || (!(padding->flags & PREV_WHITE) && token->val.source == NULL))
+ padding = token;
}
- pfile->state.parsing_args = 0;
- pfile->keep_tokens--;
- pfile->state.prevent_expansion--;
-
- if (buff)
+ if (token->type == CPP_OPEN_PAREN)
{
- if (node->value.macro->paramc > 0)
- replace_args (pfile, node->value.macro, (macro_arg *) buff->base);
- _cpp_release_buff (pfile, buff);
+ pfile->state.parsing_args = 2;
+ return collect_args (pfile, node);
}
- return buff != 0;
+ /* Back up. We may have skipped padding, in which case backing up
+ more than one token when expanding macros is in general too
+ difficult. We re-insert it in its own context. */
+ _cpp_backup_tokens (pfile, 1);
+ if (padding)
+ push_token_context (pfile, NULL, padding, 1);
+
+ return NULL;
}
-/* Push the context of a macro onto the context stack. TOKEN is the
- macro name. If we can successfully start expanding the macro,
- TOKEN is replaced with the first token of the expansion, and we
- return non-zero. */
+/* Push the context of a macro with hash entry NODE onto the context
+ stack. If we can successfully expand the macro, we push a context
+ containing its yet-to-be-rescanned replacement list and return one.
+ Otherwise, we don't push a context and return zero. */
static int
enter_macro_context (pfile, node)
cpp_reader *pfile;
cpp_hashnode *node;
{
- if (node->flags & NODE_BUILTIN)
- push_token_context (pfile, NULL, builtin_macro (pfile, node), 1);
- else
+ /* The presence of a macro invalidates a file's controlling macro. */
+ pfile->mi_valid = false;
+
+ /* Handle standard macros. */
+ if (! (node->flags & NODE_BUILTIN))
{
cpp_macro *macro = node->value.macro;
- if (macro->fun_like && !funlike_invocation_p (pfile, node))
- return 0;
+ if (macro->fun_like)
+ {
+ _cpp_buff *buff;
+
+ pfile->state.prevent_expansion++;
+ pfile->keep_tokens++;
+ pfile->state.parsing_args = 1;
+ buff = funlike_invocation_p (pfile, node);
+ pfile->state.parsing_args = 0;
+ pfile->keep_tokens--;
+ pfile->state.prevent_expansion--;
+
+ if (buff == NULL)
+ {
+ if (CPP_WTRADITIONAL (pfile) && ! node->value.macro->syshdr)
+ cpp_warning (pfile,
+ "function-like macro \"%s\" must be used with arguments in traditional C",
+ NODE_NAME (node));
+
+ return 0;
+ }
+
+ if (node->value.macro->paramc > 0)
+ replace_args (pfile, node, (macro_arg *) buff->base);
+ _cpp_release_buff (pfile, buff);
+ }
/* Disable the macro within its expansion. */
- macro->disabled = 1;
+ node->flags |= NODE_DISABLED;
if (macro->paramc == 0)
- push_token_context (pfile, macro, macro->expansion, macro->count);
+ push_token_context (pfile, node, macro->expansion, macro->count);
+
+ return 1;
}
-
- return 1;
+
+ /* Handle built-in macros and the _Pragma operator. */
+ return builtin_macro (pfile, node);
}
-/* Take the expansion of a function-like MACRO, replacing parameters
- with the actual arguments. Each argument is macro-expanded before
- replacement, unless operated upon by the # or ## operators. */
+/* Replace the parameters in a function-like macro of NODE with the
+ actual ARGS, and place the result in a newly pushed token context.
+ Expand each argument before replacing, unless it is operated upon
+ by the # or ## operators. */
static void
-replace_args (pfile, macro, args)
+replace_args (pfile, node, args)
cpp_reader *pfile;
- cpp_macro *macro;
+ cpp_hashnode *node;
macro_arg *args;
{
unsigned int i, total;
const cpp_token **dest, **first;
macro_arg *arg;
_cpp_buff *buff;
+ cpp_macro *macro;
/* First, fully macro-expand arguments, calculating the number of
tokens in the final expansion as we go. The ordering of the if
statements below is subtle; we must handle stringification before
pasting. */
+ macro = node->value.macro;
total = macro->count;
limit = macro->expansion + macro->count;
if (args[i].expanded)
free (args[i].expanded);
- push_ptoken_context (pfile, macro, buff, first, dest - first);
+ push_ptoken_context (pfile, node, buff, first, dest - first);
}
/* Return a special padding token, with padding inherited from SOURCE. */
return result;
}
-/* Move to the next context. Create one if there is none. */
+/* Get a new uninitialized context. Create a new one if we cannot
+ re-use an old one. */
static cpp_context *
next_context (pfile)
cpp_reader *pfile;
static void
push_ptoken_context (pfile, macro, buff, first, count)
cpp_reader *pfile;
- cpp_macro *macro;
+ cpp_hashnode *macro;
_cpp_buff *buff;
const cpp_token **first;
unsigned int count;
static void
push_token_context (pfile, macro, first, count)
cpp_reader *pfile;
- cpp_macro *macro;
+ cpp_hashnode *macro;
const cpp_token *first;
unsigned int count;
{
context->last.token = first + count;
}
+/* Expand an argument ARG before replacing parameters in a
+ function-like macro. This works by pushing a context with the
+ argument's tokens, and then expanding that into a temporary buffer
+ as if it were a normal part of the token stream. collect_args()
+ has terminated the argument's tokens with a CPP_EOF so that we know
+ when we have fully expanded the argument. */
static void
expand_arg (pfile, arg)
cpp_reader *pfile;
_cpp_pop_context (pfile);
}
+/* Pop the current context off the stack, re-enabling the macro if the
+ context represented a macro's replacement list. The context
+ structure is not freed so that we can re-use it later. */
void
_cpp_pop_context (pfile)
cpp_reader *pfile;
{
cpp_context *context = pfile->context;
- /* Re-enable a macro when leaving its expansion. */
if (context->macro)
- context->macro->disabled = 0;
+ context->macro->flags &= ~NODE_DISABLED;
if (context->buff)
_cpp_release_buff (pfile, context->buff);
node = result->val.node;
- /* Handle macros and the _Pragma operator. */
- if (node->type == NT_MACRO && !(result->flags & NO_EXPAND))
+ if (node->type != NT_MACRO || (result->flags & NO_EXPAND))
+ break;
+
+ if (!(node->flags & NODE_DISABLED))
{
- /* Macros invalidate controlling macros. */
- pfile->mi_valid = false;
-
- if (!(node->flags & NODE_BUILTIN) && node->value.macro->disabled)
- {
- /* Flag this token as always unexpandable. */
- cpp_token *t = _cpp_temp_token (pfile);
- t->type = result->type;
- t->flags = result->flags | NO_EXPAND;
- t->val.str = result->val.str;
- result = t;
- }
- else if (!pfile->state.prevent_expansion
- && enter_macro_context (pfile, node))
+ if (!pfile->state.prevent_expansion
+ && enter_macro_context (pfile, node))
{
if (pfile->state.in_directive)
continue;
return padding_token (pfile, result);
}
}
+ else
+ {
+ /* Flag this token as always unexpandable. FIXME: move this
+ to collect_args()?. */
+ cpp_token *t = _cpp_temp_token (pfile);
+ t->type = result->type;
+ t->flags = result->flags | NO_EXPAND;
+ t->val.str = result->val.str;
+ result = t;
+ }
- /* Don't interpret _Pragma within directives. The standard is
- not clear on this, but to me this makes most sense. */
- if (node != pfile->spec_nodes.n__Pragma
- || pfile->state.in_directive)
- break;
-
- /* Handle it, and loop back for another token. MI is cleared
- since this token came from either the lexer or a macro. */
- _cpp_do__Pragma (pfile);
+ break;
}
return result;
cpp_sys_macro_p (pfile)
cpp_reader *pfile;
{
- cpp_macro *macro = pfile->context->macro;
+ cpp_hashnode *node = pfile->context->macro;
- return macro && macro->syshdr;
+ return node && node->value.macro && node->value.macro->syshdr;
}
/* Read each token in, until EOF. Directives are transparently
while (count--)
{
pfile->cur_token--;
- if (pfile->cur_token == pfile->cur_run->base)
+ if (pfile->cur_token == pfile->cur_run->base
+ /* Possible with -fpreprocessed and no leading #line. */
+ && pfile->cur_run->prev != NULL)
{
pfile->cur_run = pfile->cur_run->prev;
pfile->cur_token = pfile->cur_run->limit;
/* Returns non-zero if a macro redefinition warning is required. */
static int
-warn_of_redefinition (pfile, node, macro2)
- cpp_reader *pfile;
+warn_of_redefinition (node, macro2)
const cpp_hashnode *node;
const cpp_macro *macro2;
{
if (node->flags & NODE_WARN)
return 1;
- if (! CPP_PEDANTIC (pfile))
- return 0;
-
/* Redefinition of a macro is allowed if and only if the old and new
definitions are the same. (6.10.3 paragraph 2). */
macro1 = node->value.macro;
}
/* Free the definition of hashnode H. */
-
void
_cpp_free_definition (h)
cpp_hashnode *h;
/* Macros and assertions no longer have anything to free. */
h->type = NT_VOID;
/* Clear builtin flag in case of redefinition. */
- h->flags &= ~NODE_BUILTIN;
+ h->flags &= ~(NODE_BUILTIN | NODE_DISABLED);
}
/* Save parameter NODE to the parameter list of macro MACRO. Returns
- zero on success, non-zero if the paramter is a duplicate. */
+ zero on success, non-zero if the parameter is a duplicate. */
static int
save_parameter (pfile, macro, node)
cpp_reader *pfile;
cpp_macro *macro;
cpp_hashnode *node;
{
- cpp_hashnode **dest;
-
/* Constraint 6.10.3.6 - duplicate parameter names. */
if (node->arg_index)
{
return 1;
}
- dest = ¯o->params[macro->paramc];
+ if (BUFF_ROOM (pfile->a_buff)
+ < (macro->paramc + 1) * sizeof (cpp_hashnode *))
+ _cpp_extend_buff (pfile, &pfile->a_buff, sizeof (cpp_hashnode *));
- /* Check we have room for the parameters. */
- if ((unsigned char *) (dest + 1) >= POOL_LIMIT (&pfile->macro_pool))
- {
- _cpp_next_chunk (&pfile->macro_pool, sizeof (cpp_hashnode *),
- (unsigned char **) ¯o->params);
- dest = ¯o->params[macro->paramc];
- }
-
- *dest = node;
- node->arg_index = ++macro->paramc;
+ ((cpp_hashnode **) BUFF_FRONT (pfile->a_buff))[macro->paramc++] = node;
+ node->arg_index = macro->paramc;
return 0;
}
-/* Check the syntax of the paramters in a MACRO definition. */
+/* Check the syntax of the parameters in a MACRO definition. */
static int
parse_params (pfile, macro)
cpp_reader *pfile;
{
unsigned int prev_ident = 0;
- macro->params = (cpp_hashnode **) POOL_FRONT (&pfile->macro_pool);
for (;;)
{
const cpp_token *token = _cpp_lex_token (pfile);
case CPP_CLOSE_PAREN:
if (prev_ident || macro->paramc == 0)
- break;
+ return 1;
/* Fall through to pick up the error. */
case CPP_COMMA:
/* We're at the end, and just expect a closing parenthesis. */
token = _cpp_lex_token (pfile);
if (token->type == CPP_CLOSE_PAREN)
- break;
+ return 1;
/* Fall through. */
case CPP_EOF:
cpp_error (pfile, "missing ')' in macro parameter list");
return 0;
}
-
- /* Success. Commit the parameter array. */
- POOL_COMMIT (&pfile->macro_pool,
- macro->paramc * sizeof (cpp_hashnode *));
- return 1;
}
}
cpp_reader *pfile;
cpp_macro *macro;
{
- cpp_token *token = ¯o->expansion[macro->count];
-
- /* Check we have room for the token. */
- if ((unsigned char *) (token + 1) >= POOL_LIMIT (&pfile->macro_pool))
- {
- _cpp_next_chunk (&pfile->macro_pool, sizeof (cpp_token),
- (unsigned char **) ¯o->expansion);
- token = ¯o->expansion[macro->count];
- }
+ if (BUFF_ROOM (pfile->a_buff) < (macro->count + 1) * sizeof (cpp_token))
+ _cpp_extend_buff (pfile, &pfile->a_buff, sizeof (cpp_token));
- macro->count++;
- return token;
+ return &((cpp_token *) BUFF_FRONT (pfile->a_buff))[macro->count++];
}
+/* Lex a token from the expansion of MACRO, but mark parameters as we
+ find them and warn of traditional stringification. */
static cpp_token *
lex_expansion_token (pfile, macro)
cpp_reader *pfile;
pfile->cur_token = alloc_expansion_token (pfile, macro);
token = _cpp_lex_direct (pfile);
- /* Is this an argument? */
+ /* Is this a parameter? */
if (token->type == CPP_NAME && token->val.node->arg_index)
{
token->type = CPP_MACRO_ARG;
const cpp_token *ctoken;
unsigned int i, ok = 1;
- macro = (cpp_macro *) _cpp_pool_alloc (&pfile->macro_pool,
- sizeof (cpp_macro));
+ macro = (cpp_macro *) _cpp_aligned_alloc (pfile, sizeof (cpp_macro));
macro->line = pfile->directive_line;
macro->params = 0;
macro->paramc = 0;
if (ctoken->type == CPP_OPEN_PAREN && !(ctoken->flags & PREV_WHITE))
{
- if (!(ok = parse_params (pfile, macro)))
+ ok = parse_params (pfile, macro);
+ macro->params = (cpp_hashnode **) BUFF_FRONT (pfile->a_buff);
+ if (!ok)
goto cleanup2;
+
+ /* Success. Commit the parameter array. */
+ BUFF_FRONT (pfile->a_buff) = (U_CHAR *) ¯o->params[macro->paramc];
macro->fun_like = 1;
}
else if (ctoken->type != CPP_EOF && !(ctoken->flags & PREV_WHITE))
cpp_pedwarn (pfile, "ISO C requires whitespace after the macro name");
- pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);
saved_cur_token = pfile->cur_token;
- macro->expansion = (cpp_token *) POOL_FRONT (&pfile->macro_pool);
if (macro->fun_like)
token = lex_expansion_token (pfile, macro);
token = lex_expansion_token (pfile, macro);
}
+ macro->expansion = (cpp_token *) BUFF_FRONT (pfile->a_buff);
+
/* Don't count the CPP_EOF. */
macro->count--;
+ /* Clear whitespace on first token for warn_of_redefinition(). */
+ if (macro->count)
+ macro->expansion[0].flags &= ~PREV_WHITE;
+
+ /* Commit the memory. */
+ BUFF_FRONT (pfile->a_buff) = (U_CHAR *) ¯o->expansion[macro->count];
+
/* Implement the macro-defined-to-itself optimisation. */
- macro->disabled = (macro->count == 1 && !macro->fun_like
- && macro->expansion[0].type == CPP_NAME
- && macro->expansion[0].val.node == node);
+ if (macro->count == 1 && !macro->fun_like
+ && macro->expansion[0].type == CPP_NAME
+ && macro->expansion[0].val.node == node)
+ node->flags |= NODE_DISABLED;
/* To suppress some diagnostics. */
macro->syshdr = pfile->map->sysp != 0;
- /* Commit the memory. */
- POOL_COMMIT (&pfile->macro_pool, macro->count * sizeof (cpp_token));
-
if (node->type != NT_VOID)
{
- if (warn_of_redefinition (pfile, node, macro))
+ if (warn_of_redefinition (node, macro))
{
cpp_pedwarn_with_line (pfile, pfile->directive_line, 0,
"\"%s\" redefined", NODE_NAME (node));
return ok;
}
-/* Warn if a token in `string' matches one of the function macro
- arguments in `info'. This function assumes that the macro is a
- function macro and not an object macro. */
+/* Warn if a token in STRING matches one of a function-like MACRO's
+ parameters. */
static void
check_trad_stringification (pfile, macro, string)
cpp_reader *pfile;
&& !memcmp (p, NODE_NAME (node), len))
{
cpp_warning (pfile,
- "macro argument \"%s\" would be stringified with -traditional.",
+ "macro argument \"%s\" would be stringified with -traditional",
NODE_NAME (node));
break;
}
debugging info. e.g. "PASTE(X, Y) X ## Y", or "MACNAME EXPANSION".
Caller is expected to generate the "#define" bit if needed. The
returned text is temporary, and automatically freed later. */
-
const unsigned char *
cpp_macro_definition (pfile, node)
cpp_reader *pfile;