/* 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"
static const cpp_token *padding_token
PARAMS ((cpp_reader *, const cpp_token *));
static void expand_arg PARAMS ((cpp_reader *, macro_arg *));
-static unsigned char *quote_string PARAMS ((unsigned char *,
- const unsigned char *,
- unsigned int));
-static const cpp_token *new_string_token PARAMS ((cpp_reader *, U_CHAR *,
+static const cpp_token *new_string_token PARAMS ((cpp_reader *, uchar *,
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 bool paste_tokens PARAMS ((cpp_reader *, const cpp_token **,
const cpp_token *));
-static void replace_args PARAMS ((cpp_reader *, cpp_hashnode *, macro_arg *));
+static void replace_args PARAMS ((cpp_reader *, cpp_hashnode *, cpp_macro *,
+ 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_unaligned_alloc (pfile, 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);
/* 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 on success, 0 to return the token to the
- caller. */
+ 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;
switch (node->value.builtin)
{
default:
- cpp_ice (pfile, "invalid builtin macro \"%s\"", NODE_NAME (node));
+ cpp_error (pfile, DL_ICE, "invalid built-in macro \"%s\"",
+ NODE_NAME (node));
return 0;
case BT_FILE:
{
unsigned int len;
const char *name;
- U_CHAR *buf;
+ uchar *buf;
const struct line_map *map = pfile->map;
if (node->value.builtin == BT_BASE_FILE)
name = map->to_file;
len = strlen (name);
buf = _cpp_unaligned_alloc (pfile, len * 4 + 1);
- len = quote_string (buf, (const unsigned char *) name, len) - buf;
+ len = cpp_quote_string (buf, (const unsigned char *) name, len) - buf;
result = new_string_token (pfile, buf, len);
}
return 1;
}
-/* Adds backslashes before all backslashes and double quotes appearing
- in strings. Non-printable characters are converted to octal. */
-static U_CHAR *
-quote_string (dest, src, len)
- U_CHAR *dest;
- const U_CHAR *src;
+/* 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. Returns
+ a pointer to the end of the string. */
+uchar *
+cpp_quote_string (dest, src, len)
+ uchar *dest;
+ const uchar *src;
unsigned int len;
{
while (len--)
{
- U_CHAR c = *src++;
+ uchar c = *src++;
if (c == '\\' || c == '"')
{
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;
_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);
+ dest = cpp_quote_string (dest, buf, len);
_cpp_release_buff (pfile, buff);
}
else
/* Ignore the final \ of invalid string literals. */
if (backslash_count & 1)
{
- cpp_warning (pfile, "invalid string literal, ignoring final '\\'");
+ cpp_error (pfile, DL_WARNING,
+ "invalid string literal, ignoring final '\\'");
dest--;
}
&& (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);
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;
/* Mandatory warning for all apart from assembler. */
if (CPP_OPTION (pfile, lang) != CLK_ASM)
- cpp_warning (pfile,
+ cpp_error (pfile, DL_WARNING,
"pasting \"%s\" and \"%s\" does not give a valid preprocessing token",
- cpp_token_as_text (pfile, lhs),
- cpp_token_as_text (pfile, rhs));
+ cpp_token_as_text (pfile, lhs),
+ cpp_token_as_text (pfile, rhs));
break;
}
}
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;
arg++;
}
}
- while (token->type != CPP_CLOSE_PAREN
- && token->type != CPP_EOF
- && token->type != CPP_HASH);
+ while (token->type != CPP_CLOSE_PAREN && token->type != CPP_EOF);
- if (token->type == CPP_EOF || token->type == CPP_HASH)
+ if (token->type == CPP_EOF)
{
- bool step_back = false;
-
- /* 6.10.3 paragraph 11: If there are sequences of preprocessing
- tokens within the list of arguments that would otherwise act
- as preprocessing directives, the behavior is undefined.
-
- This implementation will report a hard error, terminate the
- macro invocation, and proceed to process the directive. */
- if (token->type == CPP_HASH)
- {
- cpp_error (pfile,
- "directives may not be used inside a macro argument");
- step_back = true;
- }
- else
- 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)
+ if (pfile->context->prev || pfile->state.in_directive)
_cpp_backup_tokens (pfile, 1);
- cpp_error (pfile, "unterminated argument list invoking macro \"%s\"",
+ cpp_error (pfile, DL_ERROR,
+ "unterminated argument list invoking macro \"%s\"",
NODE_NAME (node));
error = true;
}
if (argc + 1 == macro->paramc && macro->variadic)
{
if (CPP_PEDANTIC (pfile) && ! macro->syshdr)
- cpp_pedwarn (pfile, "ISO C99 requires rest arguments to be used");
+ cpp_error (pfile, DL_PEDWARN,
+ "ISO C99 requires rest arguments to be used");
}
else
{
- cpp_error (pfile,
+ cpp_error (pfile, DL_ERROR,
"macro \"%s\" requires %u arguments, but only %u given",
NODE_NAME (node), macro->paramc, argc);
error = true;
/* Empty argument to a macro taking no arguments is OK. */
if (argc != 1 || arg->count)
{
- cpp_error (pfile,
+ cpp_error (pfile, DL_ERROR,
"macro \"%s\" passed %u arguments, but takes just %u",
NODE_NAME (node), argc, macro->paramc);
error = true;
return collect_args (pfile, node);
}
- /* 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);
+ /* CPP_EOF can be the end of macro arguments, or the end of the
+ file. We mustn't back up over the latter. Ugh. */
+ if (token->type != CPP_EOF || token == &pfile->eof)
+ {
+ /* 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;
{
- /* Macros invalidate controlling macros. */
+ /* The presence of a macro invalidates a file's controlling macro. */
pfile->mi_valid = false;
- /* Handle macros and the _Pragma operator. */
+ /* Handle standard macros. */
if (! (node->flags & NODE_BUILTIN))
{
cpp_macro *macro = node->value.macro;
if (buff == NULL)
{
if (CPP_WTRADITIONAL (pfile) && ! node->value.macro->syshdr)
- cpp_warning (pfile,
+ cpp_error (pfile, DL_WARNING,
"function-like macro \"%s\" must be used with arguments in traditional C",
- NODE_NAME (node));
+ NODE_NAME (node));
return 0;
}
- if (node->value.macro->paramc > 0)
- replace_args (pfile, node, (macro_arg *) buff->base);
+ if (macro->paramc > 0)
+ replace_args (pfile, node, macro, (macro_arg *) buff->base);
_cpp_release_buff (pfile, buff);
}
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, node, args)
+replace_args (pfile, node, macro, args)
cpp_reader *pfile;
cpp_hashnode *node;
+ cpp_macro *macro;
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;
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;
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->flags &= ~NODE_DISABLED;
return &pfile->avoid_paste;
}
+ if (pfile->state.in_directive && result->type == CPP_COMMENT)
+ continue;
+
if (result->type != CPP_NAME)
break;
}
else
{
- /* Flag this token as always unexpandable. */
+ /* 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;
return node && node->value.macro && node->value.macro->syshdr;
}
-/* Read each token in, until EOF. Directives are transparently
- processed. */
+/* Read each token in, until end of the current file. Directives are
+ transparently processed. */
void
cpp_scan_nooutput (pfile)
cpp_reader *pfile;
{
+ /* Request a CPP_EOF token at the end of this file, rather than
+ transparently continuing with the including file. */
+ pfile->buffer->return_at_eof = true;
+
while (cpp_get_token (pfile)->type != CPP_EOF)
;
}
/* 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;
{
}
/* Free the definition of hashnode H. */
-
void
_cpp_free_definition (h)
cpp_hashnode *h;
/* Constraint 6.10.3.6 - duplicate parameter names. */
if (node->arg_index)
{
- cpp_error (pfile, "duplicate macro parameter \"%s\"", NODE_NAME (node));
+ cpp_error (pfile, DL_ERROR, "duplicate macro parameter \"%s\"",
+ NODE_NAME (node));
return 1;
}
switch (token->type)
{
default:
- cpp_error (pfile, "\"%s\" may not appear in macro parameter list",
+ /* Allow/ignore comments in parameter lists if we are
+ preserving comments in macro expansions. */
+ if (token->type == CPP_COMMENT
+ && ! CPP_OPTION (pfile, discard_comments_in_macro_exp))
+ continue;
+
+ cpp_error (pfile, DL_ERROR,
+ "\"%s\" may not appear in macro parameter list",
cpp_token_as_text (pfile, token));
return 0;
case CPP_NAME:
if (prev_ident)
{
- cpp_error (pfile, "macro parameters must be comma-separated");
+ cpp_error (pfile, DL_ERROR,
+ "macro parameters must be comma-separated");
return 0;
}
prev_ident = 1;
case CPP_COMMA:
if (!prev_ident)
{
- cpp_error (pfile, "parameter name missing");
+ cpp_error (pfile, DL_ERROR, "parameter name missing");
return 0;
}
prev_ident = 0;
save_parameter (pfile, macro, pfile->spec_nodes.n__VA_ARGS__);
pfile->state.va_args_ok = 1;
if (! CPP_OPTION (pfile, c99) && CPP_OPTION (pfile, pedantic))
- cpp_pedwarn (pfile,
- "anonymous variadic macros were introduced in C99");
+ cpp_error (pfile, DL_PEDWARN,
+ "anonymous variadic macros were introduced in C99");
}
else if (CPP_OPTION (pfile, pedantic))
- cpp_pedwarn (pfile, "ISO C does not permit named variadic macros");
+ cpp_error (pfile, DL_PEDWARN,
+ "ISO C does not permit named variadic macros");
/* We're at the end, and just expect a closing parenthesis. */
token = _cpp_lex_token (pfile);
/* Fall through. */
case CPP_EOF:
- cpp_error (pfile, "missing ')' in macro parameter list");
+ cpp_error (pfile, DL_ERROR, "missing ')' in macro parameter list");
return 0;
}
}
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;
goto cleanup2;
/* Success. Commit the parameter array. */
- BUFF_FRONT (pfile->a_buff) = (U_CHAR *) ¯o->params[macro->paramc];
+ BUFF_FRONT (pfile->a_buff) = (uchar *) ¯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");
+ cpp_error (pfile, DL_PEDWARN,
+ "ISO C requires whitespace after the macro name");
saved_cur_token = pfile->cur_token;
else if (CPP_OPTION (pfile, lang) != CLK_ASM)
{
ok = 0;
- cpp_error (pfile, "'#' is not followed by a macro parameter");
+ cpp_error (pfile, DL_ERROR,
+ "'#' is not followed by a macro parameter");
goto cleanup1;
}
}
if (macro->count == 0 || token->type == CPP_EOF)
{
ok = 0;
- cpp_error (pfile,
+ cpp_error (pfile, DL_ERROR,
"'##' cannot appear at either end of a macro expansion");
goto cleanup1;
}
/* Don't count the CPP_EOF. */
macro->count--;
- /* Clear whitespace on first token for macro equivalence purposes. */
+ /* 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];
+ BUFF_FRONT (pfile->a_buff) = (uchar *) ¯o->expansion[macro->count];
/* Implement the macro-defined-to-itself optimisation. */
if (macro->count == 1 && !macro->fun_like
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));
+ cpp_error_with_line (pfile, DL_PEDWARN, pfile->directive_line, 0,
+ "\"%s\" redefined", NODE_NAME (node));
if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN))
- cpp_pedwarn_with_line (pfile, node->value.macro->line, 0,
+ cpp_error_with_line (pfile, DL_PEDWARN, node->value.macro->line, 0,
"this is the location of the previous definition");
}
_cpp_free_definition (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;
const cpp_string *string;
{
unsigned int i, len;
- const U_CHAR *p, *q, *limit = string->text + string->len;
+ const uchar *p, *q, *limit = string->text + string->len;
/* Loop over the string. */
for (p = string->text; p < limit; p = q)
if (NODE_LEN (node) == len
&& !memcmp (p, NODE_NAME (node), len))
{
- cpp_warning (pfile,
- "macro argument \"%s\" would be stringified with -traditional.",
- NODE_NAME (node));
+ cpp_error (pfile, DL_WARNING,
+ "macro argument \"%s\" would be stringified in traditional C",
+ 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;
if (node->type != NT_MACRO || (node->flags & NODE_BUILTIN))
{
- cpp_ice (pfile, "invalid hash type %d in cpp_macro_definition", node->type);
+ cpp_error (pfile, DL_ICE,
+ "invalid hash type %d in cpp_macro_definition", node->type);
return 0;
}
len = NODE_LEN (node) + 1; /* ' ' */
if (macro->fun_like)
{
- len += 3; /* "()" plus possible final "." of named
- varargs (we have + 2 below). */
+ len += 4; /* "()" plus possible final ".." of named
+ varargs (we have + 1 below). */
for (i = 0; i < macro->paramc; i++)
- len += NODE_LEN (macro->params[i]) + 2; /* ", " */
+ len += NODE_LEN (macro->params[i]) + 1; /* "," */
}
for (i = 0; i < macro->count; i++)
if (len > pfile->macro_buffer_len)
{
- pfile->macro_buffer = (U_CHAR *) xrealloc (pfile->macro_buffer, len);
+ pfile->macro_buffer = (uchar *) xrealloc (pfile->macro_buffer, len);
pfile->macro_buffer_len = len;
}
}
if (i + 1 < macro->paramc)
- *buffer++ = ',', *buffer++ = ' ';
+ /* Don't emit a space after the comma here; we're trying
+ to emit a Dwarf-friendly definition, and the Dwarf spec
+ forbids spaces in the argument list. */
+ *buffer++ = ',';
else if (macro->variadic)
*buffer++ = '.', *buffer++ = '.', *buffer++ = '.';
}
*buffer++ = ')';
}
+ /* The Dwarf spec requires a space after the macro name, even if the
+ definition is the empty string. */
+ *buffer++ = ' ';
+
/* Expansion tokens. */
if (macro->count)
{
- *buffer++ = ' ';
for (i = 0; i < macro->count; i++)
{
cpp_token *token = ¯o->expansion[i];