aboutsummaryrefslogtreecommitdiff
path: root/gcc/cppmacro.c
diff options
context:
space:
mode:
authorNeil Booth <neilb@earthling.net>2000-10-28 17:59:06 +0000
committerNeil Booth <neil@gcc.gnu.org>2000-10-28 17:59:06 +0000
commit93c80368d9a16c073f2b930bef4232661971765f (patch)
treeb1f50a88de9fbdd6a784d0c03fa8cd31e4ac5916 /gcc/cppmacro.c
parentde48b52da8468f94c0bdffc11fa7e8fe49b4ba66 (diff)
downloadgcc-93c80368d9a16c073f2b930bef4232661971765f.zip
gcc-93c80368d9a16c073f2b930bef4232661971765f.tar.gz
gcc-93c80368d9a16c073f2b930bef4232661971765f.tar.bz2
New macro expander.
2000-10-28 Neil Booth <neilb@earthling.net> New macro expander. * cpplib.c (struct answer): New. (struct if_stack): Use cpp_lexer_pos rather than line and col. Rename cmacro mi_cmacro. (struct directive, KANDR, STDC89, EXTENSION, COND, IF_COND, INCL, IN_I): New directive and flags. (skip_rest_of_line, check_eol, run_directive, glue_header_name, parse_answer, parse_assertion, find_answer): New functions. (parse_ifdef, detect_if_not_defined, validate_else): Remove. (lex_macro_node): New function to replace parse_ifdef and get_define_node. (_cpp_handle_directive): New function, combines _cpp_check_directive and _cpp_check_linemarker. (do_define, do_undef, parse_include, do_include, do_import, do_include_next, read_line_number, do_line, do_ident, do_pragma, do_pragma_once, do_pragma_poison, do_pragma_dependency): Update for new token getting interface. (do_ifdef, do_ifndef, do_if, do_else, do_endif, push_conditional) : Update for new multiple-include optimisation technique. (do_elif): Don't forget to invalidate controlling macros. (unwind_if_stack, cpp_defined, cpp_push_buffer, cpp_pop_buffer): Update. (parse_assertion, parse_answer, find_answer, _cpp_test_assertion): Functions to handle assertions with the new token interface. (do_assert, do_unassert): Use them. (cpp_define, _cpp_define_builtin, cpp_undef, cpp_assert, cpp_unassert): Use run_directive. (_cpp_init_stacks): Register directive names. Don't register special nodes. * cpperror.c (print_containing_files, _cpp_begin_message): Update to new position recording regime. (cpp_ice, cpp_fatal, cpp_error, cpp_error_with_line, cpp_warning, cpp_warning_with_line, cpp_pedwarn, cpp_pedwarn_with_line, cpp_pedwarn_with_file_and_line): Update for _cpp_begin_message changes. (cpp_type2name): Move to cpplex.c. * cppexp.c (parse_charconst): spec_nodes is no longer a pointer. (parse_defined): Update to handle new multiple include optimisation method. Remove poisoned identifier warning. (parse_assertion, TYPE_NAME): Delete. (lex): Update for multiple include optimisation, removal of CPP_DEFINED, to use _cpp_test_assertion for assertions and cpp_token_as_text. (_cpp_parse_expr): Update for MI optimisation, and to use op_as_text. (op_as_text): New function, to wrap cpp_token_as_text. * cppfiles.c (stack_include_file, _cpp_pop_file_buffer): Update for MI optimisation. (_cpp_execute_include): Take a token rather than 3 arguments. Fix segfault on diagnostic. (_cpp_compare_file_date): Take a token rather than 3 args. (cpp_read_file): Work correctly for zero-length files. * cpphash.c (_cpp_init_macros, _cpp_cleanup_macros): Rename _cpp_init_hashtable and _cpp_cleanup_hashtable. (cpp_lookup): Place identifiers at front of identifier pool for _cpp_lookup_with_hash. (_cpp_lookup_with_hash): Require identifiers to be at the front of the identifier pool. Commit the memory if not already in the hash table. * cppinit.c (cpp_reader_init): Move cpp_init_completed test to top. Initialise various members of cpp_reader, memory pools, and the special nodes. (cpp_printer_init): Delete. (cpp_cleanup): Update. (struct builtin, builtin_array, initialize_builtins): Update for new hashnode definition and builtin handling. (cpp_start_read, cpp_finish): Don't take or initialise a printer. Update. * cpplib.h (cpp_printer, cpp_toklist, CPP_DEFINED, BOL, PASTED, VAR_ARGS, BEG_OF_FILE, IN_DIRECTIVE, KNOWN_DIRECTIVE, T_VOID, T_SPECLINE, T_DATE, T_FILE, T_BASE_FILE, T_INCLUDE_LEVEL, T_TIME, T_STDC, T_OPERATOR, T_POISON, T_MACRO, T_ASSERTION): Delete. (struct cpp_pool, struct cpp_macro, struct cpp_lexer_pos, struct cpp_lookahead, CPP_DHASH, enum mi_state, enum mi_ind, NO_EXPAND, VARARGS_FIRST, struct cpp_token_with_pos, struct toklist, struct cpp_context, struct specnodes, TOKEN_LOOKAHEAD, TOKEN_BUFFSIZE, NODE_OPERATOR, NODE_POISONED, NODE_BUILTIN, NODE_DIAGNOSTIC, NT_VOID, NT_MACRO, NT_ASSERTION, enum builtin_type, cpp_can_paste): New. (struct cpp_token): Delete line and col members. (struct cpp_buffer): New member output_lineno. (struct lexer_state): Delete indented, in_lex_line, seen_dot. Add va_args_ok, poisoned_ok, prevent_expansion, parsing_args. (struct cpp_reader): New members lexer_pos, macro_pos, directive_pos, ident_pool, temp_string_pool, macro_pool, argument_pool, string_pool, base_context, context, directive, mi_state, mi_if_not_defined, mi_lexed, mi_cmacro, mi_ind_cmacro, la_read, la_write, la_unused, mlstring_pos, macro_buffer, macro_buffer_len. Delete members mls_line, mls_column, token_list, potential_control_macro, temp_tokens, temp_cap, temp_alloced, temp_used, first_directive_token, context_cap, cur_context, no_expand_level, paste_level, contexts, args, save_parameter_spellings, need_newline, . Change type of date, time and spec_nodes members. Change prototypes for include and ident callbacks. (struct cpp_hashnode): Change type of name. Remove union members expansion and code. Add members macro, operator and builtin. (cpp_token_len, cpp_token_as_text, cpp_spell_token, cpp_start_read, cpp_finish, cpp_avoid_paste, cpp_get_token, cpp_get_line, cpp_get_output_line, cpp_macro_definition, cpp_start_lookahead, cpp_stop_lookahead): New prototypes. (cpp_printer_init, cpp_dump_definition): Delete prototypes. (U_CHAR, U, ustrcmp, ustrncmp, ustrlen, uxstrdup, ustrchr, ufputs): Move from cpphash.h. * cpphash.h (U_CHAR, U, ustrcmp, ustrncmp, ustrlen, uxstrdup, ustrchr, ufputs): Move to cpplib.h. (enum spell_type, struct token_spelling, _cpp_token_spellings, TOKEN_SPELL, TOKEN_NAME, struct answer, FREE_ANSWER, KANDR, STDC89, EXTENSION, COND, EXPAND, INCL, COMMENTS, IN_I, struct directive, directive_handler, struct spec_nodes, _cpp_digraph_spellings, _cpp_free_temp_tokens, _cpp_init_input_buffer, _cpp_grow_token_buffer, _cpp_init_toklist, _cpp_clear_toklist, _cpp_expand_token_space, _cpp_expand_name_space, _cpp_equiv_tokens, _cpp_equiv_toklists, _cpp_process_directive, _cpp_run_directive, _cpp_get_line, _cpp_get_raw_token, _cpp_glue_header_name, _cpp_can_paste, _cpp_check_directive, _cpp_check_linemarker, _cpp_parse_assertion, _cpp_find_answer): Delete. (VALID_SIGN, ALIGN, POOL_FRONT, POOL_LIMIT, POOL_BASE, POOL_SIZE, POOL_USED, POOL_COMMIT, struct cpp_chunk, _cpp_lex_token, _cpp_init_pool, _cpp_free_pool, _cpp_pool_reserve, _cpp_pool_alloc, _cpp_next_chunk, _cpp_lock_pool, _cpp_unlock_pool, _cpp_test_assertion, _cpp_handle_directive, DSC): New. (struct include_file): New member defined. (DO_NOT_REREAD, _cpp_begin_message, _cpp_execute_include, _cpp_compare_file_date): Update. (_cpp_pop_context, _cpp_get_token, _cpp_free_lookaheads, _cpp_push_token): New. (_cpp_init_macros, _cpp_cleanup_macros): Rename to _cpp_init_hashtable, _cpp_cleanup_hashtable. * Makefile.in: Remove cppoutput.c. * cppoutput.c: Delete * fixheader.c (read_scan_file): Update for new cpp_get_token prototype. (recognized_function): New argument LINE. * scan-decls.c (skip_to_closing_brace, scan_decls): Update for new cpp_get_token prototype. * scan.h (recognized_function): Update prototype. * po/POTFILES.in: Remove cppoutput.c. From-SVN: r37098
Diffstat (limited to 'gcc/cppmacro.c')
-rw-r--r--gcc/cppmacro.c1891
1 files changed, 1473 insertions, 418 deletions
diff --git a/gcc/cppmacro.c b/gcc/cppmacro.c
index 321b318..58d3020 100644
--- a/gcc/cppmacro.c
+++ b/gcc/cppmacro.c
@@ -1,4 +1,4 @@
-/* Part of CPP library. (Macro handling.)
+/* Part of CPP library. (Macro and #define handling.)
Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998,
1999, 2000 Free Software Foundation, Inc.
Written by Per Bothner, 1994.
@@ -25,573 +25,1521 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "config.h"
#include "system.h"
+#include "intl.h" /* for _("<command line>") below. */
#include "cpplib.h"
#include "cpphash.h"
-/* Stores basic information about a macro, before it is allocated. */
-struct macro_info
+struct cpp_macro
{
- const cpp_token *first_param; /* First parameter token. */
- const cpp_token *first; /* First expansion token. */
- unsigned int paramlen; /* Length of parameter names. */
- unsigned int len; /* Length of token strings. */
- unsigned int ntokens; /* Number of tokens in expansion. */
- short paramc; /* Number of parameters. */
- unsigned char flags;
+ cpp_hashnode **params; /* Parameters, if any. */
+ cpp_token *expansion; /* First token of replacement list. */
+ const char *file; /* Defined in file name. */
+ unsigned int line; /* Starting line number. */
+ unsigned int count; /* Number of tokens in expansion. */
+ unsigned short paramc; /* Number of parameters. */
+ unsigned int fun_like : 1; /* If a function-like macro. */
+ unsigned int var_args : 1; /* If a variable-args macro. */
+ unsigned int disabled : 1; /* If macro is disabled. */
+};
+
+typedef struct macro_arg macro_arg;
+struct macro_arg
+{
+ cpp_token *first; /* First token in unexpanded argument. */
+ cpp_token *expanded; /* Macro-expanded argument. */
+ cpp_token *stringified; /* Stringified argument. */
+ unsigned int count; /* # of tokens in argument. */
+ unsigned int expanded_count; /* # of tokens in expanded argument. */
};
-static void count_params PARAMS ((cpp_reader *, struct macro_info *));
-static int is__va_args__ PARAMS ((cpp_reader *, const cpp_token *));
-
-static int parse_define PARAMS((cpp_reader *, struct macro_info *));
-static int check_macro_redefinition PARAMS((cpp_reader *, cpp_hashnode *hp,
- const cpp_toklist *));
-static const cpp_toklist * save_expansion PARAMS((cpp_reader *,
- struct macro_info *));
-static unsigned int find_param PARAMS ((const cpp_token *,
- const cpp_token *));
-static cpp_toklist * alloc_macro PARAMS ((cpp_reader *, struct macro_info *));
+/* Macro expansion. */
+
+static void lock_pools PARAMS ((cpp_reader *));
+static void unlock_pools PARAMS ((cpp_reader *));
+static int enter_macro_context PARAMS ((cpp_reader *, cpp_token *));
+static void builtin_macro PARAMS ((cpp_reader *, cpp_token *));
+static cpp_context *push_arg_context PARAMS ((cpp_reader *, macro_arg *));
+static enum cpp_ttype parse_arg PARAMS ((cpp_reader *, macro_arg *, int));
+static macro_arg *parse_args PARAMS ((cpp_reader *, const cpp_hashnode *));
+static cpp_context *next_context PARAMS ((cpp_reader *));
+static void expand_arg PARAMS ((cpp_reader *, macro_arg *));
+static unsigned char *quote_string PARAMS ((unsigned char *,
+ const unsigned char *,
+ unsigned int));
+static void make_string_token PARAMS ((cpp_pool *, cpp_token *,
+ const U_CHAR *, unsigned int));
+static void make_number_token PARAMS ((cpp_reader *, cpp_token *, int));
+static void stringify_arg PARAMS ((cpp_reader *, macro_arg *));
+static void paste_all_tokens PARAMS ((cpp_reader *, cpp_token *));
+static void paste_payloads PARAMS ((cpp_reader *, cpp_token *,
+ const cpp_token *));
+static int funlike_invocation_p PARAMS ((cpp_reader *, const cpp_hashnode *,
+ struct toklist *));
+static void replace_args PARAMS ((cpp_reader *, cpp_macro *, macro_arg *,
+ struct toklist *));
+
+/* Lookaheads. */
+
+static void save_lookahead_token PARAMS ((cpp_reader *, const cpp_token *));
+static void take_lookahead_token PARAMS ((cpp_reader *, cpp_token *));
+static void release_lookahead PARAMS ((cpp_reader *));
+static cpp_lookahead *alloc_lookahead PARAMS ((cpp_reader *));
+static void free_lookahead PARAMS ((cpp_lookahead *));
+
+/* #define directive parsing and handling. */
+
+static cpp_token *lex_expansion_token PARAMS ((cpp_reader *, cpp_macro *));
+static int check_macro_redefinition PARAMS ((cpp_reader *,
+ 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 struct macro_info *,
+ const cpp_macro *,
const cpp_string *));
-/* These are all the tokens that can have something pasted after them.
- Comma is included in the list only to support the GNU varargs extension
- (where you write a ## b and a disappears if b is an empty rest argument).
- CPP_OTHER is included because of Objective C's use of '@'. */
-#define CAN_PASTE_AFTER(type) \
-((type) <= CPP_LAST_EQ || (type) == CPP_COLON || (type) == CPP_HASH \
- || (type) == CPP_DEREF || (type) == CPP_DOT || (type) == CPP_NAME \
- || (type) == CPP_INT || (type) == CPP_FLOAT || (type) == CPP_NUMBER \
- || (type) == CPP_MACRO_ARG || (type) == CPP_PLACEMARKER \
- || (type) == CPP_COMMA || (type) == CPP_OTHER)
-
-/* 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 || first->type == CPP_DEFINED)
+/* Allocates a buffer to hold a token's TEXT, and converts TOKEN to a
+ CPP_STRING token containing TEXT in quoted form. */
+static void
+make_string_token (pool, token, text, len)
+ cpp_pool *pool;
+ cpp_token *token;
+ const U_CHAR *text;
+ unsigned int len;
+{
+ U_CHAR *buf = _cpp_pool_alloc (pool, len * 4);
+
+ token->type = CPP_STRING;
+ token->val.str.text = buf;
+ token->val.str.len = quote_string (buf, text, len) - buf;
+ token->flags = 0;
+}
+
+/* Allocates and converts a temporary token to a CPP_NUMBER token,
+ evaluating to NUMBER. */
+static void
+make_number_token (pfile, token, number)
+ cpp_reader *pfile;
+ cpp_token *token;
+ int number;
+{
+ unsigned char *buf = _cpp_pool_alloc (pfile->string_pool, 20);
+
+ sprintf ((char *) buf, "%d", number);
+ token->type = CPP_NUMBER;
+ token->val.str.text = buf;
+ token->val.str.len = ustrlen (buf);
+ token->flags = 0;
+}
+
+static const char * const monthnames[] =
+{
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+/* Handle builtin macros like __FILE__. */
+static void
+builtin_macro (pfile, token)
+ cpp_reader *pfile;
+ cpp_token *token;
+{
+ unsigned char flags = token->flags & PREV_WHITE;
+ cpp_hashnode *node = token->val.node;
+ cpp_buffer *ip;
+
+ switch (node->value.builtin)
+ {
+ case BT_FILE:
+ case BT_BASE_FILE:
{
- param++;
- if (first->val.node == token->val.node)
- return param;
+ const char *file;
+
+ ip = CPP_BUFFER (pfile);
+ if (ip == 0)
+ file = "";
+ else
+ {
+ if (node->value.builtin == BT_BASE_FILE)
+ while (CPP_PREV_BUFFER (ip) != NULL)
+ ip = CPP_PREV_BUFFER (ip);
+
+ file = ip->nominal_fname;
+ }
+ make_string_token (pfile->string_pool, token,
+ (U_CHAR *) file, strlen (file));
}
+ break;
+
+ case BT_INCLUDE_LEVEL:
+ /* pfile->include_depth counts the primary source as level 1,
+ but historically __INCLUDE_DEPTH__ has called the primary
+ source level 0. */
+ make_number_token (pfile, token, pfile->include_depth - 1);
+ break;
+
+ case BT_SPECLINE:
+ /* If __LINE__ is embedded in a macro, it must expand to the
+ line of the macro's invocation, not its definition.
+ Otherwise things like assert() will not work properly. */
+ make_number_token (pfile, token, cpp_get_line (pfile)->line);
+ break;
+
+ case BT_STDC:
+ {
+ int stdc = 1;
+
+#ifdef STDC_0_IN_SYSTEM_HEADERS
+ if (CPP_IN_SYSTEM_HEADER (pfile)
+ && pfile->spec_nodes.n__STRICT_ANSI__->type == T_VOID)
+ stdc = 0;
+#endif
+ make_number_token (pfile, token, stdc);
+ }
+ break;
- return 0;
+ case BT_DATE:
+ case BT_TIME:
+ if (pfile->date.type == CPP_EOF)
+ {
+ /* Allocate __DATE__ and __TIME__ from permanent storage,
+ and save them in pfile so we don't have to do this again.
+ We don't generate these strings at init time because
+ time() and localtime() are very slow on some systems. */
+ time_t tt = time (NULL);
+ struct tm *tb = localtime (&tt);
+
+ make_string_token (&pfile->ident_pool, &pfile->date,
+ DSC("Oct 11 1347"));
+ make_string_token (&pfile->ident_pool, &pfile->time,
+ DSC("12:34:56"));
+
+ sprintf ((char *) pfile->date.val.str.text, "%s %2d %4d",
+ monthnames[tb->tm_mon], tb->tm_mday, tb->tm_year + 1900);
+ sprintf ((char *) pfile->time.val.str.text, "%02d:%02d:%02d",
+ tb->tm_hour, tb->tm_min, tb->tm_sec);
+ }
+ *token = node->value.builtin == BT_DATE ? pfile->date: pfile->time;
+ break;
+
+ default:
+ cpp_ice (pfile, "invalid builtin macro \"%s\"", node->name);
+ break;
+ }
+
+ token->flags = flags;
}
-/* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the
- replacement list of a variable-arguments macro. TOKEN is assumed
- to be of type CPP_NAME. */
-static int
-is__va_args__ (pfile, token)
+/* Used by cpperror.c to obtain the correct line and column to report
+ in a diagnostic. */
+const cpp_lexer_pos *
+cpp_get_line (pfile)
cpp_reader *pfile;
- const cpp_token *token;
{
- if (!CPP_PEDANTIC (pfile)
- || token->val.node != pfile->spec_nodes->n__VA_ARGS__)
- return 0;
+ /* Within a macro expansion, return the position of the outermost
+ invocation. */
+ if (pfile->context->prev)
+ return &pfile->macro_pos;
+ return &pfile->lexer_pos;
+}
- cpp_pedwarn_with_line (pfile, token->line, token->col,
- "\"%s\" is only valid in the replacement list of a function-like macro",
- token->val.node->name);
- return 1;
+static void
+lock_pools (pfile)
+ cpp_reader *pfile;
+{
+ _cpp_lock_pool (&pfile->temp_string_pool);
+ _cpp_lock_pool (&pfile->argument_pool);
}
-/* Counts the parameters to a function-like macro, the length of their
- null-terminated names, and whether the macro is a variable-argument
- one. FIRST is the token immediately after the open parenthesis,
- INFO stores the data.
+static void
+unlock_pools (pfile)
+ cpp_reader *pfile;
+{
+ _cpp_unlock_pool (&pfile->temp_string_pool);
+ _cpp_unlock_pool (&pfile->argument_pool);
+}
- On success, info->first is updated to the token after the closing
- parenthesis, i.e. the first token of the expansion. Otherwise
- there was an error, which has been reported. */
static void
-count_params (pfile, info)
+paste_payloads (pfile, lhs, rhs)
cpp_reader *pfile;
- struct macro_info *info;
+ cpp_token *lhs;
+ const cpp_token *rhs;
{
- unsigned int prev_ident = 0;
- const cpp_token *token;
+ unsigned int total_len = cpp_token_len (lhs) + cpp_token_len (rhs);
+ unsigned char *result, *end;
+ cpp_pool *pool;
+
+ pool = lhs->type == CPP_NAME ? &pfile->ident_pool: pfile->string_pool;
+ result = _cpp_pool_alloc (pool, total_len + 1);
- info->paramc = 0;
- info->paramlen = 0;
- info->flags = 0;
- info->first = info->first_param; /* Not a ')' indicating success. */
+ /* Paste the spellings and null terminate. */
+ end = cpp_spell_token (pfile, rhs, cpp_spell_token (pfile, lhs, result));
+ *end = '\0';
+ total_len = end - result;
- for (token = info->first_param;; token++)
+ if (lhs->type == CPP_NAME)
{
- switch (token->type)
+ lhs->val.node = cpp_lookup (pfile, result, total_len);
+ if (lhs->val.node->flags & NODE_OPERATOR)
{
- default:
- cpp_error_with_line (pfile, token->line, token->col,
- "token may not appear in macro parameter list");
- return;
-
- case CPP_EOF:
- missing_paren:
- cpp_error_with_line (pfile, token->line, token->col,
- "missing ')' in macro parameter list");
- return;
+ lhs->flags |= NAMED_OP;
+ lhs->type = lhs->val.node->value.operator;
+ }
+ }
+ else
+ {
+ lhs->val.str.text = result;
+ lhs->val.str.len = total_len;
+ }
+}
- case CPP_COMMENT:
- continue; /* Ignore -C comments. */
+/* 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;
+ unsigned int len;
+{
+ while (len--)
+ {
+ U_CHAR c = *src++;
- case CPP_DEFINED: /* 'defined' may be used as a macro
- parameter name. */
- case CPP_NAME:
- if (prev_ident)
+ if (c == '\\' || c == '"')
+ {
+ *dest++ = '\\';
+ *dest++ = c;
+ }
+ else
+ {
+ if (ISPRINT (c))
+ *dest++ = c;
+ else
{
- cpp_error_with_line (pfile, token->line, token->col,
- "macro parameters must be comma-separated");
- return;
+ sprintf ((char *) dest, "\\%03o", c);
+ dest += 4;
}
+ }
+ }
- /* Constraint 6.10.3.5 */
- if (is__va_args__ (pfile, token))
- return;
+ return dest;
+}
- /* Constraint 6.10.3.6 - duplicate parameter names. */
- if (find_param (info->first, token))
- {
- cpp_error_with_line (pfile, token->line, token->col,
- "duplicate macro parameter \"%s\"",
- token->val.node->name);
- return;
- }
+/* Convert a token sequence to a single string token according to the
+ rules of the ISO C #-operator. */
+static void
+stringify_arg (pfile, arg)
+ cpp_reader *pfile;
+ macro_arg *arg;
+{
+ cpp_pool *pool = pfile->string_pool;
+ unsigned char *start = POOL_FRONT (pool);
+ unsigned int i, escape_it, total_len = 0, backslash_count = 0;
+ unsigned int prev_white = 0;
- prev_ident = 1;
- info->paramc++;
- info->paramlen += token->val.node->length + 1;
- continue;
+ /* Loop, reading in the argument's tokens. */
+ for (i = 0; i < arg->count; i++)
+ {
+ unsigned char *dest;
+ const cpp_token *token = &arg->first[i];
+ unsigned int len = cpp_token_len (token);
- case CPP_CLOSE_PAREN:
- if (prev_ident || info->paramc == 0)
- break;
+ escape_it = (token->type == CPP_STRING || token->type == CPP_WSTRING
+ || token->type == CPP_CHAR || token->type == CPP_WCHAR
+ || token->type == CPP_OSTRING);
- /* Fall through to pick up the error. */
- case CPP_COMMA:
- if (!prev_ident)
- {
- cpp_error_with_line (pfile, token->line, token->col,
- "parameter name expected");
- return;
- }
- prev_ident = 0;
- continue;
+ if (escape_it)
+ /* Worst case is each char is octal. */
+ len *= 4;
+ len++; /* Room for initial space. */
- 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. */
- if (!prev_ident)
- {
- cpp_token *tok = (cpp_token *) token;
+ dest = &start[total_len];
+ if (dest + len > POOL_LIMIT (pool))
+ {
+ _cpp_next_chunk (pool, len, (unsigned char **) &start);
+ dest = &start[total_len];
+ }
- tok->type = CPP_NAME;
- tok->val.node = pfile->spec_nodes->n__VA_ARGS__;
+ prev_white |= token->flags & PREV_WHITE;
+ if (token->type == CPP_PLACEMARKER)
+ continue;
- info->paramc++;
- info->paramlen += tok->val.node->length + 1;
+ /* No leading white space. */
+ if (prev_white)
+ {
+ prev_white = 0;
+ if (total_len > 0)
+ *dest++ = ' ';
+ }
- if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, c99))
- cpp_pedwarn (pfile,
- "C89 does not permit anon varargs macros");
- }
- else
+ if (escape_it)
+ {
+ unsigned char *buf = (unsigned char *) xmalloc (len);
+
+ len = cpp_spell_token (pfile, token, buf) - buf;
+ dest = quote_string (dest, buf, len);
+ free (buf);
+ }
+ else
+ dest = cpp_spell_token (pfile, token, dest);
+ total_len = dest - start;
+
+ if (token->type == CPP_BACKSLASH)
+ backslash_count++;
+ else
+ backslash_count = 0;
+ }
+
+ /* Ignore the final \ of invalid string literals. */
+ if (backslash_count & 1)
+ {
+ cpp_warning (pfile, "invalid string literal, ignoring final '\\'");
+ total_len--;
+ }
+
+ POOL_COMMIT (pool, total_len);
+
+ arg->stringified = xnew (cpp_token);
+ arg->stringified->flags = 0;
+ arg->stringified->type = CPP_STRING;
+ arg->stringified->val.str.text = start;
+ arg->stringified->val.str.len = total_len;
+}
+
+/* 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, the
+ right hand side of the ## operator is placed in the then-current
+ context's lookahead buffer, with the effect that it appears in the
+ output stream normally. */
+static void
+paste_all_tokens (pfile, lhs)
+ cpp_reader *pfile;
+ cpp_token *lhs;
+{
+ unsigned char orig_flags = lhs->flags;
+ cpp_token *rhs;
+
+ do
+ {
+ /* Take the token directly from the current context. We can do
+ this, because we are in the replacement list of either an
+ object-like macro, or a function-like macro with arguments
+ inserted. In either case, the constraints to #define
+ guarantee we have at least one more token (empty arguments
+ become placemarkers). */
+ rhs = pfile->context->list.first++;
+
+ if (rhs->type == CPP_PLACEMARKER)
+ {
+ /* GCC has special extended semantics for , ## b where b is
+ a varargs parameter: the comma disappears if b was given
+ no actual arguments (not merely if b is an empty
+ argument). */
+ if (lhs->type == CPP_COMMA && (rhs->flags & VARARGS_FIRST))
+ lhs->type = CPP_PLACEMARKER;
+ }
+ else if (lhs->type == CPP_PLACEMARKER)
+ *lhs = *rhs;
+ else
+ {
+ int digraph = 0;
+ enum cpp_ttype type = cpp_can_paste (pfile, lhs, rhs, &digraph);
+
+ if (type == CPP_EOF)
{
- if (CPP_PEDANTIC (pfile))
- cpp_pedwarn (pfile,
- "ISO C does not permit named varargs parameters");
+ /* Do nothing special about , ## <whatever> if
+ <whatever> came from a variable argument, because the
+ author probably intended the ## to trigger the
+ special extended semantics (see above). */
+ if (lhs->type == CPP_COMMA && (rhs->flags & VARARGS_FIRST))
+ /* nothing */;
+ else
+ {
+ if (CPP_OPTION (pfile, warn_paste))
+ 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));
+
+ /* The standard states that behaviour is undefined.
+ By the principle of least surpise, we step back
+ before the RHS, and mark it to prevent macro
+ expansion. Tests in the testsuite rely on
+ clearing PREV_WHITE here, though you could argue
+ we should actually set it. */
+ rhs->flags &= ~PREV_WHITE;
+ rhs->flags |= NO_EXPAND;
+ }
+
+ /* Step back so we read the RHS in next. */
+ pfile->context->list.first--;
+ break;
}
- info->flags |= VAR_ARGS;
- token++;
- if (token->type == CPP_CLOSE_PAREN)
- break;
- goto missing_paren;
+ lhs->type = type;
+ lhs->flags &= ~DIGRAPH;
+ if (digraph)
+ lhs->flags |= DIGRAPH;
+
+ if (type == CPP_NAME || type == CPP_NUMBER)
+ paste_payloads (pfile, lhs, rhs);
+ else if (type == CPP_WCHAR || type == CPP_WSTRING)
+ lhs->val.str = rhs->val.str;
+ }
+ }
+ while (rhs->flags & PASTE_LEFT);
+
+ /* The pasted token has the PREV_WHITE flag of the LHS, is no longer
+ PASTE_LEFT, and is subject to macro expansion. */
+ lhs->flags &= ~(PREV_WHITE | PASTE_LEFT | NO_EXPAND);
+ lhs->flags |= orig_flags & PREV_WHITE;
+}
+
+/* Reads the unexpanded tokens of a macro argument into ARG. Empty
+ arguments are saved as a single CPP_PLACEMARKER token. VAR_ARGS is
+ non-zero if this is a variable argument. Returns the type of the
+ token that caused reading to finish. */
+static enum cpp_ttype
+parse_arg (pfile, arg, var_args)
+ cpp_reader *pfile;
+ struct macro_arg *arg;
+ int var_args;
+{
+ enum cpp_ttype result;
+ unsigned int paren = 0;
+
+ arg->first = (cpp_token *) POOL_FRONT (&pfile->argument_pool);
+ for (;; arg->count++)
+ {
+ cpp_token *token = &arg->first[arg->count];
+ if ((unsigned char *) (token + 1) >= POOL_LIMIT (&pfile->argument_pool))
+ {
+ _cpp_next_chunk (&pfile->argument_pool, sizeof (cpp_token),
+ (unsigned char **) &arg->first);
+ token = &arg->first[arg->count];
+ }
+
+ _cpp_get_token (pfile, token);
+ result = token->type;
+
+ if (result == CPP_OPEN_PAREN)
+ paren++;
+ else if (result == CPP_CLOSE_PAREN && paren-- == 0)
+ break;
+ /* Commas are not terminators within parantheses or var_args. */
+ else if (result == CPP_COMMA && paren == 0 && !var_args)
+ break;
+ else if (result == CPP_EOF)
+ break; /* Error reported by caller. */
+ else if (result == CPP_DHASH)
+ {
+ /* 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. */
+ cpp_error (pfile, "directives may not be used inside a macro argument");
+ _cpp_push_token (pfile, token, &pfile->lexer_pos);
+ result = CPP_EOF;
+ break;
}
+ }
- /* Success. */
- info->first = token + 1;
- if (!pfile->save_parameter_spellings)
- info->paramlen = 0;
- return;
+ /* Empty arguments become a single placemarker token. */
+ if (arg->count == 0)
+ {
+ arg->first->type = CPP_PLACEMARKER;
+ arg->count = 1;
}
+
+ /* Commit the memory used to store the arguments. */
+ POOL_COMMIT (&pfile->argument_pool, arg->count * sizeof (cpp_token));
+
+ return result;
}
-/* Parses a #define directive. On success, returns zero, and INFO is
- filled in appropriately. */
+/* Parse the arguments making up a macro invocation. */
+static macro_arg *
+parse_args (pfile, node)
+ cpp_reader *pfile;
+ const cpp_hashnode *node;
+{
+ cpp_macro *macro = node->value.macro;
+ macro_arg *args, *cur;
+ enum cpp_ttype type;
+ int argc, error = 0;
+
+ /* Allocate room for at least one argument, and zero it out. */
+ argc = macro->paramc ? macro->paramc: 1;
+ args = xcnewvec (macro_arg, argc);
+
+ for (cur = args, argc = 0; ;)
+ {
+ argc++;
+
+ type = parse_arg (pfile, cur, argc == macro->paramc && macro->var_args);
+ if (type == CPP_CLOSE_PAREN || type == CPP_EOF)
+ break;
+
+ /* Re-use the last argument for excess arguments. */
+ if (argc < macro->paramc)
+ cur++;
+ }
+
+ if (type == CPP_EOF)
+ {
+ cpp_error (pfile, "unterminated argument list invoking macro \"%s\"",
+ node->name);
+ error = 1;
+ }
+ else if (argc < macro->paramc)
+ {
+ /* As an extension, a rest argument is allowed to not appear in
+ the invocation at all.
+ e.g. #define debug(format, args...) something
+ debug("string");
+
+ This is exactly the same as if there had been an empty rest
+ argument - debug("string", ). */
+
+ if (argc + 1 == macro->paramc && macro->var_args)
+ {
+ /* parse_arg ensured there was space for the closing
+ parenthesis. Use this space to store a placemarker. */
+ args[argc].first = (cpp_token *) POOL_FRONT (&pfile->argument_pool);
+ args[argc].first->type = CPP_PLACEMARKER;
+ args[argc].count = 1;
+ POOL_COMMIT (&pfile->argument_pool, sizeof (cpp_token));
+
+ if (CPP_OPTION (pfile, c99) && CPP_PEDANTIC (pfile))
+ 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, macro->paramc, argc);
+ error = 1;
+ }
+ }
+ else if (argc > macro->paramc)
+ {
+ /* An empty argument to an empty function-like macro is fine. */
+ if (argc != 1 || args[0].first->type != CPP_PLACEMARKER)
+ {
+ cpp_error (pfile,
+ "macro \"%s\" passed %u arguments, but takes just %u",
+ node->name, argc, macro->paramc);
+ error = 1;
+ }
+ }
+
+ if (error)
+ {
+ free (args);
+ args = 0;
+ }
+
+ return args;
+}
+
+static int
+funlike_invocation_p (pfile, node, list)
+ cpp_reader *pfile;
+ const cpp_hashnode *node;
+ struct toklist *list;
+{
+ cpp_context *orig_context;
+ cpp_token maybe_paren;
+ macro_arg *args = 0;
+
+ pfile->state.parsing_args = 1;
+ pfile->state.prevent_expansion++;
+ orig_context = pfile->context;
+
+ cpp_start_lookahead (pfile);
+ cpp_get_token (pfile, &maybe_paren);
+ cpp_stop_lookahead (pfile, maybe_paren.type == CPP_OPEN_PAREN);
+
+ if (maybe_paren.type == CPP_OPEN_PAREN)
+ args = parse_args (pfile, node);
+ else if (CPP_WTRADITIONAL (pfile))
+ cpp_warning (pfile,
+ "function-like macro \"%s\" must be used with arguments in traditional C",
+ node->name);
+
+ /* Restore original context. */
+ pfile->context = orig_context;
+ pfile->state.prevent_expansion--;
+ pfile->state.parsing_args = 0;
+
+ if (args)
+ {
+ if (node->value.macro->paramc > 0)
+ replace_args (pfile, node->value.macro, args, list);
+ free (args);
+ }
+
+ return args != 0;
+}
+
+/* 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. */
static int
-parse_define (pfile, info)
+enter_macro_context (pfile, token)
cpp_reader *pfile;
- struct macro_info *info;
+ cpp_token *token;
{
- const cpp_token *token;
- int prev_white = 0;
+ cpp_context *context;
+ cpp_macro *macro;
+ unsigned char flags;
+ struct toklist list;
- /* The first token after the macro's name. */
- token = _cpp_get_token (pfile);
+ macro = token->val.node->value.macro;
+ if (macro->disabled)
+ {
+ token->flags |= NO_EXPAND;
+ return 1;
+ }
- /* Constraint 6.10.3.5 */
- if (is__va_args__ (pfile, token - 1))
- return 1;
+ /* Save the position of the outermost macro invocation. */
+ if (!pfile->context->prev)
+ {
+ pfile->macro_pos = pfile->lexer_pos;
+ lock_pools (pfile);
+ }
- while (token->type == CPP_COMMENT)
- token++, prev_white = 1;
- prev_white |= token->flags & PREV_WHITE;
+ if (macro->fun_like && !funlike_invocation_p (pfile, token->val.node, &list))
+ {
+ if (!pfile->context->prev)
+ unlock_pools (pfile);
+ return 1;
+ }
- if (token->type == CPP_OPEN_PAREN && !prev_white)
+ /* Now push its context. */
+ context = next_context (pfile);
+ if (macro->paramc == 0)
{
- /* A function-like macro. */
- info->first_param = token + 1;
- count_params (pfile, info);
- if (info->first[-1].type != CPP_CLOSE_PAREN)
- return 1;
+ context->list.first = macro->expansion;
+ context->list.limit = macro->expansion + macro->count;
}
else
+ context->list = list;
+ context->macro = macro;
+
+ /* The first expansion token inherits the PREV_WHITE of TOKEN. */
+ flags = token->flags & PREV_WHITE;
+ *token = *context->list.first++;
+ token->flags |= flags;
+
+ /* Disable the macro within its expansion. */
+ macro->disabled = 1;
+
+ return 0;
+}
+
+/* Move to the next context. Create one if there is none. */
+static cpp_context *
+next_context (pfile)
+ cpp_reader *pfile;
+{
+ cpp_context *prev = pfile->context;
+ cpp_context *result = prev->next;
+
+ if (result == 0)
{
- /* An object-like macro. */
- info->paramc = -1;
- info->paramlen = 0;
- info->flags = 0;
- info->first = token;
- if (!prev_white && token->type != CPP_EOF)
- cpp_pedwarn (pfile, "ISO C requires whitespace after the macro name");
+ result = xnew (cpp_context);
+ prev->next = result;
+ result->prev = prev;
+ result->next = 0;
}
- /* Count tokens in expansion. We drop paste tokens, and stringize
- tokens, so don't count them. */
- info->ntokens = info->len = 0;
- for (token = info->first; token->type != CPP_EOF; token++)
+ pfile->context = result;
+ return result;
+}
+
+static void
+replace_args (pfile, macro, args, list)
+ cpp_reader *pfile;
+ cpp_macro *macro;
+ macro_arg *args;
+ struct toklist *list;
+{
+ unsigned int i, total;
+ const cpp_token *src, *limit;
+ cpp_token *dest;
+ macro_arg *arg;
+
+ src = macro->expansion;
+ limit = src + macro->count;
+
+ /* First, fully macro-expand arguments, calculating the number of
+ tokens in the final expansion as we go. This ensures that the
+ possible recursive use of argument_pool is fine. */
+ total = limit - src;
+ for (; src < limit; src++)
+ if (src->type == CPP_MACRO_ARG)
+ {
+ /* We have an argument. If it is not being stringified or
+ pasted it is macro-replaced before insertion. */
+ arg = &args[src->val.aux - 1];
+ if (src->flags & STRINGIFY_ARG)
+ {
+ if (!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;
+ }
+ }
+
+ dest = (cpp_token *) _cpp_pool_alloc (&pfile->argument_pool,
+ total * sizeof (cpp_token));
+ list->first = dest;
+ list->limit = list->first + total;
+
+ for (src = macro->expansion; src < limit; src++)
+ if (src->type == CPP_MACRO_ARG)
+ {
+ unsigned int count;
+ const cpp_token *from;
+
+ arg = &args[src->val.aux - 1];
+ if (src->flags & STRINGIFY_ARG)
+ from = arg->stringified, count = 1;
+ else if ((src->flags & PASTE_LEFT)
+ || (src > macro->expansion && (src[-1].flags & PASTE_LEFT)))
+ count = arg->count, from = arg->first;
+ else
+ count = arg->expanded_count, from = arg->expanded;
+ memcpy (dest, from, count * sizeof (cpp_token));
+
+ /* The first token gets PREV_WHITE of the CPP_MACRO_ARG. If
+ it is a variable argument, it is also flagged. */
+ dest->flags &= ~PREV_WHITE;
+ dest->flags |= src->flags & PREV_WHITE;
+ if (macro->var_args && src->val.aux == macro->paramc)
+ dest->flags |= VARARGS_FIRST;
+
+ /* The last token gets the PASTE_LEFT of the CPP_MACRO_ARG. */
+ dest[count - 1].flags |= src->flags & PASTE_LEFT;
+
+ dest += count;
+ }
+ else
+ *dest++ = *src;
+
+ /* Free the expanded arguments. */
+ for (i = 0; i < macro->paramc; i++)
{
- if (token->type == CPP_PASTE)
+ if (args[i].expanded)
+ free (args[i].expanded);
+ if (args[i].stringified)
+ free (args[i].stringified);
+ }
+}
+
+/* Subroutine of expand_arg to put the unexpanded tokens on the
+ context stack. */
+static cpp_context *
+push_arg_context (pfile, arg)
+ cpp_reader *pfile;
+ macro_arg *arg;
+{
+ cpp_context *context = next_context (pfile);
+ context->macro = 0;
+ context->list.first = arg->first;
+ context->list.limit = arg->first + arg->count;
+
+ return context;
+}
+
+static void
+expand_arg (pfile, arg)
+ cpp_reader *pfile;
+ macro_arg *arg;
+{
+ cpp_token *token;
+ unsigned int capacity = 256;
+
+ /* Loop, reading in the arguments. */
+ arg->expanded = (cpp_token *) xmalloc (capacity * sizeof (cpp_token));
+ arg->expanded_count = 0;
+
+ push_arg_context (pfile, arg);
+ do
+ {
+ if (arg->expanded_count >= capacity)
{
- /* Token-paste ##, can appear in both object-like and
- function-like macros, but not at the ends. Constraint
- 6.10.3.3.1 */
- if (token == info->first || token[1].type == CPP_EOF)
+ capacity *= 2;
+ arg->expanded = (cpp_token *)
+ xrealloc (arg->expanded, capacity * sizeof (cpp_token));
+ }
+ token = &arg->expanded[arg->expanded_count++];
+ _cpp_get_token (pfile, token);
+ }
+ while (token->type != CPP_EOF);
+
+ arg->expanded_count--;
+
+ /* Pop the context we pushed. */
+ pfile->context = pfile->context->prev;
+}
+
+void
+_cpp_pop_context (pfile)
+ cpp_reader *pfile;
+{
+ cpp_context *context = pfile->context;
+
+ pfile->context = context->prev;
+ /* Re-enable a macro and free resources when leaving its expansion. */
+ if (!pfile->state.parsing_args)
+ {
+ if (!pfile->context->prev)
+ unlock_pools (pfile);
+ context->macro->disabled = 0;
+ }
+}
+
+/* Internal routine to return a token, either from an in-progress
+ macro expansion, or from the source file as appropriate. Handles
+ macros, so tokens returned are post-expansion. Does not filter
+ CPP_PLACEMARKER tokens. Returns CPP_EOF at EOL and EOF. */
+void
+_cpp_get_token (pfile, token)
+ cpp_reader *pfile;
+ cpp_token *token;
+{
+ for (;;)
+ {
+ cpp_context *context = pfile->context;
+
+ if (pfile->la_read)
+ take_lookahead_token (pfile, token);
+ /* Context->prev == 0 <=> base context. */
+ else if (!context->prev)
+ _cpp_lex_token (pfile, token);
+ else if (context->list.first != context->list.limit)
+ *token = *context->list.first++;
+ else
+ {
+ if (context->macro)
{
- cpp_error_with_line (pfile, token->line, token->col,
- "'##' cannot appear at either end of a macro expansion");
- return 1;
+ _cpp_pop_context (pfile);
+ continue;
}
+ token->type = CPP_EOF;
+ token->flags = 0;
+ }
+ break;
+ }
+
+ /* Only perform macro expansion (and therefore pasting) when not
+ skipping, or when skipping but in a directive. The only
+ directive where this could be true is #elif. A possible later
+ optimisation: get do_elif to clear skipping so we don't need the
+ directive test here. */
+ if (pfile->skipping && !pfile->state.in_directive)
+ return;
+
+ for (;;)
+ {
+ if (token->flags & PASTE_LEFT)
+ paste_all_tokens (pfile, token);
+
+ if (token->type != CPP_NAME
+ || token->val.node->type != NT_MACRO
+ || pfile->state.prevent_expansion
+ || token->flags & NO_EXPAND)
+ break;
+
+ /* Macros, built-in or not, invalidate controlling macros. */
+ pfile->mi_state = MI_FAILED;
+
+ if (token->val.node->flags & NODE_BUILTIN)
+ {
+ builtin_macro (pfile, token);
+ break;
+ }
+ else if (enter_macro_context (pfile, token))
+ break;
+ }
+}
+
+/* External interface to get a token. Tokens are returned after macro
+ expansion and directives have been handled, as a continuous stream.
+ Transparently enters included files. CPP_EOF indicates end of
+ original source file. Filters out CPP_PLACEMARKER tokens.
+
+ For the benefit of #pragma callbacks which may want to get the
+ pragma's tokens, returns CPP_EOF to indicate end-of-directive in
+ this case. */
+void
+cpp_get_token (pfile, token)
+ cpp_reader *pfile;
+ cpp_token *token;
+{
+ for (;;)
+ {
+ _cpp_get_token (pfile, token);
+
+ if (token->type == CPP_EOF)
+ {
+ /* In directives we should pass through EOLs for the callbacks. */
+ if (pfile->buffer->cur == pfile->buffer->rlimit
+ || pfile->state.in_directive || pfile->state.parsing_args)
+ break;
continue;
}
- else if (token->type == CPP_HASH)
+ else if (token->type == CPP_DHASH)
{
- /* Stringifying #, but a normal character in object-like
- macros. Must come before a parameter name. Constraint
- 6.10.3.2.1. */
- if (info->paramc >= 0)
- {
- if (token[1].type == CPP_NAME
- && find_param (info->first_param, token + 1))
- continue;
- if (! CPP_OPTION (pfile, lang_asm))
- {
- cpp_error_with_line (pfile, token->line, token->col,
- "'#' is not followed by a macro parameter");
- return 1;
- }
- }
+ /* Handle directives. */
+ if (_cpp_handle_directive (pfile, token->flags & PREV_WHITE))
+ continue;
+ /* This is in fact an assembler #. */
+ if (pfile->skipping)
+ continue;
+ token->type = CPP_HASH;
}
- else if (token->type == CPP_NAME)
+ /* We are not merging the PREV_WHITE of CPP_PLACEMARKERS. I
+ don't think it really matters. */
+ else if (pfile->skipping || token->type == CPP_PLACEMARKER)
+ continue;
+
+ /* Non-comment tokens invalidate any controlling macros. */
+ if (token->type != CPP_COMMENT)
+ pfile->mi_state = MI_FAILED;
+
+ break;
+ }
+
+ if (pfile->la_write)
+ save_lookahead_token (pfile, token);
+}
+
+/* Read each token in, until EOF. Directives are transparently
+ processed. */
+void
+cpp_scan_buffer_nooutput (pfile)
+ cpp_reader *pfile;
+{
+ cpp_token token;
+
+ do
+ do
+ cpp_get_token (pfile, &token);
+ while (token.type != CPP_EOF);
+ while (cpp_pop_buffer (pfile) != 0);
+}
+
+/* Lookahead handling. */
+
+static void
+save_lookahead_token (pfile, token)
+ cpp_reader *pfile;
+ const cpp_token *token;
+{
+ if (token->type != CPP_EOF)
+ {
+ cpp_lookahead *la = pfile->la_write;
+ cpp_token_with_pos *twp;
+
+ if (la->count == la->cap)
{
- /* Constraint 6.10.3.5 */
- if (!(info->flags & VAR_ARGS) && is__va_args__ (pfile, token))
- return 1;
+ la->cap += la->cap + 8;
+ la->tokens = (cpp_token_with_pos *)
+ xrealloc (la->tokens, la->cap * sizeof (cpp_token_with_pos));
}
- info->ntokens++;
- if (TOKEN_SPELL (token) == SPELL_STRING)
- info->len += token->val.str.len;
+
+ twp = &la->tokens[la->count++];
+ twp->token = *token;
+ twp->pos = *cpp_get_line (pfile);
}
-
- return 0;
}
-/* Returns non-zero if a macro redefinition is trivial. */
-static int
-check_macro_redefinition (pfile, hp, list2)
+static void
+take_lookahead_token (pfile, token)
cpp_reader *pfile;
- cpp_hashnode *hp;
- const cpp_toklist *list2;
+ cpp_token *token;
{
- const cpp_toklist *list1;
+ cpp_lookahead *la = pfile->la_read;
+ cpp_token_with_pos *twp = &la->tokens[la->cur];
- if (hp->type != T_MACRO)
- return ! pfile->done_initializing;
+ *token = twp->token;
+ pfile->lexer_pos = twp->pos;
- /* 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 (++la->cur == la->count)
+ release_lookahead (pfile);
+}
- if (!_cpp_equiv_toklists (list1, list2))
- return 0;
+/* Moves the lookahead at the front of the read list to the free store. */
+static void
+release_lookahead (pfile)
+ cpp_reader *pfile;
+{
+ cpp_lookahead *la = pfile->la_read;
- if (CPP_OPTION (pfile, pedantic)
- && list1->paramc > 0
- && (list1->params_len != list2->params_len
- || memcmp (list1->namebuf, list2->namebuf, list1->params_len)))
- return 0;
+ pfile->la_read = la->next;
+ la->next = pfile->la_unused;
+ pfile->la_unused = la;
+ unlock_pools (pfile);
+}
- return 1;
+/* Take a new lookahead from the free store, or allocate one if none. */
+static cpp_lookahead *
+alloc_lookahead (pfile)
+ cpp_reader *pfile;
+{
+ cpp_lookahead *la = pfile->la_unused;
+
+ if (la)
+ pfile->la_unused = la->next;
+ else
+ {
+ la = xnew (cpp_lookahead);
+ la->tokens = 0;
+ la->cap = 0;
+ }
+
+ la->cur = la->count = 0;
+ return la;
}
-/* This is a dummy structure whose only purpose is getting alignment
- correct. */
-struct toklist_dummy
+/* Free memory associated with a lookahead list. */
+static void
+free_lookahead (la)
+ cpp_lookahead *la;
{
- cpp_toklist list;
- cpp_token first_token;
-};
+ if (la->tokens)
+ free ((PTR) la->tokens);
+ free ((PTR) la);
+}
-/* Allocate space to hold the token list, its tokens, their text, and
- the parameter names if needed. Empty expansions are stored as a
- single placemarker token.
+/* Free all the lookaheads of a cpp_reader. */
+void
+_cpp_free_lookaheads (pfile)
+ cpp_reader *pfile;
+{
+ cpp_lookahead *la, *lan;
+
+ if (pfile->la_read)
+ free_lookahead (pfile->la_read);
+ if (pfile->la_write)
+ free_lookahead (pfile->la_write);
+
+ for (la = pfile->la_unused; la; la = lan)
+ {
+ lan = la->next;
+ free_lookahead (la);
+ }
+}
- These are all allocated in a block together for performance
- reasons. Therefore, this token list cannot be expanded like a
- normal token list. Try to do so, and you lose. */
-static cpp_toklist *
-alloc_macro (pfile, info)
+/* Allocate a lookahead and move it to the front of the write list. */
+void
+cpp_start_lookahead (pfile)
cpp_reader *pfile;
- struct macro_info *info;
{
- unsigned int size;
- struct toklist_dummy *dummy;
- cpp_toklist *list;
+ cpp_lookahead *la = alloc_lookahead (pfile);
- /* Empty macros become a single placemarker token. */
- if (info->ntokens == 0)
- info->ntokens = 1;
+ la->next = pfile->la_write;
+ pfile->la_write = la;
- size = sizeof (struct toklist_dummy);
- size += (info->ntokens - 1) * sizeof(cpp_token);
- size += info->len + info->paramlen;
+ la->pos = *cpp_get_line (pfile);
- dummy = (struct toklist_dummy *) xmalloc (size);
- list = (cpp_toklist *) dummy;
-
- /* Initialize the monster. */
- list->tokens = &dummy->first_token;
- list->tokens_used = list->tokens_cap = info->ntokens;
+ /* Don't allow memory pools to be re-used whilst we're reading ahead. */
+ lock_pools (pfile);
+}
- list->namebuf = (unsigned char *) &list->tokens[info->ntokens];
- list->name_used = list->name_cap = info->len + info->paramlen;
+/* Stop reading ahead - either step back, or drop the read ahead. */
+void
+cpp_stop_lookahead (pfile, drop)
+ cpp_reader *pfile;
+ int drop;
+{
+ cpp_lookahead *la = pfile->la_write;
- list->directive = 0;
- list->line = pfile->token_list.line;
- list->file = pfile->token_list.file;
- list->params_len = info->paramlen;
- list->paramc = info->paramc;
- list->flags = info->flags;
+ pfile->la_write = la->next;
+ la->next = pfile->la_read;
+ pfile->la_read = la;
- return list;
+ if (drop || la->count == 0)
+ release_lookahead (pfile);
+ else
+ pfile->lexer_pos = la->pos;
}
-/* Free the definition of macro H. */
+/* Push a single token back to the front of the queue. Only to be
+ used by cpplib, and only then when necessary. POS is the position
+ to report for the preceding token. */
+void
+_cpp_push_token (pfile, token, pos)
+ cpp_reader *pfile;
+ const cpp_token *token;
+ const cpp_lexer_pos *pos;
+{
+ cpp_start_lookahead (pfile);
+ save_lookahead_token (pfile, token);
+ cpp_stop_lookahead (pfile, 0);
+ pfile->lexer_pos = *pos;
+}
+
+/* #define directive parsing and handling. */
+
+/* Returns non-zero if a macro redefinition is trivial. */
+static int
+check_macro_redefinition (pfile, node, macro2)
+ cpp_reader *pfile;
+ const cpp_hashnode *node;
+ const cpp_macro *macro2;
+{
+ const cpp_macro *macro1;
+ unsigned int i;
+
+ if (node->type != NT_MACRO || node->flags & NODE_BUILTIN)
+ return ! pfile->done_initializing;
+
+ macro1 = node->value.macro;
+
+ /* The quick failures. */
+ if (macro1->count != macro2->count
+ || macro1->paramc != macro2->paramc
+ || macro1->fun_like != macro2->fun_like
+ || macro1->var_args != macro2->var_args)
+ return 0;
+
+ /* Check each token. */
+ for (i = 0; i < macro1->count; i++)
+ if (! _cpp_equiv_tokens (&macro1->expansion[i], &macro2->expansion[i]))
+ return 0;
+
+ /* Check parameter spellings. */
+ for (i = 0; i < macro1->paramc; i++)
+ if (macro1->params[i] != macro2->params[i])
+ return 0;
+
+ return 1;
+}
+
+/* Free the definition of hashnode H. */
void
_cpp_free_definition (h)
cpp_hashnode *h;
{
- if (h->type == T_MACRO)
- free ((PTR) h->value.expansion);
- else if (h->type == T_ASSERTION)
+ /* Macros and assertions no longer have anything to free. */
+ h->type = NT_VOID;
+ /* Clear builtin flag in case of redefinition. */
+ h->flags &= ~NODE_BUILTIN;
+}
+
+static int
+save_parameter (pfile, macro, node)
+ cpp_reader *pfile;
+ cpp_macro *macro;
+ cpp_hashnode *node;
+{
+ cpp_hashnode **dest;
+
+ /* Constraint 6.10.3.6 - duplicate parameter names. */
+ if (node->arg_index)
{
- struct answer *temp, *next;
+ cpp_error (pfile, "duplicate macro parameter \"%s\"", node->name);
+ return 1;
+ }
- for (temp = h->value.answers; temp; temp = next)
- {
- next = temp->next;
- FREE_ANSWER (temp);
- }
+ dest = &macro->params[macro->paramc];
+
+ /* Check we have room for the parameters. */
+ if ((unsigned char *) (dest + 1) >= POOL_LIMIT (&pfile->macro_pool))
+ {
+ _cpp_next_chunk (&pfile->macro_pool, sizeof (cpp_hashnode *),
+ (unsigned char **) &macro->params);
+ dest = &macro->params[macro->paramc];
}
- h->type = T_VOID;
- h->value.expansion = NULL;
+ *dest = node;
+ node->arg_index = ++macro->paramc;
+ return 0;
}
-/* Copy the tokens of the expansion, beginning with info->first until
- CPP_EOF. INFO contains information about the macro.
-
- Change the type of macro arguments in the expansion 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 the
- token list for the macro expansion. */
-static const cpp_toklist *
-save_expansion (pfile, info)
+static int
+parse_params (pfile, macro)
cpp_reader *pfile;
- struct macro_info *info;
+ cpp_macro *macro;
{
- const cpp_token *token;
- cpp_toklist *list;
- cpp_token *dest;
- unsigned char *buf;
-
- list = alloc_macro (pfile, info);
- buf = list->namebuf;
-
- /* Store the null-terminated parameter spellings of a macro, to
- provide pedantic warnings to satisfy 6.10.3.2, or for use when
- dumping macro definitions. They must go first. */
- if (list->params_len)
- for (token = info->first_param; token < info->first; token++)
- if (token->type == CPP_NAME || token->type == CPP_DEFINED)
- {
- /* Copy null too. */
- memcpy (buf, token->val.node->name, token->val.node->length + 1);
- buf += token->val.node->length + 1;
- }
+ cpp_token token;
+ unsigned int prev_ident = 0;
- dest = list->tokens;
- for (token = info->first; token->type != CPP_EOF; token++)
+ macro->params = (cpp_hashnode **) POOL_FRONT (&pfile->macro_pool);
+ for (;;)
{
- unsigned int param_no;
+ _cpp_lex_token (pfile, &token);
- switch (token->type)
+ switch (token.type)
{
- case CPP_DEFINED:
+ default:
+ cpp_error (pfile, "\"%s\" may not appear in macro parameter list",
+ cpp_token_as_text (pfile, &token));
+ return 0;
+
case CPP_NAME:
- if (list->paramc == -1)
- break;
+ 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;
- /* Check if the name is a macro parameter. */
- param_no = find_param (info->first_param, token);
- if (param_no == 0)
+ case CPP_CLOSE_PAREN:
+ if (prev_ident || macro->paramc == 0)
break;
- dest->val.aux = param_no - 1;
- dest->type = CPP_MACRO_ARG;
- if (token[-1].type == CPP_HASH)
- dest->flags = token[-1].flags | STRINGIFY_ARG;
- else
- dest->flags = token->flags; /* Particularly PREV_WHITE. */
- /* Turn off PREV_WHITE if we immediately follow a paste.
- That way, even if the paste turns out to be invalid, there
- will be no space between the two tokens in the output. */
- if (token[-1].type == CPP_PASTE)
- dest->flags &= ~PREV_WHITE;
- dest++;
+ /* Fall through to pick up the error. */
+ case CPP_COMMA:
+ if (!prev_ident)
+ {
+ cpp_error (pfile, "parameter name missing");
+ return 0;
+ }
+ prev_ident = 0;
continue;
- case CPP_PASTE:
- /* Set the paste flag on the token to our left, unless there
- is no possible token to which it might be pasted. That
- is critical for correct operation under some circumstances;
- see gcc.dg/cpp/paste6.c. */
- if (CAN_PASTE_AFTER (dest[-1].type) || (dest[-1].flags & NAMED_OP))
- dest[-1].flags |= PASTE_LEFT;
- else if (CPP_OPTION (pfile, warn_paste))
- cpp_warning_with_line (pfile, dest[-1].line, dest[-1].col,
- "nothing can be pasted after this token");
- continue;
+ case CPP_ELLIPSIS:
+ macro->var_args = 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,
+ "C89 does not permit anonymous variable arguments");
+ }
+ else if (CPP_OPTION (pfile, pedantic))
+ cpp_pedwarn (pfile,
+ "ISO C does not permit named variable arguments");
- case CPP_HASH:
- /* Stringifying #. Constraint 6.10.3.2.1 */
- if (list->paramc >= 0 && token[1].type == CPP_NAME
- && find_param (info->first_param, token + 1))
- continue;
- break;
+ /* We're at the end, and just expect a closing parenthesis. */
+ _cpp_lex_token (pfile, &token);
+ if (token.type == CPP_CLOSE_PAREN)
+ break;
+ /* Fall through. */
- case CPP_STRING:
- case CPP_CHAR:
- if (CPP_WTRADITIONAL (pfile) && list->paramc > 0)
- check_trad_stringification (pfile, info, &token->val.str);
- break;
-
- default:
- break;
+ case CPP_EOF:
+ cpp_error (pfile, "missing ')' in macro parameter list");
+ return 0;
}
- /* Copy the token. */
- *dest = *token;
- if (TOKEN_SPELL (token) == SPELL_STRING)
- {
- memcpy (buf, token->val.str.text, token->val.str.len);
- dest->val.str.text = buf;
- buf += dest->val.str.len;
- }
- if (token[-1].type == CPP_PASTE)
- dest->flags &= ~PREV_WHITE;
- dest++;
+ /* Success. Commit the parameter array. */
+ POOL_COMMIT (&pfile->macro_pool,
+ macro->paramc * sizeof (cpp_hashnode *));
+ return 1;
}
+}
+
+/* Lex a token from a macro's replacement list. Translate it to a
+ CPP_MACRO_ARG if appropriate. */
+static cpp_token *
+lex_expansion_token (pfile, macro)
+ cpp_reader *pfile;
+ cpp_macro *macro;
+{
+ cpp_token *token = &macro->expansion[macro->count];
- /* Empty macros become a single placemarker token. */
- if (dest == list->tokens)
+ /* Check we have room for the token. */
+ if ((unsigned char *) (token + 1) >= POOL_LIMIT (&pfile->macro_pool))
{
- dest->type = CPP_PLACEMARKER;
- dest->flags = 0;
- dest->val.aux = 0;
+ _cpp_next_chunk (&pfile->macro_pool, sizeof (cpp_token),
+ (unsigned char **) &macro->expansion);
+ token = &macro->expansion[macro->count];
}
- return list;
+ macro->count++;
+ _cpp_lex_token (pfile, token);
+
+ /* Is this an argument? */
+ if (token->type == CPP_NAME && token->val.node->arg_index)
+ {
+ token->type = CPP_MACRO_ARG;
+ token->val.aux = 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;
}
/* Parse a macro and save its expansion. Returns non-zero on success. */
int
-_cpp_create_definition (pfile, hp)
+_cpp_create_definition (pfile, node)
cpp_reader *pfile;
- cpp_hashnode *hp;
+ cpp_hashnode *node;
{
- struct macro_info info;
- const cpp_toklist *list;
+ cpp_macro *macro;
+ cpp_token *token;
+ unsigned int i, ok = 1;
+
+ macro = (cpp_macro *) _cpp_pool_alloc (&pfile->macro_pool,
+ sizeof (cpp_macro));
+ macro->file = pfile->buffer->nominal_fname;
+ macro->line = pfile->directive_pos.line;
+ macro->params = 0;
+ macro->paramc = 0;
+ macro->fun_like = 0;
+ macro->var_args = 0;
+ macro->disabled = 0;
+ macro->count = 0;
+ macro->expansion = (cpp_token *) POOL_FRONT (&pfile->macro_pool);
+
+ /* Get the first token of the expansion (or the '(' of a
+ function-like macro). */
+ token = lex_expansion_token (pfile, macro);
+ if (token->type == CPP_OPEN_PAREN && !(token->flags & PREV_WHITE))
+ {
+ if (!(ok = parse_params (pfile, macro)))
+ goto cleanup;
+ macro->count = 0;
+ macro->fun_like = 1;
+ /* Some of the pool may have been used for the parameter store. */
+ macro->expansion = (cpp_token *) POOL_FRONT (&pfile->macro_pool);
+ token = lex_expansion_token (pfile, macro);
+ }
+ else if (token->type != CPP_EOF && !(token->flags & PREV_WHITE))
+ cpp_pedwarn (pfile, "ISO C requires whitespace after the macro name");
- if (parse_define (pfile, &info))
- return 0;
- list = save_expansion (pfile, &info);
+ /* Setting it here means we don't catch leading comments. */
+ pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);
- /* 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). */
+ for (;;)
+ {
+ /* Check the stringifying # constraint 6.10.3.2.1 of
+ function-like macros when lexing the subsequent token. */
+ 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--;
+ }
+ /* Let assembler get away with murder. */
+ else if (!CPP_OPTION (pfile, lang_asm))
+ {
+ ok = 0;
+ cpp_error (pfile, "'#' is not followed by a macro parameter");
+ goto cleanup;
+ }
+ }
+
+ if (token->type == CPP_EOF)
+ break;
+
+ /* Paste operator constraint 6.10.3.3.1. */
+ if (token->type == CPP_PASTE)
+ {
+ /* Token-paste ##, can appear in both object-like and
+ function-like macros, but not at the ends. */
+ 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 cleanup;
+ }
- if (hp->type != T_VOID)
+ token[-1].flags |= PASTE_LEFT;
+ /* Give it a PREV_WHITE for -dM etc. */
+ token->flags |= PREV_WHITE;
+ }
+
+ token = lex_expansion_token (pfile, macro);
+ }
+
+ /* Don't count the CPP_EOF. Empty macros become a place marker. */
+ if (macro->count > 1)
+ macro->count--;
+ else
+ macro->expansion[0].type = CPP_PLACEMARKER;
+
+ /* Clear the whitespace flag from the leading token. */
+ macro->expansion[0].flags &= ~PREV_WHITE;
+
+ /* Commit the memory. */
+ POOL_COMMIT (&pfile->macro_pool, macro->count * sizeof (cpp_token));
+
+ /* Redefinition of a macro is allowed if and only if the old and new
+ definitions are the same. (6.10.3 paragraph 2). */
+ if (node->type != NT_VOID)
{
- if (!check_macro_redefinition (pfile, hp, list))
+ if (CPP_PEDANTIC (pfile)
+ && !check_macro_redefinition (pfile, node, macro))
{
- cpp_pedwarn (pfile, "\"%s\" redefined", hp->name);
- if (pfile->done_initializing && hp->type == T_MACRO)
+ cpp_pedwarn_with_line (pfile, pfile->directive_pos.line,
+ pfile->directive_pos.col,
+ "\"%s\" redefined", node->name);
+
+ if (pfile->done_initializing && node->type == NT_MACRO
+ && !(node->flags & NODE_BUILTIN))
cpp_pedwarn_with_file_and_line (pfile,
- hp->value.expansion->file,
- hp->value.expansion->line, 1,
+ node->value.macro->file,
+ node->value.macro->line, 1,
"this is the location of the previous definition");
}
- _cpp_free_definition (hp);
+ _cpp_free_definition (node);
}
/* Enter definition in hash table. */
- hp->type = T_MACRO;
- hp->value.expansion = list;
+ node->type = NT_MACRO;
+ node->value.macro = macro;
- return 1;
+ cleanup:
+
+ /* Stop the lexer accepting __VA_ARGS__. */
+ pfile->state.va_args_ok = 0;
+
+ /* Clear the fast argument lookup indices. */
+ for (i = macro->paramc; i-- > 0; )
+ macro->params[i]->arg_index = 0;
+
+ 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. */
static void
-check_trad_stringification (pfile, info, string)
+check_trad_stringification (pfile, macro, string)
cpp_reader *pfile;
- const struct macro_info *info;
+ const cpp_macro *macro;
const cpp_string *string;
{
+ unsigned int i, len;
const U_CHAR *p, *q, *limit = string->text + string->len;
/* Loop over the string. */
for (p = string->text; p < limit; p = q)
{
- const cpp_token *token;
-
/* Find the start of an identifier. */
while (p < limit && !is_idstart (*p))
p++;
@@ -600,23 +1548,130 @@ check_trad_stringification (pfile, info, string)
q = p;
while (q < limit && is_idchar (*q))
q++;
-
+
+ len = q - p;
+
/* Loop over the function macro arguments to see if the
identifier inside the string matches one of them. */
- for (token = info->first_param; token < info->first; token++)
- {
- /* Skip the commas in between the arguments. */
- if (token->type != CPP_NAME)
- continue;
+ for (i = 0; i < macro->paramc; i++)
+ {
+ const cpp_hashnode *node = macro->params[i];
- if (token->val.node->length == (q - p)
- && !memcmp (p, token->val.node->name, (q - p)))
+ if (node->length == len && !memcmp (p, node->name, len))
{
cpp_warning (pfile,
- "macro arg \"%.*s\" would be stringified with -traditional.",
- (int) (q - p), p);
+ "macro argument \"%s\" would be stringified with -traditional.",
+ node->name);
break;
}
}
}
}
+
+/* Returns the expansion of a macro, in a format suitable to be read
+ back in again, and therefore also for DWARF 2 debugging info.
+ Caller is expected to generate the "#define NAME" bit. The
+ returned text is temporary, and automatically freed later. */
+
+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 dump_definition", node->type);
+ return 0;
+ }
+
+ /* Calculate length. */
+ len = 1; /* ' ' */
+ if (macro->fun_like)
+ {
+ len += 3; /* "()" plus possible final "." of ellipsis. */
+ for (i = 0; i < macro->paramc; i++)
+ len += macro->params[i]->length + 2; /* ", " */
+ }
+
+ if (macro->count > 1 || macro->expansion[0].type != CPP_PLACEMARKER)
+ {
+ for (i = 0; i < macro->count; i++)
+ {
+ cpp_token *token = &macro->expansion[i];
+
+ if (token->type == CPP_MACRO_ARG)
+ len += macro->params[token->val.aux - 1]->length;
+ else
+ len += cpp_token_len (token); /* Includes room for ' '. */
+ 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);
+ buffer = pfile->macro_buffer;
+
+ /* Parameter names. */
+ 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, param->name, param->length);
+ buffer += param->length;
+ }
+
+ if (i + 1 < macro->paramc)
+ *buffer++ = ',', *buffer++ = ' ';
+ else if (macro->var_args)
+ *buffer++ = '.', *buffer++ = '.', *buffer++ = '.';
+ }
+ *buffer++ = ')';
+ }
+
+ /* Expansion tokens. */
+ if (macro->count > 1 || macro->expansion[0].type != CPP_PLACEMARKER)
+ {
+ *buffer++ = ' ';
+ for (i = 0; i < macro->count; i++)
+ {
+ cpp_token *token = &macro->expansion[i];
+
+ if (token->flags & PREV_WHITE)
+ *buffer++ = ' ';
+ if (token->flags & STRINGIFY_ARG)
+ *buffer++ = '#';
+
+ if (token->type == CPP_MACRO_ARG)
+ {
+ len = macro->params[token->val.aux - 1]->length;
+ memcpy (buffer, macro->params[token->val.aux - 1]->name, len);
+ buffer += len;
+ }
+ else
+ buffer = cpp_spell_token (pfile, token, buffer);
+
+ if (token->flags & PASTE_LEFT)
+ {
+ *buffer++ = ' ';
+ *buffer++ = '#';
+ *buffer++ = '#';
+ /* Next has PREV_WHITE; see _cpp_create_definition. */
+ }
+ }
+ }
+
+ *buffer = '\0';
+ return pfile->macro_buffer;
+}