===================================================================
@@ -23,6 +23,7 @@ along with this program; see the file CO
#include "config.h"
#include "system.h"
#include "symtab.h"
+#include "internal.h"
/* The code below is a specialization of Vladimir Makarov's expandable
hash tables (see libiberty/hashtab.c). The abstraction penalty was
@@ -30,7 +31,6 @@ along with this program; see the file CO
intrinsically how to calculate a hash value, and how to compare an
existing entry with a potential new one. */
-static unsigned int calc_hash (const unsigned char *, size_t);
static void ht_expand (hash_table *);
static double approx_sqrt (double);
@@ -39,8 +39,8 @@ static double approx_sqrt (double);
/* Calculate the hash of the string STR of length LEN. */
-static unsigned int
-calc_hash (const unsigned char *str, size_t len)
+unsigned int
+ht_calc_hash (const unsigned char *str, size_t len)
{
size_t n = len;
unsigned int r = 0;
@@ -94,7 +94,7 @@ hashnode
ht_lookup (hash_table *table, const unsigned char *str, size_t len,
enum ht_lookup_option insert)
{
- return ht_lookup_with_hash (table, str, len, calc_hash (str, len),
+ return ht_lookup_with_hash (table, str, len, ht_calc_hash (str, len),
insert);
}
@@ -361,3 +361,551 @@ approx_sqrt (double x)
while (d > .0001);
return s;
}
+
+
+/* Lookaside Identifier Hash Table */
+
+cpp_lookaside *
+cpp_lt_exchange (cpp_reader *pfile, cpp_lookaside *desired)
+{
+ cpp_lookaside *current = pfile->lookaside_table;
+ pfile->lookaside_table = desired;
+ return current;
+}
+
+cpp_lookaside *
+cpp_lt_create (unsigned int order, unsigned int debug)
+{
+ unsigned int slots = 1 << order;
+ cpp_lookaside *table = XCNEW (cpp_lookaside);
+ table->entries = XCNEWVEC (struct lae, slots);
+ table->order = order;
+ table->active = 0;
+
+ table->max_length = 0;
+ table->strings = XCNEW (struct obstack);
+ /* Strings need no alignment. */
+ _obstack_begin (table->strings, 0, 0,
+ (void *(*) (long)) xmalloc,
+ (void (*) (void *)) free);
+ obstack_alignment_mask (table->strings) = 0;
+
+ table->searches = 0;
+ table->comparisons = 0;
+ table->strcmps = 0;
+ table->collisions = 0;
+ table->misses = 0;
+ table->insertions = 0;
+ table->macrovalue = 0;
+ table->resizes = 0;
+ table->bumps = 0;
+ table->iterations = 0;
+ table->empties = 0;
+
+ table->flag_pth_debug = debug;
+
+ return table;
+}
+
+void
+cpp_lt_statistics (cpp_reader *pfile)
+{
+ struct cpp_lookaside *table = pfile->lookaside_table;
+ fprintf (stderr, "lookaside ");
+ fprintf (stderr, "order=%u, ", table->order);
+ fprintf (stderr, "active=%u, ", table->active);
+ fprintf (stderr, "search=%llu, ", table->searches);
+ fprintf (stderr, "compare=%llu, ", table->comparisons);
+ fprintf (stderr, "strcmp=%llu, ", table->strcmps);
+ fprintf (stderr, "collide=%llu, ", table->collisions);
+ fprintf (stderr, "miss=%llu, ", table->misses);
+ fprintf (stderr, "insert=%llu, ", table->insertions);
+ fprintf (stderr, "macro=%llu, ", table->macrovalue);
+ fprintf (stderr, "resize=%llu, ", table->resizes);
+ fprintf (stderr, "bump=%llu, ", table->bumps);
+ fprintf (stderr, "iterations=%llu, ", table->iterations);
+ fprintf (stderr, "empties=%llu\n", table->empties);
+ table->searches = 0;
+ table->comparisons = 0;
+ table->strcmps = 0;
+ table->collisions = 0;
+ table->misses = 0;
+ table->insertions = 0;
+ table->macrovalue = 0;
+ table->resizes = 0;
+ table->bumps = 0;
+ table->iterations = 0;
+ table->empties = 0;
+}
+
+void
+cpp_lt_destroy (cpp_lookaside *table)
+{
+ if (table->strings)
+ {
+ obstack_free (table->strings, NULL);
+ free (table->strings);
+ }
+ free (table->entries);
+ free (table);
+}
+
+unsigned int
+cpp_lt_num_entries (cpp_lookaside *table)
+{
+ return table->active;
+}
+
+unsigned int
+cpp_lt_max_length (cpp_lookaside *table)
+{
+ return table->max_length;
+}
+
+struct obstack *
+cpp_lt_take_strings (cpp_lookaside *table)
+{
+ struct obstack *strings = table->strings;
+ table->strings = NULL;
+ return strings;
+}
+
+void
+cpp_lt_forall (cpp_lookaside *table, cpp_lookback grok, void *passthru)
+{
+ unsigned int slots = 1 << table->order;
+ struct lae *entries = table->entries;
+ unsigned int index;
+ for (index = 0; index < slots ; ++index)
+ {
+ hashnode node = entries[index].node;
+ if (node)
+ grok (passthru, (const char *)node->str, node->len,
+ entries[index].value, entries[index].length);
+ }
+}
+
+/* Query a CPP_NODE for its macro value from PFILE. */
+
+static const char *
+lt_query_macro (cpp_reader *pfile, cpp_hashnode *cpp_node)
+{
+ const char *definition = NULL;
+ if (cpp_node->flags & NODE_BUILTIN)
+ {
+ const char *str = (const char *)cpp_node->ident.str;
+ if ( strcmp(str, "__DATE__") == 0
+ || strcmp(str, "__TIME__") == 0
+ || strcmp(str, "__FILE__") == 0
+ || strcmp(str, "__LINE__") == 0)
+ definition = str;
+ else
+ {
+ static char *string = 0;
+ static unsigned int space = 0;
+ unsigned int front, back, needed;
+ const char *value;
+
+ value = (const char *)_cpp_builtin_macro_text (pfile, cpp_node);
+ front = strlen (str);
+ back = strlen (value);
+ needed = front + 1 + back + 1;
+ if (space < needed)
+ {
+ if (string != NULL)
+ free (string);
+ string = XCNEWVEC (char, needed);
+ space = needed;
+ }
+ strcpy (string, str);
+ string[front] = '=';
+ strcpy (string + front + 1, value);
+
+ definition = string;
+ }
+ }
+ else
+ definition = (const char *) cpp_macro_definition (pfile, cpp_node);
+
+ if (pfile->lookaside_table->flag_pth_debug >= 3)
+ fprintf (stderr, "PTH: macro %s is %s\n",
+ (const char *)cpp_node->ident.str,
+ definition);
+
+ return definition;
+}
+
+/* Capture the current STRING definition of a macro for the
+ libcpp NODE and store it in the look ASIDE table of the PFILE. */
+
+static unsigned int
+lt_macro_value (const char** string, cpp_lookaside *aside,
+ cpp_reader *pfile, cpp_hashnode *cpp_node)
+{
+ const char *definition = lt_query_macro (pfile, cpp_node);
+ size_t macro_len = strlen (definition);
+ *string = (const char *) obstack_copy0 (aside->strings, definition, macro_len);
+ if (macro_len > aside->max_length)
+ aside->max_length = macro_len;
+ ++aside->macrovalue;
+ return macro_len;
+}
+
+/* Capture the identifier state in the lookaside table of PFILE
+ and then empty the lookaside table. */
+
+cpp_idents_used
+cpp_lt_capture (cpp_reader *pfile)
+{
+ cpp_idents_used used;
+ cpp_lookaside *aside = pfile->lookaside_table;
+ unsigned int num_entries = aside->active;
+ unsigned int slots = 1 << aside->order;
+ unsigned int table_index;
+ unsigned int summary_index = 0;
+
+ used.num_entries = aside->active;
+ used.entries = XCNEWVEC (cpp_ident_use, num_entries);
+
+ for (table_index = 0; table_index < slots ; ++table_index)
+ {
+ struct lae *table_entry = aside->entries + table_index;
+ hashnode node = table_entry->node;
+ if (node)
+ {
+ cpp_ident_use *summary_entry;
+ cpp_hashnode *cpp_node;
+
+ summary_entry = used.entries + summary_index++;
+ summary_entry->ident_len = node->len;
+ summary_entry->ident_str = (const char *)node->str;
+ summary_entry->before_len = table_entry->length;
+ summary_entry->before_str = table_entry->value;
+
+ /* Capture any macro value. */
+ cpp_node = CPP_HASHNODE (node);
+ if (cpp_node->type == NT_MACRO)
+ summary_entry->after_len = lt_macro_value
+ (&summary_entry->after_str, aside, pfile, cpp_node);
+ /* else .after_str and .after_len are still zero initialized. */
+ }
+ }
+
+ /* Now empty out the lookaside table. */
+ memset (aside->entries, 0, slots * sizeof (struct lae));
+ aside->active = 0;
+
+ /* Take the strings from the table and give to the summary. */
+ used.strings = aside->strings;
+ aside->strings = NULL;
+ used.max_length = aside->max_length;
+
+ /* Create a new string table. */
+ aside->max_length = 0;
+ aside->strings = XCNEW (struct obstack);
+ /* Strings need no alignment. */
+ _obstack_begin (aside->strings, 0, 0,
+ (void *(*) (long)) xmalloc,
+ (void (*) (void *)) free);
+ obstack_alignment_mask (aside->strings) = 0;
+
+ aside->iterations += slots;
+ ++aside->empties;
+
+ return used;
+}
+
+/* Verify that the INDENTIFIERS have before states that consistent
+ with the current identifier definitions in the READER.
+ If not, set the BAD_USE and CUR_DEF to indicate the first
+ inconsistency. A null means 'not a macro'. */
+
+bool
+cpp_lt_verify (cpp_reader *reader, cpp_idents_used* identifiers,
+ cpp_ident_use **bad_use, const char **cur_def)
+{
+ unsigned int i;
+ unsigned int num_entries = identifiers->num_entries;
+ cpp_ident_use *entries = identifiers->entries;
+
+ *bad_use = NULL;
+ *cur_def = NULL;
+
+ for (i = 0; i < num_entries; ++i)
+ {
+ cpp_hashnode *cpp_node;
+ cpp_ident_use *entry = entries + i;
+ const char *ident_str = entry->ident_str;
+ unsigned int ident_len = entry->ident_len;
+ const char *before_str = entry->before_str;
+ unsigned int before_len = entry->before_len;
+ cpp_node = cpp_peek_sym (reader, (const unsigned char *)ident_str,
+ ident_len);
+ if (cpp_node == NULL)
+ {
+ /* The symbol used to exist, but it doesn't now. */
+ if (before_str != NULL)
+ {
+ *bad_use = entry;
+ *cur_def = NULL;
+ goto fail;
+ }
+ }
+ else if (before_len == -1U)
+ {
+ /* It was not saved as a macro. */
+ if (cpp_node->type == NT_MACRO)
+ {
+ /* But it is a macro now! */
+ *bad_use = entry;
+ *cur_def = (const char*) lt_query_macro (reader, cpp_node);
+ goto fail;
+ }
+ /* Otherwise, both agree it is not a macro. */
+ }
+ else
+ {
+ /* It was saved as a macro. */
+ const char *definition;
+
+ if (cpp_node->type != NT_MACRO)
+ {
+ /* But it is not a macro now! */
+ *bad_use = entry;
+ *cur_def = NULL;
+ goto fail;
+ }
+ /* Otherwise, both agree it is a macro. */
+ definition = lt_query_macro (reader, cpp_node);
+ /* strlen is required to avoid the prefix problem. */
+ if (definition == NULL
+ || before_len != strlen (definition)
+ || memcmp (definition, before_str, before_len) != 0)
+ {
+ /* They do not have the same value. */
+ *bad_use = entry;
+ *cur_def = definition;
+ goto fail;
+ }
+ }
+ }
+/* pass: */
+ *bad_use = NULL;
+ *cur_def = NULL;
+ return true;
+
+fail:
+ return false;
+}
+
+/* Produce the macro definition syntax NEEDED by cpp_define from
+ the syntax GIVEN by cpp_macro_definition. */
+
+static void
+cpp_lt_define_syntax (char *needed, const char *given)
+{
+ char c;
+
+ c = *given++;
+
+ /* Copy over macro identifier. */
+ while ( ('0' <= c && c <= '9')
+ || ('A' <= c && c <= 'Z')
+ || ('a' <= c && c <= 'z')
+ || (c == '_'))
+ {
+ *needed++ = c;
+ c = *given++;
+ }
+
+ if (c == '(')
+ {
+ /* Copy over parameter list. */
+ while (c != ')')
+ {
+ *needed++ = c;
+ c = *given++;
+ }
+
+ /* Copy over trailing parenthesis. */
+ *needed++ = c;
+ c = *given++;
+ }
+
+ /* Replace definition space by assignment. */
+ /* (c == ' ') */
+ *needed++ = '=';
+ c = *given++;
+
+ /* Copy over macro identifier. */
+ while (c != '\0')
+ {
+ *needed++ = c;
+ c = *given++;
+ }
+
+ *needed++ = '\0';
+}
+
+/* Replay the macro definitions captured by the table of IDENTIFIERS
+ into the READER state. */
+
+void
+cpp_lt_replay (cpp_reader *reader, cpp_idents_used* identifiers)
+{
+ unsigned int i;
+ unsigned int num_entries = identifiers->num_entries;
+ cpp_ident_use *entries = identifiers->entries;
+ char *buffer = XCNEWVEC (char, identifiers->max_length + 1);
+
+ /* Prevent the lexer from invalidating the tokens we've read so far. */
+ reader->keep_tokens++;
+
+ for (i = 0; i < num_entries; ++i)
+ {
+ cpp_ident_use *entry = entries + i;
+ const char *ident_str = entry->ident_str;
+ const char *before_str = entry->before_str;
+ const char *after_str = entry->after_str;
+ if (before_str == NULL)
+ {
+ if (after_str != NULL)
+ {
+ cpp_lt_define_syntax (buffer, after_str);
+ cpp_define (reader, buffer);
+ }
+ /* else consistently not macros */
+ }
+ else
+ {
+ if (after_str == NULL)
+ {
+ cpp_undef (reader, ident_str);
+ }
+ else if (strcmp (before_str, after_str) != 0)
+ {
+ cpp_undef (reader, ident_str);
+ cpp_lt_define_syntax (buffer, after_str);
+ cpp_define (reader, buffer);
+ }
+ /* else macro with the same definition */
+ }
+ }
+
+ reader->keep_tokens--;
+
+ free (buffer);
+}
+
+/* Mappings from hash to index. */
+#define LT_MASK(order) (~(~0 << (order)))
+#define LT_FIRST(hash, order, mask) (((hash) ^ ((hash) >> (order))) & (mask))
+#define LT_NEXT(index, mask) (((index) + 1) & (mask))
+/* Linear probing. */
+
+static void
+lt_resize (cpp_lookaside *aside, unsigned int old_order, unsigned int new_order)
+{
+ unsigned int old_index;
+ unsigned int old_slots = 1 << old_order;
+ unsigned int new_slots = 1 << new_order;
+ unsigned int new_mask = LT_MASK (new_order);
+ struct lae *old_entries = aside->entries;
+ struct lae *new_entries = XCNEWVEC (struct lae, new_slots);
+ for ( old_index = 0; old_index < old_slots; ++old_index )
+ {
+ hashnode node = old_entries[old_index].node;
+ if (node)
+ {
+ unsigned int hash = old_entries[old_index].hash;
+ unsigned int new_index = LT_FIRST (hash, new_order, new_mask);
+ hashnode probe = new_entries[new_index].node;
+ while (probe)
+ {
+ new_index = LT_NEXT (new_index, new_mask);
+ probe = new_entries[new_index].node;
+ ++aside->bumps;
+ }
+ new_entries[new_index].node = node;
+ new_entries[new_index].hash = hash;
+ new_entries[new_index].length = old_entries[old_index].length;
+ new_entries[new_index].value = old_entries[old_index].value;
+ }
+ }
+ free (old_entries);
+ aside->entries = new_entries;
+ aside->order = new_order;
+ ++aside->resizes;
+}
+
+cpp_hashnode *
+lt_lookup (cpp_reader *pfile,
+ const unsigned char *identifier,
+ size_t length,
+ unsigned int hash)
+{
+ cpp_lookaside *aside = pfile->lookaside_table;
+ /* Compress the hash to an index.
+ Assume there is sufficient entropy in the lowest 2*order bits. */
+ unsigned int order = aside->order;
+ unsigned int mask = LT_MASK (order);
+ unsigned int index = LT_FIRST (hash, order, mask);
+ cpp_hashnode *cpp_node;
+
+ /* Search the lookaside table. */
+ struct lae *entries = aside->entries;
+ hashnode node = entries[index].node;
+ ++aside->searches;
+
+ /* Hashes have no sentinel value, so an entry is empty iff there is
+ a null node value. */
+ while (node)
+ {
+ if (entries[index].hash == hash)
+ {
+ ++aside->comparisons;
+ if (node->len == length)
+ {
+ ++aside->strcmps;
+ if (memcmp (node->str, identifier, length) == 0)
+ return CPP_HASHNODE (node);
+ }
+ }
+
+ ++aside->collisions;
+ index = LT_NEXT (index, mask);
+ node = entries[index].node;
+ }
+
+ ++aside->misses;
+
+ node = ht_lookup_with_hash
+ (pfile->hash_table, identifier, length, hash, HT_ALLOC);
+ cpp_node = CPP_HASHNODE(node);
+
+ /* Do not save macro parameter names; they don't affect verification. */
+ if (cpp_node->flags & NODE_MACRO_ARG)
+ return cpp_node;
+
+ ++aside->insertions;
+
+ /* Fill out new entry. */
+ ++aside->active;
+ entries[index].node = node;
+ entries[index].hash = hash;
+ if (length > aside->max_length)
+ aside->max_length = length;
+
+ /* Capture any macro value. */
+ if (cpp_node->type == NT_MACRO)
+ entries[index].length = lt_macro_value
+ (&entries[index].value, aside, pfile, cpp_node);
+ /* else .value and .length are still zero from initialization. */
+
+ /* Check table load factor. */
+ if (aside->active >= (unsigned)(1 << (order - 1)))
+ /* Table is at least half full; double it. */
+ lt_resize (aside, order, order + 1);
+
+ return cpp_node;
+}
===================================================================
@@ -1515,15 +1515,14 @@ _cpp_save_parameter (cpp_reader *pfile,
((cpp_hashnode **) BUFF_FRONT (pfile->a_buff))[macro->paramc++] = node;
node->flags |= NODE_MACRO_ARG;
- len = macro->paramc * sizeof (union _cpp_hashnode_value);
- if (len > pfile->macro_buffer_len)
+ len = macro->paramc;
+ if (len > pfile->param_buffer_len)
{
- pfile->macro_buffer = XRESIZEVEC (unsigned char, pfile->macro_buffer,
- len);
- pfile->macro_buffer_len = len;
+ pfile->param_buffer = XRESIZEVEC (union _cpp_hashnode_value,
+ pfile->param_buffer, len);
+ pfile->param_buffer_len = len;
}
- ((union _cpp_hashnode_value *) pfile->macro_buffer)[macro->paramc - 1]
- = node->value;
+ pfile->param_buffer[macro->paramc - 1] = node->value;
node->value.arg_index = macro->paramc;
return false;
@@ -1888,7 +1887,7 @@ _cpp_create_definition (cpp_reader *pfil
{
struct cpp_hashnode *node = macro->params[i];
node->flags &= ~ NODE_MACRO_ARG;
- node->value = ((union _cpp_hashnode_value *) pfile->macro_buffer)[i];
+ node->value = pfile->param_buffer[i];
}
if (!ok)
===================================================================
@@ -788,7 +788,7 @@ do_include_common (cpp_reader *pfile, en
pfile->directive->name, fname, angle_brackets,
buf);
- _cpp_stack_include (pfile, fname, angle_brackets, type);
+ _cpp_stack_include (pfile, NULL, fname, angle_brackets, type);
}
XDELETEVEC (fname);
===================================================================
@@ -37,6 +37,7 @@ typedef struct cpp_hashnode cpp_hashnode
typedef struct cpp_macro cpp_macro;
typedef struct cpp_callbacks cpp_callbacks;
typedef struct cpp_dir cpp_dir;
+typedef struct lexer_state lexer_state;
struct answer;
struct _cpp_file;
@@ -607,6 +608,9 @@ enum cpp_builtin_type
BT_LAST_USER = BT_FIRST_USER + 31
};
+/* #include types. */
+enum include_type {IT_INCLUDE, IT_INCLUDE_NEXT, IT_IMPORT, IT_CMDLINE};
+
#define CPP_HASHNODE(HNODE) ((cpp_hashnode *) (HNODE))
#define HT_NODE(NODE) ((ht_identifier *) (NODE))
#define NODE_LEN(NODE) HT_LEN (&(NODE)->ident)
@@ -915,6 +919,8 @@ extern const char *cpp_type2name (enum c
string literal. Handles all relevant diagnostics. */
extern cppchar_t cpp_parse_escape (cpp_reader *, const unsigned char ** pstr,
const unsigned char *limit, int wide);
+extern lexer_state *cpp_reset_lexer_state (cpp_reader *);
+extern void cpp_restore_lexer_state (cpp_reader *, lexer_state *);
/* Structure used to hold a comment block at a given location in the
source code. */
@@ -942,6 +948,27 @@ typedef struct
int allocated;
} cpp_comment_table;
+/* Structure describing an offset into a cpp_buffer. */
+
+typedef struct GTY(()) cpp_offset
+{
+ /* Distance, in bytes, from the start of the buffer to the current
+ character location. */
+ size_t cur;
+
+ /* Distance, in bytes, from the start of the buffer to the start of
+ the current physical line. */
+ size_t line_base;
+
+ /* Distance, in bytes, from the start of the buffer to the start of
+ the next logical line (the start of the to-be-cleaned line). */
+ size_t next_line;
+} cpp_offset;
+
+/* Constants for cpp_get_pos and cpp_set_pos. */
+extern const cpp_offset cpp_buffer_start;
+extern const cpp_offset cpp_buffer_end;
+
/* Returns the table of comments encountered by the preprocessor. This
table is only populated when pfile->state.save_comments is true. */
extern cpp_comment_table *cpp_get_comments (cpp_reader *);
@@ -952,9 +979,18 @@ extern cpp_comment_table *cpp_get_commen
table if it is not already there. */
extern cpp_hashnode *cpp_lookup (cpp_reader *, const unsigned char *,
unsigned int);
+extern cpp_hashnode *cpp_lookup_with_hash
+ (cpp_reader *, const unsigned char *, unsigned int, unsigned int);
+extern cpp_hashnode *cpp_peek_sym (cpp_reader *, const unsigned char *,
+ unsigned int);
+/* In identifiers.c */
typedef int (*cpp_cb) (cpp_reader *, cpp_hashnode *, void *);
extern void cpp_forall_identifiers (cpp_reader *, cpp_cb, void *);
+extern void cpp_dump_identifier (cpp_reader *, FILE *, cpp_hashnode *);
+extern void cpp_debug_identifier (cpp_reader *, cpp_hashnode *);
+extern void cpp_dump_identifiers (cpp_reader *, FILE *);
+extern void cpp_debug_identifiers (cpp_reader *);
/* In macro.c */
extern void cpp_scan_nooutput (cpp_reader *);
@@ -967,6 +1003,8 @@ extern bool cpp_included (cpp_reader *,
extern bool cpp_included_before (cpp_reader *, const char *, source_location);
extern void cpp_make_system_header (cpp_reader *, int, int);
extern bool cpp_push_include (cpp_reader *, const char *);
+extern bool cpp_push_include_type (cpp_reader *, const char *, const char *,
+ bool, enum include_type);
extern void cpp_change_file (cpp_reader *, enum lc_reason, const char *);
extern const char *cpp_get_path (struct _cpp_file *);
extern cpp_dir *cpp_get_dir (struct _cpp_file *);
@@ -974,6 +1012,9 @@ extern cpp_buffer *cpp_get_buffer (cpp_r
extern struct _cpp_file *cpp_get_file (cpp_buffer *);
extern cpp_buffer *cpp_get_prev (cpp_buffer *);
extern void cpp_clear_file_cache (cpp_reader *);
+extern cpp_offset cpp_get_pos (cpp_buffer *);
+extern void cpp_set_pos (cpp_buffer *, cpp_offset);
+extern void cpp_return_at_eof (cpp_buffer *, bool);
/* In pch.c */
struct save_macro_data;
===================================================================
@@ -101,4 +101,87 @@ extern void ht_load (hash_table *ht, has
/* Dump allocation statistics to stderr. */
extern void ht_dump_statistics (hash_table *);
+
+/* A lookaside identifier table for subsets of the token stream. */
+
+typedef struct cpp_lookaside cpp_lookaside;
+
+/* A summary of the identifier uses captured by the lookaside table. */
+
+typedef struct GTY(()) cpp_ident_use
+{
+ unsigned int ident_len;
+ const char *ident_str;
+ unsigned int before_len;
+ const char *before_str;
+ unsigned int after_len;
+ const char *after_str;
+} cpp_ident_use;
+
+typedef struct GTY(()) cpp_idents_used
+{
+ unsigned int max_length;
+ unsigned int num_entries;
+ cpp_ident_use *entries;
+ struct obstack * GTY((skip)) strings;
+} cpp_idents_used;
+
+/* Exchange the reader's current lookaside table with a new table.
+ To deactivate the lookaside table, set it to NULL.
+ The current table is the return value.
+ Clients are responsible for creating and destroying the tables. */
+cpp_lookaside *
+cpp_lt_exchange (struct cpp_reader *pfile, cpp_lookaside *desired);
+
+/* Create the lookaside table. */
+cpp_lookaside *
+cpp_lt_create (unsigned int order, unsigned int debug);
+
+/* Frees all memory associated with a lookaside table. */
+void
+cpp_lt_destroy (cpp_lookaside *table);
+
+/* Captures the current state of the lookaside table,
+ together with macro definition state before and after the table,
+ and then empties the table. */
+cpp_idents_used
+cpp_lt_capture (struct cpp_reader *pfile);
+
+/* Verifies that the previously captured identifiers
+ are consistent with the current state of the reader.
+ If not, set the bad_use and cur_def to indicate the first
+ inconsistency. A null means 'not a macro'. */
+bool
+cpp_lt_verify (struct cpp_reader *reader, cpp_idents_used* identifiers,
+ cpp_ident_use **bad_use, const char **cur_def);
+
+/* Replay the macro definitions captured by the table of identifiers used
+ into the reader state. */
+void
+cpp_lt_replay (struct cpp_reader *reader, cpp_idents_used* identifiers);
+
+/* Query the number of entries in the lookaside table. */
+unsigned int
+cpp_lt_num_entries (cpp_lookaside *table);
+
+/* Query the string length in the lookaside table. */
+unsigned int
+cpp_lt_max_length (cpp_lookaside *table);
+
+/* Take ownership of the obstack holding strings in the lookaside table. */
+struct obstack *
+cpp_lt_take_strings (cpp_lookaside *table);
+
+/* Visit all the entries in the lookaside table. */
+typedef void (*cpp_lookback) (void *passthru,
+ const char *ident_str, unsigned int ident_len,
+ const char *macro_str, unsigned int macro_len);
+void
+cpp_lt_forall (cpp_lookaside *table, cpp_lookback grok, void *passthru);
+
+/* Dump the lookaside table statistics to stderr. */
+void
+cpp_lt_statistics (struct cpp_reader *pfile);
+
+
#endif /* LIBCPP_SYMTAB_H */
===================================================================
@@ -32,6 +32,9 @@ along with this program; see the file CO
#include "md5.h"
#include <dirent.h>
+const cpp_offset cpp_buffer_start = {0, 0, 0};
+const cpp_offset cpp_buffer_end = {-1, -1, -1};
+
/* Variable length record files on VMS will have a stat size that includes
record control characters that won't be included in the read size. */
#ifdef VMS
@@ -174,8 +177,9 @@ static bool find_file_in_dir (cpp_reader
static bool read_file_guts (cpp_reader *pfile, _cpp_file *file);
static bool read_file (cpp_reader *pfile, _cpp_file *file);
static bool should_stack_file (cpp_reader *, _cpp_file *file, bool import);
-static struct cpp_dir *search_path_head (cpp_reader *, const char *fname,
- int angle_brackets, enum include_type);
+static struct cpp_dir *search_path_head (cpp_reader *, const char *dname,
+ const char *fname, int angle_brackets,
+ enum include_type);
static const char *dir_name_of_file (_cpp_file *file);
static void open_file_failed (cpp_reader *pfile, _cpp_file *file, int);
static struct file_hash_entry *search_cache (struct file_hash_entry *head,
@@ -843,11 +847,12 @@ _cpp_mark_file_once_only (cpp_reader *pf
}
/* Return the directory from which searching for FNAME should start,
- considering the directive TYPE and ANGLE_BRACKETS. If there is
- nothing left in the path, returns NULL. */
+ considering the directive TYPE and ANGLE_BRACKETS. If ANGLE_BRACKETS
+ is 0, TYPE is IT_INCLUDE and DNAME is given, it returns a directory
+ entry for DNAME. If there is nothing left in the path, returns NULL. */
static struct cpp_dir *
-search_path_head (cpp_reader *pfile, const char *fname, int angle_brackets,
- enum include_type type)
+search_path_head (cpp_reader *pfile, const char *dname, const char *fname,
+ int angle_brackets, enum include_type type)
{
cpp_dir *dir;
_cpp_file *file;
@@ -873,7 +878,7 @@ search_path_head (cpp_reader *pfile, con
else if (pfile->quote_ignores_source_dir)
dir = pfile->quote_include;
else
- return make_cpp_dir (pfile, dir_name_of_file (file),
+ return make_cpp_dir (pfile, (dname) ? dname : dir_name_of_file (file),
pfile->buffer ? pfile->buffer->sysp : 0);
if (dir == NULL)
@@ -906,13 +911,13 @@ dir_name_of_file (_cpp_file *file)
including HEADER, and the command line -imacros and -include.
Returns true if a buffer was stacked. */
bool
-_cpp_stack_include (cpp_reader *pfile, const char *fname, int angle_brackets,
- enum include_type type)
+_cpp_stack_include (cpp_reader *pfile, const char *dname, const char *fname,
+ int angle_brackets, enum include_type type)
{
struct cpp_dir *dir;
_cpp_file *file;
- dir = search_path_head (pfile, fname, angle_brackets, type);
+ dir = search_path_head (pfile, dname, fname, angle_brackets, type);
if (!dir)
return false;
@@ -1325,7 +1330,7 @@ _cpp_compare_file_date (cpp_reader *pfil
_cpp_file *file;
struct cpp_dir *dir;
- dir = search_path_head (pfile, fname, angle_brackets, IT_INCLUDE);
+ dir = search_path_head (pfile, NULL, fname, angle_brackets, IT_INCLUDE);
if (!dir)
return -1;
@@ -1347,7 +1352,20 @@ _cpp_compare_file_date (cpp_reader *pfil
bool
cpp_push_include (cpp_reader *pfile, const char *fname)
{
- return _cpp_stack_include (pfile, fname, false, IT_CMDLINE);
+ return _cpp_stack_include (pfile, NULL, fname, false, IT_CMDLINE);
+}
+
+/* Pushes the given file onto the buffer stack. Returns true if
+ successful. This is similar to cpp_push_include but it also
+ allows to specify whether a #include, #include_next or #import
+ should be used. If ANGLE_BRACKETS is true, it searches
+ the file in the system include path. */
+bool
+cpp_push_include_type (cpp_reader *pfile, const char *dname,
+ const char *fname, bool angle_brackets,
+ enum include_type itype)
+{
+ return _cpp_stack_include (pfile, dname, fname, angle_brackets, itype);
}
/* Do appropriate cleanup when a file INC's buffer is popped off the
@@ -1825,3 +1843,53 @@ check_file_against_entries (cpp_reader *
return bsearch (&d, pchf->entries, pchf->count, sizeof (struct pchf_entry),
pchf_compare) != NULL;
}
+
+
+/* Return the current position (in bytes) into BUFFER where the next
+ token will be read from. */
+
+cpp_offset
+cpp_get_pos (cpp_buffer *buffer)
+{
+ cpp_offset pos;
+
+ pos.cur = (buffer->cur) ? buffer->cur - buffer->buf : 0;
+ pos.line_base = (buffer->line_base) ? buffer->line_base - buffer->buf : 0;
+ pos.next_line = (buffer->next_line) ? buffer->next_line - buffer->buf : 0;
+
+ return pos;
+}
+
+
+/* Set the current position (in bytes) into BUFFER where the next
+ token should be read from. */
+
+void
+cpp_set_pos (cpp_buffer *buffer, cpp_offset pos)
+{
+ if (pos.cur == cpp_buffer_end.cur)
+ buffer->cur = buffer->line_base = buffer->next_line = buffer->rlimit;
+ else if (pos.cur == cpp_buffer_start.cur)
+ {
+ buffer->cur = buffer->line_base = NULL;
+ buffer->next_line = buffer->buf;
+ }
+ else
+ {
+ buffer->cur = buffer->buf + pos.cur;
+ buffer->line_base = buffer->buf + pos.line_base;
+ buffer->next_line = buffer->buf + pos.next_line;
+ }
+}
+
+
+/* Set the return-at-eof marker for BUFFER to VAL. If VAL is true, a
+ CPP_EOF token will be returned when the reader find the end of
+ file. Otherwise, the reader will transparently continue reading the
+ including file. */
+
+void
+cpp_return_at_eof (cpp_buffer *buffer, bool val)
+{
+ buffer->return_at_eof = val;
+}
===================================================================
@@ -231,10 +231,12 @@ cpp_create_reader (enum c_lang lang, has
_cpp_init_files (pfile);
_cpp_init_hashtable (pfile, table);
+ pfile->lookaside_table = NULL;
return pfile;
}
+
/* Set the line_table entry in PFILE. This is called after reading a
PCH file, as the old line_table will be incorrect. */
void
@@ -268,6 +270,13 @@ cpp_destroy (cpp_reader *pfile)
pfile->macro_buffer_len = 0;
}
+ if (pfile->param_buffer)
+ {
+ free (pfile->param_buffer);
+ pfile->param_buffer = NULL;
+ pfile->param_buffer_len = 0;
+ }
+
if (pfile->deps)
deps_free (pfile->deps);
obstack_free (&pfile->buffer_ob, 0);
===================================================================
@@ -86,22 +86,48 @@ _cpp_destroy_hashtable (cpp_reader *pfil
}
}
+/* Returns the hash entry for the STR of length LEN with hash HASH,
+ creating one if necessary. The return is not NULL. */
+cpp_hashnode *
+cpp_lookup_with_hash (cpp_reader *pfile,
+ const unsigned char *str, unsigned int len,
+ unsigned int hash)
+{
+ cpp_hashnode *n;
+
+ if (pfile->lookaside_table)
+ n = lt_lookup (pfile, str, len, hash);
+ else
+ n = CPP_HASHNODE (ht_lookup_with_hash (pfile->hash_table, str, len,
+ hash, HT_ALLOC));
+
+ return n;
+}
+
/* Returns the hash entry for the STR of length LEN, creating one
- if necessary. */
+ if necessary. The return is not NULL. */
cpp_hashnode *
cpp_lookup (cpp_reader *pfile, const unsigned char *str, unsigned int len)
{
- /* ht_lookup cannot return NULL. */
- return CPP_HASHNODE (ht_lookup (pfile->hash_table, str, len, HT_ALLOC));
+ unsigned int hash = ht_calc_hash (str, len);
+ return cpp_lookup_with_hash (pfile, str, len, hash);
+}
+
+/* Returns the hash entry for STR of length LEN from PFILE's symbol
+ table. If no entry exists, it returns NULL. */
+cpp_hashnode *
+cpp_peek_sym (cpp_reader *pfile, const unsigned char *str, unsigned int len)
+{
+ cpp_hashnode *node;
+ node = CPP_HASHNODE (ht_lookup (pfile->hash_table, str, len, HT_NO_INSERT));
+ return node;
}
/* Determine whether the str STR, of length LEN, is a defined macro. */
int
cpp_defined (cpp_reader *pfile, const unsigned char *str, int len)
{
- cpp_hashnode *node;
-
- node = CPP_HASHNODE (ht_lookup (pfile->hash_table, str, len, HT_NO_INSERT));
+ cpp_hashnode *node = cpp_peek_sym (pfile, str, len);
/* If it's of type NT_MACRO, it cannot be poisoned. */
return node && node->type == NT_MACRO;
@@ -119,3 +145,56 @@ cpp_forall_identifiers (cpp_reader *pfil
{
ht_forall (pfile->hash_table, (ht_cb) cb, v);
}
+
+/* Dump a single identifier in PFILE to FILE. */
+void
+cpp_dump_identifier (cpp_reader *pfile, FILE *file, cpp_hashnode *node)
+{
+ const unsigned char *name;
+ unsigned int len;
+
+ name = NODE_NAME (node);
+ len = NODE_LEN (node);
+
+ fprintf (file, "%.*s ", len, name);
+ if (node->is_directive)
+ fprintf (file, " [directive]");
+
+ if (node->type == NT_MACRO)
+ fprintf (file, " = %s", cpp_macro_definition (pfile, node));
+
+ fprintf (file, "\n");
+}
+
+
+/* Dump a single identifier in PFILE to stderr. */
+void
+cpp_debug_identifier (cpp_reader *pfile, cpp_hashnode *node)
+{
+ cpp_dump_identifier (pfile, stderr, node);
+}
+
+
+/* Callback for cpp_dump_identifiers. */
+static int
+cpp_dump_identifiers_r (cpp_reader *pfile, cpp_hashnode *node, void *data)
+{
+ cpp_dump_identifier (pfile, (FILE *) data, node);
+ return 1;
+}
+
+
+/* Dump all identifiers in PFILE to FILE. */
+void
+cpp_dump_identifiers (cpp_reader *pfile, FILE *file)
+{
+ cpp_forall_identifiers (pfile, cpp_dump_identifiers_r, file);
+}
+
+
+/* Dump all identifiers in PFILE to stderr. */
+void
+cpp_debug_identifiers (cpp_reader *pfile)
+{
+ cpp_dump_identifiers (pfile, stderr);
+}
===================================================================
@@ -115,9 +115,6 @@ extern unsigned char *_cpp_unaligned_all
#define BUFF_FRONT(BUFF) ((BUFF)->cur)
#define BUFF_LIMIT(BUFF) ((BUFF)->limit)
-/* #include types. */
-enum include_type {IT_INCLUDE, IT_INCLUDE_NEXT, IT_IMPORT, IT_CMDLINE};
-
union utoken
{
const cpp_token *token;
@@ -326,6 +323,57 @@ struct def_pragma_macro {
unsigned int is_undef : 1;
};
+
+/* A lookaside identifier table for subsets of the token stream. */
+
+/* The lookaside entry. */
+struct lae {
+ hashnode node; /* The entry in hash_table. */
+ unsigned int hash; /* Hash value. */
+ unsigned int length; /* Macro value length. */
+ const char *value; /* Macro value string. */
+};
+
+/* The lookaside table. */
+struct cpp_lookaside {
+ struct lae *entries; /* The entry storage. */
+ unsigned int order; /* 2^order slots in the entries array. */
+ unsigned int active; /* Number of active entries. */
+ struct obstack *strings; /* For macro value storage. */
+ unsigned int max_length; /* Largest string encountered. */
+
+ /* Table usage statistics. */
+ unsigned long long searches; /* Number of calls to lt_lookup. */
+ unsigned long long comparisons; /* Key comparisons. */
+ unsigned long long strcmps; /* Key comparisons using strcmp. */
+ unsigned long long collisions; /* Found unwanted hash or key. */
+ unsigned long long misses; /* Searches not found in table. */
+ unsigned long long insertions; /* Number insertions in table. */
+ unsigned long long macrovalue; /* Number of macro values computed. */
+ unsigned long long resizes; /* Had to resize (grow) the table. */
+ unsigned long long bumps; /* Collisions in the resize process. */
+ unsigned long long iterations; /* Cells iterated over table. */
+ unsigned long long empties; /* Number of table empty/capture. */
+
+ /* Table debugging. */
+ unsigned int flag_pth_debug;
+};
+
+/* Lookup an identifer in the lookaside table,
+ and failing that, lookup in the main hash table.
+ The return will always be non-null. */
+cpp_hashnode *
+lt_lookup (cpp_reader *pfile,
+ const unsigned char *identifier,
+ size_t length,
+ unsigned int hash);
+
+/* The hash parameter is obtained with the following function,
+ or with the HT_... macros in include/symtab.h. */
+unsigned int
+ht_calc_hash (const unsigned char *str, size_t len);
+
+
/* A cpp_reader encapsulates the "state" of a pre-processor run.
Applying cpp_get_token repeatedly yields a stream of pre-processor
tokens. Usually, there is only one cpp_reader object active. */
@@ -413,6 +461,10 @@ struct cpp_reader
unsigned char *macro_buffer;
unsigned int macro_buffer_len;
+ /* Buffer to save parameter values during macro parameter processing. */
+ union _cpp_hashnode_value *param_buffer;
+ unsigned int param_buffer_len;
+
/* Descriptor for converting from the source character set to the
execution character set. */
struct cset_converter narrow_cset_desc;
@@ -461,6 +513,7 @@ struct cpp_reader
/* Identifier hash table. */
struct ht *hash_table;
+ cpp_lookaside *lookaside_table;
/* Expression parser stack. */
struct op *op_stack, *op_limit;
@@ -574,7 +627,7 @@ extern bool _cpp_find_failed (_cpp_file
extern void _cpp_mark_file_once_only (cpp_reader *, struct _cpp_file *);
extern void _cpp_fake_include (cpp_reader *, const char *);
extern bool _cpp_stack_file (cpp_reader *, _cpp_file*, bool);
-extern bool _cpp_stack_include (cpp_reader *, const char *, int,
+extern bool _cpp_stack_include (cpp_reader *, const char *, const char *, int,
enum include_type);
extern int _cpp_compare_file_date (cpp_reader *, const char *, int);
extern void _cpp_report_missing_guards (cpp_reader *);
===================================================================
@@ -1075,8 +1075,7 @@ lex_identifier_intern (cpp_reader *pfile
}
len = cur - base;
hash = HT_HASHFINISH (hash, len);
- result = CPP_HASHNODE (ht_lookup_with_hash (pfile->hash_table,
- base, len, hash, HT_ALLOC));
+ result = cpp_lookup_with_hash (pfile, base, len, hash);
/* Rarely, identifiers require diagnostics when lexed. */
if (__builtin_expect ((result->flags & NODE_DIAGNOSTIC)
@@ -1151,8 +1150,7 @@ lex_identifier (cpp_reader *pfile, const
len = cur - base;
hash = HT_HASHFINISH (hash, len);
- result = CPP_HASHNODE (ht_lookup_with_hash (pfile->hash_table,
- base, len, hash, HT_ALLOC));
+ result = cpp_lookup_with_hash (pfile, base, len, hash);
}
/* Rarely, identifiers require diagnostics when lexed. */
@@ -1795,6 +1793,7 @@ _cpp_lex_token (cpp_reader *pfile)
{
cpp_token *result;
+ result = NULL;
for (;;)
{
if (pfile->cur_token == pfile->cur_run->limit)
@@ -2836,3 +2835,27 @@ cpp_token_val_index (cpp_token *tok)
return CPP_TOKEN_FLD_NONE;
}
}
+
+/* Reset the lexer state in PFILE and return its previous setting. */
+
+lexer_state *
+cpp_reset_lexer_state (cpp_reader *pfile)
+{
+ lexer_state *s;
+
+ s = (lexer_state *) xmalloc (sizeof (lexer_state));
+ memcpy (s, &pfile->state, sizeof (pfile->state));
+ memset (&pfile->state, 0, sizeof (pfile->state));
+
+ return s;
+}
+
+
+/* Restore the lexer state in PFILE to S. */
+
+void
+cpp_restore_lexer_state (cpp_reader *pfile, lexer_state *s)
+{
+ memcpy (&pfile->state, s, sizeof (pfile->state));
+ free (s);
+}
===================================================================
@@ -1676,8 +1676,7 @@ _cpp_interpret_identifier (cpp_reader *p
}
}
- return CPP_HASHNODE (ht_lookup (pfile->hash_table,
- buf, bufp - buf, HT_ALLOC));
+ return cpp_lookup (pfile, buf, bufp - buf);
}
/* Convert an input buffer (containing the complete contents of one