-/* 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.
#include "system.h"
#include "cpplib.h"
#include "cpphash.h"
-#include "version.h"
-#undef abort
+#include "obstack.h"
-static unsigned int hashf PARAMS ((const U_CHAR *, int));
-static int comp_def_part PARAMS ((int, U_CHAR *, int, U_CHAR *,
- int, int));
-static void push_macro_expansion PARAMS ((cpp_reader *,
- U_CHAR *, int, HASHNODE *));
-static int unsafe_chars PARAMS ((cpp_reader *, int, int));
-static int macro_cleanup PARAMS ((cpp_buffer *, cpp_reader *));
-static enum cpp_token macarg PARAMS ((cpp_reader *, int));
-static struct tm *timestamp PARAMS ((cpp_reader *));
-static void special_symbol PARAMS ((HASHNODE *, cpp_reader *));
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
-#define CPP_IS_MACRO_BUFFER(PBUF) ((PBUF)->data != NULL)
-#define FORWARD(N) CPP_FORWARD (CPP_BUFFER (pfile), (N))
-#define PEEKC() CPP_BUF_PEEK (CPP_BUFFER (pfile))
+/* Initial hash table size. (It can grow if necessary.) This is the
+ largest prime number smaller than 2**12. */
+#define HASHSIZE 4093
-/* The arglist structure is built by create_definition to tell
- collect_expansion where the argument names begin. That
- is, for a define like "#define f(x,y,z) foo+x-bar*y", the arglist
- would contain pointers to the strings x, y, and z.
- collect_expansion would then build a DEFINITION node,
- with reflist nodes pointing to the places x, y, and z had
- appeared. So the arglist is just convenience data passed
- between these two routines. It is not kept around after
- the current #define has been processed and entered into the
- hash table. */
-
-struct arg
-{
- U_CHAR *name;
- int len;
- char rest_arg;
-};
-
-struct arglist
-{
- U_CHAR *namebuf;
- struct arg *argv;
- int argc;
-};
-
-
-static DEFINITION *collect_expansion PARAMS ((cpp_reader *, struct arglist *));
-static struct arglist *collect_formal_parameters PARAMS ((cpp_reader *));
-
-/* This structure represents one parsed argument in a macro call.
- `raw' points to the argument text as written (`raw_length' is its length).
- `expanded' points to the argument's macro-expansion
- (its length is `expand_length').
- `stringified_length' is the length the argument would have
- if stringified. */
-
-/* raw and expanded are relative to ARG_BASE */
-#define ARG_BASE ((pfile)->token_buffer)
-
-struct argdata
+/* This is the structure used for the hash table. */
+struct htab
{
- /* Strings relative to pfile->token_buffer */
- long raw, expanded, stringified;
- int raw_length, expand_length;
- int stringified_length;
+ struct cpp_hashnode **entries;
+ size_t size;
+ size_t nelts;
};
+static void expand_hash PARAMS ((struct htab *));
+static unsigned long higher_prime_number PARAMS ((unsigned long));
-/* Calculate hash function on a string. */
-
-static unsigned int
-hashf (s, len)
- register const U_CHAR *s;
- register int len;
-{
- unsigned int n = len;
- unsigned int r = 0;
-
- do
- r = r * 67 + (*s++ - 113);
- while (--n);
- return r + len;
-}
-
-/* Find the most recent hash node for name "name" (ending with first
- non-identifier char) installed by cpp_install
-
- If LEN is >= 0, it is the length of the name.
- Otherwise, compute the length by scanning the entire name. */
-
-HASHNODE *
-_cpp_lookup (pfile, name, len)
+/* Set up and tear down internal structures for macro expansion. */
+void
+_cpp_init_hashtable (pfile)
cpp_reader *pfile;
- const U_CHAR *name;
- int len;
{
- register const U_CHAR *bp;
- register HASHNODE *bucket;
- register unsigned int hash;
-
- if (len < 0)
- {
- for (bp = name; is_idchar (*bp); bp++);
- len = bp - name;
- }
+ pfile->hash_ob = xnew (struct obstack);
+ obstack_init (pfile->hash_ob);
- hash = hashf (name, len) % HASHSIZE;
+ pfile->hashtab = xobnew (pfile->hash_ob, struct htab);
- bucket = pfile->hashtab[hash];
- while (bucket)
- {
- if (bucket->length == len && strncmp (bucket->name, name, len) == 0)
- return bucket;
- bucket = bucket->next;
- }
- return (HASHNODE *) 0;
+ pfile->hashtab->nelts = 0;
+ pfile->hashtab->size = HASHSIZE;
+ pfile->hashtab->entries = xcnewvec (cpp_hashnode *, HASHSIZE);
}
-/* Free a DEFINITION structure. Used by delete_macro, and by
- do_define when redefining macros. */
-
void
-_cpp_free_definition (d)
- DEFINITION *d;
+_cpp_cleanup_hashtable (pfile)
+ cpp_reader *pfile;
{
- struct reflist *ap, *nextap;
+ cpp_hashnode **p, **limit;
- for (ap = d->pattern; ap != NULL; ap = nextap)
+ p = pfile->hashtab->entries;
+ limit = p + pfile->hashtab->size;
+ do
{
- nextap = ap->next;
- free (ap);
+ if (*p)
+ {
+ _cpp_free_definition (*p);
+ (*p)->fe_value = 0; /* expose the node to GC */
+ }
}
- if (d->nargs >= 0)
- free (d->argnames);
- free (d);
-}
-
-/*
- * Delete a hash node. Some weirdness to free junk from macros.
- * More such weirdness will have to be added if you define more hash
- * types that need it.
- */
-
-void
-_cpp_delete_macro (hp)
- HASHNODE *hp;
-{
- if (hp->prev != NULL)
- hp->prev->next = hp->next;
- if (hp->next != NULL)
- hp->next->prev = hp->prev;
-
- /* make sure that the bucket chain header that
- the deleted guy was on points to the right thing afterwards. */
- if (hp == *hp->bucket_hdr)
- *hp->bucket_hdr = hp->next;
+ while (++p < limit);
- if (hp->type == T_MACRO)
- _cpp_free_definition (hp->value.defn);
-
- free (hp);
+ free (pfile->hashtab->entries);
+ obstack_free (pfile->hash_ob, 0);
+ free (pfile->hash_ob);
}
-/* Install a name in the main hash table, even if it is already there.
- Name stops with first non alphanumeric, except leading '#'.
- Caller must check against redefinition if that is desired.
- delete_macro () removes things installed by cpp_install () in fifo order.
- this is important because of the `defined' special symbol used
- in #if, and also if pushdef/popdef directives are ever implemented.
-
- If LEN is >= 0, it is the length of the name.
- Otherwise, compute the length by scanning the entire name.
+/* 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. */
- If HASH is >= 0, it is the precomputed hash code.
- Otherwise, compute the hash code. */
-
-HASHNODE *
-_cpp_install (pfile, name, len, type, value)
+cpp_hashnode *
+cpp_lookup (pfile, name, len)
cpp_reader *pfile;
const U_CHAR *name;
- int len;
- enum node_type type;
- const char *value;
+ size_t len;
{
- register HASHNODE *hp;
- register int i, bucket;
- register const U_CHAR *p;
- unsigned int hash;
+ size_t n = len;
+ unsigned int r = 0;
+ const U_CHAR *str = name;
+ U_CHAR *dest = _cpp_pool_reserve (&pfile->ident_pool, len + 1);
- if (len < 0)
+ do
{
- p = name;
- while (is_idchar(*p))
- p++;
- len = p - name;
+ r = HASHSTEP (r, *str);
+ *dest++ = *str++;
}
+ while (--n);
+ *dest = '\0';
- hash = hashf (name, len) % HASHSIZE;
-
- i = sizeof (HASHNODE) + len + 1;
- hp = (HASHNODE *) xmalloc (i);
- bucket = hash;
- hp->bucket_hdr = &pfile->hashtab[bucket];
- hp->next = pfile->hashtab[bucket];
- pfile->hashtab[bucket] = hp;
- hp->prev = NULL;
- if (hp->next != NULL)
- hp->next->prev = hp;
- hp->type = type;
- hp->length = len;
- hp->value.cpval = value;
- hp->name = ((U_CHAR *) hp) + sizeof (HASHNODE);
- bcopy (name, hp->name, len);
- hp->name[len] = 0;
- return hp;
-}
-
-static int
-macro_cleanup (pbuf, pfile)
- cpp_buffer *pbuf;
- cpp_reader *pfile ATTRIBUTE_UNUSED;
-{
- HASHNODE *macro = (HASHNODE *) pbuf->data;
- if (macro->type == T_DISABLED)
- macro->type = T_MACRO;
- if (macro->type != T_MACRO || pbuf->buf != macro->value.defn->expansion)
- free (pbuf->buf);
- return 0;
+ return _cpp_lookup_with_hash (pfile, len, r);
}
-
-/* Read a replacement list for a macro, and build the DEFINITION
- structure. ARGLIST specifies the formal parameters to look for in
- the text of the definition. If ARGLIST is null, this is an
- object-like macro; if it points to an empty arglist, this is a
- function-like macro with no arguments.
-
- A good half of this is devoted to supporting -traditional.
- Kill me now. */
-
-static DEFINITION *
-collect_expansion (pfile, arglist)
+/* NAME is a null-terminated identifier of length len. It is assumed
+ to have been placed at the front of the identifier pool. */
+cpp_hashnode *
+_cpp_lookup_with_hash (pfile, len, hash)
cpp_reader *pfile;
- struct arglist *arglist;
+ size_t len;
+ unsigned int hash;
{
- DEFINITION *defn;
- struct reflist *pat = 0, *endpat = 0;
- enum cpp_token token;
- long start, here, last;
- int i;
- int argc;
- size_t len;
- struct arg *argv;
- U_CHAR *tok, *exp;
- enum { START = 0, NORM, ARG, STRIZE, PASTE } last_token = START;
-
- if (arglist)
- {
- argv = arglist->argv;
- argc = arglist->argc;
- }
- else
- {
- argv = 0;
- argc = 0;
- }
-
- last = start = CPP_WRITTEN (pfile);
- last -= 2; /* two extra chars for the leading escape */
- for (;;)
- {
- /* We use cpp_get_token because get_directive_token would
- discard whitespace and we can't cope with that yet. Macro
- expansion is off, so we are guaranteed not to see POP or EOF. */
-
- while (PEEKC () == '\r')
- {
- FORWARD (1);
- CPP_BUMP_LINE (pfile);
- }
- if (PEEKC () == '\n')
- goto done;
- here = CPP_WRITTEN (pfile);
- token = cpp_get_token (pfile);
- tok = pfile->token_buffer + here;
- switch (token)
- {
- case CPP_POP:
- case CPP_EOF:
- case CPP_VSPACE:
- cpp_ice (pfile, "EOF or VSPACE in collect_expansion");
- goto done;
-
- case CPP_HSPACE:
- if (last_token == STRIZE || last_token == PASTE
- || last_token == START)
- CPP_SET_WRITTEN (pfile, here);
- break;
-
- case CPP_STRINGIZE:
- if (last_token == PASTE)
- /* Not really a stringifier. */
- goto norm;
- last_token = STRIZE;
- CPP_SET_WRITTEN (pfile, here); /* delete from replacement text */
- break;
-
- case CPP_TOKPASTE:
- /* If the last token was an argument, discard this token and
- any hspace between it and the argument's position. Then
- mark the arg raw_after. */
- if (last_token == ARG)
- {
- endpat->raw_after = 1;
- last_token = PASTE;
- CPP_SET_WRITTEN (pfile, last);
- break;
- }
- else if (last_token == PASTE)
- /* ## ## - the second ## is ordinary. */
- goto norm;
- else if (last_token == START)
- cpp_error (pfile, "`##' at start of macro definition");
-
- /* Discard the token and any hspace before it. */
- while (is_hspace (pfile->token_buffer[here-1]))
- here--;
- CPP_SET_WRITTEN (pfile, here);
-
- if (last_token == STRIZE)
- /* Oops - that wasn't a stringify operator. */
- CPP_PUTC (pfile, '#');
- last_token = PASTE;
- break;
-
- case CPP_COMMENT:
- /* We must be in -traditional mode. Pretend this was a
- token paste, but only if there was no leading or
- trailing space. */
- CPP_SET_WRITTEN (pfile, here);
- if (is_hspace (pfile->token_buffer[here-1]))
- break;
- if (is_hspace (PEEKC ()))
- break;
- if (last_token == ARG)
- endpat->raw_after = 1;
- last_token = PASTE;
- break;
-
- case CPP_STRING:
- case CPP_CHAR:
- if (last_token == STRIZE)
- cpp_error (pfile, "`#' is not followed by a macro argument name");
-
- if (CPP_TRADITIONAL (pfile) || CPP_OPTIONS (pfile)->warn_stringify)
- goto maybe_trad_stringify;
- else
- goto norm;
-
- case CPP_NAME:
- for (i = 0; i < argc; i++)
- if (!strncmp (tok, argv[i].name, argv[i].len)
- && ! is_idchar (tok[argv[i].len]))
- goto addref;
-
- /* fall through */
- default:
- norm:
- if (last_token == STRIZE)
- cpp_error (pfile, "`#' is not followed by a macro argument name");
- last_token = NORM;
- break;
- }
- continue;
+ unsigned int index;
+ size_t size;
+ cpp_hashnode *entry;
+ cpp_hashnode **entries;
+ unsigned char *name = POOL_FRONT (&pfile->ident_pool);
- addref:
- {
- struct reflist *tpat;
-
- /* Make a pat node for this arg and add it to the pat list */
- tpat = (struct reflist *) xmalloc (sizeof (struct reflist));
- tpat->next = NULL;
- tpat->raw_before = (last_token == PASTE);
- tpat->raw_after = 0;
- tpat->stringify = (last_token == STRIZE);
- tpat->rest_args = argv[i].rest_arg;
- tpat->argno = i;
- tpat->nchars = here - last;
-
- if (endpat == NULL)
- pat = tpat;
- else
- endpat->next = tpat;
- endpat = tpat;
- last = here;
- }
- CPP_SET_WRITTEN (pfile, here); /* discard arg name */
- last_token = ARG;
- continue;
-
- maybe_trad_stringify:
- last_token = NORM;
- {
- U_CHAR *base, *p, *limit;
- struct reflist *tpat;
-
- base = p = pfile->token_buffer + here;
- limit = CPP_PWRITTEN (pfile);
+ entries = pfile->hashtab->entries;
+ size = pfile->hashtab->size;
- while (++p < limit)
- {
- if (is_idstart (*p))
- continue;
- for (i = 0; i < argc; i++)
- if (!strncmp (tok, argv[i].name, argv[i].len)
- && ! is_idchar (tok[argv[i].len]))
- goto mts_addref;
- continue;
-
- mts_addref:
- if (!CPP_TRADITIONAL (pfile))
- {
- /* Must have got here because of -Wtraditional. */
- cpp_warning (pfile,
- "macro argument `%.*s' would be stringified with -traditional",
- (int) argv[i].len, argv[i].name);
- continue;
- }
- if (CPP_OPTIONS (pfile)->warn_stringify)
- cpp_warning (pfile, "macro argument `%.*s' is stringified",
- (int) argv[i].len, argv[i].name);
-
- /* Remove the argument from the string. */
- memmove (p, p + argv[i].len, limit - (p + argv[i].len));
- limit -= argv[i].len;
-
- /* Make a pat node for this arg and add it to the pat list */
- tpat = (struct reflist *) xmalloc (sizeof (struct reflist));
- tpat->next = NULL;
-
- /* Don't attempt to paste this with anything. */
- tpat->raw_before = 0;
- tpat->raw_after = 0;
- tpat->stringify = 1;
- tpat->rest_args = argv[i].rest_arg;
- tpat->argno = i;
- tpat->nchars = (p - base) + here - last;
-
- if (endpat == NULL)
- pat = tpat;
- else
- endpat->next = tpat;
- endpat = tpat;
- last = (p - base) + here;
- }
- CPP_ADJUST_WRITTEN (pfile, CPP_PWRITTEN (pfile) - limit);
- }
- }
- done:
+ hash += len;
+ index = hash % size;
- if (last_token == STRIZE)
- cpp_error (pfile, "`#' is not followed by a macro argument name");
- else if (last_token == PASTE)
- cpp_error (pfile, "`##' at end of macro definition");
-
- if (last_token == START)
- {
- /* Empty macro definition. */
- exp = xstrdup ("\r \r ");
- len = 1;
- }
- else
- {
- /* Trim trailing white space from definition. */
- here = CPP_WRITTEN (pfile);
- while (here > last && is_hspace (pfile->token_buffer [here-1]))
- here--;
- CPP_SET_WRITTEN (pfile, here);
-
- CPP_NUL_TERMINATE (pfile);
- len = CPP_WRITTEN (pfile) - start + 1;
- exp = xmalloc (len + 4); /* space for no-concat markers at either end */
- exp[0] = '\r';
- exp[1] = ' ';
- exp[len + 1] = '\r';
- exp[len + 2] = ' ';
- exp[len + 3] = '\0';
- memcpy (&exp[2], pfile->token_buffer + start, len - 1);
- }
-
- CPP_SET_WRITTEN (pfile, start);
-
- defn = (DEFINITION *) xmalloc (sizeof (DEFINITION));
- defn->length = len + 3;
- defn->expansion = exp;
- defn->pattern = pat;
- defn->rest_args = 0;
- if (arglist)
- {
- defn->nargs = argc;
- defn->argnames = arglist->namebuf;
- if (argv)
- {
- defn->rest_args = argv[argc - 1].rest_arg;
- free (argv);
- }
- free (arglist);
- }
- else
+ entry = entries[index];
+ if (entry)
{
- defn->nargs = -1;
- defn->argnames = 0;
- defn->rest_args = 0;
- }
- return defn;
-}
+ unsigned int hash2;
-static struct arglist *
-collect_formal_parameters (pfile)
- cpp_reader *pfile;
-{
- struct arglist *result = 0;
- struct arg *argv = 0;
- U_CHAR *namebuf = (U_CHAR *) xstrdup ("");
+ if (entry->hash == hash && entry->length == len
+ && !memcmp (entry->name, name, len))
+ return entry;
- U_CHAR *name, *tok;
- size_t argslen = 1;
- int len;
- int argc = 0;
- int i;
- enum cpp_token token;
- long old_written;
+ hash2 = 1 + hash % (size - 2);
- old_written = CPP_WRITTEN (pfile);
- token = get_directive_token (pfile);
- if (token != CPP_LPAREN)
- {
- cpp_ice (pfile, "first token = %d not %d in collect_formal_parameters",
- token, CPP_LPAREN);
- goto invalid;
- }
-
- argv = (struct arg *) xmalloc (sizeof (struct arg));
- argv[argc].len = 0;
- argv[argc].rest_arg = 0;
- for (;;)
- {
- CPP_SET_WRITTEN (pfile, old_written);
- token = get_directive_token (pfile);
- switch (token)
+ for (;;)
{
- case CPP_NAME:
- tok = pfile->token_buffer + old_written;
- len = CPP_PWRITTEN (pfile) - tok;
- if (namebuf
- && (name = strstr (namebuf, tok))
- && name[len] == ','
- && (name == namebuf || name[-1] == ','))
- {
- cpp_error (pfile, "duplicate macro argument name `%s'", tok);
- continue;
- }
- if (CPP_PEDANTIC (pfile) && CPP_OPTIONS (pfile)->c99
- && strncmp (tok, "__VA_ARGS__", sizeof "__VA_ARGS__" - 1))
- cpp_pedwarn (pfile,
- "C99 does not permit use of `__VA_ARGS__' as a macro argument name");
- namebuf = xrealloc (namebuf, argslen + len + 1);
- name = &namebuf[argslen - 1];
- argslen += len + 1;
-
- memcpy (name, tok, len);
- name[len] = ',';
- name[len+1] = '\0';
- argv[argc].len = len;
- argv[argc].rest_arg = 0;
- break;
-
- case CPP_COMMA:
- argc++;
- argv = xrealloc (argv, (argc + 1)*sizeof(struct arg));
- argv[argc].len = 0;
- break;
+ index += hash2;
+ if (index >= size)
+ index -= size;
+ entry = entries[index];
- case CPP_RPAREN:
- goto done;
-
- case CPP_3DOTS:
- goto rest_arg;
-
- case CPP_VSPACE:
- cpp_error (pfile, "missing right paren in macro argument list");
- goto invalid;
-
- default:
- cpp_error (pfile, "syntax error in #define");
- goto invalid;
+ if (entry == NULL)
+ break;
+ if (entry->hash == hash && entry->length == len
+ && !memcmp (entry->name, name, len))
+ return entry;
}
}
- rest_arg:
- /* There are two possible styles for a vararg macro:
- the C99 way: #define foo(a, ...) a, __VA_ARGS__
- the gnu way: #define foo(a, b...) a, b
- The C99 way can be considered a special case of the gnu way.
- There are also some constraints to worry about, but we'll handle
- those elsewhere. */
- if (argv[argc].len == 0)
- {
- if (CPP_PEDANTIC (pfile) && ! CPP_OPTIONS (pfile)->c99)
- cpp_pedwarn (pfile, "C89 does not permit varargs macros");
+ /* Commit the memory for the identifier. */
+ POOL_COMMIT (&pfile->ident_pool, len + 1);
- len = sizeof "__VA_ARGS__" - 1;
- namebuf = xrealloc (namebuf, argslen + len + 1);
- name = &namebuf[argslen - 1];
- argslen += len;
- memcpy (name, "__VA_ARGS__", len);
- argv[argc].len = len;
- }
- else
- if (CPP_PEDANTIC (pfile))
- cpp_pedwarn (pfile, "ISO C does not permit named varargs macros");
-
- argv[argc].rest_arg = 1;
-
- token = get_directive_token (pfile);
- if (token != CPP_RPAREN)
- {
- cpp_error (pfile, "another parameter follows `...'");
- goto invalid;
- }
+ /* Create a new hash node and insert it in the table. */
+ entries[index] = obstack_alloc (pfile->hash_ob, sizeof (cpp_hashnode));
- done:
- /* Go through argv and fix up the pointers. */
- len = 0;
- for (i = 0; i <= argc; i++)
- {
- argv[i].name = namebuf + len;
- len += argv[i].len + 1;
- namebuf[len - 1] = '\0';
- }
+ entry = entries[index];
+ entry->type = NT_VOID;
+ entry->flags = 0;
+ entry->fe_value = 0;
+ entry->directive_index = 0;
+ entry->arg_index = 0;
+ entry->length = len;
+ entry->hash = hash;
+ entry->name = name;
+ entry->value.macro = 0;
- CPP_SET_WRITTEN (pfile, old_written);
-
- result = (struct arglist *) xmalloc (sizeof (struct arglist));
- if (namebuf[0] != '\0')
- {
- result->namebuf = namebuf;
- result->argc = argc + 1;
- result->argv = argv;
- }
- else
- {
- free (namebuf);
- result->namebuf = 0;
- result->argc = 0;
- result->argv = 0;
- }
-
- return result;
-
- invalid:
- if (argv)
- free (argv);
- if (namebuf)
- free (namebuf);
- return 0;
-}
-
-/* Create a DEFINITION node for a macro. The reader's point is just
- after the macro name. If FUNLIKE is true, this is a function-like
- macro. */
-
-DEFINITION *
-_cpp_create_definition (pfile, funlike)
- cpp_reader *pfile;
- int funlike;
-{
- struct arglist *args = 0;
- long line, col;
- const char *file;
- DEFINITION *defn;
-
- cpp_buf_line_and_col (CPP_BUFFER (pfile), &line, &col);
- file = CPP_BUFFER (pfile)->nominal_fname;
-
- pfile->no_macro_expand++;
- pfile->parsing_define_directive++;
- CPP_OPTIONS (pfile)->discard_comments++;
- CPP_OPTIONS (pfile)->no_line_commands++;
-
- if (funlike)
- {
- args = collect_formal_parameters (pfile);
- if (args == 0)
- goto err;
- }
-
- defn = collect_expansion (pfile, args);
- if (defn == 0)
- goto err;
-
- defn->line = line;
- defn->file = file;
- defn->col = col;
-
- pfile->no_macro_expand--;
- pfile->parsing_define_directive--;
- CPP_OPTIONS (pfile)->discard_comments--;
- CPP_OPTIONS (pfile)->no_line_commands--;
- return defn;
-
- err:
- pfile->no_macro_expand--;
- pfile->parsing_define_directive--;
- CPP_OPTIONS (pfile)->discard_comments--;
- CPP_OPTIONS (pfile)->no_line_commands--;
- return 0;
-}
-
-/*
- * Parse a macro argument and append the info on PFILE's token_buffer.
- * REST_ARGS means to absorb the rest of the args.
- * Return nonzero to indicate a syntax error.
- */
-
-static enum cpp_token
-macarg (pfile, rest_args)
- cpp_reader *pfile;
- int rest_args;
-{
- int paren = 0;
- enum cpp_token token;
-
- /* Try to parse as much of the argument as exists at this
- input stack level. */
- for (;;)
- {
- token = cpp_get_token (pfile);
- switch (token)
- {
- case CPP_EOF:
- return token;
- case CPP_POP:
- /* If we've hit end of file, it's an error (reported by caller).
- Ditto if it's the end of cpp_expand_to_buffer text.
- If we've hit end of macro, just continue. */
- if (!CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
- return token;
- break;
- case CPP_LPAREN:
- paren++;
- break;
- case CPP_RPAREN:
- if (--paren < 0)
- goto found;
- break;
- case CPP_COMMA:
- /* if we've returned to lowest level and
- we aren't absorbing all args */
- if (paren == 0 && rest_args == 0)
- goto found;
- break;
- found:
- /* Remove ',' or ')' from argument buffer. */
- CPP_ADJUST_WRITTEN (pfile, -1);
- return token;
- default:;
- }
- }
-}
-\f
+ pfile->hashtab->nelts++;
+ if (size * 3 <= pfile->hashtab->nelts * 4)
+ expand_hash (pfile->hashtab);
-static struct tm *
-timestamp (pfile)
- cpp_reader *pfile;
-{
- if (!pfile->timebuf)
- {
- time_t t = time ((time_t *) 0);
- pfile->timebuf = localtime (&t);
- }
- return pfile->timebuf;
+ return entry;
}
-static const char * const monthnames[] =
-{
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
-};
-
-/*
- * expand things like __FILE__. Place the expansion into the output
- * buffer *without* rescanning.
- */
-
static void
-special_symbol (hp, pfile)
- HASHNODE *hp;
- cpp_reader *pfile;
-{
- const char *buf;
- int len;
- cpp_buffer *ip;
-
- switch (hp->type)
- {
- case T_FILE:
- case T_BASE_FILE:
- {
- ip = cpp_file_buffer (pfile);
- if (hp->type == T_BASE_FILE)
- {
- while (CPP_PREV_BUFFER (ip) != NULL)
- ip = CPP_PREV_BUFFER (ip);
- }
-
- buf = ip->nominal_fname;
-
- if (!buf)
- buf = "";
- CPP_RESERVE (pfile, 3 + 4 * strlen (buf));
- quote_string (pfile, buf);
- return;
- }
-
- case T_INCLUDE_LEVEL:
- {
- int true_indepth = 1;
- ip = cpp_file_buffer (pfile);
- while ((ip = CPP_PREV_BUFFER (ip)) != NULL)
- true_indepth++;
-
- CPP_RESERVE (pfile, 10);
- sprintf (CPP_PWRITTEN (pfile), "%d", true_indepth);
- CPP_ADJUST_WRITTEN (pfile, strlen (CPP_PWRITTEN (pfile)));
- return;
- }
-
- case T_VERSION:
- len = strlen (version_string);
- CPP_RESERVE (pfile, 3 + len);
- CPP_PUTC_Q (pfile, '"');
- CPP_PUTS_Q (pfile, version_string, len);
- CPP_PUTC_Q (pfile, '"');
- CPP_NUL_TERMINATE_Q (pfile);
- return;
-
- case T_CONST:
- buf = hp->value.cpval;
- if (!buf)
- return;
- if (*buf == '\0')
- buf = "\r ";
-
- len = strlen (buf);
- CPP_RESERVE (pfile, len + 1);
- CPP_PUTS_Q (pfile, buf, len);
- CPP_NUL_TERMINATE_Q (pfile);
- return;
-
- case T_STDC:
- CPP_RESERVE (pfile, 2);
-#ifdef STDC_0_IN_SYSTEM_HEADERS
- ip = cpp_file_buffer (pfile);
- if (ip->system_header_p
- && !cpp_defined (pfile, (const U_CHAR *) "__STRICT_ANSI__", 15))
- CPP_PUTC_Q (pfile, '0');
- else
-#endif
- CPP_PUTC_Q (pfile, '1');
- CPP_NUL_TERMINATE_Q (pfile);
- return;
-
- case T_SPECLINE:
- {
- long line;
- cpp_buf_line_and_col (cpp_file_buffer (pfile), &line, NULL);
-
- CPP_RESERVE (pfile, 10);
- sprintf (CPP_PWRITTEN (pfile), "%ld", line);
- CPP_ADJUST_WRITTEN (pfile, strlen (CPP_PWRITTEN (pfile)));
- return;
- }
-
- case T_DATE:
- case T_TIME:
- {
- struct tm *timebuf;
-
- CPP_RESERVE (pfile, 20);
- timebuf = timestamp (pfile);
- if (hp->type == T_DATE)
- sprintf (CPP_PWRITTEN (pfile), "\"%s %2d %4d\"",
- monthnames[timebuf->tm_mon],
- timebuf->tm_mday, timebuf->tm_year + 1900);
- else
- sprintf (CPP_PWRITTEN (pfile), "\"%02d:%02d:%02d\"",
- timebuf->tm_hour, timebuf->tm_min, timebuf->tm_sec);
-
- CPP_ADJUST_WRITTEN (pfile, strlen (CPP_PWRITTEN (pfile)));
- return;
- }
-
- case T_POISON:
- cpp_error (pfile, "attempt to use poisoned `%s'.", hp->name);
- CPP_RESERVE (pfile, 1);
- CPP_PUTC_Q (pfile, '0');
- CPP_NUL_TERMINATE_Q (pfile);
- break;
-
- default:
- cpp_ice (pfile, "invalid special hash type");
- return;
- }
-}
-
-/* Expand a macro call.
- HP points to the symbol that is the macro being called.
- Put the result of expansion onto the input stack
- so that subsequent input by our caller will use it.
-
- If macro wants arguments, caller has already verified that
- an argument list follows; arguments come from the input stack. */
-
-void
-_cpp_macroexpand (pfile, hp)
- cpp_reader *pfile;
- HASHNODE *hp;
+expand_hash (htab)
+ struct htab *htab;
{
- int nargs;
- DEFINITION *defn;
- register U_CHAR *xbuf;
- long start_line, start_column;
- int xbuf_len;
- struct argdata *args = 0;
- long old_written = CPP_WRITTEN (pfile);
- int rest_args, rest_zero = 0;
- register int i;
+ cpp_hashnode **oentries;
+ cpp_hashnode **olimit;
+ cpp_hashnode **p;
+ size_t size;
- cpp_buf_line_and_col (cpp_file_buffer (pfile), &start_line, &start_column);
+ oentries = htab->entries;
+ olimit = oentries + htab->size;
- /* 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;
- }
+ htab->size = size = higher_prime_number (htab->size * 2);
+ htab->entries = xcnewvec (cpp_hashnode *, size);
- defn = hp->value.defn;
- nargs = defn->nargs;
- pfile->output_escapes++;
-
- if (nargs >= 0)
+ for (p = oentries; p < olimit; p++)
{
- enum cpp_token token;
-
- args = (struct argdata *) alloca ((nargs + 1) * sizeof (struct argdata));
-
- for (i = 0; i < nargs; i++)
- {
- args[i].raw = args[i].expanded = 0;
- args[i].raw_length = 0;
- args[i].expand_length = args[i].stringified_length = -1;
- }
-
- /* Parse all the macro args that are supplied. I counts them.
- The first NARGS args are stored in ARGS.
- The rest are discarded. If rest_args is set then we assume
- macarg absorbed the rest of the args. */
- i = 0;
- rest_args = 0;
-
- /* Skip over the opening parenthesis. */
- CPP_OPTIONS (pfile)->discard_comments++;
- CPP_OPTIONS (pfile)->no_line_commands++;
- pfile->no_macro_expand++;
- pfile->no_directives++;
-
- token = cpp_get_non_space_token (pfile);
- if (token != CPP_LPAREN)
- cpp_ice (pfile, "macroexpand: unexpected token %d (wanted LPAREN)",
- token);
- CPP_ADJUST_WRITTEN (pfile, -1);
-
- token = CPP_EOF;
- do
- {
- if (rest_args)
- continue;
- if (i < nargs || (nargs == 0 && i == 0))
- {
- /* if we are working on last arg which absorbs rest of args... */
- if (i == nargs - 1 && defn->rest_args)
- rest_args = 1;
- args[i].raw = CPP_WRITTEN (pfile);
- token = macarg (pfile, rest_args);
- args[i].raw_length = CPP_WRITTEN (pfile) - args[i].raw;
- }
- else
- token = macarg (pfile, 0);
- if (token == CPP_EOF || token == CPP_POP)
- cpp_error_with_line (pfile, start_line, start_column,
- "unterminated macro call");
- i++;
- }
- while (token == CPP_COMMA);
- CPP_OPTIONS (pfile)->discard_comments--;
- CPP_OPTIONS (pfile)->no_line_commands--;
- pfile->no_macro_expand--;
- pfile->no_directives--;
- if (token != CPP_RPAREN)
- return;
-
- /* If we got one arg but it was just whitespace, call that 0 args. */
- if (i == 1)
- {
- register U_CHAR *bp = ARG_BASE + args[0].raw;
- register U_CHAR *lim = bp + args[0].raw_length;
- /* cpp.texi says for foo ( ) we provide one argument.
- However, if foo wants just 0 arguments, treat this as 0. */
- if (nargs == 0)
- while (bp != lim && is_space(*bp))
- bp++;
- if (bp == lim)
- i = 0;
- }
-
- /* Don't output an error message if we have already output one for
- a parse error above. */
- rest_zero = 0;
- if (nargs == 0 && i > 0)
- {
- cpp_error (pfile, "arguments given to macro `%s'", hp->name);
- }
- else if (i < nargs)
- {
- /* traditional C allows foo() if foo wants one argument. */
- if (nargs == 1 && i == 0 && CPP_TRADITIONAL (pfile))
- ;
- /* the rest args token is allowed to absorb 0 tokens */
- else if (i == nargs - 1 && defn->rest_args)
- rest_zero = 1;
- else if (i == 0)
- cpp_error (pfile, "macro `%s' used without args", hp->name);
- else if (i == 1)
- cpp_error (pfile, "macro `%s' used with just one arg", hp->name);
- else
- cpp_error (pfile, "macro `%s' used with only %d args",
- hp->name, i);
- }
- else if (i > nargs)
- {
- cpp_error (pfile,
- "macro `%s' used with too many (%d) args", hp->name, i);
- }
- }
-
- /* If macro wants zero args, we parsed the arglist for checking only.
- Read directly from the macro definition. */
- if (nargs <= 0)
- {
- xbuf = defn->expansion;
- xbuf_len = defn->length;
- }
- else
- {
- register U_CHAR *exp = defn->expansion;
- register int offset; /* offset in expansion,
- copied a piece at a time */
- register int totlen; /* total amount of exp buffer filled so far */
-
- register struct reflist *ap, *last_ap;
-
- /* Macro really takes args. Compute the expansion of this call. */
-
- /* Compute length in characters of the macro's expansion.
- Also count number of times each arg is used. */
- xbuf_len = defn->length;
- for (ap = defn->pattern; ap != NULL; ap = ap->next)
- {
- if (ap->stringify)
- {
- register struct argdata *arg = &args[ap->argno];
- /* Stringify if it hasn't already been */
- if (arg->stringified_length < 0)
- {
- int arglen = arg->raw_length;
- int escaped = 0;
- int in_string = 0;
- int c;
- /* Initially need_space is -1. Otherwise, 1 means the
- previous character was a space, but we suppressed it;
- 0 means the previous character was a non-space. */
- int need_space = -1;
- i = 0;
- arg->stringified = CPP_WRITTEN (pfile);
- if (!CPP_TRADITIONAL (pfile))
- CPP_PUTC (pfile, '\"'); /* insert beginning quote */
- for (; i < arglen; i++)
- {
- c = (ARG_BASE + arg->raw)[i];
-
- if (!in_string)
- {
- /* Delete "\r " and "\r-" escapes. */
- if (c == '\r')
- {
- i++;
- continue;
- }
- /* Internal sequences of whitespace are
- replaced by one space except within
- a string or char token. */
- else if (is_space(c))
- {
- if (need_space == 0)
- need_space = 1;
- continue;
- }
- else if (need_space > 0)
- CPP_PUTC (pfile, ' ');
- need_space = 0;
- }
-
- if (escaped)
- escaped = 0;
- else
- {
- if (c == '\\')
- escaped = 1;
- if (in_string)
- {
- if (c == in_string)
- in_string = 0;
- }
- else if (c == '\"' || c == '\'')
- in_string = c;
- }
-
- /* Escape these chars */
- if (c == '\"' || (in_string && c == '\\'))
- CPP_PUTC (pfile, '\\');
- if (ISPRINT (c))
- CPP_PUTC (pfile, c);
- else
- {
- CPP_RESERVE (pfile, 4);
- sprintf ((char *) CPP_PWRITTEN (pfile), "\\%03o",
- (unsigned int) c);
- CPP_ADJUST_WRITTEN (pfile, 4);
- }
- }
- if (!CPP_TRADITIONAL (pfile))
- CPP_PUTC (pfile, '\"'); /* insert ending quote */
- arg->stringified_length
- = CPP_WRITTEN (pfile) - arg->stringified;
- }
- xbuf_len += args[ap->argno].stringified_length;
- }
- else if (ap->raw_before || ap->raw_after || CPP_TRADITIONAL (pfile))
- /* Add 4 for two \r-space markers to prevent
- token concatenation. */
- xbuf_len += args[ap->argno].raw_length + 4;
- else
- {
- /* We have an ordinary (expanded) occurrence of the arg.
- So compute its expansion, if we have not already. */
- if (args[ap->argno].expand_length < 0)
- {
- args[ap->argno].expanded = CPP_WRITTEN (pfile);
- cpp_expand_to_buffer (pfile,
- ARG_BASE + args[ap->argno].raw,
- args[ap->argno].raw_length);
-
- args[ap->argno].expand_length
- = CPP_WRITTEN (pfile) - args[ap->argno].expanded;
- }
-
- /* Add 4 for two \r-space markers to prevent
- token concatenation. */
- xbuf_len += args[ap->argno].expand_length + 4;
- }
- }
-
- xbuf = (U_CHAR *) xmalloc (xbuf_len + 1);
-
- /* Generate in XBUF the complete expansion
- with arguments substituted in.
- TOTLEN is the total size generated so far.
- OFFSET is the index in the definition
- of where we are copying from. */
- offset = totlen = 0;
- for (last_ap = NULL, ap = defn->pattern; ap != NULL;
- last_ap = ap, ap = ap->next)
+ if (*p != NULL)
{
- register struct argdata *arg = &args[ap->argno];
- int count_before = totlen;
+ unsigned int index;
+ unsigned int hash, hash2;
+ cpp_hashnode *entry = *p;
- /* Add chars to XBUF. */
- i = ap->nchars;
- memcpy (&xbuf[totlen], &exp[offset], i);
- totlen += i;
- offset += i;
+ hash = entry->hash;
+ index = hash % size;
- /* If followed by an empty rest arg with concatenation,
- delete the last run of nonwhite chars. */
- if (rest_zero && totlen > count_before
- && ((ap->rest_args && ap->raw_before)
- || (last_ap != NULL && last_ap->rest_args
- && last_ap->raw_after)))
+ if (htab->entries[index] == NULL)
{
- /* Delete final whitespace. */
- while (totlen > count_before && is_space(xbuf[totlen - 1]))
- totlen--;
-
- /* Delete the nonwhites before them. */
- while (totlen > count_before && !is_space(xbuf[totlen - 1]))
- totlen--;
+ insert:
+ htab->entries[index] = entry;
+ continue;
}
- if (ap->stringify != 0)
+ hash2 = 1 + hash % (size - 2);
+ for (;;)
{
- memcpy (xbuf + totlen, ARG_BASE + arg->stringified,
- arg->stringified_length);
- totlen += arg->stringified_length;
- }
- else if (ap->raw_before || ap->raw_after || CPP_TRADITIONAL (pfile))
- {
- U_CHAR *p1 = ARG_BASE + arg->raw;
- U_CHAR *l1 = p1 + arg->raw_length;
- if (ap->raw_before)
- {
- /* Arg is concatenated before: delete leading whitespace,
- whitespace markers, and no-reexpansion markers. */
- while (p1 != l1)
- {
- if (is_space(p1[0]))
- p1++;
- else if (p1[0] == '\r')
- p1 += 2;
- else
- break;
- }
- }
- if (ap->raw_after)
- {
- /* Arg is concatenated after: delete trailing whitespace,
- whitespace markers, and no-reexpansion markers. */
- while (p1 != l1)
- {
- if (is_space(l1[-1]))
- l1--;
- else if (l1[-1] == '\r')
- l1--;
- else if (l1[-1] == '-')
- {
- if (l1 != p1 + 1 && l1[-2] == '\r')
- l1 -= 2;
- else
- break;
- }
- else
- break;
- }
- }
-
- /* Delete any no-reexpansion marker that precedes
- an identifier at the beginning of the argument. */
- if (p1[0] == '\r' && p1[1] == '-')
- p1 += 2;
+ index += hash2;
+ if (index >= size)
+ index -= size;
- memcpy (xbuf + totlen, p1, l1 - p1);
- totlen += l1 - p1;
+ if (htab->entries[index] == NULL)
+ goto insert;
}
- else
- {
- U_CHAR *expanded = ARG_BASE + arg->expanded;
- if (!ap->raw_before && totlen > 0 && arg->expand_length
- && !CPP_TRADITIONAL (pfile)
- && unsafe_chars (pfile, xbuf[totlen - 1], expanded[0]))
- {
- xbuf[totlen++] = '\r';
- xbuf[totlen++] = ' ';
- }
-
- memcpy (xbuf + totlen, expanded, arg->expand_length);
- totlen += arg->expand_length;
-
- if (!ap->raw_after && totlen > 0 && offset < defn->length
- && !CPP_TRADITIONAL (pfile)
- && unsafe_chars (pfile, xbuf[totlen - 1], exp[offset]))
- {
- xbuf[totlen++] = '\r';
- xbuf[totlen++] = ' ';
- }
- }
-
- if (totlen > xbuf_len)
- {
- cpp_ice (pfile, "buffer overrun in macroexpand");
- return;
- }
- }
-
- /* if there is anything left of the definition
- after handling the arg list, copy that in too. */
-
- for (i = offset; i < defn->length; i++)
- {
- /* if we've reached the end of the macro */
- if (exp[i] == ')')
- rest_zero = 0;
- if (!(rest_zero && last_ap != NULL && last_ap->rest_args
- && last_ap->raw_after))
- xbuf[totlen++] = exp[i];
}
-
- xbuf[totlen] = 0;
- xbuf_len = totlen;
-
}
- pfile->output_escapes--;
-
- /* Now put the expansion on the input stack
- so our caller will commence reading from it. */
- push_macro_expansion (pfile, xbuf, xbuf_len, hp);
- CPP_BUFFER (pfile)->has_escapes = 1;
-
- /* Pop the space we've used in the token_buffer for argument expansion. */
- CPP_SET_WRITTEN (pfile, old_written);
-
- /* Recursive macro use sometimes works traditionally.
- #define foo(x,y) bar (x (y,0), y)
- foo (foo, baz) */
-
- if (!CPP_TRADITIONAL (pfile))
- hp->type = T_DISABLED;
+ free (oentries);
}
-/* Return 1 iff a token ending in C1 followed directly by a token C2
- could cause mis-tokenization. */
+/* The following function returns the nearest prime number which is
+ greater than a given source number, N. */
-static int
-unsafe_chars (pfile, c1, c2)
- cpp_reader *pfile;
- int c1, c2;
+static unsigned long
+higher_prime_number (n)
+ unsigned long n;
{
- switch (c1)
- {
- case '+': case '-':
- if (c2 == c1 || c2 == '=')
- return 1;
- goto letter;
+ unsigned long i;
- case 'e': case 'E': case 'p': case 'P':
- if (c2 == '-' || c2 == '+')
- return 1; /* could extend a pre-processing number */
- goto letter;
+ /* Ensure we have a larger number and then force to odd. */
+ n++;
+ n |= 0x01;
- case '$':
- if (CPP_OPTIONS (pfile)->dollars_in_ident)
- goto letter;
- return 0;
+ /* All odd numbers < 9 are prime. */
+ if (n < 9)
+ return n;
- case 'L':
- if (c2 == '\'' || c2 == '\"')
- return 1; /* Could turn into L"xxx" or L'xxx'. */
- goto letter;
+ /* Otherwise find the next prime using a sieve. */
- case '.': case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7': case '8': case '9':
- case '_': case 'a': case 'b': case 'c': case 'd': case 'f':
- case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
- case 'm': case 'n': case 'o': case 'q': case 'r': case 's':
- case 't': case 'u': case 'v': case 'w': case 'x': case 'y':
- case 'z': case 'A': case 'B': case 'C': case 'D': case 'F':
- case 'G': case 'H': case 'I': case 'J': case 'K': case 'M':
- case 'N': case 'O': case 'Q': case 'R': case 'S': case 'T':
- case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
- letter:
- /* We're in the middle of either a name or a pre-processing number. */
- return (is_idchar(c2) || c2 == '.');
+ next:
+ for (i = 3; i * i <= n; i += 2)
+ if (n % i == 0)
+ {
+ n += 2;
+ goto next;
+ }
- case '<': case '>': case '!': case '%': case '#': case ':':
- case '^': case '&': case '|': case '*': case '/': case '=':
- return (c2 == c1 || c2 == '=');
- }
- return 0;
+ return n;
}
-static void
-push_macro_expansion (pfile, xbuf, xbuf_len, hp)
+void
+cpp_forall_identifiers (pfile, cb, v)
cpp_reader *pfile;
- register U_CHAR *xbuf;
- int xbuf_len;
- HASHNODE *hp;
+ int (*cb) PARAMS ((cpp_reader *, cpp_hashnode *, void *));
+ void *v;
{
- register cpp_buffer *mbuf = cpp_push_buffer (pfile, xbuf, xbuf_len);
- if (mbuf == NULL)
- return;
- mbuf->cleanup = macro_cleanup;
- mbuf->data = hp;
-
- /* The first chars of the expansion should be a "\r " added by
- collect_expansion. This is to prevent accidental token-pasting
- between the text preceding the macro invocation, and the macro
- expansion text.
-
- We would like to avoid adding unneeded spaces (for the sake of
- tools that use cpp, such as imake). In some common cases we can
- tell that it is safe to omit the space.
-
- The character before the macro invocation cannot have been an
- idchar (or else it would have been pasted with the idchars of
- the macro name). Therefore, if the first non-space character
- of the expansion is an idchar, we do not need the extra space
- to prevent token pasting.
+ cpp_hashnode **p, **limit;
- Also, we don't need the extra space if the first char is '(',
- or some other (less common) characters. */
-
- if (xbuf[0] == '\r' && xbuf[1] == ' '
- && (is_idchar(xbuf[2]) || xbuf[2] == '(' || xbuf[2] == '\''
- || xbuf[2] == '\"'))
- mbuf->cur += 2;
-
- /* Likewise, avoid the extra space at the end of the macro expansion
- if this is safe. We can do a better job here since we can know
- what the next char will be. */
- if (xbuf_len >= 3
- && mbuf->rlimit[-2] == '\r'
- && mbuf->rlimit[-1] == ' ')
+ p = pfile->hashtab->entries;
+ limit = p + pfile->hashtab->size;
+ do
{
- int c1 = mbuf->rlimit[-3];
- int c2 = CPP_BUF_PEEK (CPP_PREV_BUFFER (CPP_BUFFER (pfile)));
- if (c2 == EOF || !unsafe_chars (pfile, c1, c2))
- mbuf->rlimit -= 2;
+ if (*p)
+ if ((*cb) (pfile, *p, v) == 0)
+ break;
}
+ while (++p < limit);
}
-/* Return zero if two DEFINITIONs are isomorphic. */
-
+/* Determine whether the identifier ID, of length LEN, is a defined macro. */
int
-_cpp_compare_defs (pfile, d1, d2)
+cpp_defined (pfile, id, len)
cpp_reader *pfile;
- DEFINITION *d1, *d2;
-{
- struct reflist *a1, *a2;
- U_CHAR *p1 = d1->expansion;
- U_CHAR *p2 = d2->expansion;
- int first = 1;
-
- if (d1->nargs != d2->nargs)
- return 1;
- if (CPP_PEDANTIC (pfile)
- && d1->argnames && d2->argnames)
- {
- U_CHAR *arg1 = d1->argnames;
- U_CHAR *arg2 = d2->argnames;
- size_t len;
- int i = d1->nargs;
- while (i--)
- {
- len = strlen (arg1);
- if (strcmp (arg1, arg2))
- return 1;
- arg1 += len;
- arg2 += len;
- }
- }
- for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2;
- a1 = a1->next, a2 = a2->next)
- {
- if (!((a1->nchars == a2->nchars && !strncmp (p1, p2, a1->nchars))
- || !comp_def_part (first, p1, a1->nchars, p2, a2->nchars, 0))
- || a1->argno != a2->argno
- || a1->stringify != a2->stringify
- || a1->raw_before != a2->raw_before
- || a1->raw_after != a2->raw_after)
- return 1;
- first = 0;
- p1 += a1->nchars;
- p2 += a2->nchars;
- }
- if (a1 != a2)
- return 1;
-
- return comp_def_part (first, p1, d1->length - (p1 - d1->expansion),
- p2, d2->length - (p2 - d2->expansion), 1);
-}
-
-/* Return 1 if two parts of two macro definitions are effectively different.
- One of the parts starts at BEG1 and has LEN1 chars;
- the other has LEN2 chars at BEG2.
- Any sequence of whitespace matches any other sequence of whitespace.
- FIRST means these parts are the first of a macro definition;
- so ignore leading whitespace entirely.
- LAST means these parts are the last of a macro definition;
- so ignore trailing whitespace entirely. */
-
-static int
-comp_def_part (first, beg1, len1, beg2, len2, last)
- int first;
- U_CHAR *beg1, *beg2;
- int len1, len2;
- int last;
-{
- register U_CHAR *end1 = beg1 + len1;
- register U_CHAR *end2 = beg2 + len2;
- if (first)
- {
- while (beg1 != end1 && is_space(*beg1))
- beg1++;
- while (beg2 != end2 && is_space(*beg2))
- beg2++;
- }
- if (last)
- {
- while (beg1 != end1 && is_space(end1[-1]))
- end1--;
- while (beg2 != end2 && is_space(end2[-1]))
- end2--;
- }
- while (beg1 != end1 && beg2 != end2)
- {
- if (is_space(*beg1) && is_space(*beg2))
- {
- while (beg1 != end1 && is_space(*beg1))
- beg1++;
- while (beg2 != end2 && is_space(*beg2))
- beg2++;
- }
- else if (*beg1 == *beg2)
- {
- beg1++;
- beg2++;
- }
- else
- break;
- }
- return (beg1 != end1) || (beg2 != end2);
-}
-
-/* Dump the definition of macro MACRO on stdout. The format is suitable
- to be read back in again. */
-
-void
-_cpp_dump_definition (pfile, sym, len, defn)
- cpp_reader *pfile;
- const U_CHAR *sym;
- long len;
- DEFINITION *defn;
+ const U_CHAR *id;
+ int len;
{
- if (pfile->lineno == 0)
- output_line_command (pfile, same_file);
-
- CPP_RESERVE (pfile, len + sizeof "#define ");
- CPP_PUTS_Q (pfile, "#define ", sizeof "#define " -1);
- CPP_PUTS_Q (pfile, sym, len);
-
- if (defn->nargs == -1)
- {
- CPP_PUTC_Q (pfile, ' ');
-
- /* The first and last two characters of a macro expansion are
- always "\r "; this needs to be trimmed out.
- So we need length-4 chars of space, plus one for the NUL. */
- CPP_RESERVE (pfile, defn->length - 4 + 1);
- CPP_PUTS_Q (pfile, defn->expansion + 2, defn->length - 4);
- }
- else
- {
- struct reflist *r;
- unsigned char **argv = (unsigned char **) alloca (defn->nargs *
- sizeof(char *));
- int *argl = (int *) alloca (defn->nargs * sizeof(int));
- unsigned char *x;
- int i;
-
- /* First extract the argument list. */
- x = defn->argnames;
- for (i = 0; i < defn->nargs; i++)
- {
- argv[i] = x;
- argl[i] = strlen (x);
- x += argl[i] + 1;
- }
-
- /* Now print out the argument list. */
- CPP_PUTC_Q (pfile, '(');
- for (i = 0; i < defn->nargs; i++)
- {
- CPP_RESERVE (pfile, argl[i] + 2);
- if (!(i == defn->nargs-1 && defn->rest_args
- && !strcmp (argv[i], "__VA_ARGS__")))
- CPP_PUTS_Q (pfile, argv[i], argl[i]);
- if (i < defn->nargs-1)
- CPP_PUTS_Q (pfile, ", ", 2);
- }
- if (defn->rest_args)
- CPP_PUTS (pfile, "...", 3);
- CPP_PUTS (pfile, ") ", 2);
-
- /* Now the definition. */
- x = defn->expansion;
- for (r = defn->pattern; r; r = r->next)
- {
- i = r->nchars;
- if (*x == '\r') x += 2, i -= 2;
- /* i chars for macro text, plus the length of the macro
- argument name, plus one for a stringify marker, plus two for
- each concatenation marker. */
- CPP_RESERVE (pfile,
- i + argl[r->argno] + r->stringify
- + (r->raw_before + r->raw_after) * 2);
-
- if (i > 0) CPP_PUTS_Q (pfile, x, i);
- if (r->raw_before)
- CPP_PUTS_Q (pfile, "##", 2);
- if (r->stringify)
- CPP_PUTC_Q (pfile, '#');
- CPP_PUTS_Q (pfile, argv[r->argno], argl[r->argno]);
- if (r->raw_after && !(r->next && r->next->nchars == 0
- && r->next->raw_before))
- CPP_PUTS_Q (pfile, "##", 2);
-
- x += i;
- }
-
- i = defn->length - (x - defn->expansion) - 2;
- if (*x == '\r') x += 2, i -= 2;
- if (i > 0) CPP_PUTS (pfile, x, i);
- }
+ cpp_hashnode *hp = cpp_lookup (pfile, id, len);
- if (pfile->lineno == 0)
- CPP_PUTC (pfile, '\n');
- CPP_NUL_TERMINATE (pfile);
+ /* If it's of type NT_MACRO, it cannot be poisoned. */
+ return hp->type == NT_MACRO;
}