#include "config.h"
#include "system.h"
#include "cpplib.h"
#include "cpphash.h"
#ifdef PFE
#include "pfe/pfe.h"
#include "pfe/pfe-header.h"
#undef abort
extern void pfe_find_macro PARAMS ((const char *));
#endif
#include "genindex.h"
struct cpp_macro
{
cpp_hashnode **params;
cpp_token *expansion;
#ifdef PFE
const char *file;
#endif
unsigned int line;
unsigned int count;
unsigned short paramc;
unsigned int fun_like : 1;
unsigned int variadic : 1;
unsigned int syshdr : 1;
#ifdef PFE
unsigned int pfe_entry: 1;
unsigned int pfe_redef: 1;
#endif
};
typedef struct macro_arg macro_arg;
struct macro_arg
{
const cpp_token **first;
const cpp_token **expanded;
const cpp_token *stringified;
unsigned int count;
unsigned int expanded_count;
};
static int enter_macro_context PARAMS ((cpp_reader *, cpp_hashnode *));
static int builtin_macro PARAMS ((cpp_reader *, cpp_hashnode *));
static void push_token_context
PARAMS ((cpp_reader *, cpp_hashnode *, const cpp_token *, unsigned int));
static void push_ptoken_context
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 *));
static const cpp_token *padding_token
PARAMS ((cpp_reader *, const cpp_token *));
static void expand_arg PARAMS ((cpp_reader *, macro_arg *));
static const cpp_token *new_string_token PARAMS ((cpp_reader *, U_CHAR *,
unsigned 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 _cpp_buff *funlike_invocation_p PARAMS ((cpp_reader *, cpp_hashnode *));
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 ((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 void check_trad_stringification PARAMS ((cpp_reader *,
const cpp_macro *,
const cpp_string *));
static const cpp_token *
new_string_token (pfile, text, len)
cpp_reader *pfile;
unsigned char *text;
unsigned int len;
{
cpp_token *token = _cpp_temp_token (pfile);
text[len] = '\0';
token->type = CPP_STRING;
token->val.str.len = len;
token->val.str.text = text;
token->flags = 0;
return token;
}
static const cpp_token *
new_number_token (pfile, number)
cpp_reader *pfile;
unsigned int number;
{
cpp_token *token = _cpp_temp_token (pfile);
unsigned char *buf = _cpp_unaligned_alloc (pfile, 21);
sprintf ((char *) buf, "%u", number);
token->type = CPP_NUMBER;
token->val.str.text = buf;
token->val.str.len = ustrlen (buf);
token->flags = 0;
return token;
}
static const char * const monthnames[] =
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
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 built-in macro \"%s\"", NODE_NAME (node));
return 0;
case BT_FILE:
case BT_BASE_FILE:
{
unsigned int len;
const char *name;
U_CHAR *buf;
const struct line_map *map = pfile->map;
if (node->value.builtin == BT_BASE_FILE)
while (! MAIN_FILE_P (map))
map = INCLUDED_FROM (&pfile->line_maps, map);
name = map->to_file;
len = strlen (name);
buf = _cpp_unaligned_alloc (pfile, len * 4 + 1);
len = cpp_quote_string (buf, (const unsigned char *) name, len) - buf;
result = new_string_token (pfile, buf, len);
}
break;
case BT_INCLUDE_LEVEL:
result = new_number_token (pfile, pfile->line_maps.depth - 1);
break;
case BT_SPECLINE:
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);
result = new_number_token (pfile, stdc);
}
break;
case BT_DATE:
case BT_TIME:
if (pfile->date.type == CPP_EOF)
{
time_t tt = time (NULL);
struct tm *tb = localtime (&tt);
pfile->date.val.str.text =
_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;
sprintf ((char *) pfile->date.val.str.text, "%s %2d %4d",
monthnames[tb->tm_mon], tb->tm_mday, tb->tm_year + 1900);
pfile->time.val.str.text =
_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;
sprintf ((char *) pfile->time.val.str.text, "%02d:%02d:%02d",
tb->tm_hour, tb->tm_min, tb->tm_sec);
}
if (node->value.builtin == BT_DATE)
result = &pfile->date;
else
result = &pfile->time;
break;
case BT_PRAGMA:
if (pfile->state.in_directive)
return 0;
_cpp_do__Pragma (pfile);
return 1;
}
push_token_context (pfile, NULL, result, 1);
return 1;
}
U_CHAR *
cpp_quote_string (dest, src, len)
U_CHAR *dest;
const U_CHAR *src;
unsigned int len;
{
while (len--)
{
U_CHAR c = *src++;
if (c == '\\' || c == '"')
{
*dest++ = '\\';
*dest++ = c;
}
else
{
if (ISPRINT (c))
*dest++ = c;
else
{
sprintf ((char *) dest, "\\%03o", c);
dest += 4;
}
}
}
return dest;
}
static const cpp_token *
stringify_arg (pfile, arg)
cpp_reader *pfile;
macro_arg *arg;
{
unsigned char *dest = BUFF_FRONT (pfile->u_buff);
unsigned int i, escape_it, backslash_count = 0;
const cpp_token *source = NULL;
size_t len;
for (i = 0; i < arg->count; i++)
{
const cpp_token *token = arg->first[i];
if (token->type == CPP_PADDING)
{
if (source == NULL)
source = token->val.source;
continue;
}
escape_it = (token->type == CPP_STRING || token->type == CPP_WSTRING
|| token->type == CPP_CHAR || token->type == CPP_WCHAR);
len = cpp_token_len (token);
if (escape_it)
len *= 4;
len += 2;
if ((size_t) (BUFF_LIMIT (pfile->u_buff) - dest) < 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;
}
if (dest != BUFF_FRONT (pfile->u_buff))
{
if (source == NULL)
source = token;
if (source->flags & PREV_WHITE)
*dest++ = ' ';
}
source = NULL;
if (escape_it)
{
_cpp_buff *buff = _cpp_get_buff (pfile, len);
unsigned char *buf = BUFF_FRONT (buff);
len = cpp_spell_token (pfile, token, buf) - buf;
dest = cpp_quote_string (dest, buf, len);
_cpp_release_buff (pfile, buff);
}
else
dest = cpp_spell_token (pfile, token, dest);
if (token->type == CPP_OTHER && token->val.c == '\\')
backslash_count++;
else
backslash_count = 0;
}
if (backslash_count & 1)
{
cpp_warning (pfile, "invalid string literal, ignoring final '\\'");
dest--;
}
len = dest - BUFF_FRONT (pfile->u_buff);
BUFF_FRONT (pfile->u_buff) = dest + 1;
return new_string_token (pfile, dest - len, len);
}
static bool
paste_tokens (pfile, plhs, rhs)
cpp_reader *pfile;
const cpp_token **plhs, *rhs;
{
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);
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, true, 1);
pfile->buffer->col_adjust = pfile->cur_token[-1].col - 1;
pfile->buffer->saved_flags = 0;
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;
}
static void
paste_all_tokens (pfile, lhs)
cpp_reader *pfile;
const cpp_token *lhs;
{
const cpp_token *rhs;
cpp_context *context = pfile->context;
do
{
if (context->direct_p)
rhs = context->first.token++;
else
rhs = *context->first.ptoken++;
if (rhs->type == CPP_PADDING)
abort ();
if (!paste_tokens (pfile, &lhs, rhs))
{
_cpp_backup_tokens (pfile, 1);
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);
push_token_context (pfile, NULL, lhs, 1);
}
static _cpp_buff *
collect_args (pfile, node)
cpp_reader *pfile;
const cpp_hashnode *node;
{
_cpp_buff *buff, *base_buff;
cpp_macro *macro;
macro_arg *args, *arg;
const cpp_token *token;
unsigned int argc;
bool error = false;
macro = node->value.macro;
if (macro->paramc)
argc = macro->paramc;
else
argc = 1;
buff = _cpp_get_buff (pfile, argc * (50 * sizeof (cpp_token *)
+ sizeof (macro_arg)));
base_buff = buff;
args = (macro_arg *) buff->base;
memset (args, 0, argc * sizeof (macro_arg));
buff->cur = (unsigned char *) &args[argc];
arg = args, argc = 0;
do
{
unsigned int paren_depth = 0;
unsigned int ntokens = 0;
argc++;
arg->first = (const cpp_token **) buff->cur;
for (;;)
{
if ((unsigned char *) &arg->first[ntokens + 2] > buff->limit)
{
buff = _cpp_append_extend_buff (pfile, buff,
1000 * sizeof (cpp_token *));
arg->first = (const cpp_token **) buff->cur;
}
token = cpp_get_token (pfile);
if (token->type == CPP_PADDING)
{
if (ntokens == 0)
continue;
}
else if (token->type == CPP_OPEN_PAREN)
paren_depth++;
else if (token->type == CPP_CLOSE_PAREN)
{
if (paren_depth-- == 0)
break;
}
else if (token->type == CPP_COMMA)
{
if (paren_depth == 0
&& ! (macro->variadic && argc == macro->paramc))
break;
}
else if (token->type == CPP_EOF
|| (token->type == CPP_HASH && token->flags & BOL))
break;
arg->first[ntokens++] = token;
}
while (ntokens > 0 && arg->first[ntokens - 1]->type == CPP_PADDING)
ntokens--;
arg->count = ntokens;
arg->first[ntokens] = &pfile->eof;
if (argc <= macro->paramc)
{
buff->cur = (unsigned char *) &arg->first[ntokens + 1];
if (argc != macro->paramc)
arg++;
}
}
while (token->type != CPP_CLOSE_PAREN
&& token->type != CPP_EOF
&& token->type != CPP_HASH);
if (token->type == CPP_EOF || token->type == CPP_HASH)
{
bool step_back = false;
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);
if (step_back)
_cpp_backup_tokens (pfile, 1);
cpp_error (pfile, "unterminated argument list invoking macro \"%s\"",
NODE_NAME (node));
error = true;
}
else if (argc < macro->paramc)
{
if (argc + 1 == macro->paramc && macro->variadic)
{
if (CPP_PEDANTIC (pfile) && ! macro->syshdr)
cpp_pedwarn (pfile, "ISO C99 requires rest arguments to be used");
}
else
{
cpp_error (pfile,
"macro \"%s\" requires %u arguments, but only %u given",
NODE_NAME (node), macro->paramc, argc);
error = true;
}
}
else if (argc > macro->paramc)
{
if (argc != 1 || arg->count)
{
cpp_error (pfile,
"macro \"%s\" passed %u arguments, but takes just %u",
NODE_NAME (node), argc, macro->paramc);
error = true;
}
}
if (!error)
return base_buff;
_cpp_release_buff (pfile, base_buff);
return NULL;
}
static _cpp_buff *
funlike_invocation_p (pfile, node)
cpp_reader *pfile;
cpp_hashnode *node;
{
const cpp_token *token, *padding = NULL;
for (;;)
{
token = cpp_get_token (pfile);
if (token->type != CPP_PADDING)
break;
if (padding == NULL
|| (!(padding->flags & PREV_WHITE) && token->val.source == NULL))
padding = token;
}
if (token->type == CPP_OPEN_PAREN)
{
pfile->state.parsing_args = 2;
return collect_args (pfile, node);
}
_cpp_backup_tokens (pfile, 1);
if (padding)
push_token_context (pfile, NULL, padding, 1);
return NULL;
}
static int
enter_macro_context (pfile, node)
cpp_reader *pfile;
cpp_hashnode *node;
{
pfile->mi_valid = false;
if (! (node->flags & NODE_BUILTIN))
{
cpp_macro *macro = node->value.macro;
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);
}
node->flags |= NODE_DISABLED;
if (macro->paramc == 0)
push_token_context (pfile, node, macro->expansion, macro->count);
return 1;
}
return builtin_macro (pfile, node);
}
static void
replace_args (pfile, node, args)
cpp_reader *pfile;
cpp_hashnode *node;
macro_arg *args;
{
unsigned int i, total;
const cpp_token *src, *limit;
const cpp_token **dest, **first;
macro_arg *arg;
_cpp_buff *buff;
cpp_macro *macro;
macro = node->value.macro;
total = macro->count;
limit = macro->expansion + macro->count;
for (src = macro->expansion; src < limit; src++)
if (src->type == CPP_MACRO_ARG)
{
total += 2;
arg = &args[src->val.arg_no - 1];
if (src->flags & STRINGIFY_ARG)
{
if (!arg->stringified)
arg->stringified = stringify_arg (pfile, arg);
}
else if ((src->flags & PASTE_LEFT)
|| (src > macro->expansion && (src[-1].flags & PASTE_LEFT)))
total += arg->count - 1;
else
{
if (!arg->expanded)
expand_arg (pfile, arg);
total += arg->expanded_count - 1;
}
}
buff = _cpp_get_buff (pfile, total * sizeof (cpp_token *));
first = (const cpp_token **) buff->base;
dest = first;
for (src = macro->expansion; src < limit; src++)
{
unsigned int count;
const cpp_token **from, **paste_flag;
if (src->type != CPP_MACRO_ARG)
{
*dest++ = src;
continue;
}
paste_flag = 0;
arg = &args[src->val.arg_no - 1];
if (src->flags & STRINGIFY_ARG)
count = 1, from = &arg->stringified;
else if (src->flags & PASTE_LEFT)
count = arg->count, from = arg->first;
else if (src != macro->expansion && (src[-1].flags & PASTE_LEFT))
{
count = arg->count, from = arg->first;
if (dest != first)
{
if (dest[-1]->type == CPP_COMMA
&& macro->variadic
&& src->val.arg_no == macro->paramc)
{
if (count == 0)
dest--;
else
paste_flag = dest - 1;
}
else if (count == 0)
paste_flag = dest - 1;
}
}
else
count = arg->expanded_count, from = arg->expanded;
if (!pfile->state.in_directive
&& src != macro->expansion && !(src[-1].flags & PASTE_LEFT))
*dest++ = padding_token (pfile, src);
if (count)
{
memcpy (dest, from, count * sizeof (cpp_token *));
dest += count;
if (src->flags & PASTE_LEFT)
paste_flag = dest - 1;
}
if (!pfile->state.in_directive && !(src->flags & PASTE_LEFT))
*dest++ = &pfile->avoid_paste;
if (paste_flag)
{
cpp_token *token = _cpp_temp_token (pfile);
token->type = (*paste_flag)->type;
token->val.str = (*paste_flag)->val.str;
if (src->flags & PASTE_LEFT)
token->flags = (*paste_flag)->flags | PASTE_LEFT;
else
token->flags = (*paste_flag)->flags & ~PASTE_LEFT;
*paste_flag = token;
}
}
for (i = 0; i < macro->paramc; i++)
if (args[i].expanded)
free (args[i].expanded);
push_ptoken_context (pfile, node, buff, first, dest - first);
}
static const cpp_token *
padding_token (pfile, source)
cpp_reader *pfile;
const cpp_token *source;
{
cpp_token *result = _cpp_temp_token (pfile);
result->type = CPP_PADDING;
result->val.source = source;
result->flags = 0;
return result;
}
static cpp_context *
next_context (pfile)
cpp_reader *pfile;
{
cpp_context *result = pfile->context->next;
if (result == 0)
{
result = xnew (cpp_context);
result->prev = pfile->context;
result->next = 0;
pfile->context->next = result;
}
pfile->context = result;
return result;
}
static void
push_ptoken_context (pfile, macro, buff, first, count)
cpp_reader *pfile;
cpp_hashnode *macro;
_cpp_buff *buff;
const cpp_token **first;
unsigned int count;
{
cpp_context *context = next_context (pfile);
context->direct_p = false;
context->macro = macro;
context->buff = buff;
context->first.ptoken = first;
context->last.ptoken = first + count;
}
static void
push_token_context (pfile, macro, first, count)
cpp_reader *pfile;
cpp_hashnode *macro;
const cpp_token *first;
unsigned int count;
{
cpp_context *context = next_context (pfile);
context->direct_p = true;
context->macro = macro;
context->buff = NULL;
context->first.token = first;
context->last.token = first + count;
}
static void
expand_arg (pfile, arg)
cpp_reader *pfile;
macro_arg *arg;
{
unsigned int capacity;
if (arg->count == 0)
return;
capacity = 256;
arg->expanded = (const cpp_token **)
xmalloc (capacity * sizeof (cpp_token *));
push_ptoken_context (pfile, NULL, NULL, arg->first, arg->count + 1);
for (;;)
{
const cpp_token *token;
if (arg->expanded_count + 1 >= capacity)
{
capacity *= 2;
arg->expanded = (const cpp_token **)
xrealloc (arg->expanded, capacity * sizeof (cpp_token *));
}
token = cpp_get_token (pfile);
if (token->type == CPP_EOF)
break;
arg->expanded[arg->expanded_count++] = token;
}
_cpp_pop_context (pfile);
}
void
_cpp_pop_context (pfile)
cpp_reader *pfile;
{
cpp_context *context = pfile->context;
if (context->macro)
context->macro->flags &= ~NODE_DISABLED;
if (context->buff)
_cpp_release_buff (pfile, context->buff);
pfile->context = context->prev;
}
const cpp_token *
cpp_get_token (pfile)
cpp_reader *pfile;
{
const cpp_token *result;
for (;;)
{
cpp_hashnode *node;
cpp_context *context = pfile->context;
if (!context->prev)
result = _cpp_lex_token (pfile);
else if (context->first.token != context->last.token)
{
if (context->direct_p)
result = context->first.token++;
else
result = *context->first.ptoken++;
if (result->flags & PASTE_LEFT)
{
paste_all_tokens (pfile, result);
if (pfile->state.in_directive)
continue;
return padding_token (pfile, result);
}
}
else
{
_cpp_pop_context (pfile);
if (pfile->state.in_directive)
continue;
return &pfile->avoid_paste;
}
if (result->type != CPP_NAME)
break;
node = result->val.node;
if (node->type != NT_MACRO || (result->flags & NO_EXPAND))
break;
if (!(node->flags & NODE_DISABLED))
{
if (!pfile->state.prevent_expansion
&& enter_macro_context (pfile, node))
{
if (pfile->state.in_directive)
continue;
return padding_token (pfile, result);
}
}
else
{
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;
}
break;
}
return result;
}
int
cpp_sys_macro_p (pfile)
cpp_reader *pfile;
{
cpp_hashnode *node = pfile->context->macro;
return node && node->value.macro && node->value.macro->syshdr;
}
void
cpp_scan_nooutput (pfile)
cpp_reader *pfile;
{
while (cpp_get_token (pfile)->type != CPP_EOF)
;
}
void
_cpp_backup_tokens (pfile, count)
cpp_reader *pfile;
unsigned int count;
{
if (pfile->context->prev == NULL)
{
pfile->lookaheads += count;
while (count--)
{
pfile->cur_token--;
if (pfile->cur_token == pfile->cur_run->base
&& pfile->cur_run->prev != NULL)
{
pfile->cur_run = pfile->cur_run->prev;
pfile->cur_token = pfile->cur_run->limit;
}
}
}
else
{
if (count != 1)
abort ();
if (pfile->context->direct_p)
pfile->context->first.token--;
else
pfile->context->first.ptoken--;
}
}
static int
warn_of_redefinition (node, macro2)
const cpp_hashnode *node;
const cpp_macro *macro2;
{
const cpp_macro *macro1;
unsigned int i;
if (node->flags & NODE_WARN)
return 1;
macro1 = node->value.macro;
if (macro1->count != macro2->count
|| macro1->paramc != macro2->paramc
|| macro1->fun_like != macro2->fun_like
|| macro1->variadic != macro2->variadic)
return 1;
for (i = 0; i < macro1->count; i++)
if (! _cpp_equiv_tokens (¯o1->expansion[i], ¯o2->expansion[i]))
return 1;
for (i = 0; i < macro1->paramc; i++)
if (macro1->params[i] != macro2->params[i])
return 1;
return 0;
}
void
_cpp_free_definition (h)
cpp_hashnode *h;
{
h->type = NT_VOID;
h->flags &= ~(NODE_BUILTIN | NODE_DISABLED);
}
static int
save_parameter (pfile, macro, node)
cpp_reader *pfile;
cpp_macro *macro;
cpp_hashnode *node;
{
if (node->arg_index)
{
cpp_error (pfile, "duplicate macro parameter \"%s\"", NODE_NAME (node));
return 1;
}
if (BUFF_ROOM (pfile->a_buff)
< (macro->paramc + 1) * sizeof (cpp_hashnode *))
_cpp_extend_buff (pfile, &pfile->a_buff, sizeof (cpp_hashnode *));
((cpp_hashnode **) BUFF_FRONT (pfile->a_buff))[macro->paramc++] = node;
node->arg_index = macro->paramc;
return 0;
}
static int
parse_params (pfile, macro)
cpp_reader *pfile;
cpp_macro *macro;
{
unsigned int prev_ident = 0;
for (;;)
{
const cpp_token *token = _cpp_lex_token (pfile);
switch (token->type)
{
default:
cpp_error (pfile, "\"%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");
return 0;
}
prev_ident = 1;
if (save_parameter (pfile, macro, token->val.node))
return 0;
continue;
case CPP_CLOSE_PAREN:
if (prev_ident || macro->paramc == 0)
return 1;
case CPP_COMMA:
if (!prev_ident)
{
cpp_error (pfile, "parameter name missing");
return 0;
}
prev_ident = 0;
continue;
case CPP_ELLIPSIS:
macro->variadic = 1;
if (!prev_ident)
{
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");
}
else if (CPP_OPTION (pfile, pedantic))
cpp_pedwarn (pfile, "ISO C does not permit named variadic macros");
token = _cpp_lex_token (pfile);
if (token->type == CPP_CLOSE_PAREN)
return 1;
case CPP_EOF:
cpp_error (pfile, "missing ')' in macro parameter list");
return 0;
}
}
}
static cpp_token *
alloc_expansion_token (pfile, macro)
cpp_reader *pfile;
cpp_macro *macro;
{
if (BUFF_ROOM (pfile->a_buff) < (macro->count + 1) * sizeof (cpp_token))
_cpp_extend_buff (pfile, &pfile->a_buff, sizeof (cpp_token));
return &((cpp_token *) BUFF_FRONT (pfile->a_buff))[macro->count++];
}
static cpp_token *
lex_expansion_token (pfile, macro)
cpp_reader *pfile;
cpp_macro *macro;
{
cpp_token *token;
pfile->cur_token = alloc_expansion_token (pfile, macro);
token = _cpp_lex_direct (pfile);
if (token->type == CPP_NAME && token->val.node->arg_index)
{
token->type = CPP_MACRO_ARG;
token->val.arg_no = token->val.node->arg_index;
}
else if (CPP_WTRADITIONAL (pfile) && macro->paramc > 0
&& (token->type == CPP_STRING || token->type == CPP_CHAR))
check_trad_stringification (pfile, macro, &token->val.str);
return token;
}
int
_cpp_create_definition (pfile, node)
cpp_reader *pfile;
cpp_hashnode *node;
{
cpp_macro *macro;
cpp_token *token, *saved_cur_token;
const cpp_token *ctoken;
unsigned int i, ok = 1;
macro = (cpp_macro *) _cpp_aligned_alloc (pfile, sizeof (cpp_macro));
#ifdef PFE
macro->file = PFE_SAVESTRING (pfile->map->to_file);
#endif
macro->line = pfile->directive_line;
macro->params = 0;
macro->paramc = 0;
macro->variadic = 0;
macro->count = 0;
macro->fun_like = 0;
ctoken = _cpp_lex_token (pfile);
if (ctoken->type == CPP_OPEN_PAREN && !(ctoken->flags & PREV_WHITE))
{
ok = parse_params (pfile, macro);
macro->params = (cpp_hashnode **) BUFF_FRONT (pfile->a_buff);
if (!ok)
goto cleanup2;
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");
saved_cur_token = pfile->cur_token;
if (macro->fun_like)
token = lex_expansion_token (pfile, macro);
else
{
token = alloc_expansion_token (pfile, macro);
*token = *ctoken;
}
for (;;)
{
if (macro->count > 1 && token[-1].type == CPP_HASH && macro->fun_like)
{
if (token->type == CPP_MACRO_ARG)
{
token->flags &= ~PREV_WHITE;
token->flags |= STRINGIFY_ARG;
token->flags |= token[-1].flags & PREV_WHITE;
token[-1] = token[0];
macro->count--;
}
else if (CPP_OPTION (pfile, lang) != CLK_ASM)
{
ok = 0;
cpp_error (pfile, "'#' is not followed by a macro parameter");
goto cleanup1;
}
}
if (token->type == CPP_EOF)
break;
if (token->type == CPP_PASTE)
{
if (--macro->count > 0)
token = lex_expansion_token (pfile, macro);
if (macro->count == 0 || token->type == CPP_EOF)
{
ok = 0;
cpp_error (pfile,
"'##' cannot appear at either end of a macro expansion");
goto cleanup1;
}
token[-1].flags |= PASTE_LEFT;
}
token = lex_expansion_token (pfile, macro);
}
macro->expansion = (cpp_token *) BUFF_FRONT (pfile->a_buff);
#ifdef PFE
if (pfe_is_cmd_ln_processing ())
macro->pfe_entry = 1;
#endif
macro->count--;
if (macro->count)
macro->expansion[0].flags &= ~PREV_WHITE;
BUFF_FRONT (pfile->a_buff) = (U_CHAR *) ¯o->expansion[macro->count];
if (macro->count == 1 && !macro->fun_like
&& macro->expansion[0].type == CPP_NAME
&& macro->expansion[0].val.node == node)
node->flags |= NODE_DISABLED;
macro->syshdr = pfile->map->sysp != 0;
if (node->type != NT_VOID)
{
if (warn_of_redefinition (node, macro))
{
#ifdef PFE
if (pfe_operation == PFE_LOAD && pfe_is_cmd_ln_processing ())
{
if (pfe_macro_validation)
cpp_error (pfile,
"Macro \"%s\" was defined while making pre-compiled header: \"%s\"",
NODE_NAME (node), pfe_name);
else
cpp_pedwarn_with_line (pfile, pfile->directive_line, 0,
"Macro \"%s\" redefined. Previous definition is in "
"pre-compiled header: \"%s\"",
NODE_NAME (node), pfe_name);
}
else
{
#endif
cpp_pedwarn_with_line (pfile, 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,
"this is the location of the previous definition");
#ifdef PFE
}
#endif
}
#ifdef PFE
else
{
if (pfe_operation == PFE_LOAD
&& pfe_is_cmd_ln_processing ()
&& pfe_macro_validation
&& (pfe_macro_status & PFE_MACRO_FOUND)
&& !(pfe_macro_status & PFE_MACRO_CMD_LN))
{
cpp_error (pfile,
"-D%s redefines macro in pre-compiled header: \"%s\"",
NODE_NAME (node), pfe_name);
}
}
#endif
_cpp_free_definition (node);
}
#ifdef PFE
else
{
if (pfe_operation == PFE_LOAD
&& pfe_is_cmd_ln_processing()
&& pfe_macro_validation
&& (pfe_macro_status & PFE_MACRO_FOUND))
{
cpp_error (pfile,
"-D%s defines a macro that was not defined but was used in pre-compiled header: \"%s\"",
NODE_NAME (node), pfe_name);
}
}
#endif
node->type = NT_MACRO;
node->value.macro = macro;
if (! ustrncmp (NODE_NAME (node), DSC ("__STDC_")))
node->flags |= NODE_WARN;
if (flag_gen_index && !flag_gen_index_header)
gen_indexing_info (INDEX_MACRO, (const char *) NODE_NAME (node),
SOURCE_LINE (pfile->map, pfile->cur_token[-1].line));
cleanup1:
saved_cur_token[-1].type = pfile->cur_token[-1].type;
pfile->cur_token = saved_cur_token;
cleanup2:
pfile->state.va_args_ok = 0;
for (i = macro->paramc; i-- > 0; )
macro->params[i]->arg_index = 0;
return ok;
}
static void
check_trad_stringification (pfile, macro, string)
cpp_reader *pfile;
const cpp_macro *macro;
const cpp_string *string;
{
unsigned int i, len;
const U_CHAR *p, *q, *limit = string->text + string->len;
for (p = string->text; p < limit; p = q)
{
while (p < limit && !is_idstart (*p))
p++;
q = p;
while (q < limit && is_idchar (*q))
q++;
len = q - p;
for (i = 0; i < macro->paramc; i++)
{
const cpp_hashnode *node = macro->params[i];
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));
break;
}
}
}
}
const unsigned char *
cpp_macro_definition (pfile, node)
cpp_reader *pfile;
const cpp_hashnode *node;
{
unsigned int i, len;
const cpp_macro *macro = node->value.macro;
unsigned char *buffer;
if (node->type != NT_MACRO || (node->flags & NODE_BUILTIN))
{
cpp_ice (pfile, "invalid hash type %d in cpp_macro_definition", node->type);
return 0;
}
len = NODE_LEN (node) + 1;
if (macro->fun_like)
{
len += 4;
for (i = 0; i < macro->paramc; i++)
len += NODE_LEN (macro->params[i]) + 1;
}
for (i = 0; i < macro->count; i++)
{
cpp_token *token = ¯o->expansion[i];
if (token->type == CPP_MACRO_ARG)
len += NODE_LEN (macro->params[token->val.arg_no - 1]);
else
len += cpp_token_len (token);
if (token->flags & STRINGIFY_ARG)
len++;
if (token->flags & PASTE_LEFT)
len += 3;
}
if (len > pfile->macro_buffer_len)
{
pfile->macro_buffer = (U_CHAR *) xrealloc (pfile->macro_buffer, len);
pfile->macro_buffer_len = len;
}
buffer = pfile->macro_buffer;
memcpy (buffer, NODE_NAME (node), NODE_LEN (node));
buffer += NODE_LEN (node);
if (macro->fun_like)
{
*buffer++ = '(';
for (i = 0; i < macro->paramc; i++)
{
cpp_hashnode *param = macro->params[i];
if (param != pfile->spec_nodes.n__VA_ARGS__)
{
memcpy (buffer, NODE_NAME (param), NODE_LEN (param));
buffer += NODE_LEN (param);
}
if (i + 1 < macro->paramc)
*buffer++ = ',';
else if (macro->variadic)
*buffer++ = '.', *buffer++ = '.', *buffer++ = '.';
}
*buffer++ = ')';
}
*buffer++ = ' ';
if (macro->count)
{
for (i = 0; i < macro->count; i++)
{
cpp_token *token = ¯o->expansion[i];
if (token->flags & PREV_WHITE)
*buffer++ = ' ';
if (token->flags & STRINGIFY_ARG)
*buffer++ = '#';
if (token->type == CPP_MACRO_ARG)
{
len = NODE_LEN (macro->params[token->val.arg_no - 1]);
memcpy (buffer,
NODE_NAME (macro->params[token->val.arg_no - 1]), len);
buffer += len;
}
else
buffer = cpp_spell_token (pfile, token, buffer);
if (token->flags & PASTE_LEFT)
{
*buffer++ = ' ';
*buffer++ = '#';
*buffer++ = '#';
}
}
}
*buffer = '\0';
return pfile->macro_buffer;
}
#ifdef PFE
void
pfe_freeze_thaw_cpp_macro (mp)
struct cpp_macro **mp;
{
struct cpp_macro *m = PFE_FREEZE_THAW_PTR (mp);
unsigned int i;
struct cpp_token *token, *expansion;
struct cpp_hashnode **params;
if (!m)
return;
#if 0
if (pfe_operation == PFE_DUMP)
{
printf("pfe_freeze_thaw_cpp_macro: 0x%x\n", (unsigned)m);
if (m->file == NULL)
printf(" file: <NULL>\n");
else
printf(" file: '%s'\n", m->file);
printf(" line: %d\n", m->line);
printf(" paramc: %d\n", m->paramc);
printf(" count: %d\n", m->count);
printf(" expansion: 0x%x\n", (unsigned)m->expansion);
if (m->fun_like)
printf(" fun_like\n");
if (m->variadic)
printf(" variadic\n");
if (m->disabled)
printf(" disabled\n");
if (m->syshdr)
printf(" syshdr\n");
}
#endif
if (m->pfe_entry)
pfe_compiler_state_ptr->cmd_ln_macro_count++;
if (m->params != NULL)
{
params = PFE_FREEZE_THAW_PTR (&m->params);
if (params == NULL)
return;
for (i = 0; i < m->paramc; i++)
pfe_freeze_thaw_cpp_hashnode (¶ms[i]);
}
if (m->expansion != NULL)
{
struct cpp_token *token_orig = m->expansion;
expansion = PFE_FREEZE_THAW_PTR (&m->expansion);
if (expansion == NULL)
return;
for (i = 0; i < m->count; i++)
{
token = token_orig;
pfe_using_temp_ptr((void **)&token);
pfe_freeze_thaw_cpp_token (&token);
token_orig++;
}
}
pfe_freeze_thaw_ptr_fp (&m->file);
#if 0
if (pfe_operation == PFE_LOAD)
{
printf("pfe_freeze_thaw_cpp_macro: 0x%x\n", (unsigned)m);
if (m->file == NULL)
printf(" file: <NULL>\n");
else
printf(" file: '%s'\n", m->file);
printf(" line: %d\n", m->line);
printf(" paramc: %d\n", m->paramc);
if (m->paramc > 0)
{
params = m->params;
for (i = 0; i < m->paramc; i++)
printf(" param[%d]: 0x%x '%s'\n", i, params[i], params[i]->ident.str);
}
printf(" count: %d\n", m->count);
printf(" expansion: 0x%x\n", (unsigned)m->expansion);
if (m->fun_like)
printf(" fun_like\n");
if (m->variadic)
printf(" variadic\n");
if (m->disabled)
printf(" disabled\n");
if (m->syshdr)
printf(" syshdr\n");
}
#endif
}
void
pfe_find_macro (macro_name)
const char *macro_name;
{
cpp_hashnode *node;
char *buf, *p;
if (!macro_name)
return;
p = strchr (macro_name, ' ');
if (p)
{
size_t count;
count = strlen (macro_name);
buf = (char *) alloca (count + 2);
memcpy (buf, macro_name, count);
buf [p - macro_name] = NULL;
}
else
{
buf = (char *)macro_name;
}
node = (cpp_hashnode *)ht_lookup (pfe_compiler_state_ptr->ident_hash,
(const unsigned char *) buf,
strlen (buf), HT_NO_INSERT);
if (node)
{
cpp_macro *macro = node->value.macro;
pfe_macro_status |= PFE_MACRO_FOUND;
if (macro && macro->pfe_entry)
{
pfe_cmd_ln_macro_count++;
pfe_macro_status |= PFE_MACRO_CMD_LN;
}
}
}
DEFINE_CHECK_STRUCT_FUNCTION (cpp_macro)
#endif