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:
parent
3c8c10b8c6
commit
d9e0bd53b2
6 changed files with 830 additions and 646 deletions
|
@ -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
|
||||
|
|
648
gcc/cpphash.c
648
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,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 *));
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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;
|
||||
|
|
88
gcc/cpplib.c
88
gcc/cpplib.c
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue