diff options
author | Neil Booth <neilb@earthling.net> | 2000-10-28 17:59:06 +0000 |
---|---|---|
committer | Neil Booth <neil@gcc.gnu.org> | 2000-10-28 17:59:06 +0000 |
commit | 93c80368d9a16c073f2b930bef4232661971765f (patch) | |
tree | b1f50a88de9fbdd6a784d0c03fa8cd31e4ac5916 /gcc/cppmacro.c | |
parent | de48b52da8468f94c0bdffc11fa7e8fe49b4ba66 (diff) | |
download | gcc-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.c | 1891 |
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 (¯o1->expansion[i], ¯o2->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 = ¯o->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 **) ¯o->params); + dest = ¯o->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 = ¯o->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 **) ¯o->expansion); + token = ¯o->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 = ¯o->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 = ¯o->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; +} |