gcc/gcc/cpphash.c
Zack Weinberg ff2b53efb1 cpphash.c (CPP_IS_MACRO_BUFFER, [...]): Delete.
* cpphash.c (CPP_IS_MACRO_BUFFER, FORWARD, PEEKC): Delete.
	(macro_cleanup): No need to cast pbuf->macro.
	(collect_expansion): Use _cpp_get_define_token.  Goto done if
	it returns VSPACE.  Remove check for trailing space after
	CPP_COMMENT.
	(_cpp_create_definition): Don't diddle flags here.  Return
	directly on error.
	(unsafe_chars): Handle c1 being EOF.
	(push_macro_expansion): Use unsafe_chars for both accidental-paste
	checks.  Don't push the buffer till after we're done with
	them.
	* cpplex.c (PEEKBUF, GETBUF, FORWARDBUF): New.
	(PEEKN, FORWARD, GETC, PEEKC): Use them.
	(cpp_push_buffer): Don't set new->alimit.  Set new->mark
	appropriately.
	(_cpp_parse_assertion): Don't NUL terminate.
	(_cpp_lex_token): Fix -traditional macro handling.  Don't skip
	hspace before calling _cpp_parse_assertion.  Remove all sets
	of only_seen_white. Treat '\f' as hspace.  Don't do anything
	special with '\n' here.
	(maybe_macroexpand): Handle T_EMPTY hash entries without
	pushing a buffer at all.
	(cpp_get_token): Handle clearing only_seen_white here.  Handle
	incrementing the line number here.  Clear
	potential_control_macro as well as only_seen_white, if
	appropriate.
	(cpp_get_non_space_token): Don't eat CPP_POP tokens.
	(_cpp_get_define_token): New function, basically like
	_cpp_get_directive_token was but doesn't eat horizontal space.
	Don't do anything with only_seen_white here.
	(_cpp_get_directive_token): Just call _cpp_get_define_token
	repeatedly till it returns non-hspace.

	* cpplib.c (PEEKN, FORWARD, GETC, PEEKC): Delete.
	(conditional_skip, skip_if_group): Return int.
	(DIRECTIVE_TABLE): Change origin of all conditional directives
	to "COND".
	(TRAD_DIRECT_P): New macro.
	(_cpp_handle_directive): Use _cpp_get_directive_token.  Issue
	an error for a bogus directive, unless -lang-asm.  Use
	TRAD_DIRECT_P. Loop calling handler functions till one returns
	zero.
	(get_macro_name): Don't diddle flags here.
	(do_define): Diddle flags here.  Use _cpp_get_directive_token.
	Create T_EMPTY nodes for #define macro /* nothing */.
	(do_undef): Don't copy the name.  Use _cpp_get_directive_token.
	Use hp->name when calling pass_thru_directive.
	(do_if, do_else, do_elif, do_ifdef, do_ifndef, conditional_skip):
	Return the result of conditional_skip and/or skip_if_group.
	Don't call _cpp_output_line_command.
	(consider_directive_while_skipping): Use _cpp_get_directive_token.
	Issue -Wtraditional warnings as appropriate.  Don't complain
	about unrecognized directives.  If we are to stop skipping,
	return the number of the directive that ended the skip.
	(skip_if_group): Use _cpp_get_directive_token.  Turn off macro
	expansion and line commands while skipping.  Return the result
	of consider_directive_while_skipping, if nonzero.
	(do_endif): Just set potential_control_macro here.
	(validate_else): Use _cpp_get_directive_token.
	(do_assert, do_unassert): Don't save pointers into the
	token_buffer across calls to the lexer.  Use
	_cpp_get_directive_token.

	* cpplib.h (cpp_buffer): Remove alimit and colno.  Make mark a
	pointer, not an offset.  Replace 'data', which was a generic
	pointer, with 'macro', which points to a struct hashnode.
	(cpp_reader): Add 'potential_control_macro' pointer.
	* cpphash.h (T_UNUSED): Replace with T_EMPTY.
	(CPP_BUF_GET, CPP_FORWARD): Delete.
	(CPP_IN_COLUMN_1, ADJACENT_TO_MARK): New macros.
	(CPP_IS_MACRO_BUFFER, CPP_SET_BUF_MARK, CPP_GOTO_BUF_MARK,
	ACTIVE_MARK_P): Update.
	(_cpp_get_define_token): New internal function.
	* cppfiles.c (read_include_file): Don't set fp->alimit or fp->colno.

From-SVN: r32965
2000-04-06 07:56:14 +00:00

1736 lines
44 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* 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"
#include "hashtab.h"
#undef abort
static unsigned int hash_HASHNODE PARAMS ((const void *));
static int eq_HASHNODE PARAMS ((const void *, const void *));
static void del_HASHNODE PARAMS ((void *));
static int dump_hash_helper PARAMS ((void **, void *));
static int comp_def_part PARAMS ((int, U_CHAR *, int, U_CHAR *,
int, int));
static void push_macro_expansion PARAMS ((cpp_reader *,
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_token macarg PARAMS ((cpp_reader *, int));
static struct tm *timestamp PARAMS ((cpp_reader *));
static void special_symbol PARAMS ((HASHNODE *, cpp_reader *));
/* Initial hash table size. (It can grow if necessary - see hashtab.c.) */
#define HASHSIZE 500
/* The arglist structure is built by create_definition to tell
collect_expansion where the argument names begin. That
is, for a define like "#define f(x,y,z) foo+x-bar*y", the arglist
would contain pointers to the strings x, y, and z.
collect_expansion would then build a DEFINITION node,
with reflist nodes pointing to the places x, y, and z had
appeared. So the arglist is just convenience data passed
between these two routines. It is not kept around after
the current #define has been processed and entered into the
hash table. */
struct arg
{
U_CHAR *name;
int len;
char rest_arg;
};
struct arglist
{
U_CHAR *namebuf;
struct arg *argv;
int argc;
};
static DEFINITION *collect_expansion PARAMS ((cpp_reader *, struct arglist *));
static struct arglist *collect_formal_parameters PARAMS ((cpp_reader *));
/* This structure represents one parsed argument in a macro call.
`raw' points to the argument text as written (`raw_length' is its length).
`expanded' points to the argument's macro-expansion
(its length is `expand_length').
`stringified_length' is the length the argument would have
if stringified. */
/* raw and expanded are relative to ARG_BASE */
#define ARG_BASE ((pfile)->token_buffer)
struct argdata
{
/* Strings relative to pfile->token_buffer */
long raw, expanded, stringified;
int raw_length, expand_length;
int stringified_length;
};
/* Calculate hash of a string of length LEN. */
unsigned int
_cpp_calc_hash (str, len)
const U_CHAR *str;
size_t len;
{
size_t n = len;
unsigned int r = 0;
do
r = r * 67 + (*str++ - 113);
while (--n);
return r + len;
}
/* Calculate hash of a HASHNODE structure. */
static unsigned int
hash_HASHNODE (x)
const void *x;
{
const HASHNODE *h = (const HASHNODE *)x;
return h->hash;
}
/* Compare two HASHNODE structures. */
static int
eq_HASHNODE (x, y)
const void *x;
const void *y;
{
const HASHNODE *a = (const HASHNODE *)x;
const HASHNODE *b = (const HASHNODE *)y;
return (a->length == b->length
&& !strncmp (a->name, b->name, a->length));
}
/* Destroy a HASHNODE. */
static void
del_HASHNODE (x)
void *x;
{
HASHNODE *h = (HASHNODE *)x;
if (h->type == T_MACRO)
_cpp_free_definition (h->value.defn);
free ((void *) h->name);
free (h);
}
/* Allocate and initialize a HASHNODE structure.
Caller must fill in the value field. */
HASHNODE *
_cpp_make_hashnode (name, len, type, hash)
const U_CHAR *name;
size_t len;
enum node_type type;
unsigned long hash;
{
HASHNODE *hp = (HASHNODE *) xmalloc (sizeof (HASHNODE));
U_CHAR *p = xmalloc (len + 1);
hp->type = type;
hp->length = len;
hp->name = p;
hp->hash = hash;
memcpy (p, name, len);
p[len] = 0;
return hp;
}
/* Find the hash node for name "name", which ends at the first
non-identifier char.
If LEN is >= 0, it is the length of the name.
Otherwise, compute the length now. */
HASHNODE *
_cpp_lookup (pfile, name, len)
cpp_reader *pfile;
const U_CHAR *name;
int len;
{
const U_CHAR *bp;
HASHNODE dummy;
if (len < 0)
{
for (bp = name; is_idchar (*bp); bp++);
len = bp - name;
}
dummy.name = name;
dummy.length = len;
dummy.hash = _cpp_calc_hash (name, len);
return (HASHNODE *) htab_find_with_hash (pfile->hashtab,
(void *)&dummy, dummy.hash);
}
/* Find the hashtable slot for name "name". Used to insert or delete. */
HASHNODE **
_cpp_lookup_slot (pfile, name, len, insert, hash)
cpp_reader *pfile;
const U_CHAR *name;
int len;
int insert;
unsigned long *hash;
{
const U_CHAR *bp;
HASHNODE dummy;
HASHNODE **slot;
if (len < 0)
{
for (bp = name; is_idchar (*bp); bp++);
len = bp - name;
}
dummy.name = name;
dummy.length = len;
dummy.hash = _cpp_calc_hash (name, len);
slot = (HASHNODE **) htab_find_slot_with_hash (pfile->hashtab,
(void *)&dummy,
dummy.hash, insert);
if (insert)
*hash = dummy.hash;
return slot;
}
/* Init the hash table. In here so it can see the hash and eq functions. */
void
_cpp_init_macro_hash (pfile)
cpp_reader *pfile;
{
pfile->hashtab = htab_create (HASHSIZE, hash_HASHNODE,
eq_HASHNODE, del_HASHNODE);
}
/* Free a DEFINITION structure. Used by delete_macro, and by
do_define when redefining macros. */
void
_cpp_free_definition (d)
DEFINITION *d;
{
struct reflist *ap, *nextap;
for (ap = d->pattern; ap != NULL; ap = nextap)
{
nextap = ap->next;
free (ap);
}
if (d->argnames)
free (d->argnames);
free (d);
}
static int
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)
free ((PTR) pbuf->buf);
return 0;
}
/* Read a replacement list for a macro, and build the DEFINITION
structure. 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.
A good half of this is devoted to supporting -traditional.
Kill me now. */
static DEFINITION *
collect_expansion (pfile, arglist)
cpp_reader *pfile;
struct arglist *arglist;
{
DEFINITION *defn;
struct reflist *pat = 0, *endpat = 0;
enum cpp_token token;
long start, here, last;
int i;
int argc;
size_t len;
struct arg *argv;
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;
}
last = start = CPP_WRITTEN (pfile);
last -= 2; /* two extra chars for the leading escape */
for (;;)
{
/* Macro expansion is off, so we are guaranteed not to see POP
or EOF. */
here = CPP_WRITTEN (pfile);
token = _cpp_get_define_token (pfile);
tok = pfile->token_buffer + here;
switch (token)
{
case CPP_POP:
case CPP_EOF:
cpp_ice (pfile, "EOF in collect_expansion");
/* fall through */
case CPP_VSPACE:
goto done;
case CPP_HSPACE:
if (last_token == STRIZE || last_token == PASTE
|| last_token == START)
CPP_SET_WRITTEN (pfile, here);
break;
case CPP_STRINGIZE:
/* # is not special in object-like macros. It is special in
function-like macros with no args. (6.10.3.2 para 1.) */
if (arglist == NULL)
goto norm;
/* # is not special immediately after PASTE.
(Implied by 6.10.3.3 para 4.) */
if (last_token == PASTE)
goto norm;
last_token = STRIZE;
CPP_SET_WRITTEN (pfile, here); /* delete from replacement text */
break;
case CPP_TOKPASTE:
/* If the last token was an argument, discard this token and
any hspace between it and the argument's position. Then
mark the arg raw_after. */
if (last_token == ARG)
{
endpat->raw_after = 1;
last_token = PASTE;
CPP_SET_WRITTEN (pfile, last);
break;
}
else if (last_token == PASTE)
/* ## ## - the second ## is ordinary. */
goto norm;
else if (last_token == START)
cpp_error (pfile, "`##' at start of macro definition");
/* Discard the token and any hspace before it. */
while (is_hspace (pfile->token_buffer[here-1]))
here--;
CPP_SET_WRITTEN (pfile, here);
if (last_token == STRIZE)
/* Oops - that wasn't a stringify operator. */
CPP_PUTC (pfile, '#');
last_token = PASTE;
break;
case CPP_COMMENT:
/* We must be in -traditional mode. Pretend this was a
token paste, but only if there was no leading or
trailing space and it's in the middle of the line.
_cpp_lex_token won't return a COMMENT if there was trailing
space. */
CPP_SET_WRITTEN (pfile, here);
if (last_token == START)
break;
if (is_hspace (pfile->token_buffer[here-1]))
break;
if (last_token == ARG)
endpat->raw_after = 1;
last_token = PASTE;
break;
case CPP_STRING:
case CPP_CHAR:
if (last_token == STRIZE)
cpp_error (pfile, "`#' is not followed by a macro argument name");
if (CPP_TRADITIONAL (pfile) || CPP_WTRADITIONAL (pfile))
goto maybe_trad_stringify;
else
goto norm;
case CPP_NAME:
for (i = 0; i < argc; i++)
if (!strncmp (tok, argv[i].name, argv[i].len)
&& ! is_idchar (tok[argv[i].len]))
goto addref;
/* fall through */
default:
norm:
if (last_token == STRIZE)
cpp_error (pfile, "`#' is not followed by a macro argument name");
last_token = NORM;
break;
}
continue;
addref:
{
struct reflist *tpat;
/* Make a pat node for this arg and add it to the pat list */
tpat = (struct reflist *) xmalloc (sizeof (struct reflist));
tpat->next = NULL;
tpat->raw_before = (last_token == PASTE);
tpat->raw_after = 0;
tpat->stringify = (last_token == STRIZE);
tpat->rest_args = argv[i].rest_arg;
tpat->argno = i;
tpat->nchars = here - last;
if (endpat == NULL)
pat = tpat;
else
endpat->next = tpat;
endpat = tpat;
last = here;
}
CPP_SET_WRITTEN (pfile, here); /* discard arg name */
last_token = ARG;
continue;
maybe_trad_stringify:
last_token = NORM;
{
U_CHAR *base, *p, *limit;
struct reflist *tpat;
base = p = pfile->token_buffer + here;
limit = CPP_PWRITTEN (pfile);
while (++p < limit)
{
if (is_idstart (*p))
continue;
for (i = 0; i < argc; i++)
if (!strncmp (tok, argv[i].name, argv[i].len)
&& ! is_idchar (tok[argv[i].len]))
goto mts_addref;
continue;
mts_addref:
if (!CPP_TRADITIONAL (pfile))
{
/* Must have got here because of -Wtraditional. */
cpp_warning (pfile,
"macro argument `%.*s' would be stringified with -traditional",
(int) argv[i].len, argv[i].name);
continue;
}
if (CPP_WTRADITIONAL (pfile))
cpp_warning (pfile, "macro argument `%.*s' is stringified",
(int) argv[i].len, argv[i].name);
/* Remove the argument from the string. */
memmove (p, p + argv[i].len, limit - (p + argv[i].len));
limit -= argv[i].len;
/* Make a pat node for this arg and add it to the pat list */
tpat = (struct reflist *) xmalloc (sizeof (struct reflist));
tpat->next = NULL;
/* Don't attempt to paste this with anything. */
tpat->raw_before = 0;
tpat->raw_after = 0;
tpat->stringify = 1;
tpat->rest_args = argv[i].rest_arg;
tpat->argno = i;
tpat->nchars = (p - base) + here - last;
if (endpat == NULL)
pat = tpat;
else
endpat->next = tpat;
endpat = tpat;
last = (p - base) + here;
}
CPP_ADJUST_WRITTEN (pfile, CPP_PWRITTEN (pfile) - limit);
}
}
done:
if (last_token == STRIZE)
cpp_error (pfile, "`#' is not followed by a macro argument name");
else if (last_token == PASTE)
cpp_error (pfile, "`##' at end of macro definition");
if (last_token == START)
{
/* Empty macro definition. */
exp = (U_CHAR *) xstrdup ("\r \r ");
len = 1;
}
else
{
/* Trim trailing white space from definition. */
here = CPP_WRITTEN (pfile);
while (here > last && is_hspace (pfile->token_buffer [here-1]))
here--;
CPP_SET_WRITTEN (pfile, here);
CPP_NUL_TERMINATE (pfile);
len = CPP_WRITTEN (pfile) - start + 1;
/* space for no-concat markers at either end */
exp = (U_CHAR *) xmalloc (len + 4);
exp[0] = '\r';
exp[1] = ' ';
exp[len + 1] = '\r';
exp[len + 2] = ' ';
exp[len + 3] = '\0';
memcpy (&exp[2], pfile->token_buffer + start, len - 1);
}
CPP_SET_WRITTEN (pfile, start);
defn = (DEFINITION *) xmalloc (sizeof (DEFINITION));
defn->length = len + 3;
defn->expansion = exp;
defn->pattern = pat;
defn->rest_args = 0;
if (arglist)
{
defn->nargs = argc;
defn->argnames = arglist->namebuf;
if (argv)
{
defn->rest_args = argv[argc - 1].rest_arg;
free (argv);
}
free (arglist);
}
else
{
defn->nargs = -1;
defn->argnames = 0;
defn->rest_args = 0;
}
return defn;
}
static struct arglist *
collect_formal_parameters (pfile)
cpp_reader *pfile;
{
struct arglist *result = 0;
struct arg *argv = 0;
U_CHAR *namebuf = (U_CHAR *) xstrdup ("");
U_CHAR *name, *tok;
size_t argslen = 1;
int len;
int argc = 0;
int i;
enum cpp_token token;
long old_written;
old_written = CPP_WRITTEN (pfile);
token = _cpp_get_directive_token (pfile);
if (token != CPP_LPAREN)
{
cpp_ice (pfile, "first token = %d not %d in collect_formal_parameters",
token, CPP_LPAREN);
goto invalid;
}
argv = (struct arg *) xmalloc (sizeof (struct arg));
argv[argc].len = 0;
argv[argc].rest_arg = 0;
for (;;)
{
CPP_SET_WRITTEN (pfile, old_written);
token = _cpp_get_directive_token (pfile);
switch (token)
{
case CPP_NAME:
tok = pfile->token_buffer + old_written;
len = CPP_PWRITTEN (pfile) - tok;
if (namebuf
&& (name = (U_CHAR *) strstr (namebuf, tok))
&& name[len] == ','
&& (name == namebuf || name[-1] == ','))
{
cpp_error (pfile, "duplicate macro argument name `%s'", tok);
continue;
}
if (CPP_PEDANTIC (pfile) && CPP_OPTION (pfile, c99)
&& len == sizeof "__VA_ARGS__" - 1
&& !strncmp (tok, "__VA_ARGS__", len))
cpp_pedwarn (pfile,
"C99 does not permit use of `__VA_ARGS__' as a macro argument name");
namebuf = (U_CHAR *) xrealloc (namebuf, argslen + len + 1);
name = &namebuf[argslen - 1];
argslen += len + 1;
memcpy (name, tok, len);
name[len] = ',';
name[len+1] = '\0';
argv[argc].len = len;
argv[argc].rest_arg = 0;
break;
case CPP_COMMA:
argc++;
argv = (struct arg *) xrealloc (argv, (argc + 1)*sizeof(struct arg));
argv[argc].len = 0;
break;
case CPP_RPAREN:
goto done;
case CPP_3DOTS:
goto rest_arg;
case CPP_VSPACE:
cpp_error (pfile, "missing right paren in macro argument list");
goto invalid;
default:
cpp_error (pfile, "syntax error in #define");
goto invalid;
}
}
rest_arg:
/* There are two possible styles for a vararg macro:
the C99 way: #define foo(a, ...) a, __VA_ARGS__
the gnu way: #define foo(a, b...) a, b
The C99 way can be considered a special case of the gnu way.
There are also some constraints to worry about, but we'll handle
those elsewhere. */
if (argv[argc].len == 0)
{
if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, c99))
cpp_pedwarn (pfile, "C89 does not permit varargs macros");
len = sizeof "__VA_ARGS__" - 1;
namebuf = (U_CHAR *) xrealloc (namebuf, argslen + len + 1);
name = &namebuf[argslen - 1];
argslen += len;
memcpy (name, "__VA_ARGS__", len);
argv[argc].len = len;
}
else
if (CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "ISO C does not permit named varargs macros");
argv[argc].rest_arg = 1;
token = _cpp_get_directive_token (pfile);
if (token != CPP_RPAREN)
{
cpp_error (pfile, "another parameter follows `...'");
goto invalid;
}
done:
/* Go through argv and fix up the pointers. */
len = 0;
for (i = 0; i <= argc; i++)
{
argv[i].name = namebuf + len;
len += argv[i].len + 1;
namebuf[len - 1] = '\0';
}
CPP_SET_WRITTEN (pfile, old_written);
result = (struct arglist *) xmalloc (sizeof (struct arglist));
if (namebuf[0] != '\0')
{
result->namebuf = namebuf;
result->argc = argc + 1;
result->argv = argv;
}
else
{
free (namebuf);
result->namebuf = 0;
result->argc = 0;
result->argv = 0;
}
return result;
invalid:
if (argv)
free (argv);
if (namebuf)
free (namebuf);
return 0;
}
/* Create a DEFINITION node for a macro. The reader's point is just
after the macro name. If FUNLIKE is true, this is a function-like
macro. */
DEFINITION *
_cpp_create_definition (pfile, funlike)
cpp_reader *pfile;
int funlike;
{
struct arglist *args = 0;
long line, col;
const char *file;
DEFINITION *defn;
cpp_buf_line_and_col (CPP_BUFFER (pfile), &line, &col);
file = CPP_BUFFER (pfile)->nominal_fname;
if (funlike)
{
args = collect_formal_parameters (pfile);
if (args == 0)
return 0;
}
defn = collect_expansion (pfile, args);
if (defn == 0)
return 0;
defn->line = line;
defn->file = file;
defn->col = col;
return defn;
}
/*
* Parse a macro argument and append the info on PFILE's token_buffer.
* REST_ARGS means to absorb the rest of the args.
* Return nonzero to indicate a syntax error.
*/
static enum cpp_token
macarg (pfile, rest_args)
cpp_reader *pfile;
int rest_args;
{
int paren = 0;
enum cpp_token token;
/* Try to parse as much of the argument as exists at this
input stack level. */
for (;;)
{
token = cpp_get_token (pfile);
switch (token)
{
case CPP_EOF:
return token;
case CPP_POP:
/* If we've hit end of file, it's an error (reported by caller).
Ditto if it's the end of cpp_expand_to_buffer text.
If we've hit end of macro, just continue. */
if (!CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
return token;
break;
case CPP_LPAREN:
paren++;
break;
case CPP_RPAREN:
if (--paren < 0)
goto found;
break;
case CPP_COMMA:
/* if we've returned to lowest level and
we aren't absorbing all args */
if (paren == 0 && rest_args == 0)
goto found;
break;
found:
/* Remove ',' or ')' from argument buffer. */
CPP_ADJUST_WRITTEN (pfile, -1);
return token;
default:;
}
}
}
static struct tm *
timestamp (pfile)
cpp_reader *pfile;
{
if (!pfile->timebuf)
{
time_t t = time ((time_t *) 0);
pfile->timebuf = localtime (&t);
}
return pfile->timebuf;
}
static const char * const monthnames[] =
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
};
/* Place into PFILE a quoted string representing the string SRC.
Caller must reserve enough space in pfile->token_buffer. */
void
_cpp_quote_string (pfile, src)
cpp_reader *pfile;
const char *src;
{
U_CHAR c;
CPP_PUTC_Q (pfile, '\"');
for (;;)
switch ((c = *src++))
{
default:
if (ISPRINT (c))
CPP_PUTC_Q (pfile, c);
else
{
sprintf ((char *)CPP_PWRITTEN (pfile), "\\%03o", c);
CPP_ADJUST_WRITTEN (pfile, 4);
}
break;
case '\"':
case '\\':
CPP_PUTC_Q (pfile, '\\');
CPP_PUTC_Q (pfile, c);
break;
case '\0':
CPP_PUTC_Q (pfile, '\"');
CPP_NUL_TERMINATE_Q (pfile);
return;
}
}
/*
* expand things like __FILE__. Place the expansion into the output
* buffer *without* rescanning.
*/
static void
special_symbol (hp, pfile)
HASHNODE *hp;
cpp_reader *pfile;
{
const char *buf;
int len;
cpp_buffer *ip;
switch (hp->type)
{
case T_FILE:
case T_BASE_FILE:
{
ip = cpp_file_buffer (pfile);
if (hp->type == T_BASE_FILE)
{
while (CPP_PREV_BUFFER (ip) != NULL)
ip = CPP_PREV_BUFFER (ip);
}
buf = ip->nominal_fname;
if (!buf)
buf = "";
CPP_RESERVE (pfile, 3 + 4 * strlen (buf));
_cpp_quote_string (pfile, buf);
return;
}
case T_INCLUDE_LEVEL:
{
int true_indepth = 1;
ip = cpp_file_buffer (pfile);
while ((ip = CPP_PREV_BUFFER (ip)) != NULL)
true_indepth++;
CPP_RESERVE (pfile, 10);
sprintf (CPP_PWRITTEN (pfile), "%d", true_indepth);
CPP_ADJUST_WRITTEN (pfile, strlen (CPP_PWRITTEN (pfile)));
return;
}
case T_VERSION:
len = strlen (hp->value.cpval);
CPP_RESERVE (pfile, 3 + len);
CPP_PUTC_Q (pfile, '"');
CPP_PUTS_Q (pfile, hp->value.cpval, len);
CPP_PUTC_Q (pfile, '"');
CPP_NUL_TERMINATE_Q (pfile);
return;
case T_CONST:
buf = hp->value.cpval;
if (!buf)
return;
if (*buf == '\0')
buf = "\r ";
len = strlen (buf);
CPP_RESERVE (pfile, len + 1);
CPP_PUTS_Q (pfile, buf, len);
CPP_NUL_TERMINATE_Q (pfile);
return;
case T_STDC:
CPP_RESERVE (pfile, 2);
#ifdef STDC_0_IN_SYSTEM_HEADERS
ip = cpp_file_buffer (pfile);
if (ip->system_header_p
&& !cpp_defined (pfile, (const U_CHAR *) "__STRICT_ANSI__", 15))
CPP_PUTC_Q (pfile, '0');
else
#endif
CPP_PUTC_Q (pfile, '1');
CPP_NUL_TERMINATE_Q (pfile);
return;
case T_SPECLINE:
{
long line;
cpp_buf_line_and_col (cpp_file_buffer (pfile), &line, NULL);
CPP_RESERVE (pfile, 10);
sprintf (CPP_PWRITTEN (pfile), "%ld", line);
CPP_ADJUST_WRITTEN (pfile, strlen (CPP_PWRITTEN (pfile)));
return;
}
case T_DATE:
case T_TIME:
{
struct tm *timebuf;
CPP_RESERVE (pfile, 20);
timebuf = timestamp (pfile);
if (hp->type == T_DATE)
sprintf (CPP_PWRITTEN (pfile), "\"%s %2d %4d\"",
monthnames[timebuf->tm_mon],
timebuf->tm_mday, timebuf->tm_year + 1900);
else
sprintf (CPP_PWRITTEN (pfile), "\"%02d:%02d:%02d\"",
timebuf->tm_hour, timebuf->tm_min, timebuf->tm_sec);
CPP_ADJUST_WRITTEN (pfile, strlen (CPP_PWRITTEN (pfile)));
return;
}
case T_POISON:
cpp_error (pfile, "attempt to use poisoned `%s'.", hp->name);
CPP_RESERVE (pfile, 1);
CPP_PUTC_Q (pfile, '0');
CPP_NUL_TERMINATE_Q (pfile);
break;
default:
cpp_ice (pfile, "invalid special hash type");
return;
}
}
/* Expand a macro call.
HP points to the symbol that is the macro being called.
Put the result of expansion onto the input stack
so that subsequent input by our caller will use it.
If macro wants arguments, caller has already verified that
an argument list follows; arguments come from the input stack. */
void
_cpp_macroexpand (pfile, hp)
cpp_reader *pfile;
HASHNODE *hp;
{
int nargs;
DEFINITION *defn;
register U_CHAR *xbuf;
long start_line, start_column;
int xbuf_len;
struct argdata *args = 0;
long old_written = CPP_WRITTEN (pfile);
int rest_args, rest_zero = 0;
register int i;
cpp_buf_line_and_col (cpp_file_buffer (pfile), &start_line, &start_column);
/* Check for and handle special symbols. */
if (hp->type != T_MACRO)
{
special_symbol (hp, pfile);
xbuf_len = CPP_WRITTEN (pfile) - old_written;
xbuf = (U_CHAR *) xmalloc (xbuf_len + 1);
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;
return;
}
defn = hp->value.defn;
nargs = defn->nargs;
pfile->output_escapes++;
if (nargs >= 0)
{
enum cpp_token token;
args = (struct argdata *) alloca ((nargs + 1) * sizeof (struct argdata));
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;
}
/* 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)++;
CPP_OPTION (pfile, no_line_commands)++;
pfile->no_macro_expand++;
pfile->no_directives++;
token = cpp_get_non_space_token (pfile);
if (token != CPP_LPAREN)
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)--;
CPP_OPTION (pfile, no_line_commands)--;
pfile->no_macro_expand--;
pfile->no_directives--;
if (token != CPP_RPAREN)
return;
/* If we got one arg but it was just whitespace, call that 0 args. */
if (i == 1)
{
register U_CHAR *bp = ARG_BASE + args[0].raw;
register U_CHAR *lim = bp + args[0].raw_length;
/* cpp.texi says for foo ( ) we provide one argument.
However, if foo wants just 0 arguments, treat this as 0. */
if (nargs == 0)
while (bp != lim && is_space(*bp))
bp++;
if (bp == lim)
i = 0;
}
/* 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)
{
cpp_error (pfile,
"macro `%s' used with too many (%d) args", hp->name, i);
}
}
/* If macro wants zero args, we parsed the arglist for checking only.
Read directly from the macro definition. */
if (nargs <= 0)
{
xbuf = defn->expansion;
xbuf_len = defn->length;
}
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;
/* Macro really takes args. Compute the expansion of this call. */
/* 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];
/* 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);
if (!CPP_TRADITIONAL (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);
}
}
if (!CPP_TRADITIONAL (pfile))
CPP_PUTC (pfile, '\"'); /* insert ending quote */
arg->stringified_length
= CPP_WRITTEN (pfile) - arg->stringified;
}
xbuf_len += args[ap->argno].stringified_length;
}
else if (ap->raw_before || ap->raw_after || CPP_TRADITIONAL (pfile))
/* 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)
{
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;
}
/* 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 (rest_zero && 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 || CPP_TRADITIONAL (pfile))
{
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)
{
if (is_space(p1[0]))
p1++;
else if (p1[0] == '\r')
p1 += 2;
else
break;
}
}
if (ap->raw_after)
{
/* 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 (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
&& !CPP_TRADITIONAL (pfile)
&& unsafe_chars (pfile, xbuf[totlen - 1], expanded[0]))
{
xbuf[totlen++] = '\r';
xbuf[totlen++] = ' ';
}
memcpy (xbuf + totlen, expanded, arg->expand_length);
totlen += arg->expand_length;
if (!ap->raw_after && totlen > 0 && offset < defn->length
&& !CPP_TRADITIONAL (pfile)
&& unsafe_chars (pfile, xbuf[totlen - 1], exp[offset]))
{
xbuf[totlen++] = '\r';
xbuf[totlen++] = ' ';
}
}
if (totlen > xbuf_len)
{
cpp_ice (pfile, "buffer overrun in macroexpand");
return;
}
}
/* if there is anything left of the definition
after handling the arg list, copy that in too. */
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];
}
xbuf[totlen] = 0;
xbuf_len = totlen;
}
pfile->output_escapes--;
/* 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;
/* Pop the space we've used in the token_buffer for argument expansion. */
CPP_SET_WRITTEN (pfile, old_written);
/* Recursive macro use sometimes works traditionally.
#define foo(x,y) bar (x (y,0), y)
foo (foo, baz) */
if (!CPP_TRADITIONAL (pfile))
hp->type = T_DISABLED;
}
/* Return 1 iff a token ending in C1 followed directly by a token C2
could cause mis-tokenization. */
static int
unsafe_chars (pfile, c1, c2)
cpp_reader *pfile;
int c1, c2;
{
switch (c1)
{
case EOF:
/* We don't know what the previous character was. We do know
that it can't have been an idchar (or else it would have been
pasted with the idchars of the macro name), and there are a
number of second characters for which it doesn't matter what
the first was. */
if (is_idchar (c2) || c2 == '\'' || c2 == '\"'
|| c2 == '(' || c2 == '[' || c2 == '{'
|| c2 == ')' || c2 == ']' || c2 == '}')
return 0;
return 1;
case '+': case '-':
if (c2 == c1 || c2 == '=')
return 1;
goto letter;
case 'e': case 'E': case 'p': case 'P':
if (c2 == '-' || c2 == '+')
return 1; /* could extend a pre-processing number */
goto letter;
case '$':
if (CPP_OPTION (pfile, dollars_in_ident))
goto letter;
return 0;
case 'L':
if (c2 == '\'' || c2 == '\"')
return 1; /* Could turn into L"xxx" or L'xxx'. */
goto letter;
case '.': case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7': case '8': case '9':
case '_': case 'a': case 'b': case 'c': case 'd': case 'f':
case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'q': case 'r': case 's':
case 't': case 'u': case 'v': case 'w': case 'x': case 'y':
case 'z': case 'A': case 'B': case 'C': case 'D': case 'F':
case 'G': case 'H': case 'I': case 'J': case 'K': case 'M':
case 'N': case 'O': case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
letter:
/* We're in the middle of either a name or a pre-processing number. */
return (is_idchar(c2) || c2 == '.');
case '<': case '>': case '!': case '%': case '#': case ':':
case '^': case '&': case '|': case '*': case '/': case '=':
return (c2 == c1 || c2 == '=');
}
return 0;
}
static void
push_macro_expansion (pfile, xbuf, len, hp)
cpp_reader *pfile;
register U_CHAR *xbuf;
int len;
HASHNODE *hp;
{
cpp_buffer *mbuf;
int advance_cur = 0;
/* The first chars of the expansion should be a "\r " added by
collect_expansion. This is to prevent accidental token-pasting
between the text preceding the macro invocation, and the macro
expansion text.
We would like to avoid adding unneeded spaces (for the sake of
tools that use cpp, such as imake). In some common cases we can
tell that it is safe to omit the space. */
if (xbuf[0] == '\r' && xbuf[1] == ' '
&& !unsafe_chars (pfile, EOF, xbuf[2]))
advance_cur = 1;
/* Likewise, avoid the extra space at the end of the macro expansion
if this is safe. We can do a better job here since we can know
what the next char will be. */
if (len >= 3
&& xbuf[len-2] == '\r'
&& xbuf[len-1] == ' ')
{
int c = CPP_BUF_PEEK (CPP_BUFFER (pfile));
if (c == EOF || !unsafe_chars (pfile, xbuf[len-3], c))
len -= 2;
}
mbuf = cpp_push_buffer (pfile, xbuf, len);
if (mbuf == NULL)
return;
if (advance_cur)
mbuf->cur += 2;
mbuf->cleanup = macro_cleanup;
mbuf->macro = hp;
}
/* Return zero if two DEFINITIONs are isomorphic. */
int
_cpp_compare_defs (pfile, d1, d2)
cpp_reader *pfile;
DEFINITION *d1, *d2;
{
struct reflist *a1, *a2;
U_CHAR *p1 = d1->expansion;
U_CHAR *p2 = d2->expansion;
int first = 1;
if (d1->nargs != d2->nargs)
return 1;
if (CPP_PEDANTIC (pfile)
&& d1->argnames && d2->argnames)
{
U_CHAR *arg1 = d1->argnames;
U_CHAR *arg2 = d2->argnames;
size_t len;
int i = d1->nargs;
while (i--)
{
len = strlen (arg1) + 1;
if (strcmp (arg1, arg2))
return 1;
arg1 += len;
arg2 += len;
}
}
for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2;
a1 = a1->next, a2 = a2->next)
{
if (!((a1->nchars == a2->nchars && !strncmp (p1, p2, a1->nchars))
|| !comp_def_part (first, p1, a1->nchars, p2, a2->nchars, 0))
|| a1->argno != a2->argno
|| a1->stringify != a2->stringify
|| a1->raw_before != a2->raw_before
|| a1->raw_after != a2->raw_after)
return 1;
first = 0;
p1 += a1->nchars;
p2 += a2->nchars;
}
if (a1 != a2)
return 1;
return comp_def_part (first, p1, d1->length - (p1 - d1->expansion),
p2, d2->length - (p2 - d2->expansion), 1);
}
/* Return 1 if two parts of two macro definitions are effectively different.
One of the parts starts at BEG1 and has LEN1 chars;
the other has LEN2 chars at BEG2.
Any sequence of whitespace matches any other sequence of whitespace.
FIRST means these parts are the first of a macro definition;
so ignore leading whitespace entirely.
LAST means these parts are the last of a macro definition;
so ignore trailing whitespace entirely. */
static int
comp_def_part (first, beg1, len1, beg2, len2, last)
int first;
U_CHAR *beg1, *beg2;
int len1, len2;
int last;
{
register U_CHAR *end1 = beg1 + len1;
register U_CHAR *end2 = beg2 + len2;
if (first)
{
while (beg1 != end1 && is_space(*beg1))
beg1++;
while (beg2 != end2 && is_space(*beg2))
beg2++;
}
if (last)
{
while (beg1 != end1 && is_space(end1[-1]))
end1--;
while (beg2 != end2 && is_space(end2[-1]))
end2--;
}
while (beg1 != end1 && beg2 != end2)
{
if (is_space(*beg1) && is_space(*beg2))
{
while (beg1 != end1 && is_space(*beg1))
beg1++;
while (beg2 != end2 && is_space(*beg2))
beg2++;
}
else if (*beg1 == *beg2)
{
beg1++;
beg2++;
}
else
break;
}
return (beg1 != end1) || (beg2 != end2);
}
/* Dump the definition of macro MACRO on stdout. The format is suitable
to be read back in again. */
void
_cpp_dump_definition (pfile, sym, len, defn)
cpp_reader *pfile;
const U_CHAR *sym;
long len;
DEFINITION *defn;
{
if (pfile->lineno == 0)
_cpp_output_line_command (pfile, same_file);
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_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++)
{
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);
/* 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;
}
i = defn->length - (x - defn->expansion) - 2;
if (*x == '\r') x += 2, i -= 2;
if (i > 0) CPP_PUTS (pfile, x, i);
}
if (pfile->lineno == 0)
CPP_PUTC (pfile, '\n');
CPP_NUL_TERMINATE (pfile);
}
/* Dump out the hash table. */
static int
dump_hash_helper (h, p)
void **h;
void *p;
{
HASHNODE *hp = (HASHNODE *)*h;
cpp_reader *pfile = (cpp_reader *)p;
if (hp->type == T_MACRO)
{
_cpp_dump_definition (pfile, hp->name, hp->length, hp->value.defn);
CPP_PUTC (pfile, '\n');
}
return 1;
}
void
_cpp_dump_macro_hash (pfile)
cpp_reader *pfile;
{
htab_traverse (pfile->hashtab, dump_hash_helper, pfile);
}