#include "config.h"
#include "system.h"
#include "cpplib.h"
#include "cpphash.h"
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 *, uchar *,
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 *, cpp_macro *,
macro_arg *));
static
_cpp_buff *funlike_invocation_p PARAMS ((cpp_reader *, cpp_hashnode *));
static
bool
create_iso_definition PARAMS ((cpp_reader *, cpp_macro *));
static
cpp_token *alloc_expansion_token PARAMS ((cpp_reader *, cpp_macro *));
static
cpp_token *lex_expansion_token PARAMS ((cpp_reader *, cpp_macro *));
static
bool
warn_of_redefinition PARAMS ((cpp_reader *,
const
cpp_hashnode *,
const
cpp_macro *));
static
bool
parse_params PARAMS ((cpp_reader *, cpp_macro *));
static
void
check_trad_stringification PARAMS ((cpp_reader *,
const
cpp_macro *,
const
cpp_string *));
int
_cpp_warn_if_unused_macro (pfile, node, v)
cpp_reader *pfile;
cpp_hashnode *node;
void
*v ATTRIBUTE_UNUSED;
{
if
(node->type == NT_MACRO && !(node->flags & NODE_BUILTIN))
{
cpp_macro *macro = node->value.macro;
if
(!macro->used
&& macro->line >= pfile->first_unused_line
&& MAIN_FILE_P (lookup_line (&pfile->line_maps, macro->line)))
cpp_error_with_line (pfile, DL_WARNING, macro->line, 0,
"macro \"%s\" is not used"
, NODE_NAME (node));
}
return
1;
}
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
char
*
const
monthnames[] =
{
"Jan"
,
"Feb"
,
"Mar"
,
"Apr"
,
"May"
,
"Jun"
,
"Jul"
,
"Aug"
,
"Sep"
,
"Oct"
,
"Nov"
,
"Dec"
};
const
uchar *
_cpp_builtin_macro_text (pfile, node)
cpp_reader *pfile;
cpp_hashnode *node;
{
const
uchar *result = NULL;
unsigned
int
number = 1;
switch
(node->value.builtin)
{
default
:
cpp_error (pfile, DL_ICE,
"invalid built-in macro \"%s\""
,
NODE_NAME (node));
break
;
case
BT_FILE:
case
BT_BASE_FILE:
{
unsigned
int
len;
const
char
*name;
uchar *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 + 3);
result = buf;
*buf =
'"'
;
buf = cpp_quote_string (buf + 1, (
const
unsigned
char
*) name, len);
*buf++ =
'"'
;
*buf =
'\0'
;
}
break
;
case
BT_INCLUDE_LEVEL:
number = pfile->line_maps.depth - 1;
break
;
case
BT_SPECLINE:
if
(CPP_OPTION (pfile, traditional))
number = pfile->line;
else
number = pfile->cur_token[-1].line;
number = SOURCE_LINE (pfile->map, number);
break
;
case
BT_STDC:
{
if
(CPP_IN_SYSTEM_HEADER (pfile)
&& CPP_OPTION (pfile, stdc_0_in_system_headers)
&& !CPP_OPTION (pfile,std))
number = 0;
else
number = 1;
}
break
;
case
BT_DATE:
case
BT_TIME:
if
(pfile->date == NULL)
{
time_t
tt;
struct
tm
*tb = NULL;
errno
= 0;
tt =
time
(NULL);
if
(tt != (
time_t
)-1 ||
errno
== 0)
tb =
localtime
(&tt);
if
(tb)
{
pfile->date = _cpp_unaligned_alloc (pfile,
sizeof
(
"\"Oct 11 1347\""
));
sprintf
((
char
*) pfile->date,
"\"%s %2d %4d\""
,
monthnames[tb->tm_mon], tb->tm_mday, tb->tm_year + 1900);
pfile->
time
= _cpp_unaligned_alloc (pfile,
sizeof
(
"\"12:34:56\""
));
sprintf
((
char
*) pfile->
time
,
"\"%02d:%02d:%02d\""
,
tb->tm_hour, tb->tm_min, tb->tm_sec);
}
else
{
cpp_errno (pfile, DL_WARNING,
"could not determine date and time"
);
pfile->date = U
"\"??? ?? ????\""
;
pfile->
time
= U
"\"??:??:??\""
;
}
}
if
(node->value.builtin == BT_DATE)
result = pfile->date;
else
result = pfile->
time
;
break
;
}
if
(result == NULL)
{
result = _cpp_unaligned_alloc (pfile, 21);
sprintf
((
char
*) result,
"%u"
, number);
}
return
result;
}
static
int
builtin_macro (pfile, node)
cpp_reader *pfile;
cpp_hashnode *node;
{
const
uchar *buf;
if
(node->value.builtin == BT_PRAGMA)
{
if
(pfile->state.in_directive)
return
0;
_cpp_do__Pragma (pfile);
return
1;
}
buf = _cpp_builtin_macro_text (pfile, node);
cpp_push_buffer (pfile, buf, ustrlen (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);
push_token_context (pfile, NULL, _cpp_lex_direct (pfile), 1);
if
(pfile->buffer->cur != pfile->buffer->rlimit)
cpp_error (pfile, DL_ICE,
"invalid built-in macro \"%s\""
,
NODE_NAME (node));
_cpp_pop_buffer (pfile);
return
1;
}
uchar *
cpp_quote_string (dest, src, len)
uchar *dest;
const
uchar *src;
unsigned
int
len;
{
while
(len--)
{
uchar 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_error (pfile, DL_WARNING,
"invalid string literal, ignoring final '\\'"
);
dest--;
}
if
((
size_t
) (BUFF_LIMIT (pfile->u_buff) - dest) < 1)
{
size_t
len_so_far = dest - BUFF_FRONT (pfile->u_buff);
_cpp_extend_buff (pfile, &pfile->u_buff, 1);
dest = BUFF_FRONT (pfile->u_buff) + len_so_far;
}
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_EQ)
*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 = FIRST (context).token++;
else
rhs = *FIRST (context).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_error (pfile, DL_ERROR,
"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);
}
bool
_cpp_arguments_ok (pfile, macro, node, argc)
cpp_reader *pfile;
cpp_macro *macro;
const
cpp_hashnode *node;
unsigned
int
argc;
{
if
(argc == macro->paramc)
return
true
;
if
(argc < macro->paramc)
{
if
(argc + 1 == macro->paramc && macro->variadic)
{
if
(CPP_PEDANTIC (pfile) && ! macro->syshdr)
cpp_error (pfile, DL_PEDWARN,
"ISO C99 requires rest arguments to be used"
);
return
true
;
}
cpp_error (pfile, DL_ERROR,
"macro \"%s\" requires %u arguments, but only %u given"
,
NODE_NAME (node), macro->paramc, argc);
}
else
cpp_error (pfile, DL_ERROR,
"macro \"%s\" passed %u arguments, but takes just %u"
,
NODE_NAME (node), argc, macro->paramc);
return
false
;
}
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;
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);
if
(token->type == CPP_EOF)
{
if
(pfile->context->prev || pfile->state.in_directive)
_cpp_backup_tokens (pfile, 1);
cpp_error (pfile, DL_ERROR,
"unterminated argument list invoking macro \"%s\""
,
NODE_NAME (node));
}
else
{
if
(argc == 1 && macro->paramc == 0 && args[0].count == 0)
argc = 0;
if
(_cpp_arguments_ok (pfile, macro, node, argc))
{
if
(macro->variadic && (argc < macro->paramc
|| (argc == 1 && args[0].count == 0
&& !CPP_OPTION (pfile, std))))
args[macro->paramc - 1].first = NULL;
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);
}
if
(token->type != CPP_EOF || token == &pfile->eof)
{
_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
;
pfile->state.angled_headers =
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_error (pfile, DL_WARNING,
"function-like macro \"%s\" must be used with arguments in traditional C"
,
NODE_NAME (node));
return
0;
}
if
(macro->paramc > 0)
replace_args (pfile, node, macro, (macro_arg *) buff->base);
_cpp_release_buff (pfile, buff);
}
node->flags |= NODE_DISABLED;
macro->used = 1;
if
(macro->paramc == 0)
push_token_context (pfile, node, macro->
exp
.tokens, macro->count);
return
1;
}
return
builtin_macro (pfile, node);
}
static
void
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 *src, *limit;
const
cpp_token **dest, **first;
macro_arg *arg;
_cpp_buff *buff;
total = macro->count;
limit = macro->
exp
.tokens + macro->count;
for
(src = macro->
exp
.tokens; 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->
exp
.tokens && (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->
exp
.tokens; 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->
exp
.tokens && (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
(from == NULL)
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 || pfile->state.directive_wants_padding)
&& src != macro->
exp
.tokens && !(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;
FIRST (context).ptoken = first;
LAST (context).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;
FIRST (context).token = first;
LAST (context).token = first + count;
}
void
_cpp_push_text_context (pfile, macro, start, len)
cpp_reader *pfile;
cpp_hashnode *macro;
const
uchar *start;
size_t
len;
{
cpp_context *context = next_context (pfile);
context->direct_p =
true
;
context->macro = macro;
context->buff = NULL;
CUR (context) = start;
RLIMIT (context) = start + len;
macro->flags |= NODE_DISABLED;
}
static
void
expand_arg (pfile, arg)
cpp_reader *pfile;
macro_arg *arg;
{
unsigned
int
capacity;
bool
saved_warn_trad;
if
(arg->count == 0)
return
;
saved_warn_trad = CPP_WTRADITIONAL (pfile);
CPP_WTRADITIONAL (pfile) = 0;
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);
CPP_WTRADITIONAL (pfile) = saved_warn_trad;
}
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
(FIRST (context).token != LAST (context).token)
{
if
(context->direct_p)
result = FIRST (context).token++;
else
result = *FIRST (context).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
(pfile->state.in_directive && result->type == CPP_COMMENT)
continue
;
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;
{
pfile->buffer->return_at_eof =
true
;
if
(CPP_OPTION (pfile, traditional))
while
(_cpp_read_logical_line_trad (pfile))
;
else
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)
FIRST (pfile->context).token--;
else
FIRST (pfile->context).ptoken--;
}
}
static
bool
warn_of_redefinition (pfile, node, macro2)
cpp_reader *pfile;
const
cpp_hashnode *node;
const
cpp_macro *macro2;
{
const
cpp_macro *macro1;
unsigned
int
i;
if
(node->flags & NODE_WARN)
return
true
;
macro1 = node->value.macro;
if
(macro1->paramc != macro2->paramc
|| macro1->fun_like != macro2->fun_like
|| macro1->variadic != macro2->variadic)
return
true
;
for
(i = 0; i < macro1->paramc; i++)
if
(macro1->params[i] != macro2->params[i])
return
true
;
if
(CPP_OPTION (pfile, traditional))
return
_cpp_expansions_different_trad (macro1, macro2);
if
(macro1->count != macro2->count)
return
true
;
for
(i = 0; i < macro1->count; i++)
if
(!_cpp_equiv_tokens (¯o1->
exp
.tokens[i], ¯o2->
exp
.tokens[i]))
return
true
;
return
false
;
}
void
_cpp_free_definition (h)
cpp_hashnode *h;
{
h->type = NT_VOID;
h->flags &= ~(NODE_BUILTIN | NODE_DISABLED);
}
bool
_cpp_save_parameter (pfile, macro, node)
cpp_reader *pfile;
cpp_macro *macro;
cpp_hashnode *node;
{
if
(node->arg_index)
{
cpp_error (pfile, DL_ERROR,
"duplicate macro parameter \"%s\""
,
NODE_NAME (node));
return
true
;
}
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
false
;
}
static
bool
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
:
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
false
;
case
CPP_NAME:
if
(prev_ident)
{
cpp_error (pfile, DL_ERROR,
"macro parameters must be comma-separated"
);
return
false
;
}
prev_ident = 1;
if
(_cpp_save_parameter (pfile, macro, token->val.node))
return
false
;
continue
;
case
CPP_CLOSE_PAREN:
if
(prev_ident || macro->paramc == 0)
return
true
;
case
CPP_COMMA:
if
(!prev_ident)
{
cpp_error (pfile, DL_ERROR,
"parameter name missing"
);
return
false
;
}
prev_ident = 0;
continue
;
case
CPP_ELLIPSIS:
macro->variadic = 1;
if
(!prev_ident)
{
_cpp_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_error (pfile, DL_PEDWARN,
"anonymous variadic macros were introduced in C99"
);
}
else
if
(CPP_OPTION (pfile, pedantic))
cpp_error (pfile, DL_PEDWARN,
"ISO C does not permit named variadic macros"
);
token = _cpp_lex_token (pfile);
if
(token->type == CPP_CLOSE_PAREN)
return
true
;
case
CPP_EOF:
cpp_error (pfile, DL_ERROR,
"missing ')' in macro parameter list"
);
return
false
;
}
}
}
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;
}
static
bool
create_iso_definition (pfile, macro)
cpp_reader *pfile;
cpp_macro *macro;
{
cpp_token *token;
const
cpp_token *ctoken;
ctoken = _cpp_lex_token (pfile);
if
(ctoken->type == CPP_OPEN_PAREN && !(ctoken->flags & PREV_WHITE))
{
bool
ok = parse_params (pfile, macro);
macro->params = (cpp_hashnode **) BUFF_FRONT (pfile->a_buff);
if
(!ok)
return
false
;
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_error (pfile, DL_PEDWARN,
"ISO C requires whitespace after the macro name"
);
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)
{
cpp_error (pfile, DL_ERROR,
"'#' is not followed by a macro parameter"
);
return
false
;
}
}
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)
{
cpp_error (pfile, DL_ERROR,
"'##' cannot appear at either end of a macro expansion"
);
return
false
;
}
token[-1].flags |= PASTE_LEFT;
}
token = lex_expansion_token (pfile, macro);
}
macro->
exp
.tokens = (cpp_token *) BUFF_FRONT (pfile->a_buff);
macro->count--;
if
(macro->count)
macro->
exp
.tokens[0].flags &= ~PREV_WHITE;
BUFF_FRONT (pfile->a_buff) = (uchar *) ¯o->
exp
.tokens[macro->count];
return
true
;
}
bool
_cpp_create_definition (pfile, node)
cpp_reader *pfile;
cpp_hashnode *node;
{
cpp_macro *macro;
unsigned
int
i;
bool
ok;
macro = (cpp_macro *) _cpp_aligned_alloc (pfile,
sizeof
(cpp_macro));
macro->line = pfile->directive_line;
macro->params = 0;
macro->paramc = 0;
macro->variadic = 0;
macro->used = 0;
macro->count = 0;
macro->fun_like = 0;
macro->syshdr = pfile->map->sysp != 0;
if
(CPP_OPTION (pfile, traditional))
ok = _cpp_create_trad_definition (pfile, macro);
else
{
cpp_token *saved_cur_token = pfile->cur_token;
ok = create_iso_definition (pfile, macro);
saved_cur_token[-1].type = pfile->cur_token[-1].type;
pfile->cur_token = saved_cur_token;
pfile->state.va_args_ok = 0;
}
for
(i = macro->paramc; i-- > 0; )
macro->params[i]->arg_index = 0;
if
(!ok)
return
ok;
if
(node->type == NT_MACRO)
{
if
(CPP_OPTION (pfile, warn_unused_macros))
_cpp_warn_if_unused_macro (pfile, node, NULL);
if
(warn_of_redefinition (pfile, node, macro))
{
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_error_with_line (pfile, DL_PEDWARN,
node->value.macro->line, 0,
"this is the location of the previous definition"
);
}
}
if
(node->type != NT_VOID)
_cpp_free_definition (node);
node->type = NT_MACRO;
node->value.macro = macro;
if
(! ustrncmp (NODE_NAME (node), DSC (
"__STDC_"
)))
node->flags |= NODE_WARN;
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
uchar *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_error (pfile, DL_WARNING,
"macro argument \"%s\" would be stringified in traditional C"
,
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_error (pfile, DL_ICE,
"invalid hash type %d in cpp_macro_definition"
, node->type);
return
0;
}
len = NODE_LEN (node) + 2;
if
(macro->fun_like)
{
len += 4;
for
(i = 0; i < macro->paramc; i++)
len += NODE_LEN (macro->params[i]) + 1;
}
if
(CPP_OPTION (pfile, traditional))
len += _cpp_replacement_text_len (macro);
else
{
for
(i = 0; i < macro->count; i++)
{
cpp_token *token = ¯o->
exp
.tokens[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 = (uchar *) 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
(CPP_OPTION (pfile, traditional))
buffer = _cpp_copy_replacement_text (macro, buffer);
else
if
(macro->count)
{
for
(i = 0; i < macro->count; i++)
{
cpp_token *token = ¯o->
exp
.tokens[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;
}