cpphash.h (struct definition): Move file, line, col members...

* 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.

From-SVN: r33355
This commit is contained in:
Zack Weinberg 2000-04-23 17:03:31 +00:00
parent 3c8c10b8c6
commit d9e0bd53b2
6 changed files with 830 additions and 646 deletions

View file

@ -1,3 +1,37 @@
2000-04-23 Zack Weinberg <zack@wolery.cumb.org>
* 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.
Sun Apr 23 14:27:44 MET DST 2000 Jan Hubicka <jh@suse.cz>
* loop.c (maybe_eliminate_biv_1): Use GET_CODE (x) == CONST_INT instead

View file

@ -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,7 +75,10 @@ struct arglist
};
static DEFINITION *collect_expansion PARAMS ((cpp_reader *, cpp_toklist *,
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;
}
/* 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_WTRADITIONAL (pfile))
warn_trad_stringify (pfile, tok, len, argc, argv);
}
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->rest_args = argc && argv[argc - 1].rest_arg;
defn->nargs = argc;
defn->argnames = arglist->namebuf;
if (argv)
free ((PTR) argv);
}
else
{
defn->nargs = -1;
defn->argnames = 0;
}
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;
{
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';
}
}
/* 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;
DEFINITION *defn;
int replacement = 1; /* replacement begins at this token */
int replacement;
if (funlike)
{
replacement = collect_params (pfile, list, &args);
if (replacement == 0)
return 0;
}
defn = collect_expansion (pfile, list, funlike ? &args : 0, replacement);
defn = collect_funlike_expansion (pfile, list, &args, replacement);
if (defn == 0)
return 0;
defn->file = CPP_BUFFER (pfile)->nominal_fname;
defn->line = list->line;
defn->col = list->tokens[0].col;
return defn;
ntype = T_FMACRO;
}
/* 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 = 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,18 +1181,87 @@ _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);
/* Object like macro - most common case. */
if (hp->type == T_MACRO)
{
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;
}
/* Or a special symbol? */
if (hp->type != T_FMACRO)
{
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);
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;
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 macro wants zero args, we parsed the arglist for checking only.
Read directly from the macro definition. */
if (defn->nargs == 0 || defn->pattern == 0)
{
CPP_SET_WRITTEN (pfile, old_written);
pfile->output_escapes--;
push_macro_expansion (pfile, defn->expansion, defn->length, hp);
return;
}
funlike_macroexpand (pfile, hp, args);
pfile->output_escapes--;
}
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);
@ -1025,42 +1270,11 @@ _cpp_macroexpand (pfile, hp)
else
start_line = start_column = 0;
/* 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_ttype 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. */
/* 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)++;
@ -1076,15 +1290,10 @@ _cpp_macroexpand (pfile, hp)
token = CPP_EOF;
do
{
if (rest_args)
continue;
if (i < nargs || (nargs == 0 && i == 0))
if (i < MAX (nargs, 1))
{
/* 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);
token = macarg (pfile, (i == nargs - 1 && defn->rest_args));
args[i].raw_length = CPP_WRITTEN (pfile) - args[i].raw;
}
else
@ -1105,7 +1314,7 @@ _cpp_macroexpand (pfile, hp)
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)
if (i == 1 && nargs == 0)
{
register U_CHAR *bp = ARG_BASE + args[0].raw;
register U_CHAR *lim = bp + args[0].raw_length;
@ -1117,10 +1326,9 @@ _cpp_macroexpand (pfile, hp)
/* 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);
cpp_error (pfile, "arguments given to macro `%s'", name);
}
else if (i < nargs)
{
@ -1129,58 +1337,33 @@ _cpp_macroexpand (pfile, hp)
;
/* 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);
cpp_error (pfile, "macro `%s' used without args", name);
else if (i == 1)
cpp_error (pfile, "macro `%s' used with just one arg", hp->name);
cpp_error (pfile, "macro `%s' used with just one arg", name);
else
cpp_error (pfile, "macro `%s' used with only %d args",
hp->name, i);
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", hp->name, i);
cpp_error (pfile, "macro `%s' used with too many (%d) args", 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)
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;
/* 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 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);
@ -1197,9 +1380,8 @@ _cpp_macroexpand (pfile, hp)
i++;
continue;
}
/* Internal sequences of whitespace are
replaced by one space except within
a string or char token. */
/* 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)
@ -1234,15 +1416,40 @@ _cpp_macroexpand (pfile, hp)
else
{
CPP_RESERVE (pfile, 4);
sprintf ((char *) CPP_PWRITTEN (pfile), "\\%03o",
(unsigned int) c);
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;
arg->stringified_length = CPP_WRITTEN (pfile) - arg->stringified;
}
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)
{
/* 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)
@ -1256,8 +1463,7 @@ _cpp_macroexpand (pfile, hp)
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,
_cpp_expand_to_buffer (pfile, ARG_BASE + args[ap->argno].raw,
args[ap->argno].raw_length);
args[ap->argno].expand_length
@ -1272,11 +1478,10 @@ _cpp_macroexpand (pfile, hp)
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. */
/* 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)
@ -1292,7 +1497,7 @@ _cpp_macroexpand (pfile, hp)
/* If followed by an empty rest arg with concatenation,
delete the last run of nonwhite chars. */
if (rest_zero && totlen > count_before
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)))
@ -1380,55 +1585,25 @@ _cpp_macroexpand (pfile, hp)
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--;
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,27 +1786,46 @@ _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_RESERVE (pfile, hp->length + sizeof "#define ");
CPP_PUTS_Q (pfile, "#define ", sizeof "#define " - 1);
CPP_PUTS_Q (pfile, sym, len);
CPP_PUTS_Q (pfile, hp->name, hp->length);
if (defn->nargs == -1)
if (hp->type == T_EMPTY)
/* do nothing */;
else if (hp->type == T_FMACRO)
dump_DEFINITION (pfile, hp->value.defn);
else
{
CPP_PUTC_Q (pfile, ' ');
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)
{
/* 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);
CPP_RESERVE (pfile, hp->value.defn->length - 4 + 1);
CPP_PUTS_Q (pfile, hp->value.defn->expansion + 2,
hp->value.defn->length - 4);
}
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_DEFINITION (pfile, defn)
cpp_reader *pfile;
DEFINITION *defn;
{
struct reflist *r;
unsigned char **argv = (unsigned char **) alloca (defn->nargs *
@ -1673,9 +1888,6 @@ _cpp_dump_definition (pfile, sym, len, defn)
if (*x == '\r') x += 2, i -= 2;
if (i > 0) CPP_PUTS (pfile, x, i);
}
if (CPP_BUFFER (pfile) == 0 || ! pfile->done_initializing)
CPP_PUTC (pfile, '\n');
}
/* Dump out the hash table. */
static int
@ -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;
}

View file

@ -64,9 +64,6 @@ struct definition
int nargs;
int length; /* length of expansion string */
U_CHAR *expansion;
int line; /* Line number of definition */
int col;
const char *file; /* File of definition */
char rest_args; /* Nonzero if last arg. absorbs the rest */
struct reflist *pattern;
@ -86,6 +83,7 @@ struct definition
/* different flavors of hash nodes */
enum node_type
{
T_VOID = 0, /* no definition yet */
T_SPECLINE, /* `__LINE__' */
T_DATE, /* `__DATE__' */
T_FILE, /* `__FILE__' */
@ -94,10 +92,12 @@ enum node_type
T_TIME, /* `__TIME__' */
T_STDC, /* `__STDC__' */
T_CONST, /* Constant string, used by `__SIZE_TYPE__' etc */
T_MCONST, /* Ditto, but the string is malloced memory */
T_MACRO, /* macro defined by `#define' */
T_DISABLED, /* macro temporarily turned off for rescan */
T_POISON, /* macro defined with `#pragma poison' */
T_XCONST, /* Ditto, but the string is malloced memory */
T_POISON, /* poisoned identifier */
T_MCONST, /* object-like macro defined to a single identifier */
T_MACRO, /* general object-like macro */
T_FMACRO, /* general function-like macro */
T_IDENTITY, /* macro defined to itself */
T_EMPTY /* macro defined to nothing */
};
@ -118,6 +118,11 @@ struct hashnode
unsigned long hash; /* cached hash value */
union hashval value; /* pointer to expansion, or whatever */
enum node_type type; /* type of special token */
int disabled; /* macro turned off for rescan? */
const char *file; /* File, line, column of definition; */
int line;
int col;
};
/* List of directories to look for include files in. */
@ -272,12 +277,9 @@ extern HASHNODE **_cpp_lookup_slot PARAMS ((cpp_reader *,
enum insert_option,
unsigned long *));
extern void _cpp_free_definition PARAMS ((DEFINITION *));
extern DEFINITION *_cpp_create_definition PARAMS ((cpp_reader *,
cpp_toklist *, int));
extern void _cpp_dump_definition PARAMS ((cpp_reader *, const U_CHAR *,
long, DEFINITION *));
extern int _cpp_compare_defs PARAMS ((cpp_reader *, DEFINITION *,
DEFINITION *));
extern int _cpp_create_definition PARAMS ((cpp_reader *,
cpp_toklist *, HASHNODE *));
extern void _cpp_dump_definition PARAMS ((cpp_reader *, HASHNODE *));
extern void _cpp_quote_string PARAMS ((cpp_reader *, const char *));
extern void _cpp_macroexpand PARAMS ((cpp_reader *, HASHNODE *));
extern void _cpp_init_macro_hash PARAMS ((cpp_reader *));

View file

@ -635,7 +635,7 @@ static const struct builtin builtin_array[] =
{ "__LINE__", 0, T_SPECLINE, 0 },
{ "__INCLUDE_LEVEL__", 0, T_INCLUDE_LEVEL, 0 },
{ "__VERSION__", 0, T_MCONST, DUMP|VERS },
{ "__VERSION__", 0, T_XCONST, DUMP|VERS },
{ "__USER_LABEL_PREFIX__", 0, T_CONST, DUMP|ULP },
{ "__STDC__", "1", T_STDC, DUMP },
{ "__REGISTER_PREFIX__", REGISTER_PREFIX, T_CONST, DUMP },

View file

@ -1455,7 +1455,7 @@ maybe_macroexpand (pfile, written)
if (!hp)
return 0;
if (hp->type == T_DISABLED)
if (hp->disabled || hp->type == T_IDENTITY)
{
if (pfile->output_escapes)
{
@ -1479,7 +1479,7 @@ maybe_macroexpand (pfile, written)
}
/* If macro wants an arglist, verify that a '(' follows. */
if (hp->type == T_MACRO && hp->value.defn->nargs >= 0)
if (hp->type == T_FMACRO)
{
int macbuf_whitespace = 0;
int c;

View file

@ -316,10 +316,8 @@ do_define (pfile)
cpp_reader *pfile;
{
HASHNODE **slot;
DEFINITION *def = 0;
unsigned long hash;
int len;
int funlike = 0, empty = 0;
U_CHAR *sym;
cpp_toklist *list = &pfile->directbuf;
@ -350,90 +348,26 @@ do_define (pfile)
goto out;
}
if (list->tokens_used == 2 && list->tokens[1].type == CPP_VSPACE)
empty = 1; /* Empty definition of object-like macro. */
/* If the next character, with no intervening whitespace, is '(',
then this is a function-like macro. 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 & HSPACE_BEFORE))
{
if (list->tokens[1].type == CPP_OPEN_PAREN)
funlike = 1;
else
cpp_pedwarn (pfile,
"The C standard requires whitespace after #define %.*s",
len, sym);
}
if (! empty)
{
def = _cpp_create_definition (pfile, list, funlike);
if (def == 0)
goto out;
}
slot = _cpp_lookup_slot (pfile, sym, len, INSERT, &hash);
if (*slot)
{
int ok;
HASHNODE *hp = *slot;
/* Redefining a macro is ok if the definitions are the same. */
if (hp->type == T_MACRO)
ok = ! empty && ! _cpp_compare_defs (pfile, def, hp->value.defn);
else if (hp->type == T_EMPTY)
ok = empty;
/* Redefining a constant is ok with -D. */
else if (hp->type == T_CONST || hp->type == T_STDC)
ok = ! pfile->done_initializing;
/* Otherwise it's not ok. */
else
ok = 0;
/* Print the warning or error if it's not ok. */
if (! ok)
/* Check for poisoned identifiers now. All other checks
are done in cpphash.c. */
if ((*slot)->type == T_POISON)
{
if (hp->type == T_POISON)
cpp_error (pfile, "redefining poisoned `%.*s'", len, sym);
else
cpp_pedwarn (pfile, "`%.*s' redefined", len, sym);
if (hp->type == T_MACRO && pfile->done_initializing)
{
DEFINITION *d = hp->value.defn;
cpp_pedwarn_with_file_and_line (pfile, d->file, d->line, d->col,
"this is the location of the previous definition");
}
}
if (hp->type != T_POISON)
{
/* Replace the old definition. */
if (hp->type == T_MACRO)
_cpp_free_definition (hp->value.defn);
if (empty)
{
hp->type = T_EMPTY;
hp->value.defn = 0;
}
else
{
hp->type = T_MACRO;
hp->value.defn = def;
}
goto out;
}
}
else
{
HASHNODE *hp = _cpp_make_hashnode (sym, len, empty ? T_EMPTY : T_MACRO,
hash);
hp->value.defn = def;
*slot = hp;
}
*slot = _cpp_make_hashnode (sym, len, T_VOID, hash);
if (_cpp_create_definition (pfile, list, *slot) == 0)
goto out;
if (CPP_OPTION (pfile, debug_output)
|| CPP_OPTION (pfile, dump_macros) == dump_definitions)
_cpp_dump_definition (pfile, sym, len, def);
_cpp_dump_definition (pfile, *slot);
else if (CPP_OPTION (pfile, dump_macros) == dump_names)
pass_thru_directive (sym, len, pfile, T_DEFINE);
@ -769,7 +703,9 @@ do_undef (pfile)
if (CPP_OPTION (pfile, debug_output))
pass_thru_directive (hp->name, len, pfile, T_UNDEF);
if (hp->type != T_MACRO && hp->type != T_EMPTY)
if (hp->type != T_MACRO && hp->type != T_FMACRO
&& hp->type != T_MCONST
&& hp->type != T_EMPTY && hp->type != T_IDENTITY)
cpp_warning (pfile, "undefining `%s'", hp->name);
htab_clear_slot (pfile->hashtab, (void **)slot);