041c31944c
2000-07-03 Zack Weinberg <zack@wolery.cumb.org> * fix-header.c (struct partial_proto): Remove unnecessary fields. (recognized_extern, recognized_function, read_scan_file): Update for new scheme. (check_protection): It's still a multiple include guard even if it doesn't always trigger. * scan-decls.c (skip_to_closing_brace, scan_decls): Update for new scheme. * scan.h: Declare struct cpp_token. Update prototypes. 2000-07-03 Neil Booth <neilb@earthling.net> Zack Weinberg <zack@wolery.cumb.org> Complete overhaul of the lexer and macro expander. * cpphash.c (object_defn, funct_defn, push_macro_expansion, arg, arglist, argdata, reflist, collect_objlike_expansion, collect_funlike_expansion, collect_params, warn_trad_stringify, trad_stringify, duplicate_arg_p, add_pat, unsafe_chars, macarg, compare_defs, special_symbol, scan_arguments, stringify, funlike_macroexpand, _cpp_quote_string, monthnames): Delete. (cpp_lookup, _cpp_free_definition, dump_funlike_macro, _cpp_create_definition, _cpp_dump_definition, dump_hash_helper): Adjust. (find_param, count_params, parse_define, var_args_str, check_macro_redefinition, save_expansion): New. * cpplex.c (skip_block_comment, skip_line_comment, parse_name, parse_string, output_line_command, trigraph_replace, lex_line, cpp_push_buffer, cpp_pop_buffer, cpp_output_tokens, cpp_scan_buffer_nooutput, cpp_scan_buffer, cpp_free_toklist, cpp_idcmp, _cpp_get_directive_token, _cpp_init_input_buffer, _cpp_skip_rest_of_line): Modify. (maybe_macroexpand, skip_comment, copy_comment, skip_string, find_position, null_warning, bump_column, expand_name_space, pedantic_whitespace, _cpp_output_list, _cpp_slice_toklist, _cpp_squeeze_toklist, _cpp_scan_until, _cpp_skip_hspace, _cpp_parse_name, _cpp_lex_token, cpp_get_non_space_token, _cpp_prescan): Delete. (dump_param_spelling, process_directive, lex_next, is_macro_disabled, stringify_arg, expand_context_stack, output_token, make_string_token, alloc_number_token, special_symbol, duplicate_token, maybe_paste_with_next, can_paste, prevent_macro_expansion, restore_macro_expansion, get_temp_token, release_temp_tokens, quote_string, token_names, token_spellings, _cpp_expand_name_space, _cpp_glue_header_name, _cpp_reserve_name_space, digraph_spellings, trigraph_ok, skip_whitespace, save_comment, placemarker_token, eof_token, cpp_context, macro_args, get_raw_token, parse_arg, parse_args, save_token, push_arg_context, push_macro_context, pop_context, do_pop_context, free_macro_args, _cpp_get_line, _cpp_run_directive): New. * cpplib.c (validate_else, parse_include, push_conditional, pass_thru_directive, read_line_number, parse_ifdef, detect_if_not_defined, _cpp_check_directive, do_define, do_undef, do_include, do_import, do_include_next, do_error, do_warning, do_ident, do_pragma, pragma_dispatch, gcc_pragmas, top_pragmas, do_pragma_gcc, do_pragma_implementation, do_pragma_poison, do_pragma_system_header, do_pragma_dependency, do_sccs, do_ifdef, do_ifndef, do_else, dl_elif, do_endif, _cpp_unwind_if_stack, do_assert, do_unassert, cpp_define, cpp_undef, cpp_assert, cpp_unassert, cpp_defined): Update for new scheme. (strtoul_for_line, get_define_node, dump_macro_name, _cpp_check_linemarker, _cpp_parse_assertion): New. (_cpp_handle_directive, do_pragma_default): Delete. * cpphash.h (struct predicate): Now struct answer. (enum spell_type, struct token_spelling, struct directive, directive_handler): New. Update prototypes. Remove unused macros. * cpplib.h: Update prototypes. Remove unused macros, structure definitions, and fields. * cpperror.c (print_containing_files, v_message): Adjust. * cppexp.c (parse_assertion, lex, parse_escape, _cpp_parse_expr): Adjust. * cppfiles.c (open_include_file, _cpp_execute_include, _cpp_compare_file_date, cpp_read_file, read_include_file): Adjust. * cppinit.c (dump_special_to_buffer): Delete. (append_include_chain, merge_include_chains, cpp_reader_init, cpp_cleanup, initialize_builtins, builtin_array, cpp_start_read, cpp_finish, handle_option, print_help): Adjust. * cppmain.c (main): Adjust. testsuite: 2000-07-03 Zack Weinberg <zack@wolery.cumb.org> * testsuite/gcc.dg/cpp/19951025-1.c: Adjust regexps. * testsuite/gcc.dg/cpp/19990703-1.c: Likewise. * testsuite/gcc.dg/cpp/20000625-1.c: Likewise. * testsuite/gcc.dg/cpp/20000625-2.c: Likewise. * testsuite/gcc.dg/cpp/macro1.c, testsuite/gcc.dg/cpp/paste1.c, testsuite/gcc.dg/cpp/paste2.c, testsuite/gcc.dg/cpp/paste3.c, testsuite/gcc.dg/cpp/paste4.c, testsuite/gcc.dg/cpp/strify1.c, testsuite/gcc.dg/cpp/strify2.c: New tests. From-SVN: r34859
685 lines
18 KiB
C
685 lines
18 KiB
C
/* Part of CPP library. (Macro handling.)
|
|
Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998,
|
|
1999, 2000 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
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by the
|
|
Free Software Foundation; either version 2, or (at your option) any
|
|
later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
In other words, you are welcome to use, share and improve this program.
|
|
You are forbidden to forbid anyone else to use, share and improve
|
|
what you give them. Help stamp out software-hoarding! */
|
|
|
|
#include "config.h"
|
|
#include "system.h"
|
|
#include "cpplib.h"
|
|
#include "hashtab.h"
|
|
#include "cpphash.h"
|
|
|
|
#undef abort
|
|
|
|
/* This is the second argument to eq_HASHNODE. */
|
|
struct hashdummy
|
|
{
|
|
const U_CHAR *name;
|
|
unsigned short length;
|
|
};
|
|
|
|
/* Initial hash table size. (It can grow if necessary - see hashtab.c.) */
|
|
#define HASHSIZE 500
|
|
|
|
static unsigned int hash_HASHNODE PARAMS ((const void *));
|
|
static int eq_HASHNODE PARAMS ((const void *, const void *));
|
|
static void del_HASHNODE PARAMS ((void *));
|
|
static cpp_hashnode *make_HASHNODE PARAMS ((const U_CHAR *, size_t,
|
|
enum node_type, unsigned int));
|
|
static int dump_hash_helper PARAMS ((void **, void *));
|
|
|
|
static void dump_funlike_macro PARAMS ((cpp_reader *, cpp_hashnode *));
|
|
|
|
static const cpp_token *count_params PARAMS ((cpp_reader *,
|
|
const cpp_token *,
|
|
cpp_toklist *));
|
|
static cpp_toklist *parse_define PARAMS((cpp_reader *));
|
|
static int check_macro_redefinition PARAMS((cpp_reader *, cpp_hashnode *hp,
|
|
const cpp_toklist *));
|
|
static int save_expansion PARAMS((cpp_reader *, cpp_toklist *,
|
|
const cpp_token *, const cpp_token *));
|
|
static unsigned int find_param PARAMS ((const cpp_token *,
|
|
const cpp_token *));
|
|
|
|
static const unsigned char var_args_str[] = "__VA_ARGS__";
|
|
|
|
/* Calculate hash of a string of length LEN. */
|
|
unsigned int
|
|
_cpp_calc_hash (str, len)
|
|
const U_CHAR *str;
|
|
size_t len;
|
|
{
|
|
size_t n = len;
|
|
unsigned int r = 0;
|
|
|
|
do
|
|
r = r * 67 + (*str++ - 113);
|
|
while (--n);
|
|
return r + len;
|
|
}
|
|
|
|
/* Calculate hash of a cpp_hashnode structure. */
|
|
static unsigned int
|
|
hash_HASHNODE (x)
|
|
const void *x;
|
|
{
|
|
const cpp_hashnode *h = (const cpp_hashnode *)x;
|
|
return h->hash;
|
|
}
|
|
|
|
/* Compare a cpp_hashnode structure (already in the table) with a
|
|
hashdummy structure (not yet in the table). This relies on the
|
|
rule that the existing entry is the first argument, the potential
|
|
entry the second. It also relies on the comparison function never
|
|
being called except as a direct consequence of a call to
|
|
htab_find(_slot)_with_hash. */
|
|
static int
|
|
eq_HASHNODE (x, y)
|
|
const void *x;
|
|
const void *y;
|
|
{
|
|
const cpp_hashnode *a = (const cpp_hashnode *)x;
|
|
const struct hashdummy *b = (const struct hashdummy *)y;
|
|
|
|
return (a->length == b->length
|
|
&& !ustrncmp (a->name, b->name, a->length));
|
|
}
|
|
|
|
/* Destroy a cpp_hashnode. */
|
|
static void
|
|
del_HASHNODE (x)
|
|
void *x;
|
|
{
|
|
cpp_hashnode *h = (cpp_hashnode *)x;
|
|
|
|
_cpp_free_definition (h);
|
|
free (h);
|
|
}
|
|
|
|
/* Allocate and initialize a cpp_hashnode structure.
|
|
Caller must fill in the value field. */
|
|
|
|
static cpp_hashnode *
|
|
make_HASHNODE (name, len, type, hash)
|
|
const U_CHAR *name;
|
|
size_t len;
|
|
enum node_type type;
|
|
unsigned int hash;
|
|
{
|
|
cpp_hashnode *hp = (cpp_hashnode *) xmalloc (sizeof (cpp_hashnode) + len);
|
|
U_CHAR *p = (U_CHAR *)hp + offsetof (cpp_hashnode, name);
|
|
|
|
hp->type = type;
|
|
hp->length = len;
|
|
hp->hash = hash;
|
|
hp->disabled = 0;
|
|
|
|
memcpy (p, name, len);
|
|
p[len] = 0;
|
|
|
|
return hp;
|
|
}
|
|
|
|
/* Find the hash node for name "name", of length LEN. */
|
|
|
|
cpp_hashnode *
|
|
cpp_lookup (pfile, name, len)
|
|
cpp_reader *pfile;
|
|
const U_CHAR *name;
|
|
int len;
|
|
{
|
|
struct hashdummy dummy;
|
|
cpp_hashnode *new, **slot;
|
|
unsigned int hash;
|
|
|
|
dummy.name = name;
|
|
dummy.length = len;
|
|
hash = _cpp_calc_hash (name, len);
|
|
|
|
slot = (cpp_hashnode **)
|
|
htab_find_slot_with_hash (pfile->hashtab, (void *)&dummy, hash, INSERT);
|
|
if (*slot)
|
|
return *slot;
|
|
|
|
new = make_HASHNODE (name, len, T_VOID, hash);
|
|
new->value.expansion = NULL;
|
|
|
|
*slot = new;
|
|
return new;
|
|
}
|
|
|
|
/* Init the hash table. In here so it can see the hash and eq functions. */
|
|
void
|
|
_cpp_init_macro_hash (pfile)
|
|
cpp_reader *pfile;
|
|
{
|
|
pfile->hashtab = htab_create (HASHSIZE, hash_HASHNODE,
|
|
eq_HASHNODE, del_HASHNODE);
|
|
}
|
|
|
|
/* Free the definition of macro H. */
|
|
|
|
void
|
|
_cpp_free_definition (h)
|
|
cpp_hashnode *h;
|
|
{
|
|
if (h->type == T_MACRO)
|
|
_cpp_free_toklist (h->value.expansion);
|
|
h->value.expansion = NULL;
|
|
}
|
|
|
|
/* Scans for a given token, returning the parameter number if found,
|
|
or 0 if not found. Scans from FIRST to TOKEN - 1 or the first
|
|
CPP_CLOSE_PAREN for TOKEN. */
|
|
static unsigned int
|
|
find_param (first, token)
|
|
const cpp_token *first, *token;
|
|
{
|
|
unsigned int param = 0;
|
|
|
|
for (; first < token && first->type != CPP_CLOSE_PAREN; first++)
|
|
if (first->type == CPP_NAME)
|
|
{
|
|
param++;
|
|
if (first->val.name.len == token->val.name.len
|
|
&& !memcmp (first->val.name.text, token->val.name.text,
|
|
token->val.name.len))
|
|
return param;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Counts the parameters to a function like macro, and saves their
|
|
spellings if necessary. Returns the token that we stopped scanning
|
|
at; if it's type isn't CPP_CLOSE_PAREN there was an error, which
|
|
has been reported. */
|
|
static const cpp_token *
|
|
count_params (pfile, first, list)
|
|
cpp_reader *pfile;
|
|
const cpp_token *first;
|
|
cpp_toklist *list;
|
|
{
|
|
unsigned int params_len = 0, prev_ident = 0;
|
|
unsigned int line = pfile->token_list.line;
|
|
const cpp_token *token, *temp;
|
|
|
|
list->paramc = 0;
|
|
for (token = first;; token++)
|
|
{
|
|
switch (token->type)
|
|
{
|
|
case CPP_EOF:
|
|
cpp_error_with_line (pfile, line, token->col,
|
|
"missing ')' in macro parameter list");
|
|
goto out;
|
|
|
|
case CPP_COMMENT:
|
|
continue; /* Ignore -C comments. */
|
|
|
|
case CPP_NAME:
|
|
if (prev_ident)
|
|
{
|
|
cpp_error_with_line (pfile, line, token->col,
|
|
"macro parameters must be comma-separated");
|
|
goto out;
|
|
}
|
|
|
|
/* Constraint 6.10.3.5 */
|
|
if (token->val.name.len == sizeof (var_args_str) - 1
|
|
&& !ustrncmp (token->val.name.text, var_args_str,
|
|
sizeof (var_args_str) - 1))
|
|
{
|
|
cpp_error_with_line (pfile, line, token->col,
|
|
"\"%s\" is not a valid parameter name",
|
|
var_args_str);
|
|
goto out;
|
|
}
|
|
|
|
params_len += token->val.name.len + 1;
|
|
prev_ident = 1;
|
|
list->paramc++;
|
|
|
|
/* Constraint 6.10.3.6 - duplicate parameter names. */
|
|
if (find_param (first, token))
|
|
{
|
|
cpp_error_with_line (pfile, line, token->col,
|
|
"duplicate macro parameter \"%.*s\"",
|
|
(int) token->val.name.len,
|
|
token->val.name.text);
|
|
goto out;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
cpp_error_with_line (pfile, line, token->col,
|
|
"illegal token in macro parameter list");
|
|
goto out;
|
|
|
|
case CPP_CLOSE_PAREN:
|
|
if (prev_ident || list->paramc == 0)
|
|
goto scanned;
|
|
|
|
/* Fall through to pick up the error. */
|
|
case CPP_COMMA:
|
|
if (!prev_ident)
|
|
{
|
|
cpp_error_with_line (pfile, line, token->col,
|
|
"missing parameter name");
|
|
goto out;
|
|
}
|
|
prev_ident = 0;
|
|
break;
|
|
|
|
case CPP_ELLIPSIS:
|
|
/* Convert ISO-style var_args to named varargs by changing
|
|
the ellipsis into an identifier with name __VA_ARGS__.
|
|
This simplifies other handling. We can safely have its
|
|
text outside list->namebuf because there is no reason to
|
|
extend the size of the list's namebuf (and thus change
|
|
the pointer) in do_define. */
|
|
if (!prev_ident)
|
|
{
|
|
cpp_token *tok = (cpp_token *) token;
|
|
|
|
tok->type = CPP_NAME;
|
|
tok->val.name.len = sizeof (var_args_str) - 1;
|
|
tok->val.name.text = var_args_str; /* Safe. */
|
|
list->paramc++;
|
|
|
|
if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, c99))
|
|
cpp_pedwarn (pfile,
|
|
"C89 does not permit anon varargs macros");
|
|
}
|
|
else if (CPP_PEDANTIC (pfile))
|
|
cpp_pedwarn (pfile,
|
|
"ISO C does not permit named varargs parameters");
|
|
|
|
list->flags |= VAR_ARGS;
|
|
token++;
|
|
if (token->type == CPP_CLOSE_PAREN)
|
|
goto scanned;
|
|
cpp_error_with_line (pfile, line, token->col,
|
|
"')' expected after \"...\"");
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
scanned:
|
|
/* Store the null-terminated parameter spellings of a function, to
|
|
provide pedantic warnings to satisfy 6.10.3.2, or for use when
|
|
dumping macro definitions. */
|
|
if (list->paramc > 0 && pfile->save_parameter_spellings)
|
|
{
|
|
U_CHAR *buf;
|
|
|
|
_cpp_reserve_name_space (list, params_len);
|
|
list->params_len = list->name_used = params_len;
|
|
buf = list->namebuf;
|
|
for (temp = first; temp <= token; temp++)
|
|
if (temp->type == CPP_NAME)
|
|
{
|
|
memcpy (buf, temp->val.name.text, temp->val.name.len);
|
|
buf += temp->val.name.len;
|
|
*buf++ = '\0';
|
|
}
|
|
}
|
|
|
|
out:
|
|
return token;
|
|
}
|
|
|
|
/* Parses a #define directive. Returns null pointer on error. */
|
|
static cpp_toklist *
|
|
parse_define (pfile)
|
|
cpp_reader *pfile;
|
|
{
|
|
const cpp_token *token, *first_param;
|
|
cpp_toklist *list;
|
|
int prev_white = 0;
|
|
|
|
while ((token = cpp_get_token (pfile))->type == CPP_COMMENT)
|
|
prev_white = 1;
|
|
|
|
/* Allocate the expansion's list. It will go in the hash table. */
|
|
list = (cpp_toklist *) xmalloc (sizeof (cpp_toklist));
|
|
_cpp_init_toklist (list, 0);
|
|
first_param = token + 1;
|
|
list->paramc = -1; /* Object-like macro. */
|
|
|
|
if (!prev_white && !(token->flags & PREV_WHITE))
|
|
{
|
|
if (token->type == CPP_OPEN_PAREN)
|
|
{
|
|
token = count_params (pfile, first_param, list);
|
|
if (token->type != CPP_CLOSE_PAREN)
|
|
goto error;
|
|
token++;
|
|
}
|
|
else if (token->type != CPP_EOF)
|
|
cpp_pedwarn (pfile,
|
|
"ISO C requires whitespace after the macro name");
|
|
}
|
|
|
|
if (save_expansion (pfile, list, token, first_param))
|
|
{
|
|
error:
|
|
_cpp_free_toklist (list);
|
|
list = 0;
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
static int
|
|
check_macro_redefinition (pfile, hp, list2)
|
|
cpp_reader *pfile;
|
|
cpp_hashnode *hp;
|
|
const cpp_toklist *list2;
|
|
{
|
|
const cpp_toklist *list1;
|
|
|
|
if (hp->type != T_MACRO)
|
|
return ! pfile->done_initializing;
|
|
|
|
/* Clear the whitespace and BOL flags of the first tokens. They get
|
|
altered during macro expansion, but is not significant here. */
|
|
list1 = hp->value.expansion;
|
|
list1->tokens[0].flags &= ~(PREV_WHITE|BOL);
|
|
list2->tokens[0].flags &= ~(PREV_WHITE|BOL);
|
|
|
|
if (!_cpp_equiv_toklists (list1, list2))
|
|
return 0;
|
|
|
|
if (CPP_OPTION (pfile, pedantic)
|
|
&& list1->paramc > 0
|
|
&& (list1->params_len != list2->params_len
|
|
|| memcmp (list1->namebuf, list2->namebuf, list1->params_len)))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* Copy the tokens of the expansion. Change the type of macro
|
|
arguments from CPP_NAME to CPP_MACRO_ARG. Remove #'s that
|
|
represent stringification, flagging the CPP_MACRO_ARG it operates
|
|
on STRINGIFY. Remove ##'s, flagging the token on its immediate
|
|
left PASTE_LEFT. Returns non-zero on error. */
|
|
static int
|
|
save_expansion (pfile, list, first, first_param)
|
|
cpp_reader *pfile;
|
|
cpp_toklist *list;
|
|
const cpp_token *first;
|
|
const cpp_token *first_param;
|
|
{
|
|
const cpp_token *token;
|
|
cpp_token *dest;
|
|
unsigned int len, ntokens;
|
|
unsigned char *buf;
|
|
|
|
/* Count tokens in expansion. We drop paste tokens, and stringize
|
|
tokens, so don't count them. */
|
|
ntokens = len = 0;
|
|
for (token = first; token->type != CPP_EOF; token++)
|
|
{
|
|
const char *msg;
|
|
|
|
if (token->type == CPP_PASTE)
|
|
{
|
|
/* Token-paste ##, but is a normal token if traditional. */
|
|
if (! CPP_TRADITIONAL (pfile))
|
|
{
|
|
msg = "\"##\" cannot appear at either end of a macro expansion";
|
|
/* Constraint 6.10.3.3.1 */
|
|
if (token == first || token[1].type == CPP_EOF)
|
|
goto error;
|
|
continue;
|
|
}
|
|
}
|
|
else if (token->type == CPP_HASH)
|
|
{
|
|
/* Stringifying #, but is a normal character if traditional,
|
|
or in object-like macros. Constraint 6.10.3.2.1. */
|
|
if (list->paramc >= 0 && ! CPP_TRADITIONAL (pfile))
|
|
{
|
|
if (token[1].type == CPP_NAME
|
|
&& find_param (first_param, token + 1))
|
|
continue;
|
|
if (! CPP_OPTION (pfile, lang_asm))
|
|
{
|
|
msg = "'#' is not followed by a macro parameter";
|
|
error:
|
|
cpp_error_with_line (pfile, token->line, token->col, msg);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
ntokens++;
|
|
if (token_spellings[token->type].type > SPELL_NONE)
|
|
len += token->val.name.len;
|
|
}
|
|
|
|
/* Allocate space to hold the tokens. Empty expansions are stored
|
|
as a single placemarker token. */
|
|
if (ntokens == 0)
|
|
ntokens++;
|
|
_cpp_expand_token_space (list, ntokens);
|
|
if (len > 0)
|
|
_cpp_expand_name_space (list, len);
|
|
|
|
dest = list->tokens;
|
|
buf = list->namebuf + list->name_used;
|
|
for (token = first; token->type != CPP_EOF; token++)
|
|
{
|
|
unsigned int param_no;
|
|
|
|
switch (token->type)
|
|
{
|
|
case CPP_NAME:
|
|
if (list->paramc == -1)
|
|
break;
|
|
|
|
/* Check if the name is a macro parameter. */
|
|
param_no = find_param (first_param, token);
|
|
if (param_no == 0)
|
|
break;
|
|
dest->val.aux = param_no - 1;
|
|
|
|
dest->type = CPP_MACRO_ARG;
|
|
if (token[-1].type == CPP_HASH && ! CPP_TRADITIONAL (pfile))
|
|
dest->flags = token[-1].flags | STRINGIFY_ARG;
|
|
else
|
|
dest->flags = token->flags; /* Particularly PREV_WHITE. */
|
|
|
|
if ((int) param_no == list->paramc && list->flags & VAR_ARGS
|
|
&& dest != list->tokens && dest[-1].flags & PASTE_LEFT)
|
|
dest[-1].flags |= GNU_VARARGS;
|
|
dest++;
|
|
continue;
|
|
|
|
case CPP_PASTE:
|
|
if (! CPP_TRADITIONAL (pfile))
|
|
{
|
|
dest[-1].flags |= PASTE_LEFT;
|
|
continue;
|
|
}
|
|
break;
|
|
|
|
case CPP_HASH:
|
|
/* Stringifying #. Constraint 6.10.3.2.1 */
|
|
if (list->paramc >= 0 && ! CPP_TRADITIONAL (pfile)
|
|
&& token[1].type == CPP_NAME
|
|
&& find_param (first_param, token + 1))
|
|
continue;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* Copy the token. */
|
|
*dest = *token;
|
|
if (token_spellings[token->type].type > SPELL_NONE)
|
|
{
|
|
memcpy (buf, token->val.name.text, token->val.name.len);
|
|
dest->val.name.text = buf;
|
|
buf += dest->val.name.len;
|
|
}
|
|
dest++;
|
|
}
|
|
|
|
if (dest == list->tokens)
|
|
{
|
|
dest->type = CPP_PLACEMARKER;
|
|
dest->flags = 0;
|
|
}
|
|
|
|
list->tokens_used = ntokens;
|
|
list->line = pfile->token_list.line;
|
|
list->file = pfile->token_list.file;
|
|
list->name_used = len;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
_cpp_create_definition (pfile, hp)
|
|
cpp_reader *pfile;
|
|
cpp_hashnode *hp;
|
|
{
|
|
cpp_toklist *list;
|
|
|
|
list = parse_define (pfile);
|
|
if (!list)
|
|
return 0;
|
|
|
|
/* Check for a redefinition. Redefinition of a macro is allowed if
|
|
and only if the old and new definitions are the same.
|
|
(6.10.3 paragraph 2). */
|
|
|
|
if (hp->type != T_VOID)
|
|
{
|
|
if (!check_macro_redefinition (pfile, hp, list))
|
|
{
|
|
cpp_pedwarn (pfile, "\"%s\" redefined", hp->name);
|
|
if (pfile->done_initializing && hp->type == T_MACRO)
|
|
cpp_pedwarn_with_file_and_line (pfile,
|
|
hp->value.expansion->file,
|
|
hp->value.expansion->line, 1,
|
|
"this is the location of the previous definition");
|
|
}
|
|
_cpp_free_definition (hp);
|
|
}
|
|
|
|
/* Enter definition in hash table. */
|
|
hp->type = T_MACRO;
|
|
hp->value.expansion = list;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* Dump the definition of macro MACRO on stdout. The format is suitable
|
|
to be read back in again. */
|
|
|
|
void
|
|
_cpp_dump_definition (pfile, hp)
|
|
cpp_reader *pfile;
|
|
cpp_hashnode *hp;
|
|
{
|
|
CPP_RESERVE (pfile, hp->length + sizeof "#define ");
|
|
CPP_PUTS_Q (pfile, "#define ", sizeof "#define " - 1);
|
|
CPP_PUTS_Q (pfile, hp->name, hp->length);
|
|
|
|
if (hp->type == T_MACRO)
|
|
{
|
|
if (hp->value.expansion->paramc >= 0)
|
|
dump_funlike_macro (pfile, hp);
|
|
else
|
|
{
|
|
const cpp_toklist *list = hp->value.expansion;
|
|
list->tokens[0].flags &= ~BOL;
|
|
list->tokens[0].flags |= PREV_WHITE;
|
|
_cpp_dump_list (pfile, list, list->tokens, 1);
|
|
}
|
|
}
|
|
else
|
|
cpp_ice (pfile, "invalid hash type %d in dump_definition", hp->type);
|
|
|
|
if (CPP_BUFFER (pfile) == 0 || ! pfile->done_initializing)
|
|
CPP_PUTC (pfile, '\n');
|
|
}
|
|
|
|
static void
|
|
dump_funlike_macro (pfile, node)
|
|
cpp_reader *pfile;
|
|
cpp_hashnode *node;
|
|
{
|
|
int i = 0;
|
|
const cpp_toklist * list = node->value.expansion;
|
|
const U_CHAR *param;
|
|
|
|
param = list->namebuf;
|
|
CPP_PUTC_Q (pfile, '(');
|
|
for (i = 0; i++ < list->paramc;)
|
|
{
|
|
unsigned int len;
|
|
|
|
len = ustrlen (param);
|
|
CPP_PUTS (pfile, param, len);
|
|
if (i < list->paramc)
|
|
CPP_PUTS(pfile, ", ", 2);
|
|
else if (list->flags & VAR_ARGS)
|
|
{
|
|
if (!ustrcmp (param, var_args_str))
|
|
pfile->limit -= sizeof (var_args_str) - 1;
|
|
CPP_PUTS (pfile, "...", 3);
|
|
}
|
|
param += len + 1;
|
|
}
|
|
CPP_PUTC (pfile, ')');
|
|
list->tokens[0].flags &= ~BOL;
|
|
list->tokens[0].flags |= PREV_WHITE;
|
|
_cpp_dump_list (pfile, list, list->tokens, 1);
|
|
}
|
|
|
|
/* Dump out the hash table. */
|
|
static int
|
|
dump_hash_helper (h, p)
|
|
void **h;
|
|
void *p;
|
|
{
|
|
cpp_hashnode *hp = (cpp_hashnode *)*h;
|
|
cpp_reader *pfile = (cpp_reader *)p;
|
|
|
|
if (hp->type == T_MACRO)
|
|
_cpp_dump_definition (pfile, hp);
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
_cpp_dump_macro_hash (pfile)
|
|
cpp_reader *pfile;
|
|
{
|
|
htab_traverse (pfile->hashtab, dump_hash_helper, pfile);
|
|
}
|