diff options
author | zack <zack@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-07-18 00:59:49 +0000 |
---|---|---|
committer | zack <zack@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-07-18 00:59:49 +0000 |
commit | 69461e0d90d5ee950b9e0b8ba60d4bbf3299f472 (patch) | |
tree | a8929adb35764d62c4016b482a4cb4b619be00cb /gcc/cppmacro.c | |
parent | c25f946dfdb078a45f04f77f6d2ba17241d27716 (diff) | |
download | gcc-69461e0d90d5ee950b9e0b8ba60d4bbf3299f472.tar.gz |
2000-02-17 Zack Weinberg <zack@wolery.cumb.org>
* cpphash.c: Don't include hashtab.h. Most macro-handling code
moved to cppmacro.c.
(hash_HASHNODE, eq_HASHNODE, _cpp_dump_macro_hash,
dump_hash_helper): Delete.
(expand_hash, higher_prime_number, _cpp_lookup_with_hash,
cpp_forall_identifiers): New. Implement specialized version of
Vlad's expandable hash table.
(cpp_lookup): Use new functions.
(_cpp_init_macros, _cpp_cleanup_macros): Adjust for new
implementation.
* cppmacro.c: New file.
* cppinit.c (dump_macros_helper): New.
(cpp_finish): Iterate over the identifier table directly.
* cpplex.c (parse_name): Calculate the hash of the identifier
while we scan it. Use _cpp_lookup_with_hash when we can.
* cpphash.h: Update prototypes.
(xcnewvec, HASHSTEP): New helper macros.
* cpplib.h: Update prototypes.
* Makefile.in (LIBCPP_OBJS): Add cppmacro.o.
(cppmacro.o): New rule.
(cpphash.o): Update deps.
* cppmain.c: Do not set pfile->printer if no_output is on.
2000-02-15 Neil Booth <neilb@earthling.net>
* cpplib.c: Change all directive-handler functions to return
void, not int.
* cpphash.h: Update typedefs.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@35113 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cppmacro.c')
-rw-r--r-- | gcc/cppmacro.c | 603 |
1 files changed, 603 insertions, 0 deletions
diff --git a/gcc/cppmacro.c b/gcc/cppmacro.c new file mode 100644 index 00000000000..710dbdedaa1 --- /dev/null +++ b/gcc/cppmacro.c @@ -0,0 +1,603 @@ +/* Part of CPP library. (Macro handling.) + Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998, + 1999, 2000 Free Software Foundation, Inc. + Written by Per Bothner, 1994. + Based on CCCP program by Paul Rubin, June 1986 + Adapted to ANSI C, Richard Stallman, Jan 1987 + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +#include "config.h" +#include "system.h" +#include "cpplib.h" +#include "cpphash.h" + +/* Stores basic information about a macro, before it is allocated. */ +struct macro_info +{ + 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; +}; + +static void dump_funlike_macro PARAMS ((cpp_reader *, cpp_hashnode *)); +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 *)); + + +/* Scans for a given token, returning the parameter number if found, + or 0 if not found. Scans from FIRST to TOKEN - 1 or the first + CPP_CLOSE_PAREN for TOKEN. */ +static unsigned int +find_param (first, token) + const cpp_token *first, *token; +{ + unsigned int param = 0; + + for (; first < token && first->type != CPP_CLOSE_PAREN; first++) + if (first->type == CPP_NAME) + { + param++; + if (first->val.node == token->val.node) + return param; + } + + return 0; +} + +/* 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) + cpp_reader *pfile; + const cpp_token *token; +{ + if (!CPP_PEDANTIC (pfile) + || token->val.node != pfile->spec_nodes->n__VA_ARGS__) + return 0; + + 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; +} + +/* 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. + + 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) + cpp_reader *pfile; + struct macro_info *info; +{ + unsigned int prev_ident = 0; + const cpp_token *token; + + info->paramc = 0; + info->paramlen = 0; + info->flags = 0; + info->first = info->first_param; /* Not a ')' indicating success. */ + + for (token = info->first_param;; token++) + { + switch (token->type) + { + default: + cpp_error_with_line (pfile, token->line, token->col, + "illegal token 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; + + case CPP_COMMENT: + continue; /* Ignore -C comments. */ + + case CPP_NAME: + if (prev_ident) + { + cpp_error_with_line (pfile, token->line, token->col, + "macro parameters must be comma-separated"); + return; + } + + /* Constraint 6.10.3.5 */ + if (is__va_args__ (pfile, token)) + return; + + /* 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; + } + + prev_ident = 1; + info->paramc++; + info->paramlen += token->val.node->length + 1; + continue; + + case CPP_CLOSE_PAREN: + if (prev_ident || info->paramc == 0) + break; + + /* 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; + + 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; + + tok->type = CPP_NAME; + tok->val.node = pfile->spec_nodes->n__VA_ARGS__; + + info->paramc++; + info->paramlen += tok->val.node->length + 1; + + if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, c99)) + cpp_pedwarn (pfile, + "C89 does not permit anon varargs macros"); + } + else + { + info->flags |= GNU_REST_ARGS; + if (CPP_PEDANTIC (pfile)) + cpp_pedwarn (pfile, + "ISO C does not permit named varargs parameters"); + } + + info->flags |= VAR_ARGS; + token++; + if (token->type == CPP_CLOSE_PAREN) + break; + goto missing_paren; + } + + /* Success. */ + info->first = token + 1; + if (!pfile->save_parameter_spellings) + info->paramlen = 0; + return; + } +} + +/* Parses a #define directive. On success, returns zero, and INFO is + filled in appropriately. */ +static int +parse_define (pfile, info) + cpp_reader *pfile; + struct macro_info *info; +{ + const cpp_token *token; + int prev_white = 0; + + /* The first token after the macro's name. */ + token = _cpp_get_token (pfile); + + /* Constraint 6.10.3.5 */ + if (is__va_args__ (pfile, token - 1)) + return 1; + + while (token->type == CPP_COMMENT) + token++, prev_white = 1; + prev_white |= token->flags & PREV_WHITE; + + if (token->type == CPP_OPEN_PAREN && !prev_white) + { + /* A function-like macro. */ + info->first_param = token + 1; + count_params (pfile, info); + if (info->first[-1].type != CPP_CLOSE_PAREN) + return 1; + } + else + { + /* 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"); + } + + /* 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++) + { + if (token->type == CPP_PASTE) + { + /* 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) + { + cpp_error_with_line (pfile, token->line, token->col, + "'##' cannot appear at either end of a macro expansion"); + return 1; + } + continue; + } + else if (token->type == CPP_HASH) + { + /* 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; + } + } + } + else if (token->type == CPP_NAME) + { + /* Constraint 6.10.3.5 */ + if (!(info->flags & VAR_ARGS) && is__va_args__ (pfile, token)) + return 1; + /* It might be worth doing a check here that we aren't a + macro argument, since we don't store the text of macro + arguments. This would reduce "len" and save space. */ + } + info->ntokens++; + if (TOKEN_SPELL (token) == SPELL_STRING) + info->len += token->val.str.len; + } + + return 0; +} + +/* Returns non-zero if a macro redefinition is trivial. */ +static int +check_macro_redefinition (pfile, hp, list2) + cpp_reader *pfile; + cpp_hashnode *hp; + const cpp_toklist *list2; +{ + const cpp_toklist *list1; + + if (hp->type != T_MACRO) + return ! pfile->done_initializing; + + /* Clear the whitespace and BOL flags of the first tokens. They get + altered during macro expansion, but is not significant here. */ + list1 = hp->value.expansion; + list1->tokens[0].flags &= ~(PREV_WHITE|BOL); + list2->tokens[0].flags &= ~(PREV_WHITE|BOL); + + if (!_cpp_equiv_toklists (list1, list2)) + return 0; + + if (CPP_OPTION (pfile, pedantic) + && list1->paramc > 0 + && (list1->params_len != list2->params_len + || memcmp (list1->namebuf, list2->namebuf, list1->params_len))) + return 0; + + return 1; +} + +/* This is a dummy structure whose only purpose is getting alignment + correct. */ +struct toklist_dummy +{ + cpp_toklist list; + cpp_token first_token; +}; + +/* 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. + + 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) + cpp_reader *pfile; + struct macro_info *info; +{ + unsigned int size; + struct toklist_dummy *dummy; + cpp_toklist *list; + + /* Empty macros become a single placemarker token. */ + if (info->ntokens == 0) + info->ntokens = 1; + + size = sizeof (struct toklist_dummy); + size += (info->ntokens - 1) * sizeof(cpp_token); + size += info->len + info->paramlen; + + 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; + + list->namebuf = (unsigned char *) &list->tokens[info->ntokens]; + list->name_used = list->name_cap = info->len + info->paramlen; + + 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; + + return list; +} + +/* Free the definition of macro H. */ + +void +_cpp_free_definition (h) + cpp_hashnode *h; +{ + if (h->type == T_MACRO) + free ((PTR) h->value.expansion); + h->value.expansion = NULL; +} + +/* 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) + cpp_reader *pfile; + struct macro_info *info; +{ + 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) + { + /* Copy null too. */ + memcpy (buf, token->val.node->name, token->val.node->length + 1); + buf += token->val.node->length + 1; + } + + dest = list->tokens; + for (token = info->first; token->type != CPP_EOF; token++) + { + unsigned int param_no; + + switch (token->type) + { + case CPP_NAME: + if (list->paramc == -1) + break; + + /* Check if the name is a macro parameter. */ + param_no = find_param (info->first_param, token); + if (param_no == 0) + break; + dest->val.aux = param_no - 1; + + dest->type = CPP_MACRO_ARG; + if (token[-1].type == CPP_HASH) + 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 illegal, there + will be no space between the two tokens in the output. */ + if (token[-1].type == CPP_PASTE) + dest->flags &= ~PREV_WHITE; + dest++; + continue; + + case CPP_PASTE: + dest[-1].flags |= PASTE_LEFT; + continue; + + 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; + + default: + break; + } + + /* 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++; + } + + /* Empty macros become a single placemarker token. */ + if (dest == list->tokens) + { + dest->type = CPP_PLACEMARKER; + dest->flags = 0; + } + + return list; +} + +/* Parse a macro and save its expansion. Returns non-zero on success. */ +int +_cpp_create_definition (pfile, hp) + cpp_reader *pfile; + cpp_hashnode *hp; +{ + struct macro_info info; + const cpp_toklist *list; + + if (parse_define (pfile, &info)) + return 0; + list = save_expansion (pfile, &info); + + /* Check for a redefinition. Redefinition of a macro is allowed if + and only if the old and new definitions are the same. + (6.10.3 paragraph 2). */ + + if (hp->type != T_VOID) + { + if (!check_macro_redefinition (pfile, hp, list)) + { + cpp_pedwarn (pfile, "\"%s\" redefined", hp->name); + if (pfile->done_initializing && hp->type == T_MACRO) + cpp_pedwarn_with_file_and_line (pfile, + hp->value.expansion->file, + hp->value.expansion->line, 1, + "this is the location of the previous definition"); + } + _cpp_free_definition (hp); + } + + /* Enter definition in hash table. */ + hp->type = T_MACRO; + hp->value.expansion = list; + + return 1; +} + +/* Dump the definition of macro MACRO on stdout. The format is suitable + to be read back in again. */ + +void +_cpp_dump_definition (pfile, hp) + cpp_reader *pfile; + cpp_hashnode *hp; +{ + CPP_RESERVE (pfile, hp->length + sizeof "#define "); + CPP_PUTS_Q (pfile, "#define ", sizeof "#define " - 1); + CPP_PUTS_Q (pfile, hp->name, hp->length); + + if (hp->type == T_MACRO) + { + if (hp->value.expansion->paramc >= 0) + dump_funlike_macro (pfile, hp); + else + { + const cpp_toklist *list = hp->value.expansion; + list->tokens[0].flags &= ~BOL; + list->tokens[0].flags |= PREV_WHITE; + _cpp_dump_list (pfile, list, list->tokens, 1); + } + } + else + cpp_ice (pfile, "invalid hash type %d in dump_definition", hp->type); + + if (CPP_BUFFER (pfile) == 0 || ! pfile->done_initializing) + CPP_PUTC (pfile, '\n'); +} + +static void +dump_funlike_macro (pfile, node) + cpp_reader *pfile; + cpp_hashnode *node; +{ + int i = 0; + const cpp_toklist * list = node->value.expansion; + const U_CHAR *param; + + param = list->namebuf; + CPP_PUTC_Q (pfile, '('); + for (i = 0; i++ < list->paramc;) + { + unsigned int len; + + len = ustrlen (param); + CPP_PUTS (pfile, param, len); + if (i < list->paramc) + CPP_PUTS(pfile, ", ", 2); + else if (list->flags & VAR_ARGS) + { + if (!ustrcmp (param, U"__VA_ARGS__")) + pfile->limit -= sizeof (U"__VA_ARGS__") - 1; + CPP_PUTS_Q (pfile, "...", 3); + } + param += len + 1; + } + CPP_PUTC (pfile, ')'); + list->tokens[0].flags &= ~BOL; + list->tokens[0].flags |= PREV_WHITE; + _cpp_dump_list (pfile, list, list->tokens, 1); +} |