From 5de859e40230f447d73e4f37870dc764a7569588 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Tue, 5 Nov 2002 12:28:40 +0000 Subject: [PATCH] Replace class List_Node with class KeywordExt. --- ChangeLog | 17 +++ src/Makefile.in | 13 +-- src/gen-perf.cc | 86 +++++++++------ src/gen-perf.h | 6 +- src/hash-table.cc | 8 +- src/hash-table.h | 10 +- src/key-list.cc | 262 +++++++++++++++++++++++--------------------- src/key-list.h | 14 +-- src/keyword-list.cc | 29 +++++ src/keyword-list.h | 44 ++++++++ src/keyword.cc | 72 ++++++++++++ src/keyword.h | 6 + src/options.cc | 2 +- src/read-line.icc | 8 +- 14 files changed, 387 insertions(+), 190 deletions(-) create mode 100644 src/keyword-list.cc create mode 100644 src/keyword-list.h diff --git a/ChangeLog b/ChangeLog index 08a0681..6fe8cca 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,22 @@ 2002-10-03 Bruno Haible + * src/keyword-list.h: New file. + * src/keyword-list.cc: New file. + * src/list-node.h: Remove file. + * src/list-node.cc: Remove file. + * src/keyword.h (KeywordExt::init_selchars): New declaration. + * src/keyword.cc (sort_char_set, KeywordExt::init_selchars): New, from + old list-node.cc. + * src/gen-perf.cc: Replace List_Node by KeywordExt or KeywordExt_List, + as appropriate. + * src/hash-table.h: Likewise. + * src/key-list.h: Likewise. + * src/key-list.cc: Likewise. + * src/Makefile.in (OBJECTS): Remove list-node.o, add keyword-list.o. + (LIST_NODE_H): Remove macro. + (list-node.o): Remove rule. + (keyword-list.o): New rule. + * src/keyword.h (KeywordExt): New class. * src/keyword.cc (KeywordExt): New constructor. * src/list-node.h (List_Node): Inherit from KeywordExt. diff --git a/src/Makefile.in b/src/Makefile.in index bee850d..892849d 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -59,9 +59,9 @@ SHELL = /bin/sh VPATH = $(srcdir) -OBJECTS = options.o iterator.o main.o gen-perf.o key-list.o list-node.o \ +OBJECTS = options.o iterator.o main.o gen-perf.o key-list.o \ hash-table.o bool-array.o read-line.o vectors.o version.o \ - keyword.o + keyword.o keyword-list.o LIBS = ../lib/libgp.a @GPERF_LIBM@ CPPFLAGS = -I. -I$(srcdir)/../lib @@ -87,10 +87,9 @@ VERSION_H = version.h VECTORS_H = vectors.h READ_LINE_H = read-line.h read-line.icc OPTIONS_H = options.h options.icc -LIST_NODE_H = list-node.h $(VECTORS_H) -KEY_LIST_H = key-list.h $(LIST_NODE_H) $(VECTORS_H) $(READ_LINE_H) +KEY_LIST_H = key-list.h $(VECTORS_H) $(READ_LINE_H) ITERATOR_H = iterator.h -HASH_TABLE_H = hash-table.h $(LIST_NODE_H) +HASH_TABLE_H = hash-table.h BOOL_ARRAY_H = bool-array.h bool-array.icc $(OPTIONS_H) GEN_PERF_H = gen-perf.h $(KEY_LIST_H) $(BOOL_ARRAY_H) @@ -104,8 +103,6 @@ iterator.o : iterator.cc $(ITERATOR_H) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/iterator.cc key-list.o : key-list.cc $(KEY_LIST_H) $(OPTIONS_H) $(READ_LINE_H) $(HASH_TABLE_H) $(VERSION_H) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/key-list.cc -list-node.o : list-node.cc $(LIST_NODE_H) $(OPTIONS_H) - $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/list-node.cc main.o : main.cc $(OPTIONS_H) $(GEN_PERF_H) $(CONFIG_H) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/main.cc options.o : options.cc $(OPTIONS_H) $(ITERATOR_H) $(VECTORS_H) $(VERSION_H) @@ -118,6 +115,8 @@ version.o : version.cc $(VERSION_H) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/version.cc keyword.o : keyword.cc keyword.h $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/keyword.cc +keyword-list.o : keyword-list.cc keyword-list.h + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/keyword-list.cc install : all force $(MKINSTALLDIRS) $(DESTDIR)$(bindir) diff --git a/src/gen-perf.cc b/src/gen-perf.cc index 0dd1681..c950ce9 100644 --- a/src/gen-perf.cc +++ b/src/gen-perf.cc @@ -148,7 +148,7 @@ Gen_Perf::sort_set (char *union_set, int len) /* Generate a key set's hash value. */ inline int -Gen_Perf::hash (List_Node *key_node) +Gen_Perf::hash (KeywordExt *key_node) { int sum = option[NOLENGTH] ? 0 : key_node->allchars_length; @@ -167,7 +167,7 @@ Gen_Perf::hash (List_Node *key_node) Option.Get_Jump was forced to be an odd value! */ inline int -Gen_Perf::affects_prev (char c, List_Node *curr) +Gen_Perf::affects_prev (char c, KeywordExt *curr) { int original_char = asso_values[(unsigned char)c]; int total_iterations = !option[FAST] @@ -189,16 +189,20 @@ Gen_Perf::affects_prev (char c, List_Node *curr) /* See how this asso_value change affects previous keywords. If it does better than before we'll take it! */ - for (List_Node *ptr = head; - !collision_detector->set_bit (hash (ptr)) || ++collisions < fewest_collisions; - ptr = ptr->next) - if (ptr == curr) - { - fewest_collisions = collisions; - if (option[DEBUG]) - fprintf (stderr, "- resolved after %d iterations", total_iterations - i); - return 0; - } + for (KeywordExt_List *ptr = head; ; ptr = ptr->rest()) + { + KeywordExt *keyword = ptr->first(); + if (collision_detector->set_bit (hash (keyword)) + && ++collisions >= fewest_collisions) + break; + if (keyword == curr) + { + fewest_collisions = collisions; + if (option[DEBUG]) + fprintf (stderr, "- resolved after %d iterations", total_iterations - i); + return 0; + } + } } /* Restore original values, no more tries. */ @@ -210,7 +214,7 @@ Gen_Perf::affects_prev (char c, List_Node *curr) /* Change a character value, try least-used characters first. */ void -Gen_Perf::change (List_Node *prior, List_Node *curr) +Gen_Perf::change (KeywordExt *prior, KeywordExt *curr) { static char *union_set; int union_set_length; @@ -247,8 +251,13 @@ Gen_Perf::change (List_Node *prior, List_Node *curr) return; /* Good, doesn't affect previous hash values, we'll take it. */ } - for (List_Node *ptr = head; ptr != curr; ptr = ptr->next) - hash (ptr); + for (KeywordExt_List *ptr = head; ; ptr = ptr->rest()) + { + KeywordExt* keyword = ptr->first(); + if (keyword == curr) + break; + hash (keyword); + } hash (curr); @@ -275,17 +284,23 @@ Gen_Perf::change (List_Node *prior, List_Node *curr) int Gen_Perf::doit_all (void) { - List_Node *curr; - for (curr = head; curr; curr = curr->next) + KeywordExt_List *curr; + for (curr = head; curr != NULL; curr = curr->rest()) { - hash (curr); + KeywordExt *currkw = curr->first(); - for (List_Node *ptr = head; ptr != curr; ptr = ptr->next) - if (ptr->hash_value == curr->hash_value) - { - change (ptr, curr); - break; - } + hash (currkw); + + for (KeywordExt_List *ptr = head; ptr != curr; ptr = ptr->rest()) + { + KeywordExt *ptrkw = ptr->first(); + + if (ptrkw->hash_value == currkw->hash_value) + { + change (ptrkw, currkw); + break; + } + } num_done++; } @@ -293,16 +308,23 @@ Gen_Perf::doit_all (void) collision_detector->clear (); - for (curr = head; curr; curr = curr->next) - if (collision_detector->set_bit (hash (curr))) - if (option[DUP]) /* Keep track of this number... */ - total_duplicates++; - else /* Yow, big problems. we're outta here! */ + for (curr = head; curr; curr = curr->rest()) + { + unsigned int hashcode = hash (curr->first()); + if (collision_detector->set_bit (hashcode)) { - fprintf (stderr, "\nInternal error, duplicate value %d:\n" - "try options -D or -r, or use new key positions.\n\n", hash (curr)); - return 1; + if (option[DUP]) /* Keep track of this number... */ + total_duplicates++; + else /* Yow, big problems. we're outta here! */ + { + fprintf (stderr, + "\nInternal error, duplicate value %d:\n" + "try options -D or -r, or use new key positions.\n\n", + hashcode); + return 1; + } } + } /* Sorts the key word list by hash value, and then outputs the list. The generated hash table code is only output if the early stage of diff --git a/src/gen-perf.h b/src/gen-perf.h index 144020b..a7c5eca 100644 --- a/src/gen-perf.h +++ b/src/gen-perf.h @@ -36,9 +36,9 @@ private: int num_done; /* Number of keywords processed without a collision. */ Bool_Array *collision_detector; - void change (List_Node *prior, List_Node *curr); - int affects_prev (char c, List_Node *curr); - static int hash (List_Node *key_node); + void change (KeywordExt *prior, KeywordExt *curr); + int affects_prev (char c, KeywordExt *curr); + static int hash (KeywordExt *key_node); static int compute_disjoint_union (const char *set_1, int size_1, const char *set_2, int size_2, char *set_3); static void sort_set (char *union_set, int len); diff --git a/src/hash-table.cc b/src/hash-table.cc index c37d666..c058b51 100644 --- a/src/hash-table.cc +++ b/src/hash-table.cc @@ -34,7 +34,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ This compromises information hiding somewhat, but greatly reduces memory fragmentation, since we can now use alloca! */ -Hash_Table::Hash_Table (List_Node **table_ptr, int s, int ignore_len): +Hash_Table::Hash_Table (KeywordExt **table_ptr, int s, int ignore_len): table (table_ptr), size (s), collisions (0), ignore_length (ignore_len) { memset ((char *) table, 0, size * sizeof (*table)); @@ -68,8 +68,8 @@ Hash_Table::~Hash_Table (void) in the table. Otherwise inserts the ITEM, and returns FALSE. Uses double hashing. */ -List_Node * -Hash_Table::insert (List_Node *item) +KeywordExt * +Hash_Table::insert (KeywordExt *item) { unsigned hash_val = hashpjw (item->selchars, item->selchars_length); int probe = hash_val & (size - 1); @@ -87,5 +87,5 @@ Hash_Table::insert (List_Node *item) } table[probe] = item; - return (List_Node *) 0; + return NULL; } diff --git a/src/hash-table.h b/src/hash-table.h index 86438d0..5bff139 100644 --- a/src/hash-table.h +++ b/src/hash-table.h @@ -2,7 +2,7 @@ /* Hash table used to check for duplicate keyword entries. - Copyright (C) 1989-1998, 2000 Free Software Foundation, Inc. + Copyright (C) 1989-1998, 2000, 2002 Free Software Foundation, Inc. written by Douglas C. Schmidt (schmidt@ics.uci.edu) This file is part of GNU GPERF. @@ -24,20 +24,20 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #ifndef hash_table_h #define hash_table_h 1 -#include "list-node.h" +#include "keyword.h" class Hash_Table { private: - List_Node **table; /* Vector of pointers to linked lists of List_Node's. */ + KeywordExt **table; /* Vector of pointers to linked lists of keywords. */ int size; /* Size of the vector. */ int collisions; /* Find out how well our double hashing is working! */ int ignore_length; public: - Hash_Table (List_Node **t, int s, int ignore_len); + Hash_Table (KeywordExt **t, int s, int ignore_len); ~Hash_Table (void); - List_Node *insert (List_Node *item); + KeywordExt *insert (KeywordExt *item); }; #endif diff --git a/src/key-list.cc b/src/key-list.cc index 23d1206..2614322 100644 --- a/src/key-list.cc +++ b/src/key-list.cc @@ -203,9 +203,10 @@ Key_List::set_output_types (void) } } -/* Extracts a key from an input line and creates a new List_Node for it. */ +/* Extracts a key from an input line and creates a new KeywordExt_List for + it. */ -static List_Node * +static KeywordExt_List * parse_line (const char *line, const char *delimiters) { if (*line == '"') @@ -324,7 +325,7 @@ parse_line (const char *line, const char *delimiters) } lp++; } - return new List_Node (key, kp - key, option[TYPE] ? lp : ""); + return new KeywordExt_List (key, kp - key, option[TYPE] ? lp : ""); } else { @@ -337,7 +338,7 @@ parse_line (const char *line, const char *delimiters) else /* Skip the first delimiter. */ rest = &line[len + 1]; - return new List_Node (line, len, option[TYPE] ? rest : ""); + return new KeywordExt_List (line, len, option[TYPE] ? rest : ""); } } @@ -364,15 +365,18 @@ Key_List::read_keys (void) else { const char *delimiter = option.get_delimiter (); - List_Node *temp, *trail = 0; + KeywordExt_List *temp; + KeywordExt_List *trail = NULL; head = parse_line (ptr, delimiter); + head->first()->init_selchars(this); for (temp = head; (ptr = Read_Line::read_next_line ()) && strcmp (ptr, "%%"); - temp = temp->next) + temp = temp->rest()) { - temp->next = parse_line (ptr, delimiter); + temp->rest() = parse_line (ptr, delimiter); + temp->rest()->first()->init_selchars(this); total_keys++; } @@ -383,7 +387,7 @@ Key_List::read_keys (void) /* Hash table this number of times larger than keyword number. */ int table_size = (list_len = total_keys) * TABLE_MULTIPLE; /* Table must be a power of 2 for the hash function scheme to work. */ - List_Node **table = new List_Node*[POW (table_size)]; + KeywordExt **table = new KeywordExt*[POW (table_size)]; /* Make large hash table for efficiency. */ Hash_Table found_link (table, table_size, option[NOLENGTH]); @@ -391,38 +395,39 @@ Key_List::read_keys (void) /* Test whether there are any links and also set the maximum length of an identifier in the keyword list. */ - for (temp = head; temp; temp = temp->next) + for (temp = head; temp; temp = temp->rest()) { - List_Node *ptr = found_link.insert (temp); + KeywordExt *keyword = temp->first(); + KeywordExt *other_keyword = found_link.insert (keyword); /* Check for links. We deal with these by building an equivalence class of all duplicate values (i.e., links) so that only 1 keyword is representative of the entire collection. This *greatly* simplifies processing during later stages of the program. */ - if (ptr) + if (other_keyword) { total_duplicates++; list_len--; - trail->next = temp->next; - temp->duplicate_link = ptr->duplicate_link; - ptr->duplicate_link = temp; + trail->rest() = temp->rest(); + temp->first()->duplicate_link = other_keyword->duplicate_link; + other_keyword->duplicate_link = temp->first(); /* Complain if user hasn't enabled the duplicate option. */ if (!option[DUP] || option[DEBUG]) fprintf (stderr, "Key link: \"%.*s\" = \"%.*s\", with key set \"%.*s\".\n", - temp->allchars_length, temp->allchars, - ptr->allchars_length, ptr->allchars, - temp->selchars_length, temp->selchars); + keyword->allchars_length, keyword->allchars, + other_keyword->allchars_length, other_keyword->allchars, + keyword->selchars_length, keyword->selchars); } else trail = temp; /* Update minimum and maximum keyword length, if needed. */ - if (max_key_len < temp->allchars_length) - max_key_len = temp->allchars_length; - if (min_key_len > temp->allchars_length) - min_key_len = temp->allchars_length; + if (max_key_len < keyword->allchars_length) + max_key_len = keyword->allchars_length; + if (min_key_len > keyword->allchars_length) + min_key_len = keyword->allchars_length; } delete[] table; @@ -458,11 +463,11 @@ Key_List::read_keys (void) almost identical code without incurring the overhead of a function call comparison. */ -List_Node * -Key_List::merge (List_Node *list1, List_Node *list2) +KeywordExt_List * +Key_List::merge (KeywordExt_List *list1, KeywordExt_List *list2) { - List_Node *result; - List_Node **resultp = &result; + KeywordExt_List *result; + KeywordExt_List **resultp = &result; for (;;) { if (!list1) @@ -475,16 +480,16 @@ Key_List::merge (List_Node *list1, List_Node *list2) *resultp = list1; break; } - if (occurrence_sort && list1->occurrence < list2->occurrence - || hash_sort && list1->hash_value > list2->hash_value) + if (occurrence_sort && list1->first()->occurrence < list2->first()->occurrence + || hash_sort && list1->first()->hash_value > list2->first()->hash_value) { *resultp = list2; - resultp = &list2->next; list2 = list1; list1 = *resultp; + resultp = &list2->rest(); list2 = list1; list1 = *resultp; } else { *resultp = list1; - resultp = &list1->next; list1 = *resultp; + resultp = &list1->rest(); list1 = *resultp; } } return result; @@ -493,26 +498,26 @@ Key_List::merge (List_Node *list1, List_Node *list2) /* Applies the merge sort algorithm to recursively sort the key list by frequency of occurrence of elements in the key set. */ -List_Node * -Key_List::merge_sort (List_Node *head) +KeywordExt_List * +Key_List::merge_sort (KeywordExt_List *head) { - if (!head || !head->next) + if (!head || !head->rest()) return head; else { - List_Node *middle = head; - List_Node *temp = head->next->next; + KeywordExt_List *middle = head; + KeywordExt_List *temp = head->rest()->rest(); while (temp) { - temp = temp->next; - middle = middle->next; + temp = temp->rest(); + middle = middle->rest(); if (temp) - temp = temp->next; + temp = temp->rest(); } - temp = middle->next; - middle->next = 0; + temp = middle->rest(); + middle->rest() = 0; return merge (merge_sort (head), merge_sort (temp)); } } @@ -520,7 +525,7 @@ Key_List::merge_sort (List_Node *head) /* Returns the frequency of occurrence of elements in the key set. */ inline int -Key_List::get_occurrence (List_Node *ptr) +Key_List::get_occurrence (KeywordExt *ptr) { int value = 0; @@ -536,7 +541,7 @@ Key_List::get_occurrence (List_Node *ptr) determined. */ inline void -Key_List::set_determined (List_Node *ptr) +Key_List::set_determined (KeywordExt *ptr) { const char *p = ptr->selchars; unsigned int i = ptr->selchars_length; @@ -547,7 +552,7 @@ Key_List::set_determined (List_Node *ptr) /* Returns TRUE if PTR's key set is already completely determined. */ inline int -Key_List::already_determined (List_Node *ptr) +Key_List::already_determined (KeywordExt *ptr) { int is_determined = 1; @@ -568,32 +573,36 @@ Key_List::already_determined (List_Node *ptr) void Key_List::reorder (void) { - List_Node *ptr; - for (ptr = head; ptr; ptr = ptr->next) - ptr->occurrence = get_occurrence (ptr); + KeywordExt_List *ptr; + for (ptr = head; ptr; ptr = ptr->rest()) + { + KeywordExt *keyword = ptr->first(); + + keyword->occurrence = get_occurrence (keyword); + } hash_sort = 0; occurrence_sort = 1; - for (ptr = head = merge_sort (head); ptr->next; ptr = ptr->next) + head = merge_sort (head); + + for (ptr = head; ptr->rest(); ptr = ptr->rest()) { - set_determined (ptr); + set_determined (ptr->first()); - if (already_determined (ptr->next)) - continue; - else + if (!already_determined (ptr->rest()->first())) { - List_Node *trail_ptr = ptr->next; - List_Node *run_ptr = trail_ptr->next; + KeywordExt_List *trail_ptr = ptr->rest(); + KeywordExt_List *run_ptr = trail_ptr->rest(); - for (; run_ptr; run_ptr = trail_ptr->next) + for (; run_ptr; run_ptr = trail_ptr->rest()) { - if (already_determined (run_ptr)) + if (already_determined (run_ptr->first())) { - trail_ptr->next = run_ptr->next; - run_ptr->next = ptr->next; - ptr = ptr->next = run_ptr; + trail_ptr->rest() = run_ptr->rest(); + run_ptr->rest() = ptr->rest(); + ptr = ptr->rest() = run_ptr; } else trail_ptr = run_ptr; @@ -647,12 +656,12 @@ static const char *char_to_index; void Key_List::compute_min_max (void) { - List_Node *temp; - for (temp = head; temp->next; temp = temp->next) + KeywordExt_List *temp; + for (temp = head; temp->rest(); temp = temp->rest()) ; - min_hash_value = head->hash_value; - max_hash_value = temp->hash_value; + min_hash_value = head->first()->hash_value; + max_hash_value = temp->first()->hash_value; } /* ------------------------------------------------------------------------- */ @@ -663,15 +672,14 @@ int Key_List::num_hash_values (void) { int count = 1; - List_Node *temp; + KeywordExt_List *temp; int value; - for (temp = head, value = temp->hash_value; temp->next; ) + for (temp = head, value = temp->first()->hash_value; (temp = temp->rest()) != NULL; ) { - temp = temp->next; - if (value != temp->hash_value) + if (value != temp->first()->hash_value) { - value = temp->hash_value; + value = temp->first()->hash_value; count++; } } @@ -1135,7 +1143,7 @@ Key_List::output_keylength_table (void) int index; int column; const char *indent = option[GLOBAL] ? "" : " "; - List_Node *temp; + KeywordExt_List *temp; printf ("%sstatic %s%s lengthtable[] =\n%s {", indent, const_readonly_array, @@ -1145,17 +1153,17 @@ Key_List::output_keylength_table (void) /* Generate an array of lengths, similar to output_keyword_table. */ column = 0; - for (temp = head, index = 0; temp; temp = temp->next) + for (temp = head, index = 0; temp; temp = temp->rest()) { if (option[SWITCH] && !option[TYPE] - && !(temp->duplicate_link - || (temp->next && temp->hash_value == temp->next->hash_value))) + && !(temp->first()->duplicate_link + || (temp->rest() && temp->first()->hash_value == temp->rest()->first()->hash_value))) continue; - if (index < temp->hash_value && !option[SWITCH] && !option[DUP]) + if (index < temp->first()->hash_value && !option[SWITCH] && !option[DUP]) { /* Some blank entries. */ - for ( ; index < temp->hash_value; index++) + for ( ; index < temp->first()->hash_value; index++) { if (index > 0) printf (","); @@ -1169,11 +1177,11 @@ Key_List::output_keylength_table (void) printf (","); if ((column++ % columns) == 0) printf("\n%s ", indent); - printf ("%3d", temp->allchars_length); + printf ("%3d", temp->first()->allchars_length); /* Deal with links specially. */ - if (temp->duplicate_link) // implies option[DUP] - for (KeywordExt *links = temp->duplicate_link; links; links = links->duplicate_link) + if (temp->first()->duplicate_link) // implies option[DUP] + for (KeywordExt *links = temp->first()->duplicate_link; links; links = links->duplicate_link) { ++index; printf (","); @@ -1253,7 +1261,7 @@ Key_List::output_keyword_table (void) { const char *indent = option[GLOBAL] ? "" : " "; int index; - List_Node *temp; + KeywordExt_List *temp; printf ("%sstatic ", indent); @@ -1265,31 +1273,31 @@ Key_List::output_keyword_table (void) /* Generate an array of reserved words at appropriate locations. */ - for (temp = head, index = 0; temp; temp = temp->next) + for (temp = head, index = 0; temp; temp = temp->rest()) { if (option[SWITCH] && !option[TYPE] - && !(temp->duplicate_link - || (temp->next && temp->hash_value == temp->next->hash_value))) + && !(temp->first()->duplicate_link + || (temp->rest() && temp->first()->hash_value == temp->rest()->first()->hash_value))) continue; if (index > 0) printf (",\n"); - if (index < temp->hash_value && !option[SWITCH] && !option[DUP]) + if (index < temp->first()->hash_value && !option[SWITCH] && !option[DUP]) { /* Some blank entries. */ - output_keyword_blank_entries (temp->hash_value - index, indent); + output_keyword_blank_entries (temp->first()->hash_value - index, indent); printf (",\n"); - index = temp->hash_value; + index = temp->first()->hash_value; } - temp->final_index = index; + temp->first()->final_index = index; - output_keyword_entry (temp, indent); + output_keyword_entry (temp->first(), indent); /* Deal with links specially. */ - if (temp->duplicate_link) // implies option[DUP] - for (KeywordExt *links = temp->duplicate_link; links; links = links->duplicate_link) + if (temp->first()->duplicate_link) // implies option[DUP] + for (KeywordExt *links = temp->first()->duplicate_link; links; links = links->duplicate_link) { links->final_index = ++index; printf (",\n"); @@ -1336,24 +1344,24 @@ Key_List::output_lookup_array (void) /* Now dup_ptr = &duplicates[0] and lookup_ptr = &lookup_array[0]. */ - for (List_Node *temp = head; temp; temp = temp->next) + for (KeywordExt_List *temp = head; temp; temp = temp->rest()) { - int hash_value = temp->hash_value; - lookup_array[hash_value] = temp->final_index; + int hash_value = temp->first()->hash_value; + lookup_array[hash_value] = temp->first()->final_index; if (option[DEBUG]) fprintf (stderr, "keyword = %.*s, index = %d\n", - temp->allchars_length, temp->allchars, temp->final_index); - if (temp->duplicate_link - || (temp->next && hash_value == temp->next->hash_value)) + temp->first()->allchars_length, temp->first()->allchars, temp->first()->final_index); + if (temp->first()->duplicate_link + || (temp->rest() && hash_value == temp->rest()->first()->hash_value)) { /* Start a duplicate entry. */ dup_ptr->hash_value = hash_value; - dup_ptr->index = temp->final_index; + dup_ptr->index = temp->first()->final_index; dup_ptr->count = 1; for (;;) { - for (KeywordExt *ptr = temp->duplicate_link; ptr; ptr = ptr->duplicate_link) + for (KeywordExt *ptr = temp->first()->duplicate_link; ptr; ptr = ptr->duplicate_link) { dup_ptr->count++; if (option[DEBUG]) @@ -1362,15 +1370,15 @@ Key_List::output_lookup_array (void) ptr->allchars_length, ptr->allchars, ptr->final_index); } - if (!(temp->next && hash_value == temp->next->hash_value)) + if (!(temp->rest() && hash_value == temp->rest()->first()->hash_value)) break; - temp = temp->next; + temp = temp->rest(); dup_ptr->count++; if (option[DEBUG]) fprintf (stderr, "dynamic linked keyword = %.*s, index = %d\n", - temp->allchars_length, temp->allchars, temp->final_index); + temp->first()->allchars_length, temp->first()->allchars, temp->first()->final_index); } assert (dup_ptr->count >= 2); dup_ptr++; @@ -1497,29 +1505,29 @@ Key_List::output_lookup_tables (void) /* Output a single switch case (including duplicates). Advance list. */ -static List_Node * -output_switch_case (List_Node *list, int indent, int *jumps_away) +static KeywordExt_List * +output_switch_case (KeywordExt_List *list, int indent, int *jumps_away) { if (option[DEBUG]) printf ("%*s/* hash value = %4d, keyword = \"%.*s\" */\n", - indent, "", list->hash_value, list->allchars_length, list->allchars); + indent, "", list->first()->hash_value, list->first()->allchars_length, list->first()->allchars); if (option[DUP] - && (list->duplicate_link - || (list->next && list->hash_value == list->next->hash_value))) + && (list->first()->duplicate_link + || (list->rest() && list->first()->hash_value == list->rest()->first()->hash_value))) { if (option[LENTABLE]) printf ("%*slengthptr = &lengthtable[%d];\n", - indent, "", list->final_index); + indent, "", list->first()->final_index); printf ("%*swordptr = &%s[%d];\n", - indent, "", option.get_wordlist_name (), list->final_index); + indent, "", option.get_wordlist_name (), list->first()->final_index); int count = 0; - for (List_Node *temp = list; ; temp = temp->next) + for (KeywordExt_List *temp = list; ; temp = temp->rest()) { - for (KeywordExt *links = temp; links; links = links->duplicate_link) + for (KeywordExt *links = temp->first(); links; links = links->duplicate_link) count++; - if (!(temp->next && temp->hash_value == temp->next->hash_value)) + if (!(temp->rest() && temp->first()->hash_value == temp->rest()->first()->hash_value)) break; } @@ -1535,16 +1543,16 @@ output_switch_case (List_Node *list, int indent, int *jumps_away) { printf ("%*sif (len == %d)\n" "%*s {\n", - indent, "", list->allchars_length, + indent, "", list->first()->allchars_length, indent, ""); indent += 4; } printf ("%*sresword = ", indent, ""); if (option[TYPE]) - printf ("&%s[%d]", option.get_wordlist_name (), list->final_index); + printf ("&%s[%d]", option.get_wordlist_name (), list->first()->final_index); else - output_string (list->allchars, list->allchars_length); + output_string (list->first()->allchars, list->first()->allchars_length); printf (";\n"); printf ("%*sgoto compare;\n", indent, ""); @@ -1558,9 +1566,9 @@ output_switch_case (List_Node *list, int indent, int *jumps_away) *jumps_away = 1; } - while (list->next && list->hash_value == list->next->hash_value) - list = list->next; - list = list->next; + while (list->rest() && list->first()->hash_value == list->rest()->first()->hash_value) + list = list->rest(); + list = list->rest(); return list; } @@ -1568,7 +1576,7 @@ output_switch_case (List_Node *list, int indent, int *jumps_away) where 0 < num_switches <= size. */ static void -output_switches (List_Node *list, int num_switches, int size, int min_hash_value, int max_hash_value, int indent) +output_switches (KeywordExt_List *list, int num_switches, int size, int min_hash_value, int max_hash_value, int indent) { if (option[DEBUG]) printf ("%*s/* know %d <= key <= %d, contains %d cases */\n", @@ -1581,27 +1589,27 @@ output_switches (List_Node *list, int num_switches, int size, int min_hash_value int size1 = (int)((double)size / (double)num_switches * (double)part1 + 0.5); int size2 = size - size1; - List_Node *temp = list; + KeywordExt_List *temp = list; for (int count = size1; count > 0; count--) { - while (temp->hash_value == temp->next->hash_value) - temp = temp->next; - temp = temp->next; + while (temp->first()->hash_value == temp->rest()->first()->hash_value) + temp = temp->rest(); + temp = temp->rest(); } printf ("%*sif (key < %d)\n" "%*s {\n", - indent, "", temp->hash_value, + indent, "", temp->first()->hash_value, indent, ""); - output_switches (list, part1, size1, min_hash_value, temp->hash_value-1, indent+4); + output_switches (list, part1, size1, min_hash_value, temp->first()->hash_value-1, indent+4); printf ("%*s }\n" "%*selse\n" "%*s {\n", indent, "", indent, "", indent, ""); - output_switches (temp, part2, size2, temp->hash_value, max_hash_value, indent+4); + output_switches (temp, part2, size2, temp->first()->hash_value, max_hash_value, indent+4); printf ("%*s }\n", indent, ""); @@ -1609,7 +1617,7 @@ output_switches (List_Node *list, int num_switches, int size, int min_hash_value else { /* Output a single switch. */ - int lowest_case_value = list->hash_value; + int lowest_case_value = list->first()->hash_value; if (size == 1) { int jumps_away = 0; @@ -1640,7 +1648,7 @@ output_switches (List_Node *list, int num_switches, int size, int min_hash_value { int jumps_away = 0; printf ("%*s case %d:\n", - indent, "", list->hash_value - lowest_case_value); + indent, "", list->first()->hash_value - lowest_case_value); list = output_switch_case (list, indent+6, &jumps_away); if (!jumps_away) printf ("%*s break;\n", @@ -2066,11 +2074,11 @@ Key_List::dump () fprintf (stderr, "\nList contents are:\n(hash value, key length, index, %*s, keyword):\n", field_width, "selchars"); - for (List_Node *ptr = head; ptr; ptr = ptr->next) + for (KeywordExt_List *ptr = head; ptr; ptr = ptr->rest()) fprintf (stderr, "%11d,%11d,%6d, %*.*s, %.*s\n", - ptr->hash_value, ptr->allchars_length, ptr->final_index, - field_width, ptr->selchars_length, ptr->selchars, - ptr->allchars_length, ptr->allchars); + ptr->first()->hash_value, ptr->first()->allchars_length, ptr->first()->final_index, + field_width, ptr->first()->selchars_length, ptr->first()->selchars, + ptr->first()->allchars_length, ptr->first()->allchars); } /* Simple-minded constructor action here... */ diff --git a/src/key-list.h b/src/key-list.h index 98b8fa5..8efc3a5 100644 --- a/src/key-list.h +++ b/src/key-list.h @@ -29,7 +29,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #ifndef key_list_h #define key_list_h 1 -#include "list-node.h" +#include "keyword-list.h" #include "vectors.h" #include "read-line.h" @@ -54,12 +54,12 @@ private: int list_len; /* Length of head's Key_List, not counting duplicates. */ int total_keys; /* Total number of keys, counting duplicates. */ static int determined[MAX_ALPHA_SIZE]; /* Used in function reorder, below. */ - static int get_occurrence (List_Node *ptr); + static int get_occurrence (KeywordExt *ptr); #ifndef strcspn static int strcspn (const char *s, const char *reject); #endif - static int already_determined (List_Node *ptr); - static void set_determined (List_Node *ptr); + static int already_determined (KeywordExt *ptr); + static void set_determined (KeywordExt *ptr); void compute_min_max (void); int num_hash_values (void); void output_constants (struct Output_Constants&); @@ -75,11 +75,11 @@ private: const char *get_array_type (void); const char *save_include_src (void); const char *get_special_input (char delimiter); - List_Node *merge (List_Node *list1, List_Node *list2); - List_Node *merge_sort (List_Node *head); + KeywordExt_List *merge (KeywordExt_List *list1, KeywordExt_List *list2); + KeywordExt_List *merge_sort (KeywordExt_List *head); protected: - List_Node *head; /* Points to the head of the linked list. */ + KeywordExt_List *head; /* Points to the head of the linked list. */ int total_duplicates; /* Total number of duplicate hash values. */ public: diff --git a/src/keyword-list.cc b/src/keyword-list.cc new file mode 100644 index 0000000..38c957a --- /dev/null +++ b/src/keyword-list.cc @@ -0,0 +1,29 @@ +/* Keyword list. + + Copyright (C) 1989-1998, 2000, 2002 Free Software Foundation, Inc. + Written by Bruno Haible . + +This file is part of GNU GPERF. + +GNU GPERF 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 1, or (at your option) +any later version. + +GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +#include +#include "keyword-list.h" + +/* Constructor. */ +KeywordExt_List::KeywordExt_List (const char *s, int s_len, const char *r) + : KeywordExt (s, s_len, r), cdr (NULL) +{ +} diff --git a/src/keyword-list.h b/src/keyword-list.h new file mode 100644 index 0000000..3b49e4e --- /dev/null +++ b/src/keyword-list.h @@ -0,0 +1,44 @@ +/* This may look like C code, but it is really -*- C++ -*- */ + +/* Keyword list. + + Copyright (C) 1989-1998, 2000, 2002 Free Software Foundation, Inc. + Written by Bruno Haible . + +This file is part of GNU GPERF. + +GNU GPERF 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 1, or (at your option) +any later version. + +GNU GPERF 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 GNU GPERF; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +#ifndef keyword_list_h +#define keyword_list_h 1 + +#include "keyword.h" + +/* List node of a linear list. */ +class KeywordExt_List : private KeywordExt { +public: + /* Constructor. */ + KeywordExt_List (const char *allchars, int allchars_length, const char *rest); + + /* Access to first element of list. */ + KeywordExt* first () { return this; } + /* Access to next element of list. */ + KeywordExt_List *& rest () { return cdr; } + +private: + KeywordExt_List * cdr; +}; + +#endif diff --git a/src/keyword.cc b/src/keyword.cc index 564e49d..2d04c90 100644 --- a/src/keyword.cc +++ b/src/keyword.cc @@ -19,11 +19,15 @@ along with GNU GPERF; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include +#include +#include #include "keyword.h" +#include "options.h" /* Keyword class. */ +/* Constructor. */ Keyword::Keyword (const char *s, int s_len, const char *r) : allchars (s), allchars_length (s_len), rest (r) { @@ -32,11 +36,79 @@ Keyword::Keyword (const char *s, int s_len, const char *r) /* KeywordExt class. */ +/* Constructor. */ KeywordExt::KeywordExt (const char *s, int s_len, const char *r) : Keyword (s, s_len, r), duplicate_link (NULL), final_index (0) { } +/* Sort a small set of 'char', base[0..len-1], in place. */ +static inline void sort_char_set (char *base, int len) +{ + /* Bubble sort is sufficient here. */ + for (int i = 1; i < len; i++) + { + int j; + char tmp; + + for (j = i, tmp = base[j]; j > 0 && tmp < base[j - 1]; j--) + base[j] = base[j - 1]; + + base[j] = tmp; + } +} + +/* Initialize selchars and selchars_length, and update v->occurrences. */ +void KeywordExt::init_selchars (Vectors *v) +{ + const char *k = allchars; + char *key_set = + new char[(option[ALLCHARS] ? allchars_length : option.get_max_keysig_size ())]; + char *ptr = key_set; + int i; + + if (option[ALLCHARS]) + /* Use all the character positions in the KEY. */ + for (i = allchars_length; i > 0; k++, ptr++, i--) + v->occurrences[(unsigned char)(*ptr = *k)]++; + else + /* Only use those character positions specified by the user. */ + { + /* Iterate through the list of key_positions, initializing occurrences + table and selchars (via char * pointer ptr). */ + + for (option.reset (); (i = option.get ()) != EOS; ) + { + if (i == WORD_END) + /* Special notation for last KEY position, i.e. '$'. */ + *ptr = allchars[allchars_length - 1]; + else if (i <= allchars_length) + /* Within range of KEY length, so we'll keep it. */ + *ptr = allchars[i - 1]; + else + /* Out of range of KEY length, so we'll just skip it. */ + continue; + v->occurrences[(unsigned char)*ptr]++; + ptr++; + } + + /* Didn't get any hits and user doesn't want to consider the + keylength, so there are essentially no usable hash positions! */ + if (ptr == selchars && option[NOLENGTH]) + { + fprintf (stderr, "Can't hash keyword %.*s with chosen key positions.\n", + allchars_length, allchars); + exit (1); + } + } + + /* Sort the KEY_SET items alphabetically. */ + sort_char_set (key_set, ptr - key_set); + + selchars = key_set; + selchars_length = ptr - key_set; +} + /* Keyword_Factory class. */ diff --git a/src/keyword.h b/src/keyword.h index d52dce3..2f9d7de 100644 --- a/src/keyword.h +++ b/src/keyword.h @@ -24,6 +24,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #ifndef keyword_h #define keyword_h 1 +#include "vectors.h" + /* An instance of this class is a keyword, as specified in the input file. */ struct Keyword { @@ -52,6 +54,10 @@ struct KeywordExt : public Keyword /* Chained list of keywords having the same selchars. */ KeywordExt * duplicate_link; + /* Methods depending on the keyposition list. */ + /* Initialize selchars and selchars_length, and update v->occurrences. */ + void init_selchars (Vectors *v); + /* Data members used by the algorithm. */ int occurrence; /* A metric for frequency of key set occurrences. */ int hash_value; /* Hash value for the key. */ diff --git a/src/options.cc b/src/options.cc index ef8e6dc..bc0093f 100644 --- a/src/options.cc +++ b/src/options.cc @@ -450,7 +450,7 @@ Options::operator() (int argc, char *argv[]) while ((option_char = getopt_long (argument_count, argument_vector, "adcCDe:Ef:F:gGhH:i:Ij:k:K:lL:nN:oprs:S:tTvW:Z:7", - long_options, (int *)0)) + long_options, NULL)) != -1) { switch (option_char) diff --git a/src/read-line.icc b/src/read-line.icc index fd8bbdd..b100549 100644 --- a/src/read-line.icc +++ b/src/read-line.icc @@ -38,21 +38,21 @@ Read_Line::read_next_line (void) ; if (c == EOF) - return (char *)0; + return NULL; } if (c == EOF) - return (char *)0; + return NULL; ungetc (c, stdin); - char *line = (char *)0; + char *line = NULL; size_t linesize = 0; int length = get_line (&line, &linesize, fp); if (length < 0) { delete[] line; - return (char *)0; + return NULL; } if (length > 0 && line[length - 1] == '\n') line[length - 1] = '\0';