diff options
author | zack <zack@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-04-23 17:03:31 +0000 |
---|---|---|
committer | zack <zack@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-04-23 17:03:31 +0000 |
commit | da2bd80d25bb0abb39d006fe4b7f6285cdbc12a1 (patch) | |
tree | dce0dfebe9bc09562c88a4bc2be4eecd8f6147d6 /gcc/cpphash.c | |
parent | 99c7b888d070a31f4a0883bb470ab5cca5892d46 (diff) | |
download | gcc-da2bd80d25bb0abb39d006fe4b7f6285cdbc12a1.tar.gz |
* cpphash.h (struct definition): Move file, line, col members...
(struct hashnode): ... here. Also add 'disabled' flag.
(enum node_type): Add T_VOID, T_XCONST, T_FMACRO, and
T_IDENTITY. Remove T_DISABLED.
Update prototypes.
* cpphash.c (_cpp_dump_definition): Split out dump_DEFINITION.
(collect_expansion): Split into collect_objlike_expansion and
collect_funlike_expansion.
(_cpp_macroexpand): Split out scan_arguments, stringify, and
funlike_macroexpand.
(_cpp_compare_defs): Rename compare_defs, make static.
(_cpp_make_hashnode): Initialize hp->disabled.
(macro_cleanup): Adjust for new token types. Clear
m->disabled.
(_cpp_create_definition): Move code here to determine what
sort of macro it is, and code to check for redefinitions, from
do_define. Implement a few simple cases without creating a
full DEFINITION.
(_cpp_macroexpand, special_symbol, _cpp_dump_definition):
Handle the simple cases.
(push_macro_expansion): Set buf->has_escapes and hp->disabled
here.
* cppinit.c (builtin_array): Change MCONST to XCONST
everywhere.
* cpplex.c (maybe_macroexpand): Handle IDENTITY macros here;
fix check for disabled and function-like macros.
* cpplib.c (do_define): Move most logic to
_cpp_create_definition.
(do_undef): Handle new special token types.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@33355 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cpphash.c')
-rw-r--r-- | gcc/cpphash.c | 1226 |
1 files changed, 719 insertions, 507 deletions
diff --git a/gcc/cpphash.c b/gcc/cpphash.c index 26d03fec055..cc704657abe 100644 --- a/gcc/cpphash.c +++ b/gcc/cpphash.c @@ -34,14 +34,17 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static unsigned int hash_HASHNODE PARAMS ((const void *)); static int eq_HASHNODE PARAMS ((const void *, const void *)); static void del_HASHNODE PARAMS ((void *)); +static void dump_DEFINITION PARAMS ((cpp_reader *, DEFINITION *)); static int dump_hash_helper PARAMS ((void **, void *)); -static void push_macro_expansion PARAMS ((cpp_reader *, - U_CHAR *, int, HASHNODE *)); +static void push_macro_expansion PARAMS ((cpp_reader *, const U_CHAR *, + int, HASHNODE *)); static int unsafe_chars PARAMS ((cpp_reader *, int, int)); static int macro_cleanup PARAMS ((cpp_buffer *, cpp_reader *)); static enum cpp_ttype macarg PARAMS ((cpp_reader *, int)); -static void special_symbol PARAMS ((HASHNODE *, cpp_reader *)); +static void special_symbol PARAMS ((cpp_reader *, HASHNODE *)); +static int compare_defs PARAMS ((cpp_reader *, DEFINITION *, + DEFINITION *)); /* Initial hash table size. (It can grow if necessary - see hashtab.c.) */ #define HASHSIZE 500 @@ -72,8 +75,11 @@ struct arglist }; -static DEFINITION *collect_expansion PARAMS ((cpp_reader *, cpp_toklist *, - struct arglist *, unsigned int)); +static DEFINITION * +collect_objlike_expansion PARAMS ((cpp_reader *, cpp_toklist *)); +static DEFINITION * +collect_funlike_expansion PARAMS ((cpp_reader *, cpp_toklist *, + struct arglist *, unsigned int)); static unsigned int collect_params PARAMS ((cpp_reader *, cpp_toklist *, struct arglist *)); @@ -105,6 +111,12 @@ struct argdata int stringified_length; }; +static void scan_arguments PARAMS ((cpp_reader *, DEFINITION *, + struct argdata *, const U_CHAR *)); +static void stringify PARAMS ((cpp_reader *, struct argdata *)); +static void funlike_macroexpand PARAMS ((cpp_reader *, HASHNODE *, + struct argdata *)); + /* Calculate hash of a string of length LEN. */ unsigned int _cpp_calc_hash (str, len) @@ -174,6 +186,7 @@ _cpp_make_hashnode (name, len, type, hash) hp->length = len; hp->name = p; hp->hash = hash; + hp->disabled = 0; memcpy (p, name, len); p[len] = 0; @@ -277,10 +290,13 @@ macro_cleanup (pbuf, pfile) cpp_buffer *pbuf; cpp_reader *pfile ATTRIBUTE_UNUSED; { - HASHNODE *macro = pbuf->macro; - if (macro->type == T_DISABLED) - macro->type = T_MACRO; - if (macro->type != T_MACRO || pbuf->buf != macro->value.defn->expansion) + HASHNODE *m = pbuf->macro; + + m->disabled = 0; + if (m->type == T_FMACRO && pbuf->buf != m->value.defn->expansion) + free ((PTR) pbuf->buf); + else if (m->type != T_MACRO && m->type != T_FMACRO && m->type != T_CONST + && m->type != T_MCONST && m->type != T_XCONST) free ((PTR) pbuf->buf); return 0; } @@ -398,16 +414,90 @@ trad_stringify (pfile, base, len, argc, argv, pat, endpat, last) return last; } +/* Read a replacement list for an object-like macro, and build the + DEFINITION structure. LIST contains the replacement list, + beginning at 1. */ +static DEFINITION * +collect_objlike_expansion (pfile, list) + cpp_reader *pfile; + cpp_toklist *list; +{ + DEFINITION *defn; + unsigned int i; + unsigned int start; + int last_was_paste = 0; + U_CHAR *exp; + size_t len; -/* Read a replacement list for a macro, and build the DEFINITION - structure. LIST contains the replacement list, beginning at - REPLACEMENT. ARGLIST specifies the formal parameters to look for - in the text of the definition. If ARGLIST is null, this is an - object-like macro; if it points to an empty arglist, this is a - function-like macro with no arguments. */ + /* We copy the expansion text into the token_buffer, then out to + its proper home. */ + start = CPP_WRITTEN (pfile); + CPP_PUTS (pfile, "\r ", 2); + + for (i = 1; i < list->tokens_used; i++) + { + switch (list->tokens[i].type) + { + case CPP_POP: + case CPP_EOF: + cpp_ice (pfile, "EOF in collect_expansion"); + /* fall through */ + case CPP_VSPACE: + goto done; + + case CPP_PASTE: + /* ## is not special if it appears right after another ##; + nor is it special if -traditional. */ + if (last_was_paste || CPP_TRADITIONAL (pfile)) + break; + if (i == 1) + cpp_error (pfile, "`##' at start of macro definition"); + + last_was_paste = 1; + continue; + + default:; + } + + if (i > 1 && !last_was_paste && (list->tokens[i].flags & HSPACE_BEFORE)) + CPP_PUTC (pfile, ' '); + + CPP_PUTS (pfile, + list->tokens[i].val.name.offset + list->namebuf, + list->tokens[i].val.name.len); + last_was_paste = 0; + } + done: + + if (last_was_paste) + cpp_error (pfile, "`##' at end of macro definition"); + + CPP_PUTS (pfile, "\r ", 2); + len = CPP_WRITTEN (pfile) - start; + CPP_SET_WRITTEN (pfile, start); + + exp = (U_CHAR *) xmalloc (len + 1); + memcpy (exp, pfile->token_buffer + start, len); + exp[len] = '\0'; + + defn = (DEFINITION *) xmalloc (sizeof (DEFINITION)); + defn->length = len; + defn->expansion = exp; + defn->pattern = 0; + defn->rest_args = 0; + defn->argnames = 0; + defn->nargs = -1; + + return defn; +} + +/* Read a replacement list for a function-like macro, and build the + DEFINITION structure. LIST contains the replacement list, + beginning at REPLACEMENT. ARGLIST specifies the formal parameters + to look for in the text of the definition. */ static DEFINITION * -collect_expansion (pfile, list, arglist, replacement) +collect_funlike_expansion (pfile, list, arglist, replacement) cpp_reader *pfile; cpp_toklist *list; struct arglist *arglist; @@ -424,16 +514,8 @@ collect_expansion (pfile, list, arglist, replacement) U_CHAR *tok, *exp; enum { START = 0, NORM, ARG, STRIZE, PASTE } last_token = START; - if (arglist) - { - argv = arglist->argv; - argc = arglist->argc; - } - else - { - argv = 0; - argc = 0; - } + argv = arglist->argv; + argc = arglist->argc; /* We copy the expansion text into the token_buffer, then out to its proper home. */ @@ -455,12 +537,11 @@ collect_expansion (pfile, list, arglist, replacement) goto done; case CPP_HASH: - /* # is not special in object-like macros. It is special in - function-like macros with no args. (6.10.3.2 para 1.) - However, it is not special after PASTE. (Implied by - 6.10.3.3 para 4.) Nor is it special if -traditional. */ - if (arglist == NULL || last_token == PASTE - || CPP_TRADITIONAL (pfile)) + /* # is special in function-like macros with no args. + (6.10.3.2 para 1.) However, it is not special after + PASTE. (Implied by 6.10.3.3 para 4.) Nor is it special + if -traditional. */ + if (last_token == PASTE || CPP_TRADITIONAL (pfile)) break; last_token = STRIZE; continue; @@ -497,18 +578,20 @@ collect_expansion (pfile, list, arglist, replacement) { case CPP_STRING: case CPP_CHAR: - if (argc) + if (argc == 0) + goto norm; + if (CPP_TRADITIONAL (pfile)) + { + last = trad_stringify (pfile, tok, len, argc, argv, + &pat, &endpat, last); + break; + } + else { - if (CPP_TRADITIONAL (pfile)) - { - last = trad_stringify (pfile, tok, len, argc, argv, - &pat, &endpat, last); - break; - } if (CPP_WTRADITIONAL (pfile)) warn_trad_stringify (pfile, tok, len, argc, argv); + goto norm; } - goto norm; case CPP_NAME: for (j = 0; j < argc; j++) @@ -521,9 +604,6 @@ collect_expansion (pfile, list, arglist, replacement) norm: if (last_token == STRIZE) cpp_error (pfile, "# is not followed by a macro argument name"); - if (last_token != PASTE && last_token != START - && (list->tokens[i].flags & HSPACE_BEFORE)) - CPP_PUTC (pfile, ' '); CPP_PUTS (pfile, tok, len); last_token = NORM; } @@ -563,19 +643,11 @@ collect_expansion (pfile, list, arglist, replacement) defn->length = len; defn->expansion = exp; defn->pattern = pat; - defn->rest_args = argv && argv[argc - 1].rest_arg; - if (arglist) - { - defn->nargs = argc; - defn->argnames = arglist->namebuf; - if (argv) - free ((PTR) argv); - } - else - { - defn->nargs = -1; - defn->argnames = 0; - } + defn->rest_args = argc && argv[argc - 1].rest_arg; + defn->nargs = argc; + defn->argnames = arglist->namebuf; + if (argv) + free ((PTR) argv); return defn; } @@ -745,31 +817,134 @@ collect_params (pfile, list, arglist) (including formal parameters if present) is in LIST. If FUNLIKE is true, this is a function-like macro. */ -DEFINITION * -_cpp_create_definition (pfile, list, funlike) +int +_cpp_create_definition (pfile, list, hp) cpp_reader *pfile; cpp_toklist *list; - int funlike; + HASHNODE *hp; { - struct arglist args; - DEFINITION *defn; - int replacement = 1; /* replacement begins at this token */ + DEFINITION *defn = 0; + U_CHAR *cpval = 0; + enum node_type ntype; + int ok; + + /* Special-case a few simple and common idioms: + #define TOKEN // nothing + #define TOKEN TOKEN + #define TOKEN OTHERTOKEN + + Might also be good to special-case these: + + #define FUNC() // nothing + #define FUNC(a, b, ...) // nothing + #define FUNC(a, b, c) FUNC(a, b, c) + #define FUNC(a, b, c) foobar(a, b, c) */ + + if (list->tokens_used == 2) + ntype = T_EMPTY; /* Empty definition of object-like macro. */ + else if (list->tokens_used == 3 && list->tokens[1].type == CPP_NAME) + { + if (list->tokens[0].val.name.len == list->tokens[1].val.name.len + && !strncmp (list->tokens[0].val.name.offset + list->namebuf, + list->tokens[1].val.name.offset + list->namebuf, + list->tokens[0].val.name.len)) + ntype = T_IDENTITY; + else + { + ntype = T_MCONST; + cpval = xmalloc (list->tokens[1].val.name.len + 1); + memcpy (cpval, list->tokens[1].val.name.offset + list->namebuf, + list->tokens[1].val.name.len); + cpval[list->tokens[1].val.name.len] = '\0'; + } + } - if (funlike) + /* The macro is function-like only if the next character, + with no intervening whitespace, is '('. */ + else if (list->tokens[1].type == CPP_OPEN_PAREN + && ! (list->tokens[1].flags & HSPACE_BEFORE)) { + struct arglist args; + int replacement; + replacement = collect_params (pfile, list, &args); if (replacement == 0) return 0; + defn = collect_funlike_expansion (pfile, list, &args, replacement); + if (defn == 0) + return 0; + + ntype = T_FMACRO; } - defn = collect_expansion (pfile, list, funlike ? &args : 0, replacement); - if (defn == 0) - return 0; + /* Otherwise it is an object-like macro, and C99 requires + whitespace after the name (6.10.3 para 3). */ + else + { + if (! (list->tokens[1].flags & CPP_OPEN_PAREN)) + cpp_pedwarn (pfile, + "The C standard requires whitespace after #define %s", + hp->name); - defn->file = CPP_BUFFER (pfile)->nominal_fname; - defn->line = list->line; - defn->col = list->tokens[0].col; - return defn; + defn = collect_objlike_expansion (pfile, list); + if (defn == 0) + return 0; + + ntype = T_MACRO; + } + + /* Check for a redefinition, and its legality. Redefining a macro + of whatever stripe is ok if the definitions are the same. + Redefining a built-in _constant_ (T_CONST or T_XCONST) is ok only + with -D. Otherwise a redefinition is not ok. */ + + switch (hp->type) + { + case T_VOID: ok = 1; break; + default: ok = 0; break; + + case T_MACRO: case T_FMACRO: + ok = (ntype == hp->type && !compare_defs (pfile, defn, hp->value.defn)); + break; + case T_IDENTITY: + case T_EMPTY: + ok = (ntype == hp->type); + break; + case T_MCONST: + ok = (ntype == hp->type && !strcmp (cpval, hp->value.cpval)); + break; + case T_CONST: + case T_XCONST: + ok = ! pfile->done_initializing; + break; + } + + /* Print the warning or error if it's not ok. */ + if (! ok) + { + cpp_pedwarn (pfile, "\"%s\" redefined", hp->name); + if (pfile->done_initializing) + cpp_pedwarn_with_file_and_line (pfile, hp->file, hp->line, hp->col, + "this is the location of the previous definition"); + } + + /* And replace the old definition (if any). */ + + if (hp->type == T_MACRO || hp->type == T_FMACRO) + _cpp_free_definition (hp->value.defn); + else if (hp->type == T_MCONST || hp->type == T_XCONST) + free ((PTR) hp->value.cpval); + + if (ntype == T_MACRO || ntype == T_FMACRO) + hp->value.defn = defn; + else + hp->value.cpval = cpval; + + hp->type = ntype; + hp->file = CPP_BUFFER (pfile)->nominal_fname; + hp->line = list->line; + hp->col = list->tokens[0].col; + return 1; } /* @@ -874,9 +1049,9 @@ _cpp_quote_string (pfile, src) #define DSC(str) (const U_CHAR *)str, sizeof str - 1 static void -special_symbol (hp, pfile) - HASHNODE *hp; +special_symbol (pfile, hp) cpp_reader *pfile; + HASHNODE *hp; { const char *buf; cpp_buffer *ip; @@ -929,6 +1104,7 @@ special_symbol (hp, pfile) /* else fall through */ case T_CONST: case T_MCONST: + case T_XCONST: constant: buf = hp->value.cpval; if (!buf) @@ -1005,430 +1181,429 @@ _cpp_macroexpand (pfile, hp) cpp_reader *pfile; HASHNODE *hp; { - int nargs; DEFINITION *defn; - register U_CHAR *xbuf; - unsigned int start_line, start_column; - cpp_buffer *ip; - int xbuf_len; - struct argdata *args = 0; - long old_written = CPP_WRITTEN (pfile); - int rest_args, rest_zero = 0; - register int i; + struct argdata *args; + unsigned int old_written; + int i; - ip = cpp_file_buffer (pfile); - if (ip) + /* Object like macro - most common case. */ + if (hp->type == T_MACRO) { - start_line = CPP_BUF_LINE (ip); - start_column = CPP_BUF_COL (ip); + push_macro_expansion (pfile, hp->value.defn->expansion, + hp->value.defn->length, hp); + return; + } + + /* Or might it be a constant string? */ + if (hp->type == T_MCONST || hp->type == T_CONST || hp->type == T_XCONST) + { + const U_CHAR *cpval = hp->value.cpval; + if (!cpval || *cpval == '\0') + cpval = (const U_CHAR *) "\r \r "; + push_macro_expansion (pfile, cpval, strlen (cpval), hp); + return; } - else - start_line = start_column = 0; - /* Check for and handle special symbols. */ - if (hp->type != T_MACRO) + /* Or a special symbol? */ + if (hp->type != T_FMACRO) { - special_symbol (hp, pfile); - xbuf_len = CPP_WRITTEN (pfile) - old_written; - xbuf = (U_CHAR *) xmalloc (xbuf_len + 1); + U_CHAR *xbuf; + unsigned int len, old_written = CPP_WRITTEN (pfile); + + special_symbol (pfile, hp); + len = CPP_WRITTEN (pfile) - old_written; CPP_SET_WRITTEN (pfile, old_written); - memcpy (xbuf, CPP_PWRITTEN (pfile), xbuf_len + 1); - push_macro_expansion (pfile, xbuf, xbuf_len, hp); - CPP_BUFFER (pfile)->has_escapes = 1; + xbuf = (U_CHAR *) xmalloc (len + 1); + memcpy (xbuf, CPP_PWRITTEN (pfile), len); + xbuf[len] = '\0'; + push_macro_expansion (pfile, xbuf, len, hp); return; } + /* Okay, it's a full-on function-like macro... */ + old_written = CPP_WRITTEN (pfile); defn = hp->value.defn; - nargs = defn->nargs; + + args = alloca (MAX (defn->nargs, 1) * sizeof (struct argdata)); + for (i = 0; i < MAX (defn->nargs, 1); i++) + { + args[i].raw = args[i].expanded = 0; + args[i].raw_length = 0; + args[i].expand_length = args[i].stringified_length = -1; + } + pfile->output_escapes++; + scan_arguments (pfile, defn, args, hp->name); - if (nargs >= 0) + /* If macro wants zero args, we parsed the arglist for checking only. + Read directly from the macro definition. */ + if (defn->nargs == 0 || defn->pattern == 0) { - enum cpp_ttype token; + CPP_SET_WRITTEN (pfile, old_written); + pfile->output_escapes--; + push_macro_expansion (pfile, defn->expansion, defn->length, hp); + return; + } - args = (struct argdata *) alloca ((nargs + 1) * sizeof (struct argdata)); + funlike_macroexpand (pfile, hp, args); + pfile->output_escapes--; +} - for (i = 0; i < nargs; i++) - { - args[i].raw = args[i].expanded = 0; - args[i].raw_length = 0; - args[i].expand_length = args[i].stringified_length = -1; - } +static void +scan_arguments (pfile, defn, args, name) + cpp_reader *pfile; + DEFINITION *defn; + struct argdata *args; + const U_CHAR *name; +{ + enum cpp_ttype token; + unsigned int start_line, start_column; + unsigned int nargs = defn->nargs; + unsigned int i; + + cpp_buffer *ip = cpp_file_buffer (pfile); + if (ip) + { + start_line = CPP_BUF_LINE (ip); + start_column = CPP_BUF_COL (ip); + } + else + start_line = start_column = 0; - /* Parse all the macro args that are supplied. I counts them. - The first NARGS args are stored in ARGS. - The rest are discarded. If rest_args is set then we assume - macarg absorbed the rest of the args. */ - i = 0; - rest_args = 0; - - /* Skip over the opening parenthesis. */ - CPP_OPTION (pfile, discard_comments)++; - pfile->no_macro_expand++; - pfile->no_directives++; - - token = cpp_get_non_space_token (pfile); - if (token != CPP_OPEN_PAREN) - cpp_ice (pfile, "macroexpand: unexpected token %d (wanted LPAREN)", - token); - CPP_ADJUST_WRITTEN (pfile, -1); - - token = CPP_EOF; - do - { - if (rest_args) - continue; - if (i < nargs || (nargs == 0 && i == 0)) - { - /* if we are working on last arg which absorbs rest of args... */ - if (i == nargs - 1 && defn->rest_args) - rest_args = 1; - args[i].raw = CPP_WRITTEN (pfile); - token = macarg (pfile, rest_args); - args[i].raw_length = CPP_WRITTEN (pfile) - args[i].raw; - } - else - token = macarg (pfile, 0); - if (token == CPP_EOF || token == CPP_POP) - cpp_error_with_line (pfile, start_line, start_column, - "unterminated macro call"); - i++; - } - while (token == CPP_COMMA); - CPP_OPTION (pfile, discard_comments)--; - pfile->no_macro_expand--; - pfile->no_directives--; - if (token != CPP_CLOSE_PAREN) - return; + /* Parse all the macro args that are supplied. I counts them. The + first NARGS args are stored in ARGS. The rest are discarded. If + rest_args is set then we assume macarg absorbed the rest of the + args. */ + i = 0; - /* foo ( ) is equivalent to foo () unless foo takes exactly one - argument, in which case the former is allowed and the latter - is not. XXX C99 is silent on this rule, but it seems - inconsistent to me. */ - if (i == 1 && nargs != 1) - { - register U_CHAR *bp = ARG_BASE + args[0].raw; - register U_CHAR *lim = bp + args[0].raw_length; - while (bp != lim && is_space(*bp)) - bp++; - if (bp == lim) - i = 0; - } + /* Skip over the opening parenthesis. */ + CPP_OPTION (pfile, discard_comments)++; + pfile->no_macro_expand++; + pfile->no_directives++; - /* Don't output an error message if we have already output one for - a parse error above. */ - rest_zero = 0; - if (nargs == 0 && i > 0) - { - cpp_error (pfile, "arguments given to macro `%s'", hp->name); - } - else if (i < nargs) - { - /* traditional C allows foo() if foo wants one argument. */ - if (nargs == 1 && i == 0 && CPP_TRADITIONAL (pfile)) - ; - /* the rest args token is allowed to absorb 0 tokens */ - else if (i == nargs - 1 && defn->rest_args) - rest_zero = 1; - else if (i == 0) - cpp_error (pfile, "macro `%s' used without args", hp->name); - else if (i == 1) - cpp_error (pfile, "macro `%s' used with just one arg", hp->name); - else - cpp_error (pfile, "macro `%s' used with only %d args", - hp->name, i); - } - else if (i > nargs) + token = cpp_get_non_space_token (pfile); + if (token != CPP_OPEN_PAREN) + cpp_ice (pfile, "macroexpand: unexpected token %d (wanted LPAREN)", + token); + CPP_ADJUST_WRITTEN (pfile, -1); + + token = CPP_EOF; + do + { + if (i < MAX (nargs, 1)) { - cpp_error (pfile, - "macro `%s' used with too many (%d) args", hp->name, i); + args[i].raw = CPP_WRITTEN (pfile); + token = macarg (pfile, (i == nargs - 1 && defn->rest_args)); + args[i].raw_length = CPP_WRITTEN (pfile) - args[i].raw; } + else + token = macarg (pfile, 0); + if (token == CPP_EOF || token == CPP_POP) + cpp_error_with_line (pfile, start_line, start_column, + "unterminated macro call"); + i++; } + while (token == CPP_COMMA); + CPP_OPTION (pfile, discard_comments)--; + pfile->no_macro_expand--; + pfile->no_directives--; + if (token != CPP_CLOSE_PAREN) + return; - /* If macro wants zero args, we parsed the arglist for checking only. - Read directly from the macro definition. */ - if (nargs <= 0) + /* foo ( ) is equivalent to foo () unless foo takes exactly one + argument, in which case the former is allowed and the latter + is not. XXX C99 is silent on this rule, but it seems + inconsistent to me. */ + if (i == 1 && nargs == 0) { - xbuf = defn->expansion; - xbuf_len = defn->length; + register U_CHAR *bp = ARG_BASE + args[0].raw; + register U_CHAR *lim = bp + args[0].raw_length; + while (bp != lim && is_space(*bp)) + bp++; + if (bp == lim) + i = 0; } - else - { - register U_CHAR *exp = defn->expansion; - register int offset; /* offset in expansion, - copied a piece at a time */ - register int totlen; /* total amount of exp buffer filled so far */ - register struct reflist *ap, *last_ap; + /* Don't output an error message if we have already output one for + a parse error above. */ + if (nargs == 0 && i > 0) + { + cpp_error (pfile, "arguments given to macro `%s'", name); + } + else if (i < nargs) + { + /* traditional C allows foo() if foo wants one argument. */ + if (nargs == 1 && i == 0 && CPP_TRADITIONAL (pfile)) + ; + /* the rest args token is allowed to absorb 0 tokens */ + else if (i == nargs - 1 && defn->rest_args) + ; + else if (i == 0) + cpp_error (pfile, "macro `%s' used without args", name); + else if (i == 1) + cpp_error (pfile, "macro `%s' used with just one arg", name); + else + cpp_error (pfile, "macro `%s' used with only %d args", name, i); + } + else if (i > nargs) + { + cpp_error (pfile, "macro `%s' used with too many (%d) args", name, i); + } +} - /* Macro really takes args. Compute the expansion of this call. */ +static void +stringify (pfile, arg) + cpp_reader *pfile; + struct argdata *arg; +{ + int arglen = arg->raw_length; + int escaped = 0; + int in_string = 0; + int c; + int i; + /* Initially need_space is -1. Otherwise, 1 means the previous + character was a space, but we suppressed it; 0 means the previous + character was a non-space. */ + int need_space = -1; + i = 0; + arg->stringified = CPP_WRITTEN (pfile); + CPP_PUTC (pfile, '\"'); /* insert beginning quote */ + for (; i < arglen; i++) + { + c = (ARG_BASE + arg->raw)[i]; - /* Compute length in characters of the macro's expansion. - Also count number of times each arg is used. */ - xbuf_len = defn->length; - for (ap = defn->pattern; ap != NULL; ap = ap->next) + if (!in_string) { - if (ap->stringify) + /* Delete "\r " and "\r-" escapes. */ + if (c == '\r') { - register struct argdata *arg = &args[ap->argno]; - /* Stringify if it hasn't already been */ - if (arg->stringified_length < 0) - { - int arglen = arg->raw_length; - int escaped = 0; - int in_string = 0; - int c; - /* Initially need_space is -1. Otherwise, 1 means the - previous character was a space, but we suppressed it; - 0 means the previous character was a non-space. */ - int need_space = -1; - i = 0; - arg->stringified = CPP_WRITTEN (pfile); - CPP_PUTC (pfile, '\"'); /* insert beginning quote */ - for (; i < arglen; i++) - { - c = (ARG_BASE + arg->raw)[i]; - - if (!in_string) - { - /* Delete "\r " and "\r-" escapes. */ - if (c == '\r') - { - i++; - continue; - } - /* Internal sequences of whitespace are - replaced by one space except within - a string or char token. */ - else if (is_space(c)) - { - if (need_space == 0) - need_space = 1; - continue; - } - else if (need_space > 0) - CPP_PUTC (pfile, ' '); - need_space = 0; - } - - if (escaped) - escaped = 0; - else - { - if (c == '\\') - escaped = 1; - if (in_string) - { - if (c == in_string) - in_string = 0; - } - else if (c == '\"' || c == '\'') - in_string = c; - } - - /* Escape these chars */ - if (c == '\"' || (in_string && c == '\\')) - CPP_PUTC (pfile, '\\'); - if (ISPRINT (c)) - CPP_PUTC (pfile, c); - else - { - CPP_RESERVE (pfile, 4); - sprintf ((char *) CPP_PWRITTEN (pfile), "\\%03o", - (unsigned int) c); - CPP_ADJUST_WRITTEN (pfile, 4); - } - } - CPP_PUTC (pfile, '\"'); /* insert ending quote */ - arg->stringified_length - = CPP_WRITTEN (pfile) - arg->stringified; - } - xbuf_len += args[ap->argno].stringified_length; + i++; + continue; } - else if (ap->raw_before || ap->raw_after) - /* Add 4 for two \r-space markers to prevent - token concatenation. */ - xbuf_len += args[ap->argno].raw_length + 4; - else + /* Internal sequences of whitespace are replaced by one + space except within a string or char token. */ + else if (is_space(c)) { - /* We have an ordinary (expanded) occurrence of the arg. - So compute its expansion, if we have not already. */ - if (args[ap->argno].expand_length < 0) - { - args[ap->argno].expanded = CPP_WRITTEN (pfile); - _cpp_expand_to_buffer (pfile, - ARG_BASE + args[ap->argno].raw, - args[ap->argno].raw_length); - - args[ap->argno].expand_length - = CPP_WRITTEN (pfile) - args[ap->argno].expanded; - } + if (need_space == 0) + need_space = 1; + continue; + } + else if (need_space > 0) + CPP_PUTC (pfile, ' '); + need_space = 0; + } - /* Add 4 for two \r-space markers to prevent - token concatenation. */ - xbuf_len += args[ap->argno].expand_length + 4; + if (escaped) + escaped = 0; + else + { + if (c == '\\') + escaped = 1; + if (in_string) + { + if (c == in_string) + in_string = 0; } + else if (c == '\"' || c == '\'') + in_string = c; } - xbuf = (U_CHAR *) xmalloc (xbuf_len + 1); + /* Escape these chars */ + if (c == '\"' || (in_string && c == '\\')) + CPP_PUTC (pfile, '\\'); + if (ISPRINT (c)) + CPP_PUTC (pfile, c); + else + { + CPP_RESERVE (pfile, 4); + sprintf ((char *) CPP_PWRITTEN (pfile), "\\%03o", (unsigned int) c); + CPP_ADJUST_WRITTEN (pfile, 4); + } + } + CPP_PUTC (pfile, '\"'); /* insert ending quote */ + arg->stringified_length = CPP_WRITTEN (pfile) - arg->stringified; +} - /* Generate in XBUF the complete expansion - with arguments substituted in. - TOTLEN is the total size generated so far. - OFFSET is the index in the definition - of where we are copying from. */ - offset = totlen = 0; - for (last_ap = NULL, ap = defn->pattern; ap != NULL; - last_ap = ap, ap = ap->next) +static void +funlike_macroexpand (pfile, hp, args) + cpp_reader *pfile; + HASHNODE *hp; + struct argdata *args; +{ + DEFINITION *defn = hp->value.defn; + register U_CHAR *xbuf; + int xbuf_len; + long old_written = CPP_WRITTEN (pfile); + U_CHAR *exp = defn->expansion; + int offset; /* offset in expansion, copied a piece at a time */ + int totlen; /* total amount of exp buffer filled so far */ + struct reflist *ap, *last_ap; + int i; + + /* Compute length in characters of the macro's expansion. + Also count number of times each arg is used. */ + xbuf_len = defn->length; + for (ap = defn->pattern; ap != NULL; ap = ap->next) + { + if (ap->stringify) { - register struct argdata *arg = &args[ap->argno]; - int count_before = totlen; - - /* Add chars to XBUF. */ - i = ap->nchars; - memcpy (&xbuf[totlen], &exp[offset], i); - totlen += i; - offset += i; - - /* If followed by an empty rest arg with concatenation, - delete the last run of nonwhite chars. */ - if (rest_zero && totlen > count_before - && ((ap->rest_args && ap->raw_before) - || (last_ap != NULL && last_ap->rest_args - && last_ap->raw_after))) + /* Stringify if it hasn't already been */ + if (args[ap->argno].stringified_length < 0) + stringify (pfile, &args[ap->argno]); + xbuf_len += args[ap->argno].stringified_length; + } + else if (ap->raw_before || ap->raw_after) + /* Add 4 for two \r-space markers to prevent + token concatenation. */ + xbuf_len += args[ap->argno].raw_length + 4; + else + { + /* We have an ordinary (expanded) occurrence of the arg. + So compute its expansion, if we have not already. */ + if (args[ap->argno].expand_length < 0) { - /* Delete final whitespace. */ - while (totlen > count_before && is_space(xbuf[totlen - 1])) - totlen--; + args[ap->argno].expanded = CPP_WRITTEN (pfile); + _cpp_expand_to_buffer (pfile, ARG_BASE + args[ap->argno].raw, + args[ap->argno].raw_length); - /* Delete the nonwhites before them. */ - while (totlen > count_before && !is_space(xbuf[totlen - 1])) - totlen--; + args[ap->argno].expand_length + = CPP_WRITTEN (pfile) - args[ap->argno].expanded; } - if (ap->stringify != 0) - { - memcpy (xbuf + totlen, ARG_BASE + arg->stringified, - arg->stringified_length); - totlen += arg->stringified_length; - } - else if (ap->raw_before || ap->raw_after) + /* Add 4 for two \r-space markers to prevent + token concatenation. */ + xbuf_len += args[ap->argno].expand_length + 4; + } + } + + xbuf = (U_CHAR *) xmalloc (xbuf_len + 1); + + /* Generate in XBUF the complete expansion with arguments + substituted in. TOTLEN is the total size generated so far. + OFFSET is the index in the definition of where we are copying + from. */ + offset = totlen = 0; + for (last_ap = NULL, ap = defn->pattern; ap != NULL; + last_ap = ap, ap = ap->next) + { + register struct argdata *arg = &args[ap->argno]; + int count_before = totlen; + + /* Add chars to XBUF. */ + i = ap->nchars; + memcpy (&xbuf[totlen], &exp[offset], i); + totlen += i; + offset += i; + + /* If followed by an empty rest arg with concatenation, + delete the last run of nonwhite chars. */ + if (arg->raw_length == 0 && totlen > count_before + && ((ap->rest_args && ap->raw_before) + || (last_ap != NULL && last_ap->rest_args + && last_ap->raw_after))) + { + /* Delete final whitespace. */ + while (totlen > count_before && is_space(xbuf[totlen - 1])) + totlen--; + + /* Delete the nonwhites before them. */ + while (totlen > count_before && !is_space(xbuf[totlen - 1])) + totlen--; + } + + if (ap->stringify != 0) + { + memcpy (xbuf + totlen, ARG_BASE + arg->stringified, + arg->stringified_length); + totlen += arg->stringified_length; + } + else if (ap->raw_before || ap->raw_after) + { + U_CHAR *p1 = ARG_BASE + arg->raw; + U_CHAR *l1 = p1 + arg->raw_length; + if (ap->raw_before) { - U_CHAR *p1 = ARG_BASE + arg->raw; - U_CHAR *l1 = p1 + arg->raw_length; - if (ap->raw_before) + /* Arg is concatenated before: delete leading whitespace, + whitespace markers, and no-reexpansion markers. */ + while (p1 != l1) { - /* Arg is concatenated before: delete leading whitespace, - whitespace markers, and no-reexpansion markers. */ - while (p1 != l1) - { - if (is_space(p1[0])) - p1++; - else if (p1[0] == '\r') - p1 += 2; - else - break; - } + if (is_space(p1[0])) + p1++; + else if (p1[0] == '\r') + p1 += 2; + else + break; } - if (ap->raw_after) + } + if (ap->raw_after) + { + /* Arg is concatenated after: delete trailing whitespace, + whitespace markers, and no-reexpansion markers. */ + while (p1 != l1) { - /* Arg is concatenated after: delete trailing whitespace, - whitespace markers, and no-reexpansion markers. */ - while (p1 != l1) + if (is_space(l1[-1])) + l1--; + else if (l1[-1] == '\r') + l1--; + else if (l1[-1] == '-') { - if (is_space(l1[-1])) - l1--; - else if (l1[-1] == '\r') - l1--; - else if (l1[-1] == '-') - { - if (l1 != p1 + 1 && l1[-2] == '\r') - l1 -= 2; - else - break; - } + if (l1 != p1 + 1 && l1[-2] == '\r') + l1 -= 2; else break; } + else + break; } - - /* Delete any no-reexpansion marker that precedes - an identifier at the beginning of the argument. */ - if (p1[0] == '\r' && p1[1] == '-') - p1 += 2; - - memcpy (xbuf + totlen, p1, l1 - p1); - totlen += l1 - p1; } - else - { - U_CHAR *expanded = ARG_BASE + arg->expanded; - if (!ap->raw_before && totlen > 0 && arg->expand_length - && unsafe_chars (pfile, xbuf[totlen - 1], expanded[0])) - { - xbuf[totlen++] = '\r'; - xbuf[totlen++] = ' '; - } - memcpy (xbuf + totlen, expanded, arg->expand_length); - totlen += arg->expand_length; + /* Delete any no-reexpansion marker that precedes + an identifier at the beginning of the argument. */ + if (p1[0] == '\r' && p1[1] == '-') + p1 += 2; - if (!ap->raw_after && totlen > 0 && offset < defn->length - && unsafe_chars (pfile, xbuf[totlen - 1], exp[offset])) - { - xbuf[totlen++] = '\r'; - xbuf[totlen++] = ' '; - } - } - - if (totlen > xbuf_len) + memcpy (xbuf + totlen, p1, l1 - p1); + totlen += l1 - p1; + } + else + { + U_CHAR *expanded = ARG_BASE + arg->expanded; + if (!ap->raw_before && totlen > 0 && arg->expand_length + && unsafe_chars (pfile, xbuf[totlen - 1], expanded[0])) { - cpp_ice (pfile, "buffer overrun in macroexpand"); - return; + xbuf[totlen++] = '\r'; + xbuf[totlen++] = ' '; } - } - /* if there is anything left of the definition - after handling the arg list, copy that in too. */ + memcpy (xbuf + totlen, expanded, arg->expand_length); + totlen += arg->expand_length; - for (i = offset; i < defn->length; i++) - { - /* if we've reached the end of the macro */ - if (exp[i] == ')') - rest_zero = 0; - if (!(rest_zero && last_ap != NULL && last_ap->rest_args - && last_ap->raw_after)) - xbuf[totlen++] = exp[i]; + if (!ap->raw_after && totlen > 0 && offset < defn->length + && unsafe_chars (pfile, xbuf[totlen - 1], exp[offset])) + { + xbuf[totlen++] = '\r'; + xbuf[totlen++] = ' '; + } } - - xbuf[totlen] = 0; - xbuf_len = totlen; - } - pfile->output_escapes--; + /* if there is anything left of the definition + after handling the arg list, copy that in too. */ + for (i = offset; i < defn->length; i++) + xbuf[totlen++] = exp[i]; + xbuf[totlen] = 0; + + if (totlen > xbuf_len) + /* Just die - we've trashed the heap at this point. */ + abort (); + /* Now put the expansion on the input stack so our caller will commence reading from it. */ - push_macro_expansion (pfile, xbuf, xbuf_len, hp); - CPP_BUFFER (pfile)->has_escapes = 1; + push_macro_expansion (pfile, xbuf, totlen, hp); /* Pop the space we've used in the token_buffer for argument expansion. */ CPP_SET_WRITTEN (pfile, old_written); - - /* In C89, a macro cannot be expanded recursively. Traditional C - permits it, but any use in an object-like macro must lead to - infinite recursion, so always follow C89 in object-like macros. - - The only example known where this doesn't cause infinite recursion - in function-like macros is: - #define foo(x,y) bar(x(y, 0)) - foo(foo, baz) - which expands to bar(foo(baz, 0)) in C89 and - bar(bar(baz(0, 0)) in K+R. This looks pathological to me. - If someone has a real-world example I would love to see it. */ - if (nargs <= 0 || !CPP_TRADITIONAL (pfile)) - hp->type = T_DISABLED; } /* Return 1 iff a token ending in C1 followed directly by a token C2 @@ -1501,7 +1676,7 @@ unsafe_chars (pfile, c1, c2) static void push_macro_expansion (pfile, xbuf, len, hp) cpp_reader *pfile; - register U_CHAR *xbuf; + const U_CHAR *xbuf; int len; HASHNODE *hp; { @@ -1539,12 +1714,33 @@ push_macro_expansion (pfile, xbuf, len, hp) mbuf->cur += 2; mbuf->cleanup = macro_cleanup; mbuf->macro = hp; + mbuf->has_escapes = 1; + + /* In C89, a macro cannot be expanded recursively. Traditional C + permits it, but any use in an object-like macro must lead to + infinite recursion, so always follow C89 in object-like macros. + Likewise, in a function-like macro it must cause infinite + recursion unless we are actually doing something with the + arguments. + + Even that criterion is too weak. The only example known where + macro recursion isn't infinite is: + #define bar(x,y) foo(x(y, 0)) + bar(bar, baz) + which expands to foo(bar(baz, 0)) in C89 and + foo(foo(baz(0, 0)) in K+R. This looks pathological to me. + If someone has a real-world example I would love to see it. */ + if (hp->type != T_FMACRO + || hp->value.defn->nargs == 0 + || hp->value.defn->pattern == 0 + || !CPP_TRADITIONAL (pfile)) + hp->disabled = 1; } /* Return zero if two DEFINITIONs are isomorphic. */ -int -_cpp_compare_defs (pfile, d1, d2) +static int +compare_defs (pfile, d1, d2) cpp_reader *pfile; DEFINITION *d1, *d2; { @@ -1590,91 +1786,107 @@ _cpp_compare_defs (pfile, d1, d2) to be read back in again. */ void -_cpp_dump_definition (pfile, sym, len, defn) +_cpp_dump_definition (pfile, hp) cpp_reader *pfile; - const U_CHAR *sym; - long len; - DEFINITION *defn; + HASHNODE *hp; { - CPP_RESERVE (pfile, len + sizeof "#define "); - CPP_PUTS_Q (pfile, "#define ", sizeof "#define " -1); - CPP_PUTS_Q (pfile, sym, len); - - if (defn->nargs == -1) + 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_EMPTY) + /* do nothing */; + else if (hp->type == T_FMACRO) + dump_DEFINITION (pfile, hp->value.defn); + else { CPP_PUTC_Q (pfile, ' '); - /* The first and last two characters of a macro expansion are - always "\r "; this needs to be trimmed out. - So we need length-4 chars of space, plus one for the NUL. */ - CPP_RESERVE (pfile, defn->length - 4 + 1); - CPP_PUTS_Q (pfile, defn->expansion + 2, defn->length - 4); - } - else - { - struct reflist *r; - unsigned char **argv = (unsigned char **) alloca (defn->nargs * - sizeof(char *)); - int *argl = (int *) alloca (defn->nargs * sizeof(int)); - unsigned char *x; - int i; - - /* First extract the argument list. */ - x = defn->argnames; - for (i = 0; i < defn->nargs; i++) - { - argv[i] = x; - argl[i] = strlen (x); - x += argl[i] + 1; - } - - /* Now print out the argument list. */ - CPP_PUTC_Q (pfile, '('); - for (i = 0; i < defn->nargs; i++) + if (hp->type == T_IDENTITY) + CPP_PUTS (pfile, hp->name, hp->length); + else if (hp->type == T_MCONST) + CPP_PUTS (pfile, hp->value.cpval, strlen (hp->value.cpval)); + else if (hp->type == T_MACRO) { - CPP_RESERVE (pfile, argl[i] + 2); - if (!(i == defn->nargs-1 && defn->rest_args - && !strcmp (argv[i], "__VA_ARGS__"))) - CPP_PUTS_Q (pfile, argv[i], argl[i]); - if (i < defn->nargs-1) - CPP_PUTS_Q (pfile, ", ", 2); + /* The first and last two characters of a macro expansion are + always "\r "; this needs to be trimmed out. + So we need length-4 chars of space, plus one for the NUL. */ + CPP_RESERVE (pfile, hp->value.defn->length - 4 + 1); + CPP_PUTS_Q (pfile, hp->value.defn->expansion + 2, + hp->value.defn->length - 4); } - if (defn->rest_args) - CPP_PUTS (pfile, "...", 3); - CPP_PUTS (pfile, ") ", 2); + 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'); +} - /* Now the definition. */ - x = defn->expansion; - for (r = defn->pattern; r; r = r->next) - { - i = r->nchars; - if (*x == '\r') x += 2, i -= 2; - /* i chars for macro text, plus the length of the macro - argument name, plus one for a stringify marker, plus two for - each concatenation marker. */ - CPP_RESERVE (pfile, - i + argl[r->argno] + r->stringify - + (r->raw_before + r->raw_after) * 2); - - if (i > 0) CPP_PUTS_Q (pfile, x, i); - if (r->raw_before) - CPP_PUTS_Q (pfile, "##", 2); - if (r->stringify) - CPP_PUTC_Q (pfile, '#'); - CPP_PUTS_Q (pfile, argv[r->argno], argl[r->argno]); - if (r->raw_after && !(r->next && r->next->nchars == 0 - && r->next->raw_before)) - CPP_PUTS_Q (pfile, "##", 2); - - x += i; - } +static void +dump_DEFINITION (pfile, defn) + cpp_reader *pfile; + DEFINITION *defn; +{ + struct reflist *r; + unsigned char **argv = (unsigned char **) alloca (defn->nargs * + sizeof(char *)); + int *argl = (int *) alloca (defn->nargs * sizeof(int)); + unsigned char *x; + int i; + + /* First extract the argument list. */ + x = defn->argnames; + for (i = 0; i < defn->nargs; i++) + { + argv[i] = x; + argl[i] = strlen (x); + x += argl[i] + 1; + } + + /* Now print out the argument list. */ + CPP_PUTC_Q (pfile, '('); + for (i = 0; i < defn->nargs; i++) + { + CPP_RESERVE (pfile, argl[i] + 2); + if (!(i == defn->nargs-1 && defn->rest_args + && !strcmp (argv[i], "__VA_ARGS__"))) + CPP_PUTS_Q (pfile, argv[i], argl[i]); + if (i < defn->nargs-1) + CPP_PUTS_Q (pfile, ", ", 2); + } + if (defn->rest_args) + CPP_PUTS (pfile, "...", 3); + CPP_PUTS (pfile, ") ", 2); - i = defn->length - (x - defn->expansion) - 2; + /* Now the definition. */ + x = defn->expansion; + for (r = defn->pattern; r; r = r->next) + { + i = r->nchars; if (*x == '\r') x += 2, i -= 2; - if (i > 0) CPP_PUTS (pfile, x, i); + /* i chars for macro text, plus the length of the macro + argument name, plus one for a stringify marker, plus two for + each concatenation marker. */ + CPP_RESERVE (pfile, + i + argl[r->argno] + r->stringify + + (r->raw_before + r->raw_after) * 2); + + if (i > 0) CPP_PUTS_Q (pfile, x, i); + if (r->raw_before) + CPP_PUTS_Q (pfile, "##", 2); + if (r->stringify) + CPP_PUTC_Q (pfile, '#'); + CPP_PUTS_Q (pfile, argv[r->argno], argl[r->argno]); + if (r->raw_after && !(r->next && r->next->nchars == 0 + && r->next->raw_before)) + CPP_PUTS_Q (pfile, "##", 2); + + x += i; } - if (CPP_BUFFER (pfile) == 0 || ! pfile->done_initializing) - CPP_PUTC (pfile, '\n'); + + i = defn->length - (x - defn->expansion) - 2; + if (*x == '\r') x += 2, i -= 2; + if (i > 0) CPP_PUTS (pfile, x, i); } /* Dump out the hash table. */ @@ -1687,7 +1899,7 @@ dump_hash_helper (h, p) cpp_reader *pfile = (cpp_reader *)p; if (hp->type == T_MACRO) - _cpp_dump_definition (pfile, hp->name, hp->length, hp->value.defn); + _cpp_dump_definition (pfile, hp); return 1; } |