[multiple changes]
2000-02-17 Zack Weinberg <zack@wolery.cumb.org> * cpphash.c: Don't include hashtab.h. Most macro-handling code moved to cppmacro.c. (hash_HASHNODE, eq_HASHNODE, _cpp_dump_macro_hash, dump_hash_helper): Delete. (expand_hash, higher_prime_number, _cpp_lookup_with_hash, cpp_forall_identifiers): New. Implement specialized version of Vlad's expandable hash table. (cpp_lookup): Use new functions. (_cpp_init_macros, _cpp_cleanup_macros): Adjust for new implementation. * cppmacro.c: New file. * cppinit.c (dump_macros_helper): New. (cpp_finish): Iterate over the identifier table directly. * cpplex.c (parse_name): Calculate the hash of the identifier while we scan it. Use _cpp_lookup_with_hash when we can. * cpphash.h: Update prototypes. (xcnewvec, HASHSTEP): New helper macros. * cpplib.h: Update prototypes. * Makefile.in (LIBCPP_OBJS): Add cppmacro.o. (cppmacro.o): New rule. (cpphash.o): Update deps. * cppmain.c: Do not set pfile->printer if no_output is on. 2000-02-15 Neil Booth <neilb@earthling.net> * cpplib.c: Change all directive-handler functions to return void, not int. * cpphash.h: Update typedefs. From-SVN: r35113
This commit is contained in:
parent
5d8fcdcb2d
commit
711b88243b
10 changed files with 939 additions and 760 deletions
|
@ -1,3 +1,36 @@
|
|||
2000-02-17 Zack Weinberg <zack@wolery.cumb.org>
|
||||
|
||||
* cpphash.c: Don't include hashtab.h. Most macro-handling code
|
||||
moved to cppmacro.c.
|
||||
(hash_HASHNODE, eq_HASHNODE, _cpp_dump_macro_hash,
|
||||
dump_hash_helper): Delete.
|
||||
(expand_hash, higher_prime_number, _cpp_lookup_with_hash,
|
||||
cpp_forall_identifiers): New. Implement specialized version of
|
||||
Vlad's expandable hash table.
|
||||
(cpp_lookup): Use new functions.
|
||||
(_cpp_init_macros, _cpp_cleanup_macros): Adjust for new
|
||||
implementation.
|
||||
* cppmacro.c: New file.
|
||||
* cppinit.c (dump_macros_helper): New.
|
||||
(cpp_finish): Iterate over the identifier table directly.
|
||||
* cpplex.c (parse_name): Calculate the hash of the identifier
|
||||
while we scan it. Use _cpp_lookup_with_hash when we can.
|
||||
|
||||
* cpphash.h: Update prototypes.
|
||||
(xcnewvec, HASHSTEP): New helper macros.
|
||||
* cpplib.h: Update prototypes.
|
||||
* Makefile.in (LIBCPP_OBJS): Add cppmacro.o.
|
||||
(cppmacro.o): New rule.
|
||||
(cpphash.o): Update deps.
|
||||
|
||||
* cppmain.c: Do not set pfile->printer if no_output is on.
|
||||
|
||||
2000-02-15 Neil Booth <neilb@earthling.net>
|
||||
|
||||
* cpplib.c: Change all directive-handler functions to return
|
||||
void, not int.
|
||||
* cpphash.h: Update typedefs.
|
||||
|
||||
2000-07-17 Geoffrey Keating <geoffk@cygnus.com>
|
||||
|
||||
* configure: Regenerate.
|
||||
|
|
|
@ -1782,9 +1782,9 @@ PREPROCESSOR_DEFINES = \
|
|||
-DCROSS_INCLUDE_DIR=\"$(gcc_tooldir)/sys-include\" \
|
||||
-DTOOL_INCLUDE_DIR=\"$(gcc_tooldir)/include\"
|
||||
|
||||
LIBCPP_OBJS = cpplib.o cpphash.o cpperror.o cppexp.o cppfiles.o \
|
||||
cppinit.o cppulp.o cpplex.o cppdefault.o mkdeps.o \
|
||||
prefix.o version.o mbchar.o @extra_cpp_objs@
|
||||
LIBCPP_OBJS = cpplib.o cpplex.o cppmacro.o cppexp.o cppfiles.o \
|
||||
cpphash.o cpperror.o cppinit.o cppulp.o cppdefault.o \
|
||||
mkdeps.o prefix.o version.o mbchar.o @extra_cpp_objs@
|
||||
|
||||
LIBCPP_DEPS = cpplib.h cpphash.h intl.h system.h
|
||||
|
||||
|
@ -1806,8 +1806,9 @@ cppulp.o: cppulp.c $(CONFIG_H) system.h output.h
|
|||
cpperror.o: cpperror.c $(CONFIG_H) $(LIBCPP_DEPS)
|
||||
cppexp.o: cppexp.c $(CONFIG_H) $(LIBCPP_DEPS)
|
||||
cpplex.o: cpplex.c $(CONFIG_H) $(LIBCPP_DEPS)
|
||||
cppmacro.o: cppmacro.c $(CONFIG_H) $(LIBCPP_DEPS)
|
||||
cpplib.o: cpplib.c $(CONFIG_H) $(LIBCPP_DEPS) $(OBSTACK_H)
|
||||
cpphash.o: cpphash.c $(CONFIG_H) $(LIBCPP_DEPS) $(OBSTACK_H) $(HASHTAB_H)
|
||||
cpphash.o: cpphash.c $(CONFIG_H) $(LIBCPP_DEPS) $(OBSTACK_H)
|
||||
cppfiles.o: cppfiles.c $(CONFIG_H) $(LIBCPP_DEPS) $(SPLAY_TREE_H) mkdeps.h
|
||||
cppinit.o: cppinit.c $(CONFIG_H) $(LIBCPP_DEPS) cppdefault.h \
|
||||
mkdeps.h prefix.h output.h version.h
|
||||
|
|
888
gcc/cpphash.c
888
gcc/cpphash.c
|
@ -1,4 +1,4 @@
|
|||
/* Part of CPP library. (Macro handling.)
|
||||
/* Part of CPP library. (Identifier and string tables.)
|
||||
Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998,
|
||||
1999, 2000 Free Software Foundation, Inc.
|
||||
Written by Per Bothner, 1994.
|
||||
|
@ -27,720 +27,252 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "system.h"
|
||||
#include "cpplib.h"
|
||||
#include "cpphash.h"
|
||||
#include "hashtab.h"
|
||||
#include "obstack.h"
|
||||
|
||||
#define obstack_chunk_alloc xmalloc
|
||||
#define obstack_chunk_free free
|
||||
|
||||
/* This is the second argument to eq_HASHNODE. */
|
||||
struct hashdummy
|
||||
/* Initial hash table size. (It can grow if necessary.) This is the
|
||||
largest prime number smaller than 2**12. */
|
||||
#define HASHSIZE 4093
|
||||
|
||||
/* This is the structure used for the hash table. */
|
||||
struct htab
|
||||
{
|
||||
const U_CHAR *name;
|
||||
unsigned int hash;
|
||||
unsigned short length;
|
||||
struct cpp_hashnode **entries;
|
||||
size_t size;
|
||||
size_t nelts;
|
||||
};
|
||||
|
||||
/* Stores basic information about a macro, before it is allocated. */
|
||||
struct macro_info
|
||||
{
|
||||
const cpp_token *first_param; /* First parameter token. */
|
||||
const cpp_token *first; /* First expansion token. */
|
||||
unsigned int paramlen; /* Length of parameter names. */
|
||||
unsigned int len; /* Length of token strings. */
|
||||
unsigned int ntokens; /* Number of tokens in expansion. */
|
||||
short paramc; /* Number of parameters. */
|
||||
unsigned char flags;
|
||||
};
|
||||
|
||||
/* Initial hash table size. (It can grow if necessary - see hashtab.c.) */
|
||||
#define HASHSIZE 4096
|
||||
|
||||
static unsigned int hash_HASHNODE PARAMS ((const void *));
|
||||
static int eq_HASHNODE PARAMS ((const void *, const void *));
|
||||
static int dump_hash_helper PARAMS ((void **, void *));
|
||||
static void dump_funlike_macro PARAMS ((cpp_reader *, cpp_hashnode *));
|
||||
static void count_params PARAMS ((cpp_reader *, struct macro_info *));
|
||||
static int is__va_args__ PARAMS ((cpp_reader *, const cpp_token *));
|
||||
|
||||
static int parse_define PARAMS((cpp_reader *, struct macro_info *));
|
||||
static int check_macro_redefinition PARAMS((cpp_reader *, cpp_hashnode *hp,
|
||||
const cpp_toklist *));
|
||||
static const cpp_toklist * save_expansion PARAMS((cpp_reader *,
|
||||
struct macro_info *));
|
||||
static unsigned int find_param PARAMS ((const cpp_token *,
|
||||
const cpp_token *));
|
||||
static cpp_toklist * alloc_macro PARAMS ((cpp_reader *, struct macro_info *));
|
||||
|
||||
/* 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 cpp_hashnode structure. */
|
||||
static unsigned int
|
||||
hash_HASHNODE (x)
|
||||
const void *x;
|
||||
{
|
||||
const cpp_hashnode *h = (const cpp_hashnode *)x;
|
||||
return h->hash;
|
||||
}
|
||||
|
||||
/* Compare a cpp_hashnode structure (already in the table) with a
|
||||
hashdummy structure (not yet in the table). This relies on the
|
||||
rule that the existing entry is the first argument, the potential
|
||||
entry the second. It also relies on the comparison function never
|
||||
being called except as a direct consequence of a call to
|
||||
the htab_find routines. */
|
||||
static int
|
||||
eq_HASHNODE (x, y)
|
||||
const void *x;
|
||||
const void *y;
|
||||
{
|
||||
const cpp_hashnode *a = (const cpp_hashnode *)x;
|
||||
const struct hashdummy *b = (const struct hashdummy *)y;
|
||||
|
||||
return (a->hash == b->hash
|
||||
&& a->length == b->length
|
||||
&& !memcmp (a->name, b->name, a->length));
|
||||
}
|
||||
|
||||
/* Find the hash node for name "name", of length LEN. */
|
||||
|
||||
cpp_hashnode *
|
||||
cpp_lookup (pfile, name, len)
|
||||
cpp_reader *pfile;
|
||||
const U_CHAR *name;
|
||||
int len;
|
||||
{
|
||||
struct hashdummy dummy;
|
||||
cpp_hashnode *new, **slot;
|
||||
unsigned int hash;
|
||||
U_CHAR *p;
|
||||
|
||||
dummy.name = name;
|
||||
dummy.length = len;
|
||||
dummy.hash = hash = _cpp_calc_hash (name, len);
|
||||
|
||||
slot = (cpp_hashnode **)
|
||||
htab_find_slot_with_hash (pfile->hashtab, (void *)&dummy, hash, INSERT);
|
||||
if (*slot)
|
||||
return *slot;
|
||||
|
||||
/* Create a new hash node. */
|
||||
p = obstack_alloc (pfile->hash_ob, sizeof (cpp_hashnode) + len);
|
||||
new = (cpp_hashnode *)p;
|
||||
p += offsetof (cpp_hashnode, name);
|
||||
|
||||
new->type = T_VOID;
|
||||
new->length = len;
|
||||
new->hash = hash;
|
||||
new->fe_value = 0;
|
||||
new->value.expansion = NULL;
|
||||
|
||||
memcpy (p, name, len);
|
||||
p[len] = 0;
|
||||
|
||||
*slot = new;
|
||||
return new;
|
||||
}
|
||||
static void expand_hash PARAMS ((struct htab *));
|
||||
static unsigned long higher_prime_number PARAMS ((unsigned long));
|
||||
|
||||
/* Set up and tear down internal structures for macro expansion. */
|
||||
void
|
||||
_cpp_init_macros (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
pfile->hashtab = htab_create (HASHSIZE, hash_HASHNODE,
|
||||
eq_HASHNODE, (htab_del) _cpp_free_definition);
|
||||
pfile->hash_ob = xnew (struct obstack);
|
||||
obstack_init (pfile->hash_ob);
|
||||
|
||||
pfile->hashtab = xobnew (pfile->hash_ob, struct htab);
|
||||
|
||||
pfile->hashtab->nelts = 0;
|
||||
pfile->hashtab->size = HASHSIZE;
|
||||
pfile->hashtab->entries = xcnewvec (cpp_hashnode *, HASHSIZE);
|
||||
}
|
||||
|
||||
void
|
||||
_cpp_cleanup_macros (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
htab_delete (pfile->hashtab);
|
||||
cpp_hashnode **p, **limit;
|
||||
|
||||
p = pfile->hashtab->entries;
|
||||
limit = p + pfile->hashtab->size;
|
||||
do
|
||||
{
|
||||
if (*p)
|
||||
{
|
||||
_cpp_free_definition (*p);
|
||||
(*p)->fe_value = 0; /* expose the node to GC */
|
||||
}
|
||||
}
|
||||
while (++p < limit);
|
||||
|
||||
free (pfile->hashtab->entries);
|
||||
obstack_free (pfile->hash_ob, 0);
|
||||
free (pfile->hash_ob);
|
||||
}
|
||||
|
||||
/* Free the definition of macro H. */
|
||||
/* The code below is a specialization of Vladimir Makarov's expandable
|
||||
hash tables (see libiberty/hashtab.c). The abstraction penalty was
|
||||
too high to continue using the generic form. This code knows
|
||||
intrinsically how to calculate a hash value, and how to compare an
|
||||
existing entry with a potential new one. Also, the ability to
|
||||
delete members from the table has been removed. */
|
||||
|
||||
void
|
||||
_cpp_free_definition (h)
|
||||
cpp_hashnode *h;
|
||||
cpp_hashnode *
|
||||
cpp_lookup (pfile, name, len)
|
||||
cpp_reader *pfile;
|
||||
const U_CHAR *name;
|
||||
size_t len;
|
||||
{
|
||||
if (h->type == T_MACRO)
|
||||
free ((PTR) h->value.expansion);
|
||||
h->value.expansion = NULL;
|
||||
size_t n = len;
|
||||
unsigned int r = 0;
|
||||
const U_CHAR *str = name;
|
||||
|
||||
do
|
||||
{
|
||||
r = HASHSTEP (r, str);
|
||||
str++;
|
||||
}
|
||||
while (--n);
|
||||
|
||||
return _cpp_lookup_with_hash (pfile, name, len, r);
|
||||
}
|
||||
|
||||
/* Scans for a given token, returning the parameter number if found,
|
||||
or 0 if not found. Scans from FIRST to TOKEN - 1 or the first
|
||||
CPP_CLOSE_PAREN for TOKEN. */
|
||||
static unsigned int
|
||||
find_param (first, token)
|
||||
const cpp_token *first, *token;
|
||||
cpp_hashnode *
|
||||
_cpp_lookup_with_hash (pfile, name, len, hash)
|
||||
cpp_reader *pfile;
|
||||
const U_CHAR *name;
|
||||
size_t len;
|
||||
unsigned int hash;
|
||||
{
|
||||
unsigned int param = 0;
|
||||
unsigned int index;
|
||||
unsigned int hash2;
|
||||
size_t size;
|
||||
cpp_hashnode *entry;
|
||||
cpp_hashnode **entries;
|
||||
|
||||
for (; first < token && first->type != CPP_CLOSE_PAREN; first++)
|
||||
if (first->type == CPP_NAME)
|
||||
entries = pfile->hashtab->entries;
|
||||
size = pfile->hashtab->size;
|
||||
|
||||
hash += len;
|
||||
index = hash % size;
|
||||
|
||||
entry = entries[index];
|
||||
if (entry == NULL)
|
||||
goto insert;
|
||||
if (entry->hash == hash && entry->length == len
|
||||
&& !memcmp (entry->name, name, len))
|
||||
return entry;
|
||||
|
||||
hash2 = 1 + hash % (size - 2);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
index += hash2;
|
||||
if (index >= size)
|
||||
index -= size;
|
||||
entry = entries[index];
|
||||
|
||||
if (entry == NULL)
|
||||
goto insert;
|
||||
if (entry->hash == hash && entry->length == len
|
||||
&& !memcmp (entry->name, name, len))
|
||||
return entry;
|
||||
}
|
||||
|
||||
insert:
|
||||
pfile->hashtab->nelts++;
|
||||
|
||||
/* Create a new hash node. */
|
||||
{
|
||||
U_CHAR *p = obstack_alloc (pfile->hash_ob, sizeof (cpp_hashnode) + len);
|
||||
entry = (cpp_hashnode *)p;
|
||||
p += offsetof (cpp_hashnode, name);
|
||||
|
||||
entry->type = T_VOID;
|
||||
entry->fe_value = 0;
|
||||
entry->length = len;
|
||||
entry->hash = hash;
|
||||
entry->value.expansion = NULL;
|
||||
memcpy (p, name, len);
|
||||
p[len] = 0;
|
||||
|
||||
entries[index] = entry;
|
||||
}
|
||||
|
||||
if (size * 3 <= pfile->hashtab->nelts * 4)
|
||||
expand_hash (pfile->hashtab);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static void
|
||||
expand_hash (htab)
|
||||
struct htab *htab;
|
||||
{
|
||||
cpp_hashnode **oentries;
|
||||
cpp_hashnode **olimit;
|
||||
cpp_hashnode **p;
|
||||
size_t size;
|
||||
|
||||
oentries = htab->entries;
|
||||
olimit = oentries + htab->size;
|
||||
|
||||
htab->size = size = higher_prime_number (htab->size * 2);
|
||||
htab->entries = xcnewvec (cpp_hashnode *, size);
|
||||
|
||||
for (p = oentries; p < olimit; p++)
|
||||
{
|
||||
if (*p != NULL)
|
||||
{
|
||||
unsigned int index;
|
||||
unsigned int hash, hash2;
|
||||
cpp_hashnode *entry = *p;
|
||||
|
||||
hash = entry->hash;
|
||||
index = hash % size;
|
||||
|
||||
if (htab->entries[index] == NULL)
|
||||
{
|
||||
insert:
|
||||
htab->entries[index] = entry;
|
||||
continue;
|
||||
}
|
||||
|
||||
hash2 = 1 + hash % (size - 2);
|
||||
for (;;)
|
||||
{
|
||||
index += hash2;
|
||||
if (index >= size)
|
||||
index -= size;
|
||||
|
||||
if (htab->entries[index] == NULL)
|
||||
goto insert;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free (oentries);
|
||||
}
|
||||
|
||||
/* The following function returns the nearest prime number which is
|
||||
greater than a given source number, N. */
|
||||
|
||||
static unsigned long
|
||||
higher_prime_number (n)
|
||||
unsigned long n;
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
/* Ensure we have a larger number and then force to odd. */
|
||||
n++;
|
||||
n |= 0x01;
|
||||
|
||||
/* All odd numbers < 9 are prime. */
|
||||
if (n < 9)
|
||||
return n;
|
||||
|
||||
/* Otherwise find the next prime using a sieve. */
|
||||
|
||||
next:
|
||||
for (i = 3; i * i <= n; i += 2)
|
||||
if (n % i == 0)
|
||||
{
|
||||
param++;
|
||||
if (first->val.node == token->val.node)
|
||||
return param;
|
||||
}
|
||||
n += 2;
|
||||
goto next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the
|
||||
replacement list of a variable-arguments macro. TOKEN is assumed
|
||||
to be of type CPP_NAME. */
|
||||
static int
|
||||
is__va_args__ (pfile, token)
|
||||
cpp_reader *pfile;
|
||||
const cpp_token *token;
|
||||
{
|
||||
if (!CPP_PEDANTIC (pfile)
|
||||
|| token->val.node != pfile->spec_nodes->n__VA_ARGS__)
|
||||
return 0;
|
||||
|
||||
cpp_pedwarn_with_line (pfile, token->line, token->col,
|
||||
"\"%s\" is only valid in the replacement list of a function-like macro",
|
||||
token->val.node->name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Counts the parameters to a function-like macro, the length of their
|
||||
null-terminated names, and whether the macro is a variable-argument
|
||||
one. FIRST is the token immediately after the open parenthesis,
|
||||
INFO stores the data.
|
||||
|
||||
On success, info->first is updated to the token after the closing
|
||||
parenthesis, i.e. the first token of the expansion. Otherwise
|
||||
there was an error, which has been reported. */
|
||||
static void
|
||||
count_params (pfile, info)
|
||||
cpp_reader *pfile;
|
||||
struct macro_info *info;
|
||||
{
|
||||
unsigned int prev_ident = 0;
|
||||
const cpp_token *token;
|
||||
|
||||
info->paramc = 0;
|
||||
info->paramlen = 0;
|
||||
info->flags = 0;
|
||||
info->first = info->first_param; /* Not a ')' indicating success. */
|
||||
|
||||
for (token = info->first_param;; token++)
|
||||
{
|
||||
switch (token->type)
|
||||
{
|
||||
default:
|
||||
cpp_error_with_line (pfile, token->line, token->col,
|
||||
"illegal token in macro parameter list");
|
||||
return;
|
||||
|
||||
case CPP_EOF:
|
||||
missing_paren:
|
||||
cpp_error_with_line (pfile, token->line, token->col,
|
||||
"missing ')' in macro parameter list");
|
||||
return;
|
||||
|
||||
case CPP_COMMENT:
|
||||
continue; /* Ignore -C comments. */
|
||||
|
||||
case CPP_NAME:
|
||||
if (prev_ident)
|
||||
{
|
||||
cpp_error_with_line (pfile, token->line, token->col,
|
||||
"macro parameters must be comma-separated");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Constraint 6.10.3.5 */
|
||||
if (is__va_args__ (pfile, token))
|
||||
return;
|
||||
|
||||
/* Constraint 6.10.3.6 - duplicate parameter names. */
|
||||
if (find_param (info->first, token))
|
||||
{
|
||||
cpp_error_with_line (pfile, token->line, token->col,
|
||||
"duplicate macro parameter \"%s\"",
|
||||
token->val.node->name);
|
||||
return;
|
||||
}
|
||||
|
||||
prev_ident = 1;
|
||||
info->paramc++;
|
||||
info->paramlen += token->val.node->length + 1;
|
||||
continue;
|
||||
|
||||
case CPP_CLOSE_PAREN:
|
||||
if (prev_ident || info->paramc == 0)
|
||||
break;
|
||||
|
||||
/* Fall through to pick up the error. */
|
||||
case CPP_COMMA:
|
||||
if (!prev_ident)
|
||||
{
|
||||
cpp_error_with_line (pfile, token->line, token->col,
|
||||
"parameter name expected");
|
||||
return;
|
||||
}
|
||||
prev_ident = 0;
|
||||
continue;
|
||||
|
||||
case CPP_ELLIPSIS:
|
||||
/* Convert ISO-style var_args to named varargs by changing
|
||||
the ellipsis into an identifier with name __VA_ARGS__.
|
||||
This simplifies other handling. */
|
||||
if (!prev_ident)
|
||||
{
|
||||
cpp_token *tok = (cpp_token *) token;
|
||||
|
||||
tok->type = CPP_NAME;
|
||||
tok->val.node = pfile->spec_nodes->n__VA_ARGS__;
|
||||
|
||||
info->paramc++;
|
||||
info->paramlen += tok->val.node->length + 1;
|
||||
|
||||
if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, c99))
|
||||
cpp_pedwarn (pfile,
|
||||
"C89 does not permit anon varargs macros");
|
||||
}
|
||||
else
|
||||
{
|
||||
info->flags |= GNU_REST_ARGS;
|
||||
if (CPP_PEDANTIC (pfile))
|
||||
cpp_pedwarn (pfile,
|
||||
"ISO C does not permit named varargs parameters");
|
||||
}
|
||||
|
||||
info->flags |= VAR_ARGS;
|
||||
token++;
|
||||
if (token->type == CPP_CLOSE_PAREN)
|
||||
break;
|
||||
goto missing_paren;
|
||||
}
|
||||
|
||||
/* Success. */
|
||||
info->first = token + 1;
|
||||
if (!pfile->save_parameter_spellings)
|
||||
info->paramlen = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parses a #define directive. On success, returns zero, and INFO is
|
||||
filled in appropriately. */
|
||||
static int
|
||||
parse_define (pfile, info)
|
||||
cpp_reader *pfile;
|
||||
struct macro_info *info;
|
||||
{
|
||||
const cpp_token *token;
|
||||
int prev_white = 0;
|
||||
|
||||
/* The first token after the macro's name. */
|
||||
token = _cpp_get_token (pfile);
|
||||
|
||||
/* Constraint 6.10.3.5 */
|
||||
if (is__va_args__ (pfile, token - 1))
|
||||
return 1;
|
||||
|
||||
while (token->type == CPP_COMMENT)
|
||||
token++, prev_white = 1;
|
||||
prev_white |= token->flags & PREV_WHITE;
|
||||
|
||||
if (token->type == CPP_OPEN_PAREN && !prev_white)
|
||||
{
|
||||
/* A function-like macro. */
|
||||
info->first_param = token + 1;
|
||||
count_params (pfile, info);
|
||||
if (info->first[-1].type != CPP_CLOSE_PAREN)
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* An object-like macro. */
|
||||
info->paramc = -1;
|
||||
info->paramlen = 0;
|
||||
info->flags = 0;
|
||||
info->first = token;
|
||||
if (!prev_white && token->type != CPP_EOF)
|
||||
cpp_pedwarn (pfile, "ISO C requires whitespace after the macro name");
|
||||
}
|
||||
|
||||
/* Count tokens in expansion. We drop paste tokens, and stringize
|
||||
tokens, so don't count them. */
|
||||
info->ntokens = info->len = 0;
|
||||
for (token = info->first; token->type != CPP_EOF; token++)
|
||||
{
|
||||
if (token->type == CPP_PASTE)
|
||||
{
|
||||
/* Token-paste ##, can appear in both object-like and
|
||||
function-like macros, but not at the ends. Constraint
|
||||
6.10.3.3.1 */
|
||||
if (token == info->first || token[1].type == CPP_EOF)
|
||||
{
|
||||
cpp_error_with_line (pfile, token->line, token->col,
|
||||
"'##' cannot appear at either end of a macro expansion");
|
||||
return 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (token->type == CPP_HASH)
|
||||
{
|
||||
/* Stringifying #, but a normal character in object-like
|
||||
macros. Must come before a parameter name. Constraint
|
||||
6.10.3.2.1. */
|
||||
if (info->paramc >= 0)
|
||||
{
|
||||
if (token[1].type == CPP_NAME
|
||||
&& find_param (info->first_param, token + 1))
|
||||
continue;
|
||||
if (! CPP_OPTION (pfile, lang_asm))
|
||||
{
|
||||
cpp_error_with_line (pfile, token->line, token->col,
|
||||
"'#' is not followed by a macro parameter");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (token->type == CPP_NAME)
|
||||
{
|
||||
/* Constraint 6.10.3.5 */
|
||||
if (!(info->flags & VAR_ARGS) && is__va_args__ (pfile, token))
|
||||
return 1;
|
||||
/* It might be worth doing a check here that we aren't a
|
||||
macro argument, since we don't store the text of macro
|
||||
arguments. This would reduce "len" and save space. */
|
||||
}
|
||||
info->ntokens++;
|
||||
if (TOKEN_SPELL (token) == SPELL_STRING)
|
||||
info->len += token->val.str.len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns non-zero if a macro redefinition is trivial. */
|
||||
static int
|
||||
check_macro_redefinition (pfile, hp, list2)
|
||||
cpp_reader *pfile;
|
||||
cpp_hashnode *hp;
|
||||
const cpp_toklist *list2;
|
||||
{
|
||||
const cpp_toklist *list1;
|
||||
|
||||
if (hp->type != T_MACRO)
|
||||
return ! pfile->done_initializing;
|
||||
|
||||
/* Clear the whitespace and BOL flags of the first tokens. They get
|
||||
altered during macro expansion, but is not significant here. */
|
||||
list1 = hp->value.expansion;
|
||||
list1->tokens[0].flags &= ~(PREV_WHITE|BOL);
|
||||
list2->tokens[0].flags &= ~(PREV_WHITE|BOL);
|
||||
|
||||
if (!_cpp_equiv_toklists (list1, list2))
|
||||
return 0;
|
||||
|
||||
if (CPP_OPTION (pfile, pedantic)
|
||||
&& list1->paramc > 0
|
||||
&& (list1->params_len != list2->params_len
|
||||
|| memcmp (list1->namebuf, list2->namebuf, list1->params_len)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* This is a dummy structure whose only purpose is getting alignment
|
||||
correct. */
|
||||
struct toklist_dummy
|
||||
{
|
||||
cpp_toklist list;
|
||||
cpp_token first_token;
|
||||
};
|
||||
|
||||
|
||||
/* Allocate space to hold the token list, its tokens, their text, and
|
||||
the parameter names if needed. Empty expansions are stored as a
|
||||
single placemarker token.
|
||||
|
||||
These are all allocated in a block together for performance
|
||||
reasons. Therefore, this token list cannot be expanded like a
|
||||
normal token list. Try to do so, and you lose. */
|
||||
static cpp_toklist *
|
||||
alloc_macro (pfile, info)
|
||||
cpp_reader *pfile;
|
||||
struct macro_info *info;
|
||||
{
|
||||
unsigned int size;
|
||||
struct toklist_dummy *dummy;
|
||||
cpp_toklist *list;
|
||||
|
||||
/* Empty macros become a single placemarker token. */
|
||||
if (info->ntokens == 0)
|
||||
info->ntokens = 1;
|
||||
|
||||
size = sizeof (struct toklist_dummy);
|
||||
size += (info->ntokens - 1) * sizeof(cpp_token);
|
||||
size += info->len + info->paramlen;
|
||||
|
||||
dummy = (struct toklist_dummy *) xmalloc (size);
|
||||
list = (cpp_toklist *) dummy;
|
||||
|
||||
/* Initialize the monster. */
|
||||
list->tokens = &dummy->first_token;
|
||||
list->tokens_used = list->tokens_cap = info->ntokens;
|
||||
|
||||
list->namebuf = (unsigned char *) &list->tokens[info->ntokens];
|
||||
list->name_used = list->name_cap = info->len + info->paramlen;
|
||||
|
||||
list->directive = 0;
|
||||
list->line = pfile->token_list.line;
|
||||
list->file = pfile->token_list.file;
|
||||
list->params_len = info->paramlen;
|
||||
list->paramc = info->paramc;
|
||||
list->flags = info->flags;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/* Copy the tokens of the expansion, beginning with info->first until
|
||||
CPP_EOF. INFO contains information about the macro.
|
||||
|
||||
Change the type of macro arguments in the expansion from CPP_NAME
|
||||
to CPP_MACRO_ARG. Remove #'s that represent stringification,
|
||||
flagging the CPP_MACRO_ARG it operates on STRINGIFY. Remove ##'s,
|
||||
flagging the token on its immediate left PASTE_LEFT. Returns the
|
||||
token list for the macro expansion. */
|
||||
static const cpp_toklist *
|
||||
save_expansion (pfile, info)
|
||||
cpp_reader *pfile;
|
||||
struct macro_info *info;
|
||||
{
|
||||
const cpp_token *token;
|
||||
cpp_toklist *list;
|
||||
cpp_token *dest;
|
||||
unsigned char *buf;
|
||||
|
||||
list = alloc_macro (pfile, info);
|
||||
buf = list->namebuf;
|
||||
|
||||
/* Store the null-terminated parameter spellings of a macro, to
|
||||
provide pedantic warnings to satisfy 6.10.3.2, or for use when
|
||||
dumping macro definitions. They must go first. */
|
||||
if (list->params_len)
|
||||
for (token = info->first_param; token < info->first; token++)
|
||||
if (token->type == CPP_NAME)
|
||||
{
|
||||
/* Copy null too. */
|
||||
memcpy (buf, token->val.node->name, token->val.node->length + 1);
|
||||
buf += token->val.node->length + 1;
|
||||
}
|
||||
|
||||
dest = list->tokens;
|
||||
for (token = info->first; token->type != CPP_EOF; token++)
|
||||
{
|
||||
unsigned int param_no;
|
||||
|
||||
switch (token->type)
|
||||
{
|
||||
case CPP_NAME:
|
||||
if (list->paramc == -1)
|
||||
break;
|
||||
|
||||
/* Check if the name is a macro parameter. */
|
||||
param_no = find_param (info->first_param, token);
|
||||
if (param_no == 0)
|
||||
break;
|
||||
dest->val.aux = param_no - 1;
|
||||
|
||||
dest->type = CPP_MACRO_ARG;
|
||||
if (token[-1].type == CPP_HASH)
|
||||
dest->flags = token[-1].flags | STRINGIFY_ARG;
|
||||
else
|
||||
dest->flags = token->flags; /* Particularly PREV_WHITE. */
|
||||
/* Turn off PREV_WHITE if we immediately follow a paste.
|
||||
That way, even if the paste turns out to be illegal, there
|
||||
will be no space between the two tokens in the output. */
|
||||
if (token[-1].type == CPP_PASTE)
|
||||
dest->flags &= ~PREV_WHITE;
|
||||
dest++;
|
||||
continue;
|
||||
|
||||
case CPP_PASTE:
|
||||
dest[-1].flags |= PASTE_LEFT;
|
||||
continue;
|
||||
|
||||
case CPP_HASH:
|
||||
/* Stringifying #. Constraint 6.10.3.2.1 */
|
||||
if (list->paramc >= 0 && token[1].type == CPP_NAME
|
||||
&& find_param (info->first_param, token + 1))
|
||||
continue;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Copy the token. */
|
||||
*dest = *token;
|
||||
if (TOKEN_SPELL (token) == SPELL_STRING)
|
||||
{
|
||||
memcpy (buf, token->val.str.text, token->val.str.len);
|
||||
dest->val.str.text = buf;
|
||||
buf += dest->val.str.len;
|
||||
}
|
||||
if (token[-1].type == CPP_PASTE)
|
||||
dest->flags &= ~PREV_WHITE;
|
||||
dest++;
|
||||
}
|
||||
|
||||
/* Empty macros become a single placemarker token. */
|
||||
if (dest == list->tokens)
|
||||
{
|
||||
dest->type = CPP_PLACEMARKER;
|
||||
dest->flags = 0;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/* Parse a macro and save its expansion. Returns non-zero on success. */
|
||||
int
|
||||
_cpp_create_definition (pfile, hp)
|
||||
cpp_reader *pfile;
|
||||
cpp_hashnode *hp;
|
||||
{
|
||||
struct macro_info info;
|
||||
const cpp_toklist *list;
|
||||
|
||||
if (parse_define (pfile, &info))
|
||||
return 0;
|
||||
list = save_expansion (pfile, &info);
|
||||
|
||||
/* Check for a redefinition. Redefinition of a macro is allowed if
|
||||
and only if the old and new definitions are the same.
|
||||
(6.10.3 paragraph 2). */
|
||||
|
||||
if (hp->type != T_VOID)
|
||||
{
|
||||
if (!check_macro_redefinition (pfile, hp, list))
|
||||
{
|
||||
cpp_pedwarn (pfile, "\"%s\" redefined", hp->name);
|
||||
if (pfile->done_initializing && hp->type == T_MACRO)
|
||||
cpp_pedwarn_with_file_and_line (pfile,
|
||||
hp->value.expansion->file,
|
||||
hp->value.expansion->line, 1,
|
||||
"this is the location of the previous definition");
|
||||
}
|
||||
_cpp_free_definition (hp);
|
||||
}
|
||||
|
||||
/* Enter definition in hash table. */
|
||||
hp->type = T_MACRO;
|
||||
hp->value.expansion = list;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Dump the definition of macro MACRO on stdout. The format is suitable
|
||||
to be read back in again. */
|
||||
|
||||
void
|
||||
_cpp_dump_definition (pfile, hp)
|
||||
cpp_reader *pfile;
|
||||
cpp_hashnode *hp;
|
||||
{
|
||||
CPP_RESERVE (pfile, hp->length + sizeof "#define ");
|
||||
CPP_PUTS_Q (pfile, "#define ", sizeof "#define " - 1);
|
||||
CPP_PUTS_Q (pfile, hp->name, hp->length);
|
||||
|
||||
if (hp->type == T_MACRO)
|
||||
{
|
||||
if (hp->value.expansion->paramc >= 0)
|
||||
dump_funlike_macro (pfile, hp);
|
||||
else
|
||||
{
|
||||
const cpp_toklist *list = hp->value.expansion;
|
||||
list->tokens[0].flags &= ~BOL;
|
||||
list->tokens[0].flags |= PREV_WHITE;
|
||||
_cpp_dump_list (pfile, list, list->tokens, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
cpp_ice (pfile, "invalid hash type %d in dump_definition", hp->type);
|
||||
|
||||
if (CPP_BUFFER (pfile) == 0 || ! pfile->done_initializing)
|
||||
CPP_PUTC (pfile, '\n');
|
||||
}
|
||||
|
||||
static void
|
||||
dump_funlike_macro (pfile, node)
|
||||
cpp_reader *pfile;
|
||||
cpp_hashnode *node;
|
||||
{
|
||||
int i = 0;
|
||||
const cpp_toklist * list = node->value.expansion;
|
||||
const U_CHAR *param;
|
||||
|
||||
param = list->namebuf;
|
||||
CPP_PUTC_Q (pfile, '(');
|
||||
for (i = 0; i++ < list->paramc;)
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
len = ustrlen (param);
|
||||
CPP_PUTS (pfile, param, len);
|
||||
if (i < list->paramc)
|
||||
CPP_PUTS(pfile, ", ", 2);
|
||||
else if (list->flags & VAR_ARGS)
|
||||
{
|
||||
if (!ustrcmp (param, U"__VA_ARGS__"))
|
||||
pfile->limit -= sizeof (U"__VA_ARGS__") - 1;
|
||||
CPP_PUTS_Q (pfile, "...", 3);
|
||||
}
|
||||
param += len + 1;
|
||||
}
|
||||
CPP_PUTC (pfile, ')');
|
||||
list->tokens[0].flags &= ~BOL;
|
||||
list->tokens[0].flags |= PREV_WHITE;
|
||||
_cpp_dump_list (pfile, list, list->tokens, 1);
|
||||
}
|
||||
|
||||
/* Dump out the hash table. */
|
||||
static int
|
||||
dump_hash_helper (h, p)
|
||||
void **h;
|
||||
void *p;
|
||||
{
|
||||
cpp_hashnode *hp = (cpp_hashnode *)*h;
|
||||
cpp_reader *pfile = (cpp_reader *)p;
|
||||
|
||||
if (hp->type == T_MACRO)
|
||||
_cpp_dump_definition (pfile, hp);
|
||||
return 1;
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
_cpp_dump_macro_hash (pfile)
|
||||
cpp_forall_identifiers (pfile, cb)
|
||||
cpp_reader *pfile;
|
||||
int (*cb) PARAMS ((cpp_reader *, cpp_hashnode *));
|
||||
{
|
||||
htab_traverse (pfile->hashtab, dump_hash_helper, pfile);
|
||||
cpp_hashnode **p, **limit;
|
||||
|
||||
p = pfile->hashtab->entries;
|
||||
limit = p + pfile->hashtab->size;
|
||||
do
|
||||
{
|
||||
if (*p)
|
||||
if ((*cb) (pfile, *p) == 0)
|
||||
break;
|
||||
}
|
||||
while (++p < limit);
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ struct answer
|
|||
#define COMMENTS (1 << 3)
|
||||
|
||||
/* Defines one #-directive, including how to handle it. */
|
||||
typedef int (*directive_handler) PARAMS ((cpp_reader *));
|
||||
typedef void (*directive_handler) PARAMS ((cpp_reader *));
|
||||
struct directive
|
||||
{
|
||||
directive_handler handler; /* Function to handle directive. */
|
||||
|
@ -202,18 +202,24 @@ extern unsigned char _cpp_IStable[256];
|
|||
#define CPP_WTRADITIONAL(PF) \
|
||||
(CPP_OPTION (PF, warn_traditional) && !CPP_IN_SYSTEM_HEADER (PF))
|
||||
|
||||
/* Hash step. The hash calculation is duplicated in cpp_lookup and
|
||||
parse_name. */
|
||||
#define HASHSTEP(r, str) ((r) * 67 + (*str - 113));
|
||||
|
||||
/* Flags for _cpp_init_toklist. */
|
||||
#define DUMMY_TOKEN 0
|
||||
#define NO_DUMMY_TOKEN 1
|
||||
|
||||
/* In cpphash.c */
|
||||
extern unsigned int _cpp_calc_hash PARAMS ((const U_CHAR *, size_t));
|
||||
/* In cppmacro.c */
|
||||
extern void _cpp_free_definition PARAMS ((cpp_hashnode *));
|
||||
extern int _cpp_create_definition PARAMS ((cpp_reader *, cpp_hashnode *));
|
||||
extern void _cpp_dump_definition PARAMS ((cpp_reader *, cpp_hashnode *));
|
||||
|
||||
/* In cpphash.c */
|
||||
extern void _cpp_init_macros PARAMS ((cpp_reader *));
|
||||
extern void _cpp_cleanup_macros PARAMS ((cpp_reader *));
|
||||
extern void _cpp_dump_macro_hash PARAMS ((cpp_reader *));
|
||||
extern cpp_hashnode *_cpp_lookup_with_hash PARAMS ((cpp_reader*, const U_CHAR *,
|
||||
size_t, unsigned int));
|
||||
|
||||
/* In cppfiles.c */
|
||||
extern void _cpp_simplify_pathname PARAMS ((char *));
|
||||
|
@ -278,6 +284,7 @@ extern void _cpp_cleanup_stacks PARAMS ((cpp_reader *));
|
|||
/* Utility routines and macros. */
|
||||
#define xnew(T) (T *) xmalloc (sizeof(T))
|
||||
#define xnewvec(T, N) (T *) xmalloc (sizeof(T) * (N))
|
||||
#define xcnewvec(T, N) (T *) xcalloc (N, sizeof(T))
|
||||
#define xobnew(O, T) (T *) obstack_alloc (O, sizeof(T))
|
||||
|
||||
/* These are inline functions instead of macros so we can get type
|
||||
|
|
|
@ -114,6 +114,7 @@ static int opt_comp PARAMS ((const void *, const void *));
|
|||
static void sort_options PARAMS ((void));
|
||||
#endif
|
||||
static int parse_option PARAMS ((const char *));
|
||||
static int dump_macros_helper PARAMS ((cpp_reader *, cpp_hashnode *));
|
||||
|
||||
/* Fourth argument to append_include_chain: chain to use */
|
||||
enum { QUOTE = 0, BRACKET, SYSTEM, AFTER };
|
||||
|
@ -891,6 +892,18 @@ cpp_start_read (pfile, print, fname)
|
|||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Dump out the hash table. */
|
||||
static int
|
||||
dump_macros_helper (pfile, hp)
|
||||
cpp_reader *pfile;
|
||||
cpp_hashnode *hp;
|
||||
{
|
||||
if (hp->type == T_MACRO)
|
||||
_cpp_dump_definition (pfile, hp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* This is called at the end of preprocessing. It pops the
|
||||
last buffer and writes dependency output. It should also
|
||||
clear macro definitions, such that you could call cpp_start_read
|
||||
|
@ -934,7 +947,7 @@ cpp_finish (pfile, print)
|
|||
}
|
||||
|
||||
if (CPP_OPTION (pfile, dump_macros) == dump_only)
|
||||
_cpp_dump_macro_hash (pfile);
|
||||
cpp_forall_identifiers (pfile, dump_macros_helper);
|
||||
|
||||
/* Flush any pending output. */
|
||||
if (print)
|
||||
|
|
19
gcc/cpplex.c
19
gcc/cpplex.c
|
@ -1070,16 +1070,21 @@ skip_whitespace (pfile, in_directive)
|
|||
}
|
||||
}
|
||||
|
||||
/* Parse (append) an identifier. */
|
||||
/* Parse (append) an identifier. Calculates the hash value of the
|
||||
token while parsing, for performance. The algorithm *must* match
|
||||
cpp_lookup(). */
|
||||
static const U_CHAR *
|
||||
parse_name (pfile, tok, cur, rlimit)
|
||||
cpp_reader *pfile;
|
||||
cpp_token *tok;
|
||||
const U_CHAR *cur, *rlimit;
|
||||
{
|
||||
const U_CHAR *name = cur;
|
||||
const U_CHAR *name;
|
||||
unsigned int len;
|
||||
unsigned int r;
|
||||
|
||||
name = cur;
|
||||
r = 0;
|
||||
while (cur < rlimit)
|
||||
{
|
||||
if (! is_idchar (*cur))
|
||||
|
@ -1092,21 +1097,23 @@ parse_name (pfile, tok, cur, rlimit)
|
|||
CPP_BUFFER (pfile)->cur = cur;
|
||||
cpp_pedwarn (pfile, "'$' character in identifier");
|
||||
}
|
||||
|
||||
r = HASHSTEP (r, cur);
|
||||
cur++;
|
||||
}
|
||||
len = cur - name;
|
||||
|
||||
if (tok->val.node)
|
||||
if (tok->val.node == 0)
|
||||
tok->val.node = _cpp_lookup_with_hash (pfile, name, len, r);
|
||||
else
|
||||
{
|
||||
unsigned int oldlen = tok->val.node->length;
|
||||
U_CHAR *newname = alloca (oldlen + len);
|
||||
memcpy (newname, tok->val.node->name, oldlen);
|
||||
memcpy (newname + oldlen, name, len);
|
||||
len += oldlen;
|
||||
name = newname;
|
||||
tok->val.node = cpp_lookup (pfile, newname, len + oldlen);
|
||||
}
|
||||
|
||||
tok->val.node = cpp_lookup (pfile, name, len);
|
||||
return cur;
|
||||
}
|
||||
|
||||
|
|
90
gcc/cpplib.c
90
gcc/cpplib.c
|
@ -113,7 +113,7 @@ SCCS_ENTRY /* 0 SVR2? */
|
|||
pointers to functions returning void. */
|
||||
|
||||
/* Don't invoke CONCAT2 with any whitespace or K&R cc will fail. */
|
||||
#define D(name, t, o, f) static int CONCAT2(do_,name) PARAMS ((cpp_reader *));
|
||||
#define D(name, t, o, f) static void CONCAT2(do_,name) PARAMS ((cpp_reader *));
|
||||
DIRECTIVE_TABLE
|
||||
#undef D
|
||||
|
||||
|
@ -272,7 +272,7 @@ get_define_node (pfile)
|
|||
}
|
||||
|
||||
/* Process a #define command. */
|
||||
static int
|
||||
static void
|
||||
do_define (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
|
@ -287,11 +287,10 @@ do_define (pfile)
|
|||
else if (CPP_OPTION (pfile, dump_macros) == dump_names)
|
||||
dump_macro_name (pfile, node);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remove the definition of a symbol from the symbol table. */
|
||||
static int
|
||||
static void
|
||||
do_undef (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
|
@ -317,8 +316,6 @@ do_undef (pfile)
|
|||
_cpp_free_definition (node);
|
||||
node->type = T_VOID;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -360,7 +357,7 @@ parse_include (pfile, dir, trail, strp, lenp, abp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
static void
|
||||
do_include (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
|
@ -369,15 +366,14 @@ do_include (pfile)
|
|||
int ab;
|
||||
|
||||
if (parse_include (pfile, dtable[T_INCLUDE].name, 0, &str, &len, &ab))
|
||||
return 0;
|
||||
return;
|
||||
|
||||
_cpp_execute_include (pfile, str, len, 0, 0, ab);
|
||||
if (CPP_OPTION (pfile, dump_includes))
|
||||
pass_thru_directive (pfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
static void
|
||||
do_import (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
|
@ -394,15 +390,14 @@ do_import (pfile)
|
|||
}
|
||||
|
||||
if (parse_include (pfile, dtable[T_IMPORT].name, 0, &str, &len, &ab))
|
||||
return 0;
|
||||
return;
|
||||
|
||||
_cpp_execute_include (pfile, str, len, 1, 0, ab);
|
||||
if (CPP_OPTION (pfile, dump_includes))
|
||||
pass_thru_directive (pfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
static void
|
||||
do_include_next (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
|
@ -412,7 +407,7 @@ do_include_next (pfile)
|
|||
int ab;
|
||||
|
||||
if (parse_include (pfile, dtable[T_INCLUDE_NEXT].name, 0, &str, &len, &ab))
|
||||
return 0;
|
||||
return;
|
||||
|
||||
/* For #include_next, skip in the search path past the dir in which
|
||||
the current file was found. If this is the last directory in the
|
||||
|
@ -426,7 +421,7 @@ do_include_next (pfile)
|
|||
{
|
||||
search_start = CPP_BUFFER (pfile)->inc->foundhere->next;
|
||||
if (!search_start)
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -435,8 +430,6 @@ do_include_next (pfile)
|
|||
_cpp_execute_include (pfile, str, len, 0, search_start, ab);
|
||||
if (CPP_OPTION (pfile, dump_includes))
|
||||
pass_thru_directive (pfile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Subroutine of do_line. Read next token from PFILE without adding it to
|
||||
|
@ -494,7 +487,7 @@ strtoul_for_line (str, len, nump)
|
|||
Note that the filename string (if any) is treated as if it were an
|
||||
include filename. That means no escape handling. */
|
||||
|
||||
static int
|
||||
static void
|
||||
do_line (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
|
@ -552,7 +545,7 @@ do_line (pfile)
|
|||
}
|
||||
|
||||
if (read_line_number (pfile, &action_number) == 0)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
if (CPP_PEDANTIC (pfile))
|
||||
cpp_pedwarn (pfile, "garbage at end of #line");
|
||||
|
@ -582,10 +575,9 @@ do_line (pfile)
|
|||
cpp_make_system_header (pfile, ip, 2);
|
||||
read_line_number (pfile, &action_number);
|
||||
}
|
||||
return 0;
|
||||
|
||||
done:
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -594,7 +586,7 @@ do_line (pfile)
|
|||
* (We use error because it prints the filename & line#.)
|
||||
*/
|
||||
|
||||
static int
|
||||
static void
|
||||
do_error (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
|
@ -605,8 +597,6 @@ do_error (pfile)
|
|||
limit = pfile->limit;
|
||||
pfile->limit = text;
|
||||
cpp_error (pfile, "%.*s", (int)(limit - text), text);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -614,7 +604,7 @@ do_error (pfile)
|
|||
* Use the text of the line in the warning message, then continue.
|
||||
*/
|
||||
|
||||
static int
|
||||
static void
|
||||
do_warning (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
|
@ -625,12 +615,11 @@ do_warning (pfile)
|
|||
limit = pfile->limit;
|
||||
pfile->limit = text;
|
||||
cpp_warning (pfile, "%.*s", (int)(limit - text), text);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Report program identification. */
|
||||
|
||||
static int
|
||||
static void
|
||||
do_ident (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
|
@ -641,11 +630,10 @@ do_ident (pfile)
|
|||
{
|
||||
/* Good - ship it. */
|
||||
pass_thru_directive (pfile);
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
cpp_error (pfile, "invalid #ident");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Pragmata handling. We handle some of these, and pass the rest on
|
||||
|
@ -708,7 +696,7 @@ static int pragma_dispatch (pfile, table, node)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
static void
|
||||
do_pragma (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
|
@ -717,17 +705,16 @@ do_pragma (pfile)
|
|||
|
||||
tok = _cpp_get_token (pfile);
|
||||
if (tok->type == CPP_EOF)
|
||||
return 0;
|
||||
return;
|
||||
else if (tok->type != CPP_NAME)
|
||||
{
|
||||
cpp_error (pfile, "malformed #pragma directive");
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
pop = pragma_dispatch (pfile, top_pragmas, tok->val.node);
|
||||
if (!pop)
|
||||
pass_thru_directive (pfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -900,11 +887,10 @@ do_pragma_dependency (pfile)
|
|||
|
||||
/* Just ignore #sccs, on systems where we define it at all. */
|
||||
#ifdef SCCS_DIRECTIVE
|
||||
static int
|
||||
static void
|
||||
do_sccs (pfile)
|
||||
cpp_reader *pfile ATTRIBUTE_UNUSED;
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -991,7 +977,7 @@ parse_ifdef (pfile, name)
|
|||
|
||||
/* #ifdef is dead simple. */
|
||||
|
||||
static int
|
||||
static void
|
||||
do_ifdef (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
|
@ -1001,13 +987,12 @@ do_ifdef (pfile)
|
|||
node = parse_ifdef (pfile, dtable[T_IFDEF].name);
|
||||
|
||||
push_conditional (pfile, !(node && node->type != T_VOID), T_IFDEF, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* #ifndef is a tad more complex, because we need to check for a
|
||||
no-reinclusion wrapper. */
|
||||
|
||||
static int
|
||||
static void
|
||||
do_ifndef (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
|
@ -1022,13 +1007,12 @@ do_ifndef (pfile)
|
|||
|
||||
push_conditional (pfile, node && node->type != T_VOID,
|
||||
T_IFNDEF, start_of_file ? node : 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* #if is straightforward; just call _cpp_parse_expr, then conditional_skip.
|
||||
Also, check for a reinclude preventer of the form #if !defined (MACRO). */
|
||||
|
||||
static int
|
||||
static void
|
||||
do_if (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
|
@ -1042,14 +1026,13 @@ do_if (pfile)
|
|||
value = _cpp_parse_expr (pfile);
|
||||
}
|
||||
push_conditional (pfile, value == 0, T_IF, cmacro);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* #else flips pfile->skipping and continues without changing
|
||||
if_stack; this is so that the error message for missing #endif's
|
||||
etc. will point to the original #if. */
|
||||
|
||||
static int
|
||||
static void
|
||||
do_else (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
|
@ -1059,7 +1042,7 @@ do_else (pfile)
|
|||
if (ifs == NULL)
|
||||
{
|
||||
cpp_error (pfile, "#else without #if");
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
if (ifs->type == T_ELSE)
|
||||
{
|
||||
|
@ -1079,7 +1062,6 @@ do_else (pfile)
|
|||
if (pfile->skipping < 2)
|
||||
pfile->skipping = ! pfile->skipping;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1087,7 +1069,7 @@ do_else (pfile)
|
|||
* see the comment above do_else.
|
||||
*/
|
||||
|
||||
static int
|
||||
static void
|
||||
do_elif (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
|
@ -1096,7 +1078,7 @@ do_elif (pfile)
|
|||
if (ifs == NULL)
|
||||
{
|
||||
cpp_error (pfile, "#elif without #if");
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
if (ifs->type == T_ELSE)
|
||||
{
|
||||
|
@ -1107,21 +1089,20 @@ do_elif (pfile)
|
|||
|
||||
ifs->type = T_ELIF;
|
||||
if (ifs->was_skipping)
|
||||
return 0; /* Don't evaluate a nested #if */
|
||||
return; /* Don't evaluate a nested #if */
|
||||
|
||||
if (pfile->skipping != 1)
|
||||
{
|
||||
pfile->skipping = 2; /* one block succeeded, so don't do any others */
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
pfile->skipping = ! _cpp_parse_expr (pfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* #endif pops the if stack and resets pfile->skipping. */
|
||||
|
||||
static int
|
||||
static void
|
||||
do_endif (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
|
@ -1138,7 +1119,6 @@ do_endif (pfile)
|
|||
pfile->potential_control_macro = ifs->cmacro;
|
||||
obstack_free (pfile->buffer_ob, ifs);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1332,7 +1312,7 @@ _cpp_find_answer (node, candidate)
|
|||
#define WARNING(msgid) do { cpp_warning(pfile, msgid); goto error; } while (0)
|
||||
#define ERROR(msgid) do { cpp_error(pfile, msgid); goto error; } while (0)
|
||||
#define ICE(msgid) do { cpp_ice(pfile, msgid); goto error; } while (0)
|
||||
static int
|
||||
static void
|
||||
do_assert (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
|
@ -1355,16 +1335,15 @@ do_assert (pfile)
|
|||
node->type = T_ASSERTION;
|
||||
node->value.answers = new_answer;
|
||||
}
|
||||
return 0;
|
||||
return;
|
||||
|
||||
err:
|
||||
cpp_warning (pfile, "\"%.*s\" re-asserted",
|
||||
node->length - 1, node->name + 1);
|
||||
FREE_ANSWER (new_answer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
static void
|
||||
do_unassert (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
|
@ -1404,7 +1383,6 @@ do_unassert (pfile)
|
|||
if (answer)
|
||||
FREE_ANSWER (answer);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* These are for -D, -U, -A. */
|
||||
|
|
24
gcc/cpplib.h
24
gcc/cpplib.h
|
@ -653,6 +653,10 @@ extern void cpp_undef PARAMS ((cpp_reader *, const char *));
|
|||
extern void cpp_unassert PARAMS ((cpp_reader *, const char *));
|
||||
|
||||
extern void cpp_free_token_list PARAMS ((cpp_toklist *));
|
||||
extern cpp_buffer *cpp_push_buffer PARAMS ((cpp_reader *,
|
||||
const unsigned char *, long));
|
||||
extern cpp_buffer *cpp_pop_buffer PARAMS ((cpp_reader *));
|
||||
extern int cpp_defined PARAMS ((cpp_reader *, const unsigned char *, int));
|
||||
|
||||
/* N.B. The error-message-printer prototypes have not been nicely
|
||||
formatted because exgettext needs to see 'msgid' on the same line
|
||||
|
@ -680,8 +684,8 @@ extern void cpp_pedwarn_with_line PARAMS ((cpp_reader *, int, int, const char *m
|
|||
ATTRIBUTE_PRINTF_4;
|
||||
extern void cpp_pedwarn_with_file_and_line PARAMS ((cpp_reader *, const char *, int, int, const char *msgid, ...))
|
||||
ATTRIBUTE_PRINTF_5;
|
||||
extern void cpp_error_from_errno PARAMS ((cpp_reader *, const char *));
|
||||
extern void cpp_notice_from_errno PARAMS ((cpp_reader *, const char *));
|
||||
extern void cpp_error_from_errno PARAMS ((cpp_reader *, const char *));
|
||||
extern void cpp_notice_from_errno PARAMS ((cpp_reader *, const char *));
|
||||
|
||||
/* In cpplex.c */
|
||||
extern cpp_buffer *cpp_push_buffer PARAMS ((cpp_reader *,
|
||||
|
@ -694,16 +698,16 @@ extern int cpp_ideq PARAMS ((const cpp_token *,
|
|||
const char *));
|
||||
|
||||
/* In cpphash.c */
|
||||
extern int cpp_defined PARAMS ((cpp_reader *,
|
||||
const unsigned char *, int));
|
||||
extern cpp_hashnode *cpp_lookup PARAMS ((cpp_reader *,
|
||||
const unsigned char *, int));
|
||||
extern cpp_hashnode *cpp_lookup PARAMS ((cpp_reader *,
|
||||
const unsigned char *, size_t));
|
||||
extern void cpp_forall_identifiers PARAMS ((cpp_reader *,
|
||||
int (*) PARAMS ((cpp_reader *,
|
||||
cpp_hashnode *))));
|
||||
|
||||
/* In cppfiles.c */
|
||||
extern int cpp_included PARAMS ((cpp_reader *, const char *));
|
||||
extern int cpp_read_file PARAMS ((cpp_reader *, const char *));
|
||||
extern void cpp_make_system_header PARAMS ((cpp_reader *,
|
||||
cpp_buffer *, int));
|
||||
extern int cpp_included PARAMS ((cpp_reader *, const char *));
|
||||
extern int cpp_read_file PARAMS ((cpp_reader *, const char *));
|
||||
extern void cpp_make_system_header PARAMS ((cpp_reader *, cpp_buffer *, int));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
603
gcc/cppmacro.c
Normal file
603
gcc/cppmacro.c
Normal file
|
@ -0,0 +1,603 @@
|
|||
/* Part of CPP library. (Macro handling.)
|
||||
Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998,
|
||||
1999, 2000 Free Software Foundation, Inc.
|
||||
Written by Per Bothner, 1994.
|
||||
Based on CCCP program by Paul Rubin, June 1986
|
||||
Adapted to ANSI C, Richard Stallman, Jan 1987
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
In other words, you are welcome to use, share and improve this program.
|
||||
You are forbidden to forbid anyone else to use, share and improve
|
||||
what you give them. Help stamp out software-hoarding! */
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "cpplib.h"
|
||||
#include "cpphash.h"
|
||||
|
||||
/* Stores basic information about a macro, before it is allocated. */
|
||||
struct macro_info
|
||||
{
|
||||
const cpp_token *first_param; /* First parameter token. */
|
||||
const cpp_token *first; /* First expansion token. */
|
||||
unsigned int paramlen; /* Length of parameter names. */
|
||||
unsigned int len; /* Length of token strings. */
|
||||
unsigned int ntokens; /* Number of tokens in expansion. */
|
||||
short paramc; /* Number of parameters. */
|
||||
unsigned char flags;
|
||||
};
|
||||
|
||||
static void dump_funlike_macro PARAMS ((cpp_reader *, cpp_hashnode *));
|
||||
static void count_params PARAMS ((cpp_reader *, struct macro_info *));
|
||||
static int is__va_args__ PARAMS ((cpp_reader *, const cpp_token *));
|
||||
|
||||
static int parse_define PARAMS((cpp_reader *, struct macro_info *));
|
||||
static int check_macro_redefinition PARAMS((cpp_reader *, cpp_hashnode *hp,
|
||||
const cpp_toklist *));
|
||||
static const cpp_toklist * save_expansion PARAMS((cpp_reader *,
|
||||
struct macro_info *));
|
||||
static unsigned int find_param PARAMS ((const cpp_token *,
|
||||
const cpp_token *));
|
||||
static cpp_toklist * alloc_macro PARAMS ((cpp_reader *, struct macro_info *));
|
||||
|
||||
|
||||
/* Scans for a given token, returning the parameter number if found,
|
||||
or 0 if not found. Scans from FIRST to TOKEN - 1 or the first
|
||||
CPP_CLOSE_PAREN for TOKEN. */
|
||||
static unsigned int
|
||||
find_param (first, token)
|
||||
const cpp_token *first, *token;
|
||||
{
|
||||
unsigned int param = 0;
|
||||
|
||||
for (; first < token && first->type != CPP_CLOSE_PAREN; first++)
|
||||
if (first->type == CPP_NAME)
|
||||
{
|
||||
param++;
|
||||
if (first->val.node == token->val.node)
|
||||
return param;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the
|
||||
replacement list of a variable-arguments macro. TOKEN is assumed
|
||||
to be of type CPP_NAME. */
|
||||
static int
|
||||
is__va_args__ (pfile, token)
|
||||
cpp_reader *pfile;
|
||||
const cpp_token *token;
|
||||
{
|
||||
if (!CPP_PEDANTIC (pfile)
|
||||
|| token->val.node != pfile->spec_nodes->n__VA_ARGS__)
|
||||
return 0;
|
||||
|
||||
cpp_pedwarn_with_line (pfile, token->line, token->col,
|
||||
"\"%s\" is only valid in the replacement list of a function-like macro",
|
||||
token->val.node->name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Counts the parameters to a function-like macro, the length of their
|
||||
null-terminated names, and whether the macro is a variable-argument
|
||||
one. FIRST is the token immediately after the open parenthesis,
|
||||
INFO stores the data.
|
||||
|
||||
On success, info->first is updated to the token after the closing
|
||||
parenthesis, i.e. the first token of the expansion. Otherwise
|
||||
there was an error, which has been reported. */
|
||||
static void
|
||||
count_params (pfile, info)
|
||||
cpp_reader *pfile;
|
||||
struct macro_info *info;
|
||||
{
|
||||
unsigned int prev_ident = 0;
|
||||
const cpp_token *token;
|
||||
|
||||
info->paramc = 0;
|
||||
info->paramlen = 0;
|
||||
info->flags = 0;
|
||||
info->first = info->first_param; /* Not a ')' indicating success. */
|
||||
|
||||
for (token = info->first_param;; token++)
|
||||
{
|
||||
switch (token->type)
|
||||
{
|
||||
default:
|
||||
cpp_error_with_line (pfile, token->line, token->col,
|
||||
"illegal token in macro parameter list");
|
||||
return;
|
||||
|
||||
case CPP_EOF:
|
||||
missing_paren:
|
||||
cpp_error_with_line (pfile, token->line, token->col,
|
||||
"missing ')' in macro parameter list");
|
||||
return;
|
||||
|
||||
case CPP_COMMENT:
|
||||
continue; /* Ignore -C comments. */
|
||||
|
||||
case CPP_NAME:
|
||||
if (prev_ident)
|
||||
{
|
||||
cpp_error_with_line (pfile, token->line, token->col,
|
||||
"macro parameters must be comma-separated");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Constraint 6.10.3.5 */
|
||||
if (is__va_args__ (pfile, token))
|
||||
return;
|
||||
|
||||
/* Constraint 6.10.3.6 - duplicate parameter names. */
|
||||
if (find_param (info->first, token))
|
||||
{
|
||||
cpp_error_with_line (pfile, token->line, token->col,
|
||||
"duplicate macro parameter \"%s\"",
|
||||
token->val.node->name);
|
||||
return;
|
||||
}
|
||||
|
||||
prev_ident = 1;
|
||||
info->paramc++;
|
||||
info->paramlen += token->val.node->length + 1;
|
||||
continue;
|
||||
|
||||
case CPP_CLOSE_PAREN:
|
||||
if (prev_ident || info->paramc == 0)
|
||||
break;
|
||||
|
||||
/* Fall through to pick up the error. */
|
||||
case CPP_COMMA:
|
||||
if (!prev_ident)
|
||||
{
|
||||
cpp_error_with_line (pfile, token->line, token->col,
|
||||
"parameter name expected");
|
||||
return;
|
||||
}
|
||||
prev_ident = 0;
|
||||
continue;
|
||||
|
||||
case CPP_ELLIPSIS:
|
||||
/* Convert ISO-style var_args to named varargs by changing
|
||||
the ellipsis into an identifier with name __VA_ARGS__.
|
||||
This simplifies other handling. */
|
||||
if (!prev_ident)
|
||||
{
|
||||
cpp_token *tok = (cpp_token *) token;
|
||||
|
||||
tok->type = CPP_NAME;
|
||||
tok->val.node = pfile->spec_nodes->n__VA_ARGS__;
|
||||
|
||||
info->paramc++;
|
||||
info->paramlen += tok->val.node->length + 1;
|
||||
|
||||
if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, c99))
|
||||
cpp_pedwarn (pfile,
|
||||
"C89 does not permit anon varargs macros");
|
||||
}
|
||||
else
|
||||
{
|
||||
info->flags |= GNU_REST_ARGS;
|
||||
if (CPP_PEDANTIC (pfile))
|
||||
cpp_pedwarn (pfile,
|
||||
"ISO C does not permit named varargs parameters");
|
||||
}
|
||||
|
||||
info->flags |= VAR_ARGS;
|
||||
token++;
|
||||
if (token->type == CPP_CLOSE_PAREN)
|
||||
break;
|
||||
goto missing_paren;
|
||||
}
|
||||
|
||||
/* Success. */
|
||||
info->first = token + 1;
|
||||
if (!pfile->save_parameter_spellings)
|
||||
info->paramlen = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parses a #define directive. On success, returns zero, and INFO is
|
||||
filled in appropriately. */
|
||||
static int
|
||||
parse_define (pfile, info)
|
||||
cpp_reader *pfile;
|
||||
struct macro_info *info;
|
||||
{
|
||||
const cpp_token *token;
|
||||
int prev_white = 0;
|
||||
|
||||
/* The first token after the macro's name. */
|
||||
token = _cpp_get_token (pfile);
|
||||
|
||||
/* Constraint 6.10.3.5 */
|
||||
if (is__va_args__ (pfile, token - 1))
|
||||
return 1;
|
||||
|
||||
while (token->type == CPP_COMMENT)
|
||||
token++, prev_white = 1;
|
||||
prev_white |= token->flags & PREV_WHITE;
|
||||
|
||||
if (token->type == CPP_OPEN_PAREN && !prev_white)
|
||||
{
|
||||
/* A function-like macro. */
|
||||
info->first_param = token + 1;
|
||||
count_params (pfile, info);
|
||||
if (info->first[-1].type != CPP_CLOSE_PAREN)
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* An object-like macro. */
|
||||
info->paramc = -1;
|
||||
info->paramlen = 0;
|
||||
info->flags = 0;
|
||||
info->first = token;
|
||||
if (!prev_white && token->type != CPP_EOF)
|
||||
cpp_pedwarn (pfile, "ISO C requires whitespace after the macro name");
|
||||
}
|
||||
|
||||
/* Count tokens in expansion. We drop paste tokens, and stringize
|
||||
tokens, so don't count them. */
|
||||
info->ntokens = info->len = 0;
|
||||
for (token = info->first; token->type != CPP_EOF; token++)
|
||||
{
|
||||
if (token->type == CPP_PASTE)
|
||||
{
|
||||
/* Token-paste ##, can appear in both object-like and
|
||||
function-like macros, but not at the ends. Constraint
|
||||
6.10.3.3.1 */
|
||||
if (token == info->first || token[1].type == CPP_EOF)
|
||||
{
|
||||
cpp_error_with_line (pfile, token->line, token->col,
|
||||
"'##' cannot appear at either end of a macro expansion");
|
||||
return 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (token->type == CPP_HASH)
|
||||
{
|
||||
/* Stringifying #, but a normal character in object-like
|
||||
macros. Must come before a parameter name. Constraint
|
||||
6.10.3.2.1. */
|
||||
if (info->paramc >= 0)
|
||||
{
|
||||
if (token[1].type == CPP_NAME
|
||||
&& find_param (info->first_param, token + 1))
|
||||
continue;
|
||||
if (! CPP_OPTION (pfile, lang_asm))
|
||||
{
|
||||
cpp_error_with_line (pfile, token->line, token->col,
|
||||
"'#' is not followed by a macro parameter");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (token->type == CPP_NAME)
|
||||
{
|
||||
/* Constraint 6.10.3.5 */
|
||||
if (!(info->flags & VAR_ARGS) && is__va_args__ (pfile, token))
|
||||
return 1;
|
||||
/* It might be worth doing a check here that we aren't a
|
||||
macro argument, since we don't store the text of macro
|
||||
arguments. This would reduce "len" and save space. */
|
||||
}
|
||||
info->ntokens++;
|
||||
if (TOKEN_SPELL (token) == SPELL_STRING)
|
||||
info->len += token->val.str.len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns non-zero if a macro redefinition is trivial. */
|
||||
static int
|
||||
check_macro_redefinition (pfile, hp, list2)
|
||||
cpp_reader *pfile;
|
||||
cpp_hashnode *hp;
|
||||
const cpp_toklist *list2;
|
||||
{
|
||||
const cpp_toklist *list1;
|
||||
|
||||
if (hp->type != T_MACRO)
|
||||
return ! pfile->done_initializing;
|
||||
|
||||
/* Clear the whitespace and BOL flags of the first tokens. They get
|
||||
altered during macro expansion, but is not significant here. */
|
||||
list1 = hp->value.expansion;
|
||||
list1->tokens[0].flags &= ~(PREV_WHITE|BOL);
|
||||
list2->tokens[0].flags &= ~(PREV_WHITE|BOL);
|
||||
|
||||
if (!_cpp_equiv_toklists (list1, list2))
|
||||
return 0;
|
||||
|
||||
if (CPP_OPTION (pfile, pedantic)
|
||||
&& list1->paramc > 0
|
||||
&& (list1->params_len != list2->params_len
|
||||
|| memcmp (list1->namebuf, list2->namebuf, list1->params_len)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* This is a dummy structure whose only purpose is getting alignment
|
||||
correct. */
|
||||
struct toklist_dummy
|
||||
{
|
||||
cpp_toklist list;
|
||||
cpp_token first_token;
|
||||
};
|
||||
|
||||
/* Allocate space to hold the token list, its tokens, their text, and
|
||||
the parameter names if needed. Empty expansions are stored as a
|
||||
single placemarker token.
|
||||
|
||||
These are all allocated in a block together for performance
|
||||
reasons. Therefore, this token list cannot be expanded like a
|
||||
normal token list. Try to do so, and you lose. */
|
||||
static cpp_toklist *
|
||||
alloc_macro (pfile, info)
|
||||
cpp_reader *pfile;
|
||||
struct macro_info *info;
|
||||
{
|
||||
unsigned int size;
|
||||
struct toklist_dummy *dummy;
|
||||
cpp_toklist *list;
|
||||
|
||||
/* Empty macros become a single placemarker token. */
|
||||
if (info->ntokens == 0)
|
||||
info->ntokens = 1;
|
||||
|
||||
size = sizeof (struct toklist_dummy);
|
||||
size += (info->ntokens - 1) * sizeof(cpp_token);
|
||||
size += info->len + info->paramlen;
|
||||
|
||||
dummy = (struct toklist_dummy *) xmalloc (size);
|
||||
list = (cpp_toklist *) dummy;
|
||||
|
||||
/* Initialize the monster. */
|
||||
list->tokens = &dummy->first_token;
|
||||
list->tokens_used = list->tokens_cap = info->ntokens;
|
||||
|
||||
list->namebuf = (unsigned char *) &list->tokens[info->ntokens];
|
||||
list->name_used = list->name_cap = info->len + info->paramlen;
|
||||
|
||||
list->directive = 0;
|
||||
list->line = pfile->token_list.line;
|
||||
list->file = pfile->token_list.file;
|
||||
list->params_len = info->paramlen;
|
||||
list->paramc = info->paramc;
|
||||
list->flags = info->flags;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/* Free the definition of macro H. */
|
||||
|
||||
void
|
||||
_cpp_free_definition (h)
|
||||
cpp_hashnode *h;
|
||||
{
|
||||
if (h->type == T_MACRO)
|
||||
free ((PTR) h->value.expansion);
|
||||
h->value.expansion = NULL;
|
||||
}
|
||||
|
||||
/* Copy the tokens of the expansion, beginning with info->first until
|
||||
CPP_EOF. INFO contains information about the macro.
|
||||
|
||||
Change the type of macro arguments in the expansion from CPP_NAME
|
||||
to CPP_MACRO_ARG. Remove #'s that represent stringification,
|
||||
flagging the CPP_MACRO_ARG it operates on STRINGIFY. Remove ##'s,
|
||||
flagging the token on its immediate left PASTE_LEFT. Returns the
|
||||
token list for the macro expansion. */
|
||||
static const cpp_toklist *
|
||||
save_expansion (pfile, info)
|
||||
cpp_reader *pfile;
|
||||
struct macro_info *info;
|
||||
{
|
||||
const cpp_token *token;
|
||||
cpp_toklist *list;
|
||||
cpp_token *dest;
|
||||
unsigned char *buf;
|
||||
|
||||
list = alloc_macro (pfile, info);
|
||||
buf = list->namebuf;
|
||||
|
||||
/* Store the null-terminated parameter spellings of a macro, to
|
||||
provide pedantic warnings to satisfy 6.10.3.2, or for use when
|
||||
dumping macro definitions. They must go first. */
|
||||
if (list->params_len)
|
||||
for (token = info->first_param; token < info->first; token++)
|
||||
if (token->type == CPP_NAME)
|
||||
{
|
||||
/* Copy null too. */
|
||||
memcpy (buf, token->val.node->name, token->val.node->length + 1);
|
||||
buf += token->val.node->length + 1;
|
||||
}
|
||||
|
||||
dest = list->tokens;
|
||||
for (token = info->first; token->type != CPP_EOF; token++)
|
||||
{
|
||||
unsigned int param_no;
|
||||
|
||||
switch (token->type)
|
||||
{
|
||||
case CPP_NAME:
|
||||
if (list->paramc == -1)
|
||||
break;
|
||||
|
||||
/* Check if the name is a macro parameter. */
|
||||
param_no = find_param (info->first_param, token);
|
||||
if (param_no == 0)
|
||||
break;
|
||||
dest->val.aux = param_no - 1;
|
||||
|
||||
dest->type = CPP_MACRO_ARG;
|
||||
if (token[-1].type == CPP_HASH)
|
||||
dest->flags = token[-1].flags | STRINGIFY_ARG;
|
||||
else
|
||||
dest->flags = token->flags; /* Particularly PREV_WHITE. */
|
||||
/* Turn off PREV_WHITE if we immediately follow a paste.
|
||||
That way, even if the paste turns out to be illegal, there
|
||||
will be no space between the two tokens in the output. */
|
||||
if (token[-1].type == CPP_PASTE)
|
||||
dest->flags &= ~PREV_WHITE;
|
||||
dest++;
|
||||
continue;
|
||||
|
||||
case CPP_PASTE:
|
||||
dest[-1].flags |= PASTE_LEFT;
|
||||
continue;
|
||||
|
||||
case CPP_HASH:
|
||||
/* Stringifying #. Constraint 6.10.3.2.1 */
|
||||
if (list->paramc >= 0 && token[1].type == CPP_NAME
|
||||
&& find_param (info->first_param, token + 1))
|
||||
continue;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Copy the token. */
|
||||
*dest = *token;
|
||||
if (TOKEN_SPELL (token) == SPELL_STRING)
|
||||
{
|
||||
memcpy (buf, token->val.str.text, token->val.str.len);
|
||||
dest->val.str.text = buf;
|
||||
buf += dest->val.str.len;
|
||||
}
|
||||
if (token[-1].type == CPP_PASTE)
|
||||
dest->flags &= ~PREV_WHITE;
|
||||
dest++;
|
||||
}
|
||||
|
||||
/* Empty macros become a single placemarker token. */
|
||||
if (dest == list->tokens)
|
||||
{
|
||||
dest->type = CPP_PLACEMARKER;
|
||||
dest->flags = 0;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/* Parse a macro and save its expansion. Returns non-zero on success. */
|
||||
int
|
||||
_cpp_create_definition (pfile, hp)
|
||||
cpp_reader *pfile;
|
||||
cpp_hashnode *hp;
|
||||
{
|
||||
struct macro_info info;
|
||||
const cpp_toklist *list;
|
||||
|
||||
if (parse_define (pfile, &info))
|
||||
return 0;
|
||||
list = save_expansion (pfile, &info);
|
||||
|
||||
/* Check for a redefinition. Redefinition of a macro is allowed if
|
||||
and only if the old and new definitions are the same.
|
||||
(6.10.3 paragraph 2). */
|
||||
|
||||
if (hp->type != T_VOID)
|
||||
{
|
||||
if (!check_macro_redefinition (pfile, hp, list))
|
||||
{
|
||||
cpp_pedwarn (pfile, "\"%s\" redefined", hp->name);
|
||||
if (pfile->done_initializing && hp->type == T_MACRO)
|
||||
cpp_pedwarn_with_file_and_line (pfile,
|
||||
hp->value.expansion->file,
|
||||
hp->value.expansion->line, 1,
|
||||
"this is the location of the previous definition");
|
||||
}
|
||||
_cpp_free_definition (hp);
|
||||
}
|
||||
|
||||
/* Enter definition in hash table. */
|
||||
hp->type = T_MACRO;
|
||||
hp->value.expansion = list;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Dump the definition of macro MACRO on stdout. The format is suitable
|
||||
to be read back in again. */
|
||||
|
||||
void
|
||||
_cpp_dump_definition (pfile, hp)
|
||||
cpp_reader *pfile;
|
||||
cpp_hashnode *hp;
|
||||
{
|
||||
CPP_RESERVE (pfile, hp->length + sizeof "#define ");
|
||||
CPP_PUTS_Q (pfile, "#define ", sizeof "#define " - 1);
|
||||
CPP_PUTS_Q (pfile, hp->name, hp->length);
|
||||
|
||||
if (hp->type == T_MACRO)
|
||||
{
|
||||
if (hp->value.expansion->paramc >= 0)
|
||||
dump_funlike_macro (pfile, hp);
|
||||
else
|
||||
{
|
||||
const cpp_toklist *list = hp->value.expansion;
|
||||
list->tokens[0].flags &= ~BOL;
|
||||
list->tokens[0].flags |= PREV_WHITE;
|
||||
_cpp_dump_list (pfile, list, list->tokens, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
cpp_ice (pfile, "invalid hash type %d in dump_definition", hp->type);
|
||||
|
||||
if (CPP_BUFFER (pfile) == 0 || ! pfile->done_initializing)
|
||||
CPP_PUTC (pfile, '\n');
|
||||
}
|
||||
|
||||
static void
|
||||
dump_funlike_macro (pfile, node)
|
||||
cpp_reader *pfile;
|
||||
cpp_hashnode *node;
|
||||
{
|
||||
int i = 0;
|
||||
const cpp_toklist * list = node->value.expansion;
|
||||
const U_CHAR *param;
|
||||
|
||||
param = list->namebuf;
|
||||
CPP_PUTC_Q (pfile, '(');
|
||||
for (i = 0; i++ < list->paramc;)
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
len = ustrlen (param);
|
||||
CPP_PUTS (pfile, param, len);
|
||||
if (i < list->paramc)
|
||||
CPP_PUTS(pfile, ", ", 2);
|
||||
else if (list->flags & VAR_ARGS)
|
||||
{
|
||||
if (!ustrcmp (param, U"__VA_ARGS__"))
|
||||
pfile->limit -= sizeof (U"__VA_ARGS__") - 1;
|
||||
CPP_PUTS_Q (pfile, "...", 3);
|
||||
}
|
||||
param += len + 1;
|
||||
}
|
||||
CPP_PUTC (pfile, ')');
|
||||
list->tokens[0].flags &= ~BOL;
|
||||
list->tokens[0].flags |= PREV_WHITE;
|
||||
_cpp_dump_list (pfile, list, list->tokens, 1);
|
||||
}
|
|
@ -68,7 +68,8 @@ main (argc, argv)
|
|||
print = cpp_printer_init (pfile, &parse_out);
|
||||
if (! print)
|
||||
return (FATAL_EXIT_CODE);
|
||||
pfile->printer = print;
|
||||
if (! CPP_OPTION (pfile, no_output))
|
||||
pfile->printer = print;
|
||||
|
||||
if (! cpp_start_read (pfile, print, CPP_OPTION (pfile, in_fname)))
|
||||
return (FATAL_EXIT_CODE);
|
||||
|
|
Loading…
Add table
Reference in a new issue