diff options
author | levine <levine@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1996-10-21 21:41:34 +0000 |
---|---|---|
committer | levine <levine@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1996-10-21 21:41:34 +0000 |
commit | a5fdebc5f6375078ec1763850a4ca23ec7fe6458 (patch) | |
tree | bcf0a25c3d45a209a6e3ac37b233a4812f29c732 /apps/gperf/src | |
download | ATCD-a5fdebc5f6375078ec1763850a4ca23ec7fe6458.tar.gz |
Initial revision
Diffstat (limited to 'apps/gperf/src')
-rw-r--r-- | apps/gperf/src/Bool_Array.cpp | 89 | ||||
-rw-r--r-- | apps/gperf/src/Bool_Array.h | 65 | ||||
-rw-r--r-- | apps/gperf/src/Gen_Perf.cpp | 345 | ||||
-rw-r--r-- | apps/gperf/src/Gen_Perf.h | 65 | ||||
-rw-r--r-- | apps/gperf/src/Hash_Table.cpp | 84 | ||||
-rw-r--r-- | apps/gperf/src/Hash_Table.h | 50 | ||||
-rw-r--r-- | apps/gperf/src/Iterator.cpp | 90 | ||||
-rw-r--r-- | apps/gperf/src/Iterator.h | 67 | ||||
-rw-r--r-- | apps/gperf/src/Key_List.cpp | 1345 | ||||
-rw-r--r-- | apps/gperf/src/Key_List.h | 116 | ||||
-rw-r--r-- | apps/gperf/src/List_Node.cpp | 110 | ||||
-rw-r--r-- | apps/gperf/src/List_Node.h | 65 | ||||
-rw-r--r-- | apps/gperf/src/Makefile | 155 | ||||
-rw-r--r-- | apps/gperf/src/Options.cpp | 616 | ||||
-rw-r--r-- | apps/gperf/src/Options.h | 140 | ||||
-rw-r--r-- | apps/gperf/src/Vectors.cpp | 33 | ||||
-rw-r--r-- | apps/gperf/src/Vectors.h | 44 | ||||
-rw-r--r-- | apps/gperf/src/Version.cpp | 25 | ||||
-rw-r--r-- | apps/gperf/src/gperf.cpp | 66 | ||||
-rw-r--r-- | apps/gperf/src/new.cpp | 75 |
20 files changed, 3645 insertions, 0 deletions
diff --git a/apps/gperf/src/Bool_Array.cpp b/apps/gperf/src/Bool_Array.cpp new file mode 100644 index 00000000000..e3243565f41 --- /dev/null +++ b/apps/gperf/src/Bool_Array.cpp @@ -0,0 +1,89 @@ +/* Fast lookup table abstraction implemented as an Iteration Number Array +// @(#)Bool_Array.cpp 1.1 10/18/96 + + Copyright (C) 1989 Free Software Foundation, Inc. + written by Douglas C. Schmidt (schmidt@ics.uci.edu) + +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 "Bool_Array.h" + +// Prints out debugging diagnostics. + +Bool_Array::~Bool_Array (void) +{ + if (option[DEBUG]) + fprintf (stderr, "\ndumping boolean array information\n" + "size = %d\niteration number = %d\nend of array dump\n", + size, generation_number); +} + +Bool_Array::Bool_Array (void) + : storage_array (0), + generation_number (0), + size (0) +{ +} + +void +Bool_Array::init (STORAGE_TYPE *buffer, STORAGE_TYPE s) +{ + size = s; + generation_number = 1; + storage_array = buffer; + + memset (storage_array, 0, s * sizeof *storage_array); + + if (option[DEBUG]) + fprintf (stderr, "\nbool array size = %d, total bytes = %d\n", + size, size * sizeof *storage_array); +} + +int +Bool_Array::find (int index) +{ + if (storage_array[index] == generation_number) + return 1; + else + { + storage_array[index] = generation_number; + return 0; + } +} + +void +Bool_Array::reset (void) +{ + if (++generation_number == 0) + { + if (option[DEBUG]) + { + fprintf (stderr, "(re-initializing bool_array)..."); + fflush (stderr); + } + + generation_number = 1; + memset (storage_array, 0, size * sizeof *storage_array); + + if (option[DEBUG]) + { + fprintf (stderr, "done\n"); + fflush (stderr); + } + } +} + diff --git a/apps/gperf/src/Bool_Array.h b/apps/gperf/src/Bool_Array.h new file mode 100644 index 00000000000..d890484e485 --- /dev/null +++ b/apps/gperf/src/Bool_Array.h @@ -0,0 +1,65 @@ +/* -*- C++ -*- */ +// @(#)Bool_Array.h 1.1 10/18/96 + +/* This may look like C code, but it is really -*- C++ -*- */ + +/* Simple lookup table abstraction implemented as an Generation Number Array. + + Copyright (C) 1989 Free Software Foundation, Inc. + written by Douglas C. Schmidt (schmidt@ics.uci.edu) + +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-1307, USA.*/ + +/* Define and implement a simple boolean array abstraction, + uses an Generation Numbering implementation to save on initialization time. */ + +#ifndef bool_array_h +#define bool_array_h 1 + +#include "Options.h" + +#ifdef LO_CAL +/* If we are on a memory diet then we'll only make these use a limited + amount of storage space. */ +typedef u_short STORAGE_TYPE; +#else +typedef int STORAGE_TYPE; +#endif + +class Bool_Array +{ +public: + Bool_Array (void); + ~Bool_Array (void); + + void init (STORAGE_TYPE *buffer, STORAGE_TYPE s); + int find (int hash_value); + void reset (void); + +private: + STORAGE_TYPE *storage_array; + // Initialization of the index space. + + STORAGE_TYPE generation_number; + // Keep track of the current Generation. + + int size; + // Keep track of array size. +}; + + +#endif diff --git a/apps/gperf/src/Gen_Perf.cpp b/apps/gperf/src/Gen_Perf.cpp new file mode 100644 index 00000000000..25c0299fd35 --- /dev/null +++ b/apps/gperf/src/Gen_Perf.cpp @@ -0,0 +1,345 @@ +/* Provides high-level routines to manipulate the keywork list +// @(#)Gen_Perf.cpp 1.1 10/18/96 + + structures the code generation output. + Copyright (C) 1989 Free Software Foundation, Inc. + written by Douglas C. Schmidt (schmidt@ics.uci.edu) + +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 "Vectors.h" +#include "Gen_Perf.h" + +/* Current release version. */ +extern char *version_string; + +/* Reads input keys, possibly applies the reordering heuristic, sets + the maximum associated value size (rounded up to the nearest power + of 2), may initialize the associated values array, and determines + the maximum hash table size. Note: using the random numbers is + often helpful, though not as deterministic, of course! */ + +Gen_Perf::Gen_Perf (void) +{ + int asso_value_max; + int non_linked_length; + + this->key_list.read_keys (); + if (option[ORDER]) + this->key_list.reorder (); + asso_value_max = option.get_asso_max (); + non_linked_length = this->key_list.keyword_list_length (); + num_done = 1; + fewest_collisions = 0; + if (asso_value_max == 0) + asso_value_max = non_linked_length; + else if (asso_value_max > 0) + asso_value_max *= non_linked_length; + else /* if (asso_value_max < 0) */ + asso_value_max = non_linked_length / -asso_value_max; + option.set_asso_max (ACE_POW (asso_value_max)); + + if (option[RANDOM]) + { + srand (time (0)); + + for (int i = 0; i < ALPHA_SIZE; i++) + Vectors::asso_values[i] = (rand () & asso_value_max - 1); + } + else + { + int asso_value = option.initial_value (); + + if (asso_value) /* Initialize array if user requests non-zero default. */ + for (int i = ALPHA_SIZE - 1; i >= 0; i--) + Vectors::asso_values[i] = asso_value & option.get_asso_max () - 1; + } + max_hash_value = this->key_list.max_key_length () + option.get_asso_max () * + option.get_max_keysig_size (); + + printf ("/* "); + if (option[C]) + printf ("C"); + else if (option[CPLUSPLUS]) + printf ("C++"); + printf (" code produced by gperf version %s */\n", version_string); + Options::print_options (); + + if (option[DEBUG]) + fprintf (stderr, "total non-linked keys = %d\nmaximum associated value is %d" + "\nmaximum size of generated hash table is %d\n", + non_linked_length, asso_value_max, max_hash_value); +} + +/* Merge two disjoint hash key multisets to form the ordered disjoint union of the sets. + (In a multiset, an element can occur multiple times). + Precondition: both set_1 and set_2 must be ordered. Returns the length + of the combined set. */ + +inline int +Gen_Perf::compute_disjoint_union (char *set_1, char *set_2, char *set_3) +{ + char *base = set_3; + + while (*set_1 && *set_2) + if (*set_1 == *set_2) + set_1++, set_2++; + else + { + *set_3 = *set_1 < *set_2 ? *set_1++ : *set_2++; + if (set_3 == base || *set_3 != *(set_3-1)) set_3++; + } + + while (*set_1) + { + *set_3 = *set_1++; + if (set_3 == base || *set_3 != *(set_3-1)) set_3++; + } + + while (*set_2) + { + *set_3 = *set_2++; + if (set_3 == base || *set_3 != *(set_3-1)) set_3++; + } + *set_3 = '\0'; + return set_3 - base; +} + +/* Sort the UNION_SET in increasing frequency of occurrence. + This speeds up later processing since we may assume the resulting + set (Set_3, in this case), is ordered. Uses insertion sort, since + the UNION_SET is typically short. */ + +inline void +Gen_Perf::sort_set (char *union_set, int len) +{ + int i, j; + + for (i = 0, j = len - 1; i < j; i++) + { + char curr, tmp; + + for (curr = i + 1, tmp = union_set[curr]; + curr > 0 && Vectors::occurrences[tmp] < Vectors::occurrences[union_set[curr-1]]; + curr--) + union_set[curr] = union_set[curr - 1]; + + union_set[curr] = tmp; + } +} + +/* Generate a key set's hash value. */ + +inline int +Gen_Perf::hash (List_Node *key_node) +{ + int sum = option[NOLENGTH] ? 0 : key_node->length; + + for (char *ptr = key_node->char_set; *ptr; ptr++) + sum += Vectors::asso_values[*ptr]; + + return key_node->hash_value = sum; +} + +/* Find out how character value change affects successfully hashed + items. Returns FALSE if no other hash values are affected, else + returns TRUE. Note that because Option.Get_Asso_Max is a power of + two we can guarantee that all legal Vectors::Asso_Values are visited without + repetition since Option.Get_Jump was forced to be an odd value! */ + +inline int +Gen_Perf::affects_prev (char c, List_Node *curr) +{ + int original_char = Vectors::asso_values[c]; + int total_iterations = !option[FAST] + ? option.get_asso_max () : option.get_iterations () ? option.get_iterations () : this->key_list.keyword_list_length (); + + /* Try all legal associated values. */ + + for (int i = total_iterations - 1; i >= 0; i--) + { + int collisions = 0; + + Vectors::asso_values[c] = Vectors::asso_values[c] + (option.get_jump () ? option.get_jump () : rand ()) + & option.get_asso_max () - 1; + + /* Iteration Number array is a win, O(1) intialization time! */ + this->char_search.reset (); + + /* See how this asso_value change affects previous keywords. If + it does better than before we'll take it! */ + + for (List_Node *ptr = this->key_list.head; + !this->char_search.find (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; + } + } + + /* Restore original values, no more tries. */ + Vectors::asso_values[c] = original_char; + /* If we're this far it's time to try the next character.... */ + return 1; +} + +/* Change a character value, try least-used characters first. */ + +void +Gen_Perf::change (List_Node *prior, List_Node *curr) +{ + static char *union_set; + + if (!union_set) + union_set = new char [2 * option.get_max_keysig_size () + 1]; + + if (option[DEBUG]) + { + fprintf (stderr, "collision on keyword #%d, prior = \"%s\", curr = \"%s\" hash = %d\n", + num_done, prior->key, curr->key, curr->hash_value); + fflush (stderr); + } + sort_set (union_set, compute_disjoint_union (prior->char_set, curr->char_set, union_set)); + + /* Try changing some values, if change doesn't alter other values continue normal action. */ + fewest_collisions++; + + for (char *temp = union_set; *temp; temp++) + if (!affects_prev (*temp, curr)) + { + if (option[DEBUG]) + { + fprintf (stderr, " by changing asso_value['%c'] (char #%d) to %d\n", + *temp, temp - union_set + 1, Vectors::asso_values[*temp]); + fflush (stderr); + } + return; /* Good, doesn't affect previous hash values, we'll take it. */ + } + + for (List_Node *ptr = this->key_list.head; ptr != curr; ptr = ptr->next) + hash (ptr); + + hash (curr); + + if (option[DEBUG]) + { + fprintf (stderr, "** collision not resolved after %d iterations, %d duplicates remain, continuing...\n", + !option[FAST] ? option.get_asso_max () : option.get_iterations () ? option.get_iterations () : this->key_list.keyword_list_length (), + fewest_collisions + this->key_list.total_duplicates); + fflush (stderr); + } +} + +/* Does the hard stuff.... + Initializes the Iteration Number array, and attempts to find a perfect + function that will hash all the key words without getting any + duplications. This is made much easier since we aren't attempting + to generate *minimum* functions, only perfect ones. + If we can't generate a perfect function in one pass *and* the user + hasn't enabled the DUP option, we'll inform the user to try the + randomization option, use -D, or choose alternative key positions. + The alternatives (e.g., back-tracking) are too time-consuming, i.e, + exponential in the number of keys. */ + +int +Gen_Perf::generate (void) +{ +#if LARGE_STACK_ARRAYS + STORAGE_TYPE buffer[max_hash_value + 1]; +#else + // Note: we don't use new, because that invokes a custom operator new. + STORAGE_TYPE *buffer + = (STORAGE_TYPE*) malloc (sizeof(STORAGE_TYPE) * (max_hash_value + 1)); + if (buffer == NULL) + abort (); +#endif + + this->char_search.init (buffer, max_hash_value + 1); + + List_Node *curr; + + for (curr = this->key_list.head; + curr; + curr = curr->next) + { + hash (curr); + + for (List_Node *ptr = this->key_list.head; + ptr != curr; + ptr = ptr->next) + if (ptr->hash_value == curr->hash_value) + { + change (ptr, curr); + break; + } + num_done++; + } + + /* Make one final check, just to make sure nothing weird happened.... */ + + this->char_search.reset (); + + for (curr = this->key_list.head; + curr; + curr = curr->next) + if (this->char_search.find (hash (curr))) + if (option[DUP]) /* Keep track of this number... */ + this->key_list.total_duplicates++; + else /* Yow, big problems. we're outta here! */ + { + ACE_ERROR ((LM_ERROR, "\nInternal error, duplicate value %d:\n" + "try options -D or -r, or use new key positions.\n\n", hash (curr))); +#if !LARGE_STACK_ARRAYS + free (buffer); +#endif + 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 + processing turned out O.K. */ + + this->key_list.sort (); + this->key_list.output (); +#if !LARGE_STACK_ARRAYS + free (buffer); +#endif + return 0; +} + +/* Prints out some diagnostics upon completion. */ + +Gen_Perf::~Gen_Perf (void) +{ + if (option[DEBUG]) + { + fprintf (stderr, "\ndumping occurrence and associated values tables\n"); + + for (int i = 0; i < ALPHA_SIZE; i++) + if (Vectors::occurrences[i]) + fprintf (stderr, "Vectors::asso_values[%c] = %6d, Vectors::occurrences[%c] = %6d\n", + i, Vectors::asso_values[i], i, Vectors::occurrences[i]); + + fprintf (stderr, "end table dumping\n"); + + } +} + diff --git a/apps/gperf/src/Gen_Perf.h b/apps/gperf/src/Gen_Perf.h new file mode 100644 index 00000000000..11817de4851 --- /dev/null +++ b/apps/gperf/src/Gen_Perf.h @@ -0,0 +1,65 @@ +/* -*- C++ -*- */ +// @(#)Gen_Perf.h 1.1 10/18/96 + +/* This may look like C code, but it is really -*- C++ -*- */ + +/* Provides high-level routines to manipulate the keyword list + structures the code generation output. + + Copyright (C) 1989 Free Software Foundation, Inc. + written by Douglas C. Schmidt (schmidt@ics.uci.edu) + +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 gen_perf_h +#define gen_perf_h 1 + +#include "Options.h" +#include "Key_List.h" +#include "Bool_Array.h" + +class Gen_Perf +{ +public: + Gen_Perf (void); + ~Gen_Perf (void); + int generate (void); + +private: + void change (List_Node *prior, List_Node *curr); + int affects_prev (char c, List_Node *curr); + static int hash (List_Node *key_node); + static int compute_disjoint_union (char *set_1, char *set_2, char *set_3); + static void sort_set (char *union_set, int len); + + int max_hash_value; + // Maximum possible hash value. + + int fewest_collisions; + // Records fewest # of collisions for asso value. + + int num_done; + // Number of keywords processed without a collision. + + Bool_Array char_search; + // Table that keeps track of key collisions. + + Key_List key_list; + // List of the keys we're trying to map into a perfect hash + // function. +}; +#endif diff --git a/apps/gperf/src/Hash_Table.cpp b/apps/gperf/src/Hash_Table.cpp new file mode 100644 index 00000000000..dfb008514ce --- /dev/null +++ b/apps/gperf/src/Hash_Table.cpp @@ -0,0 +1,84 @@ +/* Hash table for checking keyword links. Implemented using double hashing. +// @(#)Hash_Table.cpp 1.1 10/18/96 + + Copyright (C) 1989 Free Software Foundation, Inc. + written by Douglas C. Schmidt (schmidt@ics.uci.edu) + +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 "ace/ACE.h" +#include "Hash_Table.h" + +#define NIL(TYPE) (TYPE *)0 + +// The size of the hash table is always the smallest power of 2 >= the +// size indicated by the user. This allows several optimizations, +// including the use of double hashing and elimination of the mod +// instruction. Note that the size had better be larger than the +// number of items in the hash table, else there's trouble!!! Note +// that the memory for the hash table is allocated *outside* the +// intialization routine. 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) + : collisions (0), + size (s), + table (table_ptr) +{ + memset ((char *) table, 0, size * sizeof *table); +} + +Hash_Table::~Hash_Table (void) +{ + if (option[DEBUG]) + { + int field_width = option.get_max_keysig_size (); + + fprintf (stderr, "\ndumping the hash table\ntotal available table slots = %d, total bytes = %d, total collisions = %d\n" + "location, %*s, keyword\n", size, size * sizeof *table, collisions, field_width, "keysig"); + + for (int i = size - 1; i >= 0; i--) + if (table[i]) + fprintf (stderr, "%8d, %*s, %s\n", + i, field_width, table[i]->char_set, table[i]->key); + + fprintf (stderr, "\nend dumping hash table\n\n"); + } +} + +// If the ITEM is already in the hash table return the item found in +// the table. Otherwise inserts the ITEM, and returns FALSE. Uses +// double hashing. + +List_Node * +Hash_Table::operator() (List_Node *item, int ignore_length) +{ + unsigned hash_val = ACE::hash_pjw (item->char_set); + int probe = hash_val & size - 1; + int increment = (hash_val ^ item->length | 1) & size - 1; + + while (table[probe] + && (strcmp (table[probe]->char_set, item->char_set) + || (!ignore_length && table[probe]->length != item->length))) + { + collisions++; + probe = probe + increment & size - 1; + } + + return table[probe] ? table[probe] : (table[probe] = item, NIL (List_Node)); +} diff --git a/apps/gperf/src/Hash_Table.h b/apps/gperf/src/Hash_Table.h new file mode 100644 index 00000000000..c7a77a1b37b --- /dev/null +++ b/apps/gperf/src/Hash_Table.h @@ -0,0 +1,50 @@ +/* -*- C++ -*- */ +// @(#)Hash_Table.h 1.1 10/18/96 + +/* This may look like C code, but it is really -*- C++ -*- */ + +/* Hash table used to check for duplicate keyword entries. + + Copyright (C) 1989 Free Software Foundation, Inc. + written by Douglas C. Schmidt (schmidt@ics.uci.edu) + +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 hash_table_h +#define hash_table_h 1 + +#include "Options.h" +#include "List_Node.h" + +class Hash_Table +{ +public: + Hash_Table (List_Node **t, int s); + ~Hash_Table (void); + List_Node *operator () (List_Node *item, int ignore_length); + +private: + List_Node **table; + // Vector of pointers to linked lists of List_Node's. + + int size; + // Size of the vector. + + int collisions; + // Find out how well our double hashing is working! +}; +#endif diff --git a/apps/gperf/src/Iterator.cpp b/apps/gperf/src/Iterator.cpp new file mode 100644 index 00000000000..2e5d37f8f00 --- /dev/null +++ b/apps/gperf/src/Iterator.cpp @@ -0,0 +1,90 @@ +/* Provides an Iterator for keyword characters. +// @(#)Iterator.cpp 1.1 10/18/96 + + Copyright (C) 1989 Free Software Foundation, Inc. + written by Douglas C. Schmidt (schmidt@ics.uci.edu) + +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 "Iterator.h" + +// Constructor for Iterator. + +Iterator::Iterator (char *s, + int lo, + int hi, + int word_end, + int bad_val, + int key_end) + : end (key_end), + error_value (bad_val), + end_word (word_end), + str (s), + hi_bound (hi), + lo_bound (lo) +{ +} + +// Provide an Iterator, returning the ``next'' value from the list of +// valid values given in the constructor. + +int +Iterator::operator() (void) +{ + // Variables to record the Iterator's status when handling ranges, + // e.g., 3-12. + + static int size; + static int curr_value; + static int upper_bound; + + if (size) + { + if (++curr_value >= upper_bound) + size = 0; + return curr_value; + } + else + { + while (*str) + switch (*str) + { + default: return error_value; + case ',': str++; break; + case '$': str++; return end_word; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + for (curr_value = 0; isdigit (*str); str++) + curr_value = curr_value * 10 + *str - '0'; + + if (*str == '-') + { + + for (size = 1, upper_bound = 0; + isdigit (*++str); + upper_bound = upper_bound * 10 + *str - '0'); + + if (upper_bound <= curr_value || upper_bound > hi_bound) + return error_value; + } + return curr_value >= lo_bound && curr_value <= hi_bound + ? curr_value : error_value; + } + + return end; + } +} diff --git a/apps/gperf/src/Iterator.h b/apps/gperf/src/Iterator.h new file mode 100644 index 00000000000..d2c81039b3f --- /dev/null +++ b/apps/gperf/src/Iterator.h @@ -0,0 +1,67 @@ +/* -*- C++ -*- */ +// @(#)Iterator.h 1.1 10/18/96 + +/* This may look like C code, but it is really -*- C++ -*- */ + +/* Provides an Iterator for keyword characters. + + Copyright (C) 1989 Free Software Foundation, Inc. + written by Douglas C. Schmidt (schmidt@ics.uci.edu) + +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-1307, USA. */ + +/* Provides an Iterator that expands and decodes a control string + containing digits and ranges, returning an integer every time the + generator function is called. This is used to decode the user's + key position requests. For example: "-k 1,2,5-10,$" will return 1, + 2, 5, 6, 7, 8, 9, 10, and 0 ( representing the abstract ``last + character of the key'' on successive calls to the member function + operator (). No errors are handled in these routines, they are + passed back to the calling routines via a user-supplied Error_Value */ + +#ifndef iterator_h +#define iterator_h 1 + +#include "Options.h" + +class Iterator +{ +public: + Iterator (char *s, int lo, int hi, int word_end, int bad_val, int key_end); + int operator () (void); + +private: + char *str; + // A pointer to the string provided by the user. + + int end; + // Value returned after last key is processed. + + int end_word; + // A value marking the abstract ``end of word'' (usually '$'). + + int error_value; + // Error value returned when input is syntactically erroneous. + + int hi_bound; + // Greatest possible value, inclusive. + + int lo_bound; + // Smallest possible value, inclusive. +}; + +#endif diff --git a/apps/gperf/src/Key_List.cpp b/apps/gperf/src/Key_List.cpp new file mode 100644 index 00000000000..3a944b4b28b --- /dev/null +++ b/apps/gperf/src/Key_List.cpp @@ -0,0 +1,1345 @@ +/* Routines for building, ordering, and printing the keyword list. +// @(#)Key_List.cpp 1.1 10/18/96 + + Copyright (C) 1989 Free Software Foundation, Inc. + written by Douglas C. Schmidt (schmidt@ics.uci.edu) + +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 "ace/Read_Buffer.h" +#include "Hash_Table.h" +#include "Vectors.h" +#include "Key_List.h" + +/* Make the hash table 10 times larger than the number of keyword entries. */ +static const int TABLE_MULTIPLE = 10; + +/* Default type for generated code. */ +static char *const default_array_type = "char *"; + +/* in_word_set return type, by default. */ +static char *const default_return_type = "char *"; + +/* How wide the printed field width must be to contain the maximum hash value. */ +static int field_width = 0; + +static int determined[ALPHA_SIZE]; + +/* Destructor dumps diagnostics during debugging. */ + +Key_List::~Key_List (void) +{ + if (option[DEBUG]) + { + fprintf (stderr, "\nDumping key list information:\ntotal non-static linked keywords = %d" + "\ntotal keywords = %d\ntotal duplicates = %d\nmaximum key length = %d\n", + list_len, total_keys, total_duplicates ? total_duplicates + 1 : 0, max_key_len); + dump (); + ACE_ERROR ((LM_ERROR, "End dumping list.\n\n")); + } +} + +/* Gathers the input stream into a buffer until one of two things occur: + + 1. We read a '%' followed by a '%' + 2. We read a '%' followed by a '}' + + The first symbolizes the beginning of the keyword list proper, + The second symbolizes the end of the C source code to be generated + verbatim in the output file. + + I assume that the keys are separated from the optional preceding struct + declaration by a consecutive % followed by either % or } starting in + the first column. The code below uses an expandible buffer to scan off + and return a pointer to all the code (if any) appearing before the delimiter. */ + +char * +Key_List::get_special_input (char delimiter) +{ + int size = 80; + char *buf = new char[size]; + int c, i; + + for (i = 0; (c = getchar ()) != EOF; i++) + { + if (c == '%') + { + if ((c = getchar ()) == delimiter) + { + + while ((c = getchar ()) != '\n') + ; /* discard newline */ + + if (i == 0) + return ""; + else + { + buf[delimiter == '%' && buf[i - 2] == ';' ? i - 2 : i - 1] = '\0'; + return buf; + } + } + else + buf[i++] = '%'; + } + else if (i >= size) /* Yikes, time to grow the buffer! */ + { + char *temp = new char[size *= 2]; + int j; + + for (j = 0; j < i; j++) + temp[j] = buf[j]; + + buf = temp; + } + buf[i] = c; + } + + return 0; /* Problem here. */ +} + +/* Stores any C text that must be included verbatim into the + generated code output. */ + +char * +Key_List::save_include_src (void) +{ + int c; + + if ((c = getchar ()) != '%') + ungetc (c, stdin); + else if ((c = getchar ()) != '{') + ACE_ERROR ((LM_ERROR, "internal error, %c != '{' on line %d in file %s%a", c, __LINE__, __FILE__, 1)); + else + return get_special_input ('}'); + return ""; +} + +/* Determines from the input file whether the user wants to build a table + from a user-defined struct, or whether the user is content to simply + use the default array of keys. */ + +char * +Key_List::get_array_type (void) +{ + return get_special_input ('%'); +} + +/* strcspn - find length of initial segment of S consisting entirely + ANSI string package, when GNU libc comes out I'll replace this...). */ + +inline int +Key_List::strcspn (const char *s, const char *reject) +{ + const char *scan; + const char *rej_scan; + int count = 0; + + for (scan = s; *scan; scan++) + { + + for (rej_scan = reject; *rej_scan; rej_scan++) + if (*scan == *rej_scan) + return count; + + count++; + } + + return count; +} + +/* Sets up the Return_Type, the Struct_Tag type and the Array_Type + based upon various user Options. */ + +void +Key_List::set_output_types (void) +{ + if (option[TYPE] && !(array_type = get_array_type ())) + return; /* Something's wrong, bug we'll catch it later on.... */ + else if (option[TYPE]) /* Yow, we've got a user-defined type... */ + { + int struct_tag_length = strcspn (array_type, "{\n\0"); + + if (option[POINTER]) /* And it must return a pointer... */ + { + return_type = new char[struct_tag_length + 2]; + strncpy (return_type, array_type, struct_tag_length); + return_type[struct_tag_length] = '*'; + return_type[struct_tag_length + 1] = '\0'; + } + + struct_tag = new char[struct_tag_length + 1]; + strncpy (struct_tag, array_type, struct_tag_length); + struct_tag[struct_tag_length] = '\0'; + } + else if (option[POINTER]) /* Return a char *. */ + return_type = default_array_type; +} + +/* Reads in all keys from standard input and creates a linked list pointed + to by Head. This list is then quickly checked for ``links,'' i.e., + unhashable elements possessing identical key sets and lengths. */ + +void +Key_List::read_keys (void) +{ + include_src = save_include_src (); + set_output_types (); + + ACE_Read_Buffer input (stdin); + + char *ptr = input.read ('\n'); + + if (ptr == 0) + // Oops, problem with the input file. + ACE_ERROR ((LM_ERROR, "No words in input file, did you forget to prepend %s" + " or use -t accidentally?\n%a", "%%", 1)); + + /* Read in all the keywords from the input file. */ + else + { + const char *delimiter = option.get_delimiter (); + List_Node *temp, *trail = 0; + + head = new List_Node (ptr, strcspn (ptr, delimiter)); + + for (temp = head; + (ptr = input.read ('\n')) && strcmp (ptr, "%%"); + temp = temp->next) + { + temp->next = new List_Node (ptr, strcspn (ptr, delimiter)); + total_keys++; + } + + /* See if any additional source code is included at end of this file. */ + if (ptr) + additional_code = 1; + + /* Hash table this number of times larger than keyword number. */ + int table_size = (list_len = total_keys) * TABLE_MULTIPLE; + +#if LARGE_STACK_ARRAYS + /* By allocating the memory here we save on dynamic allocation overhead. + Table must be a power of 2 for the hash function scheme to work. */ + List_Node *table[ACE_POW (table_size)]; +#else + // Note: we don't use new, because that invokes a custom operator new. + int malloc_size = ACE_POW (table_size) * sizeof(List_Node*); + if (malloc_size == 0) malloc_size = 1; + List_Node **table = (List_Node**)malloc(malloc_size); + if (table == NULL) + abort (); +#endif + + /* Make large hash table for efficiency. */ + Hash_Table found_link (table, table_size); + + /* 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) + { + List_Node *ptr = found_link (temp, option[NOLENGTH]); + + /* 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) + { + total_duplicates++; + list_len--; + trail->next = temp->next; + temp->link = ptr->link; + ptr->link = temp; + + /* Complain if user hasn't enabled the duplicate option. */ + if (!option[DUP] || option[DEBUG]) + ACE_ERROR ((LM_ERROR, "Key link: \"%s\" = \"%s\", with key set \"%s\".\n", + temp->key, ptr->key, temp->char_set)); + } + else + trail = temp; + + /* Update minimum and maximum keyword length, if needed. */ + if (max_key_len < temp->length) + max_key_len = temp->length; + if (min_key_len > temp->length) + min_key_len = temp->length; + } + +#if !LARGE_STACK_ARRAYS + free (table); +#endif + + /* Exit program if links exists and option[DUP] not set, since we can't continue */ + if (total_duplicates) + ACE_ERROR ((LM_ERROR, option[DUP] + ? "%d input keys have identical hash values, examine output carefully...\n" + : "%d input keys have identical hash values,\ntry different key positions or use option -D.\n%a", total_duplicates, 1)); + if (option[ALLCHARS]) + option.set_keysig_size (max_key_len); + } +} + +/* Recursively merges two sorted lists together to form one sorted list. The + ordering criteria is by frequency of occurrence of elements in the key set + or by the hash value. This is a kludge, but permits nice sharing of + almost identical code without incurring the overhead of a function + call comparison. */ + +List_Node * +Key_List::merge (List_Node *list1, List_Node *list2) +{ + if (!list1) + return list2; + else if (!list2) + return list1; + else if (occurrence_sort && list1->occurrence < list2->occurrence + || hash_sort && list1->hash_value > list2->hash_value) + { + list2->next = merge (list2->next, list1); + return list2; + } + else + { + list1->next = merge (list1->next, list2); + return list1; + } +} + +/* 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 *a_head) +{ + if (!a_head || !a_head->next) + return a_head; + else + { + List_Node *middle = a_head; + List_Node *temp = a_head->next->next; + + while (temp) + { + temp = temp->next; + middle = middle->next; + if (temp) + temp = temp->next; + } + + temp = middle->next; + middle->next = 0; + return merge (merge_sort (a_head), merge_sort (temp)); + } +} + +/* Returns the frequency of occurrence of elements in the key set. */ + +inline int +Key_List::get_occurrence (List_Node *ptr) +{ + int value = 0; + + for (char *temp = ptr->char_set; *temp; temp++) + value += Vectors::occurrences[*temp]; + + return value; +} + +/* Enables the index location of all key set elements that are now + determined. */ + +inline void +Key_List::set_determined (List_Node *ptr) +{ + for (char *temp = ptr->char_set; *temp; temp++) + determined[*temp] = 1; +} + +/* Returns TRUE if PTR's key set is already completely determined. */ + +inline int +Key_List::already_determined (List_Node *ptr) +{ + int is_determined = 1; + + for (char *temp = ptr->char_set; is_determined && *temp; temp++) + is_determined = determined[*temp]; + + return is_determined; +} + +/* Reorders the table by first sorting the list so that frequently occuring + keys appear first, and then the list is reorded so that keys whose values + are already determined will be placed towards the front of the list. This + helps prune the search time by handling inevitable collisions early in the + search process. See Cichelli's paper from Jan 1980 JACM for details.... */ + +void +Key_List::reorder (void) +{ + List_Node *ptr; + + for (ptr = head; ptr; ptr = ptr->next) + ptr->occurrence = get_occurrence (ptr); + + occurrence_sort = !(hash_sort = 0); /* Pretty gross, eh?! */ + + for (ptr = head = merge_sort (head); ptr->next; ptr = ptr->next) + { + set_determined (ptr); + + if (already_determined (ptr->next)) + continue; + else + { + List_Node *trail_ptr = ptr->next; + List_Node *run_ptr = trail_ptr->next; + + for (; run_ptr; run_ptr = trail_ptr->next) + { + + if (already_determined (run_ptr)) + { + trail_ptr->next = run_ptr->next; + run_ptr->next = ptr->next; + ptr = ptr->next = run_ptr; + } + else + trail_ptr = run_ptr; + } + } + } +} + +/* Outputs the maximum and minimum hash values. Since the + list is already sorted by hash value all we need to do is + find the final item! */ + +void +Key_List::output_min_max () +{ + List_Node *temp; + for (temp = head; temp->next; temp = temp->next) + ; + + min_hash_value = head->hash_value; + max_hash_value = temp->hash_value; + + if (!option[ENUM]) + printf ("\n#define TOTAL_KEYWORDS %d\n#define MIN_WORD_LENGTH %d" + "\n#define MAX_WORD_LENGTH %d\n#define MIN_HASH_VALUE %d" + "\n#define MAX_HASH_VALUE %d\n#define HASH_VALUE_RANGE %d" + "\n#define DUPLICATES %d\n\n", + total_keys, min_key_len, max_key_len, min_hash_value, + max_hash_value, max_hash_value - min_hash_value + 1, + total_duplicates ? total_duplicates + 1 : 0); + else if (option[GLOBAL]) + printf ("enum\n{\n" + " TOTAL_KEYWORDS = %d,\n" + " MIN_WORD_LENGTH = %d,\n" + " MAX_WORD_LENGTH = %d,\n" + " MIN_HASH_VALUE = %d,\n" + " MAX_HASH_VALUE = %d,\n" + " HASH_VALUE_RANGE = %d,\n" + " DUPLICATES = %d\n};\n\n", + total_keys, min_key_len, max_key_len, min_hash_value, + max_hash_value, max_hash_value - min_hash_value + 1, + total_duplicates ? total_duplicates + 1 : 0); +} + +/* Generates the output using a C switch. This trades increased + search time for decreased table space (potentially *much* less + space for sparse tables). It the user has specified their own + struct in the keyword file *and* they enable the POINTER option we + have extra work to do. The solution here is to maintain a local + static array of user defined struct's, as with the + Output_Lookup_Function. Then we use for switch statements to + perform either a strcmp or strncmp, returning 0 if the str fails to + match, and otherwise returning a pointer to appropriate index + location in the local static array. */ + +void +Key_List::output_switch (void) +{ + char *comp_buffer; + List_Node *curr = head; + int pointer_and_type_enabled = option[POINTER] && option[TYPE]; + int total_switches = option.get_total_switches (); + int switch_size = keyword_list_length () / total_switches; + + if (pointer_and_type_enabled) + { +#if defined (__GNUG__) + comp_buffer = (char *) alloca (strlen ("charmap[*str] == *resword->%s && !strncasecmp (str + 1, resword->%s + 1, len - 1)") + + 2 * strlen (option.get_key_name ()) + 1); +#else + comp_buffer = new char [strlen ("charmap[*str] == *resword->%s && !strncasecmp (str + 1, resword->%s + 1, len - 1)") + + 2 * strlen (option.get_key_name ()) + 1]; +#endif + if (option[COMP]) + sprintf (comp_buffer, "%s == *resword->%s && !%s (str + 1, resword->%s + 1, len - 1)", + option[STRCASECMP] ? "charmap[*str]" : "*str", option.get_key_name (), + option[STRCASECMP] ? "strncasecmp" : "strncmp", option.get_key_name ()); + else + sprintf (comp_buffer, "%s == *resword->%s && !%s (str + 1, resword->%s + 1)", + option[STRCASECMP] ? "charmap[*str]" : "*str", option.get_key_name (), + option[STRCASECMP] ? "strcasecmp" : "strcmp", option.get_key_name ()); + } + else + { + if (option[COMP]) + comp_buffer = option[STRCASECMP] + ? "charmap[*str] == *resword && !strncasecmp (str + 1, resword + 1, len - 1)" + : "*str == *resword && !strncmp (str + 1, resword + 1, len - 1)"; + else + comp_buffer = option[STRCASECMP] + ? "charmap[*str] == *resword && !strcasecmp (str + 1, resword + 1, len - 1)" + : "*str == *resword && !strcmp (str + 1, resword + 1, len - 1)"; + } + if (!option[OPTIMIZE]) + printf (" if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)\n {\n"); + printf (" register int key = %s (str, len);\n\n", option.get_hash_name ()); + if (!option[OPTIMIZE]) + printf (" if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)\n"); + + printf (" {\n"); + + /* Properly deal with user's who request multiple switch statements. */ + + while (curr) + { + List_Node *temp = curr; + int lowest_case_value = curr->hash_value; + int number_of_cases = 0; + + /* Figure out a good cut point to end this switch. */ + + for (; temp && ++number_of_cases < switch_size; temp = temp->next) + if (temp->next && temp->hash_value == temp->next->hash_value) + while (temp->next && temp->hash_value == temp->next->hash_value) + temp = temp->next; + + if (temp && total_switches != 1) + printf (" if (key <= %d)\n {\n", temp->hash_value); + else + printf (" {\n"); + + /* Output each keyword as part of a switch statement indexed by hash value. */ + + if (option[POINTER] || option[DUP]) + { + int i = 0; + + printf (" %s%s *resword; %s\n\n", + option[CONST] ? "const " : "", + pointer_and_type_enabled ? struct_tag : "char", + option[LENTABLE] && !option[DUP] ? "int key_len;" : ""); + if (total_switches == 1) + { + printf (" switch (key)\n {\n"); + lowest_case_value = 0; + } + else + printf (" switch (key - %d)\n {\n", lowest_case_value); + + for (temp = curr; temp && ++i <= number_of_cases; temp = temp->next) + { + printf (" case %*d:", field_width, temp->hash_value - lowest_case_value); + if (option[DEBUG]) + printf (" /* hash value = %4d, keyword = \"%s\" */", temp->hash_value, temp->key); + putchar ('\n'); + + /* Handle `natural links,' i.e., those that occur statically. */ + + if (temp->link) + { + List_Node *links; + + for (links = temp; links; links = links->link) + { + if (pointer_and_type_enabled) + printf (" resword = &wordlist[%d];\n", links->index); + else + printf (" resword = \"%s\";\n", links->key); + printf (" if (%s) return resword;\n", comp_buffer); + } + } + /* Handle unresolved duplicate hash values. These are guaranteed + to be adjacent since we sorted the keyword list by increasing + hash values. */ + if (temp->next && temp->hash_value == temp->next->hash_value) + { + + for ( ; temp->next && temp->hash_value == temp->next->hash_value; + temp = temp->next) + { + if (pointer_and_type_enabled) + printf (" resword = &wordlist[%d];\n", temp->index); + else + printf (" resword = \"%s\";\n", temp->key); + printf (" if (%s) return resword;\n", comp_buffer); + } + if (pointer_and_type_enabled) + printf (" resword = &wordlist[%d];\n", temp->index); + else + printf (" resword = \"%s\";\n", temp->key); + printf (" return %s ? resword : 0;\n", comp_buffer); + } + else if (temp->link) + printf (" return 0;\n"); + else + { + if (pointer_and_type_enabled) + printf (" resword = &wordlist[%d];", temp->index); + else + printf (" resword = \"%s\";", temp->key); + if (option[LENTABLE] && !option[DUP]) + printf (" key_len = %d;", temp->length); + printf (" break;\n"); + } + } + printf (" default: return 0;\n }\n"); + if (option[OPTIMIZE]) + printf (" return resword;\n"); + else + { + printf (option[LENTABLE] && !option[DUP] + ? " if (len == key_len && %s)\n return resword;\n" + : " if (%s)\n return resword;\n", comp_buffer); + printf (" return 0;\n"); + } + printf (" }\n"); + curr = temp; + } + else /* Nothing special required here. */ + { + int i = 0; + printf (" char *s;\n\n switch (key - %d)\n {\n", + lowest_case_value); + + for (temp = curr; temp && ++i <= number_of_cases; temp = temp->next) + if (option[LENTABLE]) + printf (" case %*d: if (len == %d) s = \"%s\"; else return 0; break;\n", + field_width, temp->hash_value - lowest_case_value, + temp->length, temp->key); + else + printf (" case %*d: s = \"%s\"; break;\n", + field_width, temp->hash_value - lowest_case_value, temp->key); + + printf (" default: return 0;\n }\n "); + if (option[COMP]) + printf ("return %s == *s && !%s;\n }\n", + option[STRCASECMP] ? "charmap[*str]" : "*str", + option[STRCASECMP] ? "strncasecmp (s + 1, str + 1, len - 1)" : "strcmp (s + 1, str + 1)"); + else + printf ("return %s == *s && !%s;\n }\n", + option[STRCASECMP] ? "charmap[*str]" : "*str", + option[STRCASECMP] ? "strcasecmp (s + 1, str + 1, len - 1)" : "strcmp (s + 1, str + 1)"); + curr = temp; + } + } + printf (" }\n %s\n}\n", option[OPTIMIZE] ? "" : "}\n return 0;"); +} + +/* Prints out a table of keyword lengths, for use with the + comparison code in generated function ``in_word_set.'' */ + +void +Key_List::output_keylength_table (void) +{ + const int max_column = 15; + int index = 0; + int column = 0; + char *indent = option[GLOBAL] ? "" : " "; + List_Node *temp; + + if (!option[DUP] && !option[SWITCH]) + { + printf ("\n%sstatic %sunsigned %s lengthtable[] =\n%s%s{\n ", + indent, option[CONST] ? "const " : "", + max_key_len <= UCHAR_MAX ? "char" : (max_key_len <= USHRT_MAX ? "short" : "long"), + indent, indent); + + for (temp = head; temp; temp = temp->next, index++) + { + + if (index < temp->hash_value) + for ( ; index < temp->hash_value; index++) + printf ("%3d,%s", 0, ++column % (max_column - 1) ? "" : "\n "); + + printf ("%3d,%s", temp->length, ++column % (max_column - 1 ) ? "" : "\n "); + } + + printf ("\n%s%s};\n", indent, indent); + } +} +/* Prints out the array containing the key words for the Gen_Perf + hash function. */ + +void +Key_List::output_keyword_table (void) +{ + char *l_brace = *head->rest ? "{" : ""; + char *r_brace = *head->rest ? "}," : ""; + char *indent = option[GLOBAL] ? "" : " "; + int index = 0; + List_Node *temp; + + printf ("%sstatic %s%swordlist[] =\n%s%s{\n", + indent, option[CONST] ? "const " : "", struct_tag, indent, indent); + + /* Skip over leading blank entries if there are no duplicates. */ + + if (0 < head->hash_value) + printf (" "); + for (int column = 1; index < head->hash_value; index++, column++) + printf ("%s\"\",%s %s", l_brace, r_brace, column % 9 ? "" : "\n "); + if (0 < head->hash_value && column % 10) + printf ("\n"); + + /* Generate an array of reserved words at appropriate locations. */ + + for (temp = head ; temp; temp = temp->next, index++) + { + temp->index = index; + + if (!option[SWITCH] && (total_duplicates == 0 || !option[DUP]) && index < temp->hash_value) + { + int column; + + printf (" "); + + for (column = 1; index < temp->hash_value; index++, column++) + printf ("%s\"\",%s %s", l_brace, r_brace, column % 9 ? "" : "\n "); + + if (column % 10) + printf ("\n"); + else + { + printf ("%s\"%s\", %s%s", l_brace, temp->key, temp->rest, r_brace); + if (option[DEBUG]) + printf (" /* hash value = %d, index = %d */", temp->hash_value, temp->index); + putchar ('\n'); + continue; + } + } + + printf (" %s\"%s\", %s%s", l_brace, temp->key, temp->rest, r_brace); + if (option[DEBUG]) + printf (" /* hash value = %d, index = %d */", temp->hash_value, temp->index); + putchar ('\n'); + + /* Deal with links specially. */ + if (temp->link) + for (List_Node *links = temp->link; links; links = links->link) + { + links->index = ++index; + printf (" %s\"%s\", %s%s", l_brace, links->key, links->rest, r_brace); + if (option[DEBUG]) + printf (" /* hash value = %d, index = %d */", links->hash_value, links->index); + putchar ('\n'); + } + } + printf ("%s%s};\n\n", indent, indent); +} + +/* Generates C code for the hash function that returns the + proper encoding for each key word. */ + +void +Key_List::output_hash_function (void) +{ + const int max_column = 10; + int count = max_hash_value; + + /* Calculate maximum number of digits required for MAX_HASH_VALUE. */ + + for (field_width = 2; (count /= 10) > 0; field_width++) + ; + + if (option[GNU]) + printf ("#ifdef __GNUC__\ninline\n#endif\n"); + + if (option[C]) + printf ("static "); + printf ("unsigned int\n"); + if (option[CPLUSPLUS]) + printf ("%s::", option.get_class_name ()); + + printf (option[ANSI] + ? "%s (register const char *str, register int len)\n{\n static %sunsigned %s asso_values[] =\n {" + : "%s (str, len)\n register char *str;\n register int unsigned len;\n{\n static %sunsigned %s asso_values[] =\n {", + option.get_hash_name (), option[CONST] ? "const " : "", + max_hash_value <= UCHAR_MAX ? "char" : (max_hash_value <= USHRT_MAX ? "short" : "int")); + + for (count = 0; count < ALPHA_SIZE; ++count) + { + if (!(count % max_column)) + printf ("\n "); + + printf ("%*d,", + field_width, + Vectors::occurrences[count] ? Vectors::asso_values[count] : max_hash_value + 1); + } + + /* Optimize special case of ``-k 1,$'' */ + if (option[DEFAULTCHARS]) + { + if (option[STRCASECMP]) + printf ("\n };\n return %sasso_values[charmap[str[len - 1]]] + asso_values[charmap[str[0]]];\n}\n\n", + option[NOLENGTH] ? "" : "len + "); + else + printf ("\n };\n return %sasso_values[str[len - 1]] + asso_values[str[0]];\n}\n\n", + option[NOLENGTH] ? "" : "len + "); + } + else + { + int key_pos; + + option.reset (); + + /* Get first (also highest) key position. */ + key_pos = option.get (); + + /* We can perform additional optimizations here. */ + if (!option[ALLCHARS] && key_pos <= min_key_len) + { + printf ("\n };\n return %s", option[NOLENGTH] ? "" : "len + "); + + for (; key_pos != WORD_END; ) + { + printf (option[STRCASECMP] ? "asso_values[charmap[str[%d]]]" : "asso_values[str[%d]]", key_pos - 1); + if ((key_pos = option.get ()) != EOS) + printf (" + "); + else + break; + } + + printf ("%s;\n}\n\n", key_pos == WORD_END + ? (option[STRCASECMP] ? "asso_values[charmap[str[len - 1]]]" : "asso_values[str[len - 1]]") + : ""); + } + + /* We've got to use the correct, but brute force, technique. */ + else + { + printf ("\n };\n register int hval = %s;\n\n switch (%s)\n {\n default:\n", + option[NOLENGTH] ? "0" : "len", option[NOLENGTH] ? "len" : "hval"); + + /* User wants *all* characters considered in hash. */ + if (option[ALLCHARS]) + { + int i; + + /* Break these options up for speed (gee, is this misplaced efficiency or what?! */ + if (option[STRCASECMP]) + + for (i = max_key_len; i > 0; i--) + printf (" case %d:\n hval += asso_values[charmap[str[%d]]];\n", i, i - 1); + + else + + for (i = max_key_len; i > 0; i--) + printf (" case %d:\n hval += asso_values[str[%d]];\n", i, i - 1); + + printf (" }\n return hval;\n}\n\n"); + } + else /* do the hard part... */ + { + count = key_pos + 1; + + do + { + + while (--count > key_pos) + printf (" case %d:\n", count); + + printf (option[STRCASECMP] + ? " case %d:\n hval += asso_values[charmap[str[%d]]];\n" + : " case %d:\n hval += asso_values[str[%d]];\n", + key_pos, key_pos - 1); + } + while ((key_pos = option.get ()) != EOS && key_pos != WORD_END); + + printf (" }\n return hval%s;\n}\n\n", + key_pos == WORD_END + ? (option[STRCASECMP] ? " + asso_values[charmap[str[len - 1]]]" : " + asso_values[str[len - 1]]") + : ""); + } + } + } +} + +/* Generates the large, sparse table that maps hash values into + the smaller, contiguous range of the keyword table. */ + +void +Key_List::output_lookup_array (void) +{ + if (total_duplicates > 0) + { + const int DEFAULT_VALUE = -1; + + struct duplicate_entry + { + int hash_value; /* Hash value for this particular duplicate set. */ + int index; /* Index into the main keyword storage array. */ + int count; /* Number of consecutive duplicates at this index. */ + }; +#if LARGE_STACK_ARRAYS + duplicate_entry duplicates[total_duplicates]; + int lookup_array[max_hash_value + 1]; +#else + // Note: we don't use new, because that invokes a custom operator new. + duplicate_entry *duplicates = (duplicate_entry*) + malloc (total_duplicates * sizeof(duplicate_entry)); + int *lookup_array = (int*)malloc(sizeof(int) * (max_hash_value + 1)); + if (duplicates == NULL || lookup_array == NULL) + abort(); +#endif + duplicate_entry *dup_ptr = duplicates; + int *lookup_ptr = lookup_array + max_hash_value + 1; + + while (lookup_ptr > lookup_array) + *--lookup_ptr = DEFAULT_VALUE; + + for (List_Node *temp = head; temp; temp = temp->next) + { + int hash_value = temp->hash_value; + lookup_array[hash_value] = temp->index; + if (option[DEBUG]) + fprintf (stderr, "keyword = %s, index = %d\n", temp->key, temp->index); + if (!temp->link && + (!temp->next || hash_value != temp->next->hash_value)) + continue; +#if LARGE_STACK_ARRAYS + *dup_ptr = (duplicate_entry) { hash_value, temp->index, 1 }; +#else + duplicate_entry _dups; + _dups.hash_value = hash_value; + _dups.index = temp->index; + _dups.count = 1; + *dup_ptr = _dups; +#endif + + for (List_Node *ptr = temp->link; ptr; ptr = ptr->link) + { + dup_ptr->count++; + if (option[DEBUG]) + fprintf (stderr, "static linked keyword = %s, index = %d\n", ptr->key, ptr->index); + } + + while (temp->next && hash_value == temp->next->hash_value) + { + temp = temp->next; + dup_ptr->count++; + if (option[DEBUG]) + fprintf (stderr, "dynamic linked keyword = %s, index = %d\n", temp->key, temp->index); + + for (List_Node *ptr = temp->link; ptr; ptr = ptr->link) + { + dup_ptr->count++; + if (option[DEBUG]) + fprintf (stderr, "static linked keyword = %s, index = %d\n", ptr->key, ptr->index); + } + } + dup_ptr++; + } + + while (--dup_ptr >= duplicates) + { + if (option[DEBUG]) + fprintf (stderr, "dup_ptr[%d]: hash_value = %d, index = %d, count = %d\n", + dup_ptr - duplicates, dup_ptr->hash_value, dup_ptr->index, dup_ptr->count); + + /* Start searching for available space towards the right part of the lookup array. */ + int i; + for (i = dup_ptr->hash_value; i < max_hash_value; i++) + if (lookup_array[i] == DEFAULT_VALUE && lookup_array[i + 1] == DEFAULT_VALUE) + { + lookup_array[i] = -dup_ptr->index; + lookup_array[i + 1] = -dup_ptr->count; + lookup_array[dup_ptr->hash_value] = max_hash_value + (i - dup_ptr->hash_value); + break; + } + + /* If we didn't find it to the right look to the left instead... */ + if (i == max_hash_value) + { + + for (i = dup_ptr->hash_value; i > 0; i--) + if (lookup_array[i] == DEFAULT_VALUE && lookup_array[i - 1] == DEFAULT_VALUE) + { + lookup_array[i - 1] = -dup_ptr->index; + lookup_array[i] = -dup_ptr->count; + lookup_array[dup_ptr->hash_value] = -(max_hash_value + (dup_ptr->hash_value - i + 1)); + break; + } + + /* We are in *big* trouble if this happens! */ + assert (i != 0); + } + } + + int max = INT_MIN; + lookup_ptr = lookup_array + max_hash_value + 1; + while (lookup_ptr > lookup_array) + { + int val = abs (*--lookup_ptr); + if (max < val) + max = val; + } + + char *indent = option[GLOBAL] ? "" : " "; + printf ("%sstatic %s%s lookup[] =\n%s%s{\n ", indent, option[CONST] ? "const " : "", + max <= SCHAR_MAX ? "char" : (max <= USHRT_MAX ? "short" : "int"), + indent, indent); + + int count = max; + + /* Calculate maximum number of digits required for MAX_HASH_VALUE. */ + + for (field_width = 2; (count /= 10) > 0; field_width++) + ; + + const int max_column = 15; + int column = 0; + + for (lookup_ptr = lookup_array; + lookup_ptr < lookup_array + max_hash_value + 1; + lookup_ptr++) + printf ("%*d,%s", field_width, *lookup_ptr, ++column % (max_column - 1) ? "" : "\n "); + + printf ("\n%s%s};\n\n", indent, indent); +#if !LARGE_STACK_ARRAYS + free (duplicates); + free (lookup_array); +#endif + } +} +/* Generates C code to perform the keyword lookup. */ + +void +Key_List::output_lookup_function (void) +{ + if (!option[OPTIMIZE]) + printf (" if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)\n {\n"); + printf (" register int key = %s (str, len);\n\n", option.get_hash_name ()); + if (!option[OPTIMIZE]) + printf (" if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)\n"); + printf (" {\n"); + + if (option[DUP] && total_duplicates > 0) + { + printf (" register int index = lookup[key];\n\n" + " if (index >= 0 && index < MAX_HASH_VALUE)\n"); + if (option[OPTIMIZE]) + printf (" return %swordlist[index];\n", option[TYPE] && option[POINTER] ? "&" : ""); + else + { + printf (" {\n" + " register %schar *s = wordlist[index]", option[CONST] ? "const " : ""); + if (array_type != default_array_type) + printf (".%s", option.get_key_name ()); + + printf (";\n\n if (%s%s == *s && !%s)\n return %s;\n }\n", + option[LENTABLE] ? "len == lengthtable[key]\n && " : "", + option[STRCASECMP] ? "charmap[*str]" : "*str", + option[COMP] ? (option[STRCASECMP] ? "strncasecmp (str + 1, s + 1, len - 1)" : "strncmp (str + 1, s + 1, len - 1)") + : (option[STRCASECMP] ? "strcasecmp (str + 1, s + 1)" : "strcmp (str + 1, s + 1)"), + option[TYPE] && option[POINTER] ? "&wordlist[index]" : "s"); + printf (" else if (index < 0 && index >= -MAX_HASH_VALUE)\n" + " return 0;\n"); + } + printf (" else\n {\n" + " register int offset = key + index + (index > 0 ? -MAX_HASH_VALUE : MAX_HASH_VALUE);\n" + " register %s%s*base = &wordlist[-lookup[offset]];\n" + " register %s%s*ptr = base + -lookup[offset + 1];\n\n" + " while (--ptr >= base)\n ", + option[CONST] ? "const " : "", struct_tag, + option[CONST] ? "const " : "", struct_tag); + if (array_type != default_array_type) + { + if (option[COMP]) + printf ("if (%s == *ptr->%s && !%s (str + 1, ptr->%s + 1, len - 1", + option[STRCASECMP] ? "charmap[*str]" : "*str", option.get_key_name (), + option[STRCASECMP] ? "strncasecmp" : "strncmp", option.get_key_name ()); + else + printf ("if (%s == *ptr->%s && !%s (str + 1, ptr->%s + 1", + option[STRCASECMP] ? "charmap[*str]" : "*str", option.get_key_name (), + option[STRCASECMP] ? "strcasecmp" : "strcmp", option.get_key_name ()); + } + else + printf (option[STRCASECMP] ? "if (charmap[*str] == **ptr && !%s" : "if (*str == **ptr && !%s", + option[COMP] + ? (option[STRCASECMP] ? "strncasecmp (str + 1, *ptr + 1, len - 1" : "strncmp (str + 1, *ptr + 1, len - 1") + : (option[STRCASECMP] ? "strcasecmp (str + 1, *ptr + 1" : "strcmp (str + 1, *ptr + 1")); + printf ("))\n return %sptr;" + "\n }\n }\n %s\n}\n", array_type == + default_array_type ? "*" : "", option[OPTIMIZE] ? "" : "}\n return 0;"); + } + else + { + if (option[OPTIMIZE]) + printf (" return %swordlist[key]", option[TYPE] && option[POINTER] ? "&" : ""); + else + { + printf (" register %schar *s = wordlist[key]", option[CONST] ? "const " : ""); + + if (array_type != default_array_type) + printf (".%s", option.get_key_name ()); + + printf (";\n\n if (%s%s == *s && !%s)\n return %s", + option[LENTABLE] ? "len == lengthtable[key]\n && " : "", + option[STRCASECMP] ? "charmap[*str]" : "*str", + option[COMP] + ? (option[STRCASECMP] ? "strncasecmp (str + 1, s + 1, len - 1)" : "strncmp (str + 1, s + 1, len - 1)") + : (option[STRCASECMP] ? "strcasecmp (str + 1, s + 1)" : "strcmp (str + 1, s + 1)"), + option[TYPE] && option[POINTER] ? "&wordlist[key]" : "s"); + } + printf (";\n }\n %s\n}\n", option[OPTIMIZE] ? "" : "}\n return 0;"); + } +} + +/* Output the table and the functions that map upper case into lower case! */ + +void +Key_List::output_strcasecmp (void) +{ + printf ("%s", + "/* This array is designed for mapping upper and lower case letter\n" + " * together for a case independent comparison. The mappings are\n" + " * based upon ascii character sequences.\n */" + "static char charmap[] = {\n" + " '\\000', '\\001', '\\002', '\\003', '\\004', '\\005', '\\006', '\\007',\n" + " '\\010', '\\011', '\\012', '\\013', '\\014', '\\015', '\\016', '\\017',\n" + " '\\020', '\\021', '\\022', '\\023', '\\024', '\\025', '\\026', '\\027',\n" + " '\\030', '\\031', '\\032', '\\033', '\\034', '\\035', '\\036', '\\037',\n" + " '\\040', '\\041', '\\042', '\\043', '\\044', '\\045', '\\046', '\\047',\n" + " '\\050', '\\051', '\\052', '\\053', '\\054', '\\055', '\\056', '\\057',\n" + " '\\060', '\\061', '\\062', '\\063', '\\064', '\\065', '\\066', '\\067',\n" + " '\\070', '\\071', '\\072', '\\073', '\\074', '\\075', '\\076', '\\077',\n" + " '\\100', '\\141', '\\142', '\\143', '\\144', '\\145', '\\146', '\\147',\n" + " '\\150', '\\151', '\\152', '\\153', '\\154', '\\155', '\\156', '\\157',\n" + " '\\160', '\\161', '\\162', '\\163', '\\164', '\\165', '\\166', '\\167',\n" + " '\\170', '\\171', '\\172', '\\133', '\\134', '\\135', '\\136', '\\137',\n" + " '\\140', '\\141', '\\142', '\\143', '\\144', '\\145', '\\146', '\\147',\n" + " '\\150', '\\151', '\\152', '\\153', '\\154', '\\155', '\\156', '\\157',\n" + " '\\160', '\\161', '\\162', '\\163', '\\164', '\\165', '\\166', '\\167',\n" + " '\\170', '\\171', '\\172', '\\173', '\\174', '\\175', '\\176', '\\177',\n" + " '\\200', '\\201', '\\202', '\\203', '\\204', '\\205', '\\206', '\\207',\n" + " '\\210', '\\211', '\\212', '\\213', '\\214', '\\215', '\\216', '\\217',\n" + " '\\220', '\\221', '\\222', '\\223', '\\224', '\\225', '\\226', '\\227',\n" + " '\\230', '\\231', '\\232', '\\233', '\\234', '\\235', '\\236', '\\237',\n" + " '\\240', '\\241', '\\242', '\\243', '\\244', '\\245', '\\246', '\\247',\n" + " '\\250', '\\251', '\\252', '\\253', '\\254', '\\255', '\\256', '\\257',\n" + " '\\260', '\\261', '\\262', '\\263', '\\264', '\\265', '\\266', '\\267',\n" + " '\\270', '\\271', '\\272', '\\273', '\\274', '\\275', '\\276', '\\277',\n" + " '\\300', '\\341', '\\342', '\\343', '\\344', '\\345', '\\346', '\\347',\n" + " '\\350', '\\351', '\\352', '\\353', '\\354', '\\355', '\\356', '\\357',\n" + " '\\360', '\\361', '\\362', '\\363', '\\364', '\\365', '\\366', '\\367',\n" + " '\\370', '\\371', '\\372', '\\333', '\\334', '\\335', '\\336', '\\337',\n" + " '\\340', '\\341', '\\342', '\\343', '\\344', '\\345', '\\346', '\\347',\n" + " '\\350', '\\351', '\\352', '\\353', '\\354', '\\355', '\\356', '\\357',\n" + " '\\360', '\\361', '\\362', '\\363', '\\364', '\\365', '\\366', '\\367',\n" + " '\\370', '\\371', '\\372', '\\373', '\\374', '\\375', '\\376', '\\377',\n};\n\nstatic int\n"); + if (option[COMP]) + { + printf ("%s", option[ANSI] + ? "strncasecmp (register char *s1, register char *s2, register int n)" + : "strncasecmp (s1, s2, n)\n register char *s1, *s2;\n register int n;"); + printf ("\n{\n register char *cm = charmap;\n\n while (--n >= 0 && cm[*s1] == cm[*s2++])\n" + " if (*s1++ == '\\0')\n return 0;\n" + "\n return n < 0 ? 0 : cm[*s1] - cm[*--s2];\n}\n\n"); + } + else + { + printf ("%s", option[ANSI] + ? "strcasecmp (register char *s1, register char *s2)" + : "strcasecmp (s1, s2)\n register char *s1, *s2;"); + printf ("\n{\n register char *cm = charmap;\n\n while (cm[*s1] == cm[*s2++])\n" + " if (*s1++ == '\\0')\n return 0;\n" + "\n return cm[*s1] - cm[*--s2];\n}\n\n"); + } +} + +/* Generates the hash function and the key word recognizer function + based upon the user's Options. */ + +void +Key_List::output (void) +{ + printf ("%s\n", include_src); + + if (option[TYPE] && !option[NOTYPE]) /* Output type declaration now, reference it later on.... */ + printf ("%s;\n", array_type); + + output_min_max (); + + if (option[STRCASECMP]) + output_strcasecmp (); + if (option[CPLUSPLUS]) + printf ("class %s\n{\nprivate:\n" + " static unsigned int hash (const char *str, int len);\npublic:\n" + " static %s%s%s (const char *str, int len);\n};\n\n", + option.get_class_name (), option[CONST] ? "const " : "", + return_type, option.get_function_name ()); + + output_hash_function (); + + if (option[GLOBAL]) + if (option[SWITCH]) + { + if (option[LENTABLE] && option[DUP]) + output_keylength_table (); + if (option[POINTER] && option[TYPE]) + output_keyword_table (); + } + else + { + if (option[LENTABLE]) + output_keylength_table (); + output_keyword_table (); + output_lookup_array (); + } + + if (option[GNU]) /* Use the inline keyword to remove function overhead. */ + printf ("#ifdef __GNUC__\ninline\n#endif\n"); + + printf ("%s%s\n", option[CONST] ? "const " : "", return_type); + if (option[CPLUSPLUS]) + printf ("%s::", option.get_class_name ()); + + printf (option[ANSI] + ? "%s (register const char *str, register int len)\n{\n" + : "%s (str, len)\n register char *str;\n register unsigned int len;\n{\n", + option.get_function_name ()); + + if (option[ENUM] && !option[GLOBAL]) + printf (" enum\n {\n" + " TOTAL_KEYWORDS = %d,\n" + " MIN_WORD_LENGTH = %d,\n" + " MAX_WORD_LENGTH = %d,\n" + " MIN_HASH_VALUE = %d,\n" + " MAX_HASH_VALUE = %d,\n" + " HASH_VALUE_RANGE = %d,\n" + " DUPLICATES = %d\n };\n\n", + total_keys, min_key_len, max_key_len, min_hash_value, + max_hash_value, max_hash_value - min_hash_value + 1, + total_duplicates ? total_duplicates + 1 : 0); + /* Use the switch in place of lookup table. */ + if (option[SWITCH]) + { + if (!option[GLOBAL]) + { + if (option[LENTABLE] && option[DUP]) + output_keylength_table (); + if (option[POINTER] && option[TYPE]) + output_keyword_table (); + } + output_switch (); + } + /* Use the lookup table, in place of switch. */ + else + { + if (!option[GLOBAL]) + { + if (option[LENTABLE]) + output_keylength_table (); + output_keyword_table (); + } + if (!option[GLOBAL]) + output_lookup_array (); + output_lookup_function (); + } + + if (additional_code) + { + for (;;) + { + int c = getchar (); + + if (c == EOF) + break; + else + putchar (c); + } + } + + fflush (stdout); +} + +/* Sorts the keys by hash value. */ + +void +Key_List::sort (void) +{ + hash_sort = 1; + occurrence_sort = 0; + + head = merge_sort (head); +} + +/* Dumps the key list to stderr stream. */ + +void +Key_List::dump () +{ + int field_width = option.get_max_keysig_size (); + + fprintf (stderr, "\nList contents are:\n(hash value, key length, index, %*s, keyword):\n", + field_width, "char_set"); + + for (List_Node *ptr = head; ptr; ptr = ptr->next) + fprintf (stderr, "%11d,%11d,%6d, %*s, %s\n", + ptr->hash_value, ptr->length, ptr->index, + field_width, ptr->char_set, ptr->key); +} + +/* Simple-minded constructor action here... */ + +Key_List::Key_List (void) +{ + total_keys = 1; + max_key_len = INT_MIN; + min_key_len = INT_MAX; + return_type = default_return_type; + array_type = struct_tag = default_array_type; + head = 0; + total_duplicates = 0; + additional_code = 0; +} + +/* Returns the length of entire key list. */ + +int +Key_List::keyword_list_length (void) +{ + return list_len; +} + +/* Returns length of longest key read. */ + +int +Key_List::max_key_length (void) +{ + return max_key_len; +} + diff --git a/apps/gperf/src/Key_List.h b/apps/gperf/src/Key_List.h new file mode 100644 index 00000000000..14276eb975d --- /dev/null +++ b/apps/gperf/src/Key_List.h @@ -0,0 +1,116 @@ +/* -*- C++ -*- */ +// @(#)Key_List.h 1.1 10/18/96 + +/* This may look like C code, but it is really -*- C++ -*- */ + +/* Data and function member declarations for the keyword list class. + + Copyright (C) 1989 Free Software Foundation, Inc. + written by Douglas C. Schmidt (schmidt@ics.uci.edu) + +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. */ + +// The key word list is a useful abstraction that keeps track of +// various pieces of information that enable that fast generation of +// the Gen_Perf.hash function. A Key_List is a singly-linked list of +// List_Nodes. + +#ifndef key_list_h +#define key_list_h 1 + +#include "Options.h" +#include "List_Node.h" + +class Key_List +{ +public: + Key_List (void); + ~Key_List (void); + int keyword_list_length (void); + int max_key_length (void); + void reorder (void); + void sort (void); + void read_keys (void); + void output (void); + + List_Node *head; + // Points to the head of the linked list. + + int total_duplicates; + // Total number of duplicate hash values. + +private: + static int get_occurrence (List_Node *ptr); + static int strcspn (const char *s, const char *reject); + static int already_determined (List_Node *ptr); + static void set_determined (List_Node *ptr); + void output_min_max (void); + void output_switch (void); + void output_keyword_table (void); + void output_keylength_table (void); + void output_hash_function (void); + void output_lookup_function (void); + void output_lookup_array (void); + void output_strcasecmp (void); + void set_output_types (void); + void dump (void); + char *get_array_type (void); + char *save_include_src (void); + char *get_special_input (char delimiter); + List_Node *merge (List_Node *list1, List_Node *list2); + List_Node *merge_sort (List_Node *head); + + char *array_type; + // Pointer to the type for word list. + + char *return_type; + // Pointer to return type for lookup function. + + char *struct_tag; + // Shorthand for user-defined struct tag type. + + char *include_src; + // C source code to be included verbatim. + + int max_key_len; + // Maximum length of the longest keyword. + + int min_key_len; + // Minimum length of the shortest keyword. + + int min_hash_value; + // Minimum hash value for all keywords. + + int max_hash_value; + // Maximum hash value for all keywords. + + int occurrence_sort; + // True if sorting by occurrence. + + int hash_sort; + // True if sorting by hash value. + + int additional_code; + // True if any additional C code is included. + + int list_len; + // Length of head's Key_List, not counting duplicates. + + int total_keys; + // Total number of keys, counting duplicates. +}; +#endif diff --git a/apps/gperf/src/List_Node.cpp b/apps/gperf/src/List_Node.cpp new file mode 100644 index 00000000000..d72cc699c13 --- /dev/null +++ b/apps/gperf/src/List_Node.cpp @@ -0,0 +1,110 @@ +/* Creates and initializes a new list node. +// @(#)List_Node.cpp 1.1 10/18/96 + + Copyright (C) 1989 Free Software Foundation, Inc. + written by Douglas C. Schmidt (schmidt@ics.uci.edu) + +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 "Vectors.h" +#include "List_Node.h" + +/* Defined as a macro in string.h on some systems, which causes + conflicts. */ +#undef index + +/* Sorts the key set alphabetically to speed up subsequent operations. + Uses insertion sort since the set is probably quite small. */ + +inline void +List_Node::set_sort (char *base, int len) +{ + int i, j; + + for (i = 0, j = len - 1; i < j; i++) + { + char curr, tmp; + + for (curr = i + 1, tmp = base[curr]; curr > 0 && tmp < base[curr-1]; curr--) + base[curr] = base[curr - 1]; + + base[curr] = tmp; + + } +} + +/* Initializes a List_Node. This requires obtaining memory for the + CHAR_SET initializing them using the information stored in the + KEY_POSITIONS array in Options, and checking for simple errors. + It's important to note that KEY and REST are both pointers to the + different offsets into the same block of dynamic memory pointed to + by parameter K. The data member REST is used to store any + additional fields of the input file (it is set to the "" string if + Option[TYPE] is not enabled). This is useful if the user wishes to + incorporate a lookup structure, rather than just an array of keys. + Finally, KEY_NUMBER contains a count of the total number of keys + seen so far. This is used to initialize the INDEX field to some + useful value. */ + +List_Node::List_Node (char *k, int len) + : key (k), + next (0), + index (0), + length (len), + link (0), + rest (option[TYPE] ? k + len + 1 : "") +{ + char *ptr = new char[(option[ALLCHARS] ? len : option.get_max_keysig_size ()) + 1]; + char_set = ptr; + k[len] = '\0'; /* Null terminate KEY to separate it from REST. */ + + /* Lower case if STRCASECMP option is enabled. */ + if (option[STRCASECMP]) + for (char *p = k; *p; p++) + if (isupper (*p)) + *p = tolower (*p); + + if (option[ALLCHARS]) /* Use all the character position in the KEY. */ + for (; *k; k++, ptr++) + ++Vectors::occurrences[*ptr = *k]; + else /* Only use those character positions specified by the user. */ + { + int i; + + /* Iterate thru the list of key_positions, initializing occurrences table + and char_set (via char * pointer ptr). */ + + for (option.reset (); (i = option.get ()) != EOS; ) + { + if (i == WORD_END) /* Special notation for last KEY position, i.e. '$'. */ + *ptr = key[len - 1]; + else if (i <= len) /* Within range of KEY length, so we'll keep it. */ + *ptr = key[i - 1]; + else /* Out of range of KEY length, so we'll just skip it. */ + continue; + ++Vectors::occurrences[*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 == char_set && option[NOLENGTH]) + ACE_ERROR ((LM_ERROR, "Can't hash keyword %s with chosen key positions.\n%a", key, 1)); + } + *ptr = '\0'; /* Terminate this bastard.... */ + /* Sort the KEY_SET items alphabetically. */ + set_sort (char_set, ptr - char_set); +} diff --git a/apps/gperf/src/List_Node.h b/apps/gperf/src/List_Node.h new file mode 100644 index 00000000000..0cb512f0894 --- /dev/null +++ b/apps/gperf/src/List_Node.h @@ -0,0 +1,65 @@ +/* -*- C++ -*- */ +// @(#)List_Node.h 1.1 10/18/96 + +/* This may look like C code, but it is really -*- C++ -*- */ + +/* Data and function members for defining values and operations of a list node. + + Copyright (C) 1989 Free Software Foundation, Inc. + written by Douglas C. Schmidt (schmidt@ics.uci.edu) + +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 list_node_h +#define list_node_h 1 + +#include "Options.h" + +struct List_Node +{ + List_Node (char *key, int len); + static void set_sort (char *base, int len); + + List_Node *link; + // TRUE if key has an identical KEY_SET as another key. + + List_Node *next; + // Points to next element on the list. + + char *key; + // Each keyword string stored here. + + char *rest; + // Additional information for building hash function. + + char *char_set; + // Set of characters to hash, specified by user. + + int length; + // Length of the key. + + int hash_value; + // Hash value for the key. + + int occurrence; + // A metric for frequency of key set occurrences. + + int index; + // Position of this node relative to other nodes. +}; + +#endif diff --git a/apps/gperf/src/Makefile b/apps/gperf/src/Makefile new file mode 100644 index 00000000000..ca6221f7156 --- /dev/null +++ b/apps/gperf/src/Makefile @@ -0,0 +1,155 @@ +#---------------------------------------------------------------------------- +# @(#)Makefile 1.1 10/18/96 +# +# Makefile for GPERF release +#---------------------------------------------------------------------------- + +BIN = gperf +LIB = libGperf.a + +FILES = new \ + Options \ + Iterator \ + Gen_Perf \ + Key_List \ + List_Node \ + Hash_Table \ + Bool_Array \ + Vectors \ + Version + +LSRC = $(addsuffix .cpp,$(FILES)) +LOBJ = $(addsuffix .o,$(FILES)) + +LDLIBS = -lGperf + +VLDLIBS = $(LDLIBS:%=%$(VAR)) + +BUILD = $(VLIB) $(VBIN) + +#---------------------------------------------------------------------------- +# Include macros and targets +#---------------------------------------------------------------------------- + +include $(WRAPPER_ROOT)/include/makeinclude/wrapper_macros.GNU +include $(WRAPPER_ROOT)/include/makeinclude/macros.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.common.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.nonested.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.lib.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.bin.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.local.GNU + +# DO NOT DELETE THIS LINE -- g++dep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. + +.obj/new.o .shobj/new.so: new.cpp Options.h \ + $(WRAPPER_ROOT)/ace/Log_Msg.h \ + $(WRAPPER_ROOT)/ace/Log_Record.h \ + $(WRAPPER_ROOT)/ace/ACE.h \ + $(WRAPPER_ROOT)/ace/OS.h \ + $(WRAPPER_ROOT)/ace/Time_Value.h \ + $(WRAPPER_ROOT)/ace/config.h \ + $(WRAPPER_ROOT)/ace/Trace.h \ + $(WRAPPER_ROOT)/ace/ACE.i \ + $(WRAPPER_ROOT)/ace/Log_Priority.h \ + $(WRAPPER_ROOT)/ace/Log_Record.i +.obj/Options.o .shobj/Options.so: Options.cpp \ + $(WRAPPER_ROOT)/ace/Get_Opt.h \ + $(WRAPPER_ROOT)/ace/ACE.h \ + $(WRAPPER_ROOT)/ace/OS.h \ + $(WRAPPER_ROOT)/ace/Time_Value.h \ + $(WRAPPER_ROOT)/ace/config.h \ + $(WRAPPER_ROOT)/ace/Trace.h \ + $(WRAPPER_ROOT)/ace/ACE.i \ + $(WRAPPER_ROOT)/ace/Log_Msg.h \ + $(WRAPPER_ROOT)/ace/Log_Record.h \ + $(WRAPPER_ROOT)/ace/Log_Priority.h \ + $(WRAPPER_ROOT)/ace/Log_Record.i \ + Options.h Iterator.h +.obj/Iterator.o .shobj/Iterator.so: Iterator.cpp Iterator.h Options.h \ + $(WRAPPER_ROOT)/ace/Log_Msg.h \ + $(WRAPPER_ROOT)/ace/Log_Record.h \ + $(WRAPPER_ROOT)/ace/ACE.h \ + $(WRAPPER_ROOT)/ace/OS.h \ + $(WRAPPER_ROOT)/ace/Time_Value.h \ + $(WRAPPER_ROOT)/ace/config.h \ + $(WRAPPER_ROOT)/ace/Trace.h \ + $(WRAPPER_ROOT)/ace/ACE.i \ + $(WRAPPER_ROOT)/ace/Log_Priority.h \ + $(WRAPPER_ROOT)/ace/Log_Record.i +.obj/Gen_Perf.o .shobj/Gen_Perf.so: Gen_Perf.cpp Gen_Perf.h Options.h \ + $(WRAPPER_ROOT)/ace/Log_Msg.h \ + $(WRAPPER_ROOT)/ace/Log_Record.h \ + $(WRAPPER_ROOT)/ace/ACE.h \ + $(WRAPPER_ROOT)/ace/OS.h \ + $(WRAPPER_ROOT)/ace/Time_Value.h \ + $(WRAPPER_ROOT)/ace/config.h \ + $(WRAPPER_ROOT)/ace/Trace.h \ + $(WRAPPER_ROOT)/ace/ACE.i \ + $(WRAPPER_ROOT)/ace/Log_Priority.h \ + $(WRAPPER_ROOT)/ace/Log_Record.i \ + Key_List.h List_Node.h Bool_Array.h +.obj/Key_List.o .shobj/Key_List.so: Key_List.cpp \ + $(WRAPPER_ROOT)/ace/Read_Buffer.h \ + $(WRAPPER_ROOT)/ace/ACE.h \ + $(WRAPPER_ROOT)/ace/OS.h \ + $(WRAPPER_ROOT)/ace/Time_Value.h \ + $(WRAPPER_ROOT)/ace/config.h \ + $(WRAPPER_ROOT)/ace/Trace.h \ + $(WRAPPER_ROOT)/ace/ACE.i \ + $(WRAPPER_ROOT)/ace/Log_Msg.h \ + $(WRAPPER_ROOT)/ace/Log_Record.h \ + $(WRAPPER_ROOT)/ace/Log_Priority.h \ + $(WRAPPER_ROOT)/ace/Log_Record.i \ + $(WRAPPER_ROOT)/ace/Malloc.h \ + $(WRAPPER_ROOT)/ace/Malloc_T.h \ + $(WRAPPER_ROOT)/ace/Synch.h \ + $(WRAPPER_ROOT)/ace/Synch_T.h \ + $(WRAPPER_ROOT)/ace/Memory_Pool.h \ + $(WRAPPER_ROOT)/ace/Event_Handler.h \ + $(WRAPPER_ROOT)/ace/Signal.h \ + $(WRAPPER_ROOT)/ace/Set.h \ + $(WRAPPER_ROOT)/ace/Mem_Map.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Complex.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Simple.h \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Simple.i \ + $(WRAPPER_ROOT)/ace/SV_Semaphore_Complex.i \ + $(WRAPPER_ROOT)/ace/Read_Buffer.i \ + Hash_Table.h Options.h List_Node.h Vectors.h Key_List.h +.obj/List_Node.o .shobj/List_Node.so: List_Node.cpp Vectors.h List_Node.h Options.h \ + $(WRAPPER_ROOT)/ace/Log_Msg.h \ + $(WRAPPER_ROOT)/ace/Log_Record.h \ + $(WRAPPER_ROOT)/ace/ACE.h \ + $(WRAPPER_ROOT)/ace/OS.h \ + $(WRAPPER_ROOT)/ace/Time_Value.h \ + $(WRAPPER_ROOT)/ace/config.h \ + $(WRAPPER_ROOT)/ace/Trace.h \ + $(WRAPPER_ROOT)/ace/ACE.i \ + $(WRAPPER_ROOT)/ace/Log_Priority.h \ + $(WRAPPER_ROOT)/ace/Log_Record.i +.obj/Hash_Table.o .shobj/Hash_Table.so: Hash_Table.cpp \ + $(WRAPPER_ROOT)/ace/ACE.h \ + $(WRAPPER_ROOT)/ace/OS.h \ + $(WRAPPER_ROOT)/ace/Time_Value.h \ + $(WRAPPER_ROOT)/ace/config.h \ + $(WRAPPER_ROOT)/ace/Trace.h \ + $(WRAPPER_ROOT)/ace/ACE.i \ + $(WRAPPER_ROOT)/ace/Log_Msg.h \ + $(WRAPPER_ROOT)/ace/Log_Record.h \ + $(WRAPPER_ROOT)/ace/Log_Priority.h \ + $(WRAPPER_ROOT)/ace/Log_Record.i \ + Hash_Table.h Options.h List_Node.h +.obj/Bool_Array.o .shobj/Bool_Array.so: Bool_Array.cpp Bool_Array.h Options.h \ + $(WRAPPER_ROOT)/ace/Log_Msg.h \ + $(WRAPPER_ROOT)/ace/Log_Record.h \ + $(WRAPPER_ROOT)/ace/ACE.h \ + $(WRAPPER_ROOT)/ace/OS.h \ + $(WRAPPER_ROOT)/ace/Time_Value.h \ + $(WRAPPER_ROOT)/ace/config.h \ + $(WRAPPER_ROOT)/ace/Trace.h \ + $(WRAPPER_ROOT)/ace/ACE.i \ + $(WRAPPER_ROOT)/ace/Log_Priority.h \ + $(WRAPPER_ROOT)/ace/Log_Record.i +.obj/Version.o .shobj/Version.so: Version.cpp + +# IF YOU PUT ANYTHING HERE IT WILL GO AWAY diff --git a/apps/gperf/src/Options.cpp b/apps/gperf/src/Options.cpp new file mode 100644 index 00000000000..184187b5a4a --- /dev/null +++ b/apps/gperf/src/Options.cpp @@ -0,0 +1,616 @@ +/* Handles parsing the Options provided to the user. +// @(#)Options.cpp 1.1 10/18/96 + + Copyright (C) 1989 Free Software Foundation, Inc. + written by Douglas C. Schmidt (schmidt@ics.uci.edu) + +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 "ace/Get_Opt.h" +#include "Options.h" +#include "Iterator.h" + +/* Global option coordinator for the entire program. */ +Options option; + +/* Current program version. */ +extern char *version_string; + +/* Size to jump on a collision. */ +static const int DEFAULT_JUMP_VALUE = 5; + +/* Default name for generated lookup function. */ +static const char *const DEFAULT_NAME = "in_word_set"; + +/* Default name for the key component. */ +static const char *const DEFAULT_KEY = "name"; + +/* Default name for the generated class. */ +static const char *const DEFAULT_CLASS_NAME = "Perfect_Hash"; + +/* Default name for generated hash function. */ +static const char *const DEFAULT_HASH_NAME = "hash"; + +/* Default delimiters that separate keywords from their attributes. */ +static const char *const DEFAULT_DELIMITERS = ",\n"; + +int Options::option_word; +int Options::total_switches; +int Options::total_keysig_size; +int Options::size; +int Options::key_pos; +int Options::jump; +int Options::initial_asso_value; +int Options::argument_count; +int Options::iterations; +char **Options::argument_vector; +const char *Options::function_name; +const char *Options::key_name; +const char *Options::class_name; +const char *Options::hash_name; +const char *Options::delimiters; +char Options::key_positions[MAX_KEY_POS]; + +/* Prints program usage to standard error stream. */ + +inline void +Options::usage (void) +{ + ACE_ERROR ((LM_ERROR, "Usage: %n [-acCdDef[num]gGhH<hashname>i<init>Ijk<keys>K<keyname>lL<language>nN<function name>oOprs<size>S<switches>tTvZ<class name>].\n" + "(type %n -h for help)\n")); +} + +/* Output command-line Options. */ + +void +Options::print_options (void) +{ + int i; + + printf ("/* Command-line: "); + + for (i = 0; i < argument_count; i++) + printf ("%s ", argument_vector[i]); + + printf (" */"); +} + +/* Sorts the key positions *IN REVERSE ORDER!!* + This makes further routines more efficient. Especially when generating code. + Uses a simple Insertion Sort since the set is probably ordered. + Returns 1 if there are no duplicates, 0 otherwise. */ + +inline int +Options::key_sort (char *base, int len) +{ + int i, j; + + for (i = 0, j = len - 1; i < j; i++) + { + int curr, tmp; + + for (curr = i + 1,tmp = base[curr]; curr > 0 && tmp >= base[curr - 1]; curr--) + if ((base[curr] = base[curr - 1]) == tmp) /* oh no, a duplicate!!! */ + return 0; + + base[curr] = tmp; + } + + return 1; +} + +/* Sets the default Options. */ + +Options::Options (void) +{ + key_positions[0] = WORD_START; + key_positions[1] = WORD_END; + key_positions[2] = EOS; + total_keysig_size = 2; + delimiters = DEFAULT_DELIMITERS; + jump = DEFAULT_JUMP_VALUE; + option_word = DEFAULTCHARS | C; + function_name = DEFAULT_NAME; + key_name = DEFAULT_KEY; + hash_name = DEFAULT_HASH_NAME; + class_name = DEFAULT_CLASS_NAME; + total_switches = size = 1; + initial_asso_value = iterations = 0; +} + +/* Dumps option status when debug is set. */ + +Options::~Options (void) +{ + if (option_word & DEBUG) + { + char *ptr; + + fprintf (stderr, "\ndumping Options:\nDEBUG is.......: %s\nORDER is.......: %s" + "\nANSI is........: %s\nTYPE is........: %s\nGNU is.........: %s" + "\nRANDOM is......: %s\nDEFAULTCHARS is: %s\nSWITCH is......: %s" + "\nPOINTER is.....: %s\nNOLENGTH is....: %s\nLENTABLE is....: %s" + "\nDUP is.........: %s\nFAST is........: %s\nCOMP is.....: %s" + "\nNOTYPE is......: %s\nGLOBAL is......: %s\nCONST is....: %s" + "\nCPLUSPLUS is...: %s\nC is...........: %s\nENUM is.....: %s" + "\nSTRCASECMP is...: %s\nOPTIMIZE is...........: %s" + "\niterations = %d\nlookup function name = %s\nhash function name = %s" + "\nkey name = %s\njump value = %d\nmax associcated value = %d" + "\ninitial associated value = %d\ndelimiters = %s\nnumber of switch statements = %d\n", + option_word & DEBUG ? "enabled" : "disabled", + option_word & ORDER ? "enabled" : "disabled", + option_word & ANSI ? "enabled" : "disabled", + option_word & TYPE ? "enabled" : "disabled", + option_word & GNU ? "enabled" : "disabled", + option_word & RANDOM ? "enabled" : "disabled", + option_word & DEFAULTCHARS ? "enabled" : "disabled", + option_word & SWITCH ? "enabled" : "disabled", + option_word & POINTER ? "enabled" : "disabled", + option_word & NOLENGTH ? "enabled" : "disabled", + option_word & LENTABLE ? "enabled" : "disabled", + option_word & DUP ? "enabled" : "disabled", + option_word & FAST ? "enabled" : "disabled", + option_word & COMP ? "enabled" : "disabled", + option_word & NOTYPE ? "enabled" : "disabled", + option_word & GLOBAL ? "enabled" : "disabled", + option_word & CONST ? "enabled" : "disabled", + option_word & CPLUSPLUS ? "enabled" : "disabled", + option_word & C ? "enabled" : "disabled", + option_word & ENUM ? "enabled" : "disabled", + option_word & STRCASECMP ? "enabled" : "disabled", + option_word & OPTIMIZE ? "enabled" : "disabled", + iterations, function_name, hash_name, key_name, jump, size - 1, + initial_asso_value, delimiters, total_switches); + if (option_word & ALLCHARS) + fprintf (stderr, "all characters are used in the hash function\n"); + + fprintf (stderr, "maximum keysig size = %d\nkey positions are: \n", + total_keysig_size); + + for (ptr = key_positions; *ptr != EOS; ptr++) + if (*ptr == WORD_END) + fprintf (stderr, "$\n"); + else + fprintf (stderr, "%d\n", *ptr); + + fprintf (stderr, "finished dumping Options\n"); + } +} + + +/* Parses the command line Options and sets appropriate flags in option_word. */ + +void +Options::operator() (int argc, char *argv[]) +{ + ACE_LOG_MSG->open (argv[0]); + + ACE_Get_Opt getopt (argc, argv, "adcCDe:Ef:gGhH:i:Ij:k:K:lL:nN:oOprs:S:tTvZ:"); + int option_char; + + argument_count = argc; + argument_vector = argv; + + while ((option_char = getopt ()) != -1) + { + switch (option_char) + { + case 'a': /* Generated coded uses the ANSI prototype format. */ + { + option_word |= ANSI; + break; + } + case 'c': /* Generate strncmp rather than strcmp. */ + { + option_word |= COMP; + break; + } + case 'C': /* Make the generated tables readonly (const). */ + { + option_word |= CONST; + break; + } + case 'd': /* Enable debugging option. */ + { + option_word |= DEBUG; + ACE_ERROR ((LM_ERROR, "Starting program %n, version %s, with debuggin on.\n", + version_string)); + break; + } + case 'D': /* Enable duplicate option. */ + { + option_word |= DUP; + break; + } + case 'e': /* Allows user to provide keyword/attribute separator */ + { + option.delimiters = getopt.optarg; + break; + } + case 'E': + { + option_word |= ENUM; + break; + } + case 'f': /* Generate the hash table ``fast.'' */ + { + option_word |= FAST; + if ((iterations = atoi (getopt.optarg)) < 0) + { + ACE_ERROR ((LM_ERROR, "iterations value must not be negative, assuming 0\n")); + iterations = 0; + } + break; + } + case 'g': /* Use the ``inline'' keyword for generated sub-routines. */ + { + option_word |= GNU; + break; + } + case 'G': /* Make the keyword table a global variable. */ + { + option_word |= GLOBAL; + break; + } + case 'h': /* Displays a list of helpful Options to the user. */ + { + ACE_ERROR ((LM_ERROR, + "-a\tGenerate ANSI standard C output code, i.e., function prototypes.\n" + "-c\tGenerate comparison code using strncmp rather than strcmp.\n" + "-C\tMake the contents of generated lookup tables constant, i.e., readonly.\n" + "-d\tEnables the debugging option (produces verbose output to the standard error).\n" + "-D\tHandle keywords that hash to duplicate values. This is useful\n" + "\tfor certain highly redundant keyword sets. It enables the -S option.\n" + "-e\tAllow user to provide a string containing delimiters used to separate\n" + "\tkeywords from their attributes. Default is \",\\n\"\n" + "-E\tDefine constant values using an enum local to the lookup function\n" + "\trather than with defines\n" + "-f\tGenerate the gen-perf.hash function ``fast.'' This decreases GPERF's\n" + "\trunning time at the cost of minimizing generated table-size.\n" + "\tThe numeric argument represents the number of times to iterate when\n" + "\tresolving a collision. `0' means ``iterate by the number of keywords.''\n" + "-g\tAssume a GNU compiler, e.g., g++ or gcc. This makes all generated\n" + "\troutines use the ``inline'' keyword to remove cost of function calls.\n" + "-G\tGenerate the static table of keywords as a static global variable,\n" + "\trather than hiding it inside of the lookup function (which is the\n" + "\tdefault behavior).\n" + "-h\tPrints this mesage.\n" + "-H\tAllow user to specify name of generated hash function. Default\n" + "\tis `hash'.\n" + "-i\tProvide an initial value for the associate values array. Default is 0.\n" + "-I\tGenerate comparison code using case insensitive string comparison, e.g.,\n" + "\tstrncasecmp or strcasecmp.\n" + "\tSetting this value larger helps inflate the size of the final table.\n" + "-j\tAffects the ``jump value,'' i.e., how far to advance the associated\n" + "\tcharacter value upon collisions. Must be an odd number, default is %d.\n" + "-k\tAllows selection of the key positions used in the hash function.\n" + "\tThe allowable choices range between 1-%d, inclusive. The positions\n" + "\tare separated by commas, ranges may be used, and key positions may\n" + "\toccur in any order. Also, the meta-character '*' causes the generated\n" + "\thash function to consider ALL key positions, and $ indicates the\n" + "\t``final character'' of a key, e.g., $,1,2,4,6-10.\n" + "-K\tAllow use to select name of the keyword component in the keyword structure.\n" + "-l\tCompare key lengths before trying a string comparison. This helps\n" + "\tcut down on the number of string comparisons made during the lookup.\n" + "-L\tGenerates code in the language specified by the option's argument. Languages\n" + "\thandled are currently C++ and C. The default is C.\n" + "-n\tDo not include the length of the keyword when computing the hash function\n" + "-N\tAllow user to specify name of generated lookup function. Default\n" + "\tname is `in_word_set.'\n" + "-o\tReorders input keys by frequency of occurrence of the key sets.\n" + "\tThis should decrease the search time dramatically.\n" + "-O\tOptimize the generated lookup function by assuming that all input keywords \n" + "\tare members of the keyset from the keyfile.\n" + "-p\tChanges the return value of the generated function ``in_word_set''\n" + "\tfrom its default boolean value (i.e., 0 or 1), to type ``pointer\n" + "\tto wordlist array'' This is most useful when the -t option, allowing\n" + "\tuser-defined structs, is used.\n" + "-r\tUtilizes randomness to initialize the associated values table.\n" + "-s\tAffects the size of the generated hash table. The numeric argument\n" + "\tfor this option indicates ``how many times larger or smaller'' the associated\n" + "\tvalue range should be, in relationship to the number of keys, e.g. a value of 3\n" + "\tmeans ``allow the maximum associated value to be about 3 times larger than the\n" + "\tnumber of input keys.'' Conversely, a value of -3 means ``make the maximum\n" + "\tassociated value about 3 times smaller than the number of input keys.\n" + "\tA larger table should decrease the time required for an unsuccessful search,\n" + "\tat the expense of extra table space. Default value is 1.\n" + "-S\tCauses the generated C code to use a switch statement scheme, rather\n" + "\tthan an array lookup table. This can lead to a reduction in both\n" + "\ttime and space requirements for some keyfiles. The argument to\n" + "\tthis option determines how many switch statements are generated.\n" + "\tA value of 1 generates 1 switch containing all the elements, a value of 2\n" + "\tgenerates 2 tables with 1/2 the elements in each table, etc. This\n" + "\tis useful since many C compilers cannot correctly generate code for\n" + "\tlarge switch statements.\n" + "-t\tAllows the user to include a structured type declaration for \n" + "\tgenerated code. Any text before %%%% is consider part of the type\n" + "\tdeclaration. Key words and additional fields may follow this, one\n" + "\tgroup of fields per line.\n" + "-T\tPrevents the transfer of the type declaration to the output file.\n" + "\tUse this option if the type is already defined elsewhere.\n" + "-v\tPrints out the current version number\n" + "-Z\tAllow user to specify name of generated C++ class. Default\n" + "\tname is `Perfect_Hash.'\n%e%a", DEFAULT_JUMP_VALUE, (MAX_KEY_POS - 1), usage, 1)); + } + case 'H': /* Sets the name for the hash function */ + { + hash_name = getopt.optarg; + break; + } + case 'i': /* Sets the initial value for the associated values array. */ + { + if ((initial_asso_value = atoi (getopt.optarg)) < 0) + ACE_ERROR ((LM_ERROR, "Initial value %d should be non-zero, ignoring and continuing.\n", initial_asso_value)); + if (option[RANDOM]) + ACE_ERROR ((LM_ERROR, "warning, -r option superceeds -i, ignoring -i option and continuing\n")); + break; + } + case 'I': + { + option_word |= STRCASECMP; + break; + } + case 'j': /* Sets the jump value, must be odd for later algorithms. */ + { + if ((jump = atoi (getopt.optarg)) < 0) + ACE_ERROR ((LM_ERROR, "Jump value %d must be a positive number.\n%e%a", jump, usage, 1)); + else if (jump && ACE_EVEN (jump)) + ACE_ERROR ((LM_ERROR, "Jump value %d should be odd, adding 1 and continuing...\n", jump++)); + break; + } + case 'k': /* Sets key positions used for hash function. */ + { + const int BAD_VALUE = -1; + int value; + Iterator expand (getopt.optarg, 1, MAX_KEY_POS - 1, WORD_END, BAD_VALUE, EOS); + + if (*getopt.optarg == '*') /* Use all the characters for hashing!!!! */ + option_word = (option_word & ~DEFAULTCHARS) | ALLCHARS; + else + { + char *l_key_pos; + + for (l_key_pos = key_positions; (value = expand ()) != EOS; l_key_pos++) + if (value == BAD_VALUE) + ACE_ERROR ((LM_ERROR, "Illegal key value or range, use 1,2,3-%d,'$' or '*'.\n%e%a", + MAX_KEY_POS - 1, usage, 1)); + else + *l_key_pos = value;; + + *l_key_pos = EOS; + + if (! (total_keysig_size = (l_key_pos - key_positions))) + ACE_ERROR ((LM_ERROR, "No keys selected.\n%e%a", usage, 1)); + else if (! key_sort (key_positions, total_keysig_size)) + ACE_ERROR ((LM_ERROR, "Duplicate keys selected\n%e%a", usage, 1)); + + if (total_keysig_size != 2 + || (key_positions[0] != 1 || key_positions[1] != WORD_END)) + option_word &= ~DEFAULTCHARS; + } + break; + } + case 'K': /* Make this the keyname for the keyword component field. */ + { + key_name = getopt.optarg; + break; + } + case 'l': /* Create length table to avoid extra string compares. */ + { + option_word |= LENTABLE; + break; + } + case 'L': /* Deal with different generated languages. */ + { + option_word &= ~C; + if (!strcmp (getopt.optarg, "C++")) + option_word |= (CPLUSPLUS | ANSI); + else if (!strcmp (getopt.optarg, "C")) + option_word |= C; + else + { + ACE_ERROR ((LM_ERROR, "unsupported language option %s, defaulting to C\n", getopt.optarg)); + option_word |= C; + } + break; + } + case 'n': /* Don't include the length when computing hash function. */ + { + option_word |= NOLENGTH; + break; + } + case 'N': /* Make generated lookup function name be optarg */ + { + function_name = getopt.optarg; + break; + } + case 'o': /* Order input by frequency of key set occurrence. */ + { + option_word |= ORDER; + break; + } + case 'O': + { + option_word |= OPTIMIZE; + break; + } + case 'p': /* Generated lookup function now a pointer instead of int. */ + { + option_word |= POINTER; + break; + } + case 'r': /* Utilize randomness to initialize the associated values table. */ + { + option_word |= RANDOM; + if (option.initial_asso_value != 0) + ACE_ERROR ((LM_ERROR, "warning, -r option superceeds -i, disabling -i option and continuing\n")); + break; + } + case 's': /* Range of associated values, determines size of final table. */ + { + if (abs (size = atoi (getopt.optarg)) > 50) + ACE_ERROR ((LM_ERROR, "%d is excessive, did you really mean this?! (type %n -h for help)\n", size)); + break; + } + case 'S': /* Generate switch statement output, rather than lookup table. */ + { + option_word |= SWITCH; + if ((option.total_switches = atoi (getopt.optarg)) <= 0) + ACE_ERROR ((LM_ERROR, "number of switches %s must be a positive number\n%e%a", getopt.optarg, usage, 1)); + break; + } + case 't': /* Enable the TYPE mode, allowing arbitrary user structures. */ + { + option_word |= TYPE; + break; + } + case 'T': /* Don't print structure definition. */ + { + option_word |= NOTYPE; + break; + } + case 'v': /* Print out the version and quit. */ + ACE_ERROR ((LM_ERROR, "%n: version %s\n%e\n%a", version_string, usage, 1)); + case 'Z': /* Set the class name. */ + { + class_name = getopt.optarg; + break; + } + default: + ACE_ERROR ((LM_ERROR, "%e%a", usage, 1)); + } + + } + + if (argv[getopt.optind] && ! freopen (argv[getopt.optind], "r", stdin)) + ACE_ERROR ((LM_ERROR, "Cannot open keyword file %p\n%e%a", argv[getopt.optind], usage, 1)); + + if (++getopt.optind < argc) + ACE_ERROR ((LM_ERROR, "Extra trailing arguments to %n.\n%e%a", usage, 1)); +} + +int +Options::operator[] (Option_Type option) /* True if option enable, else false. */ +{ + return option_word & option; +} + +void +Options::operator = (enum Option_Type opt) /* Enables option OPT. */ +{ + option_word |= opt; +} + +void +Options::operator != (enum Option_Type opt) /* Disables option OPT. */ +{ + option_word &= ~opt; +} + +void +Options::reset (void) /* Initializes the key Iterator. */ +{ + key_pos = 0; +} + +int +Options::get (void) /* Returns current key_position and advanced index. */ +{ + return key_positions[key_pos++]; +} + +void +Options::set_asso_max (int r) /* Sets the size of the table size. */ +{ + size = r; +} + +int +Options::get_asso_max (void) /* Returns the size of the table size. */ +{ + return size; +} + +int +Options::get_max_keysig_size (void) /* Returns total distinct key positions. */ +{ + return total_keysig_size; +} + +void +Options::set_keysig_size (int a_size) /* Sets total distinct key positions. */ +{ + total_keysig_size = a_size; +} + +int +Options::get_jump (void) /* Returns the jump value. */ +{ + return jump; +} + +const char * +Options::get_function_name (void) /* Returns the generated function name. */ +{ + return function_name; +} + +const char * +Options::get_key_name (void) /* Returns the keyword key name. */ +{ + return key_name; +} + +const char * +Options::get_hash_name (void) /* Returns the hash function name. */ +{ + return hash_name; +} + +const char * +Options::get_class_name (void) /* Returns the generated class name. */ +{ + return class_name; +} + +int +Options::initial_value (void) /* Returns the initial associated character value. */ +{ + return initial_asso_value; +} + +int +Options::get_iterations (void) /* Returns the iterations value. */ +{ + return iterations; +} + +const char * +Options::get_delimiter () /* Returns the string used to delimit keywords from other attributes. */ +{ + return delimiters; +} + +int +Options::get_total_switches () /* Gets the total number of switch statements to generate. */ +{ + return total_switches; +} + + + + diff --git a/apps/gperf/src/Options.h b/apps/gperf/src/Options.h new file mode 100644 index 00000000000..2d67003d991 --- /dev/null +++ b/apps/gperf/src/Options.h @@ -0,0 +1,140 @@ +/* -*- C++ -*- */ +// @(#)Options.h 1.1 10/18/96 + +/* This may look like C code, but it is really -*- C++ -*- */ + +/* Handles parsing the Options provided to the user. + + Copyright (C) 1989 Free Software Foundation, Inc. + written by Douglas C. Schmidt (schmidt@ics.uci.edu) + +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. */ + +/* This module provides a uniform interface to the various options + available to a user of the gperf hash function generator. In + addition to the run-time options, found in the Option_Type below, + there is also the hash table Size and the Keys to be used in the + hashing. The overall design of this module was an experiment in + using C++ classes as a mechanism to enhance centralization of + option and and error handling, which tend to get out of hand in a C + program. */ + +#ifndef options_h +#define options_h 1 + +#include "ace/Log_Msg.h" + +/* Enumerate the potential debugging Options. */ + +enum Option_Type +{ + DEBUG = 01, /* Enable debugging (prints diagnostics to stderr). */ + ORDER = 02, /* Apply ordering heuristic to speed-up search time. */ + ANSI = 04, /* Generate ANSI prototypes. */ + ALLCHARS = 010, /* Use all characters in hash function. */ + GNU = 020, /* Assume GNU extensions (primarily function inline). */ + TYPE = 040, /* Handle user-defined type structured keyword input. */ + RANDOM = 0100, /* Randomly initialize the associated values table. */ + DEFAULTCHARS = 0200, /* Make default char positions be 1,$ (end of keyword). */ + SWITCH = 0400, /* Generate switch output to save space. */ + POINTER = 01000, /* Have in_word_set function return pointer, not boolean. */ + NOLENGTH = 02000, /* Don't include keyword length in hash computations. */ + LENTABLE = 04000, /* Generate a length table for string comparison. */ + DUP = 010000, /* Handle duplicate hash values for keywords. */ + FAST = 020000, /* Generate the hash function ``fast.'' */ + NOTYPE = 040000, /* Don't include user-defined type definition in output -- it's already defined elsewhere. */ + COMP = 0100000, /* Generate strncmp rather than strcmp. */ + GLOBAL = 0200000, /* Make the keyword table a global variable. */ + CONST = 0400000, /* Make the generated tables readonly (const). */ + CPLUSPLUS = 01000000, /* Generate C++ code. */ + C = 02000000, /* Generate C code. */ + ENUM = 04000000, /* Use enum for constants. */ + STRCASECMP = 010000000, /* Use the case insensitive comparison. */ + OPTIMIZE = 020000000, /* Assume all input keywords are in the keyset. */ + ADA = 040000000 /* Generate Ada code. */ +}; + +/* Define some useful constants (these don't really belong here, but I'm + not sure where else to put them!). These should be consts, but g++ + doesn't seem to do the right thing with them at the moment... ;-( */ + +enum +{ + MAX_KEY_POS = 128 - 1, /* Max size of each word's key set. */ + WORD_START = 1, /* Signals the start of a word. */ + WORD_END = 0, /* Signals the end of a word. */ + EOS = MAX_KEY_POS /* Signals end of the key list. */ +}; + +/* Class manager for gperf program Options. */ + +class Options +{ +public: + Options (void); + ~Options (void); + int operator[] (Option_Type option); + void operator() (int argc, char *argv[]); + void operator= (enum Option_Type); + void operator!= (enum Option_Type); + static void print_options (void); + static void set_asso_max (int r); + static int get_asso_max (void); + static void reset (void); + static int get (void); + static int get_iterations (void); + static int get_max_keysig_size (void); + static void set_keysig_size (int); + static int get_jump (void); + static int initial_value (void); + static int get_total_switches (void); + static const char *get_function_name (void); + static const char *get_key_name (void); + static const char *get_class_name (void); + static const char *get_hash_name (void); + static const char *get_delimiter (void); + +private: + static int option_word; /* Holds the user-specified Options. */ + static int total_switches; /* Number of switch statements to generate. */ + static int total_keysig_size; /* Total number of distinct key_positions. */ + static int size; /* Range of the hash table. */ + static int key_pos; /* Tracks current key position for Iterator. */ + static int jump; /* Jump length when trying alternative values. */ + static int initial_asso_value; /* Initial value for asso_values table. */ + static int argument_count; /* Records count of command-line arguments. */ + static int iterations; /* Amount to iterate when a collision occurs. */ + static char **argument_vector; /* Stores a pointer to command-line vector. */ + static const char *function_name; /* Names used for generated lookup function. */ + static const char *key_name; /* Name used for keyword key. */ + static const char *class_name; /* Name used for generated C++ class. */ + static const char *hash_name; /* Name used for generated hash function. */ + static const char *delimiters; /* Separates keywords from other attributes. */ + static char key_positions[MAX_KEY_POS]; /* Contains user-specified key choices. */ + static int key_sort (char *base, int len); /* Sorts key positions in REVERSE order. */ + static void usage (void); /* Prints proper program usage. */ +}; + +/* Global option coordinator for the entire program. */ +extern Options option; + +/* Set to 1 if your want to stack-allocate some large arrays. */ +#ifndef LARGE_STACK_ARRAYS +#define LARGE_STACK_ARRAYS 0 +#endif + +#endif diff --git a/apps/gperf/src/Vectors.cpp b/apps/gperf/src/Vectors.cpp new file mode 100644 index 00000000000..761e08b2672 --- /dev/null +++ b/apps/gperf/src/Vectors.cpp @@ -0,0 +1,33 @@ +/* This may look like C code, but it is really -*- C++ -*- */ +// @(#)Vectors.cpp 1.1 10/18/96 + + +/* Static class data members that are shared between several classes via + inheritance. + + Copyright (C) 1989 Free Software Foundation, Inc. + written by Douglas C. Schmidt (schmidt@ics.uci.edu) + +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 "Vectors.h" + +// Counts occurrences of each key set character. +int Vectors::occurrences[ALPHA_SIZE]; + +// Value associated with each character. +int Vectors::asso_values[ALPHA_SIZE]; diff --git a/apps/gperf/src/Vectors.h b/apps/gperf/src/Vectors.h new file mode 100644 index 00000000000..c01e9f27d8f --- /dev/null +++ b/apps/gperf/src/Vectors.h @@ -0,0 +1,44 @@ +/* -*- C++ -*- */ +// @(#)Vectors.h 1.1 10/18/96 + +#include <stdio.h> + +/* This may look like C code, but it is really -*- C++ -*- */ + +/* Static class data members that are shared between several classes via + inheritance. + + Copyright (C) 1989 Free Software Foundation, Inc. + written by Douglas C. Schmidt (schmidt@ics.uci.edu) + +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 vectors_h +#define vectors_h 1 + +static const int ALPHA_SIZE = 128; + +struct Vectors +{ + static int occurrences[ALPHA_SIZE]; + // Counts occurrences of each key set character. + + static int asso_values[ALPHA_SIZE]; + // Value associated with each character. +}; + +#endif diff --git a/apps/gperf/src/Version.cpp b/apps/gperf/src/Version.cpp new file mode 100644 index 00000000000..8fb0d398887 --- /dev/null +++ b/apps/gperf/src/Version.cpp @@ -0,0 +1,25 @@ +/* Current program version number. +// @(#)Version.cpp 1.1 10/18/96 + + + Copyright (C) 1989 Free Software Foundation, Inc. + written by Douglas C. Schmidt (schmidt@ics.uci.edu) + +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. */ + +char *version_string = "2.6 (GNU C++ version)"; diff --git a/apps/gperf/src/gperf.cpp b/apps/gperf/src/gperf.cpp new file mode 100644 index 00000000000..2e6aa2c6406 --- /dev/null +++ b/apps/gperf/src/gperf.cpp @@ -0,0 +1,66 @@ +/* Driver program for the Gen_Perf hash function generator Copyright +// @(#)gperf.cpp 1.1 10/18/96 + + (C) 1989 Free Software Foundation, Inc. written by Douglas + C. Schmidt (schmidt@ics.uci.edu) + +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. */ + +// Simple driver program for the Gen_Perf.hash function generator. +// All the hard work is done in class Gen_Perf and its class methods. + +#include "Options.h" +#include "Gen_Perf.h" + +int +main (int argc, char *argv[]) +{ + + struct tm *tm; + time_t clock; + + time (&clock); + tm = localtime (&clock); + printf ("/* starting time is %d:%02d:%02d */\n", tm->tm_hour, tm->tm_min, tm->tm_sec); + +#if defined(RLIMIT_STACK) && LARGE_STACK_ARRAYS + /* Get rid of any avoidable limit on stack size. */ + { + struct rlimit rlim; + + /* Set the stack limit huge so that alloca does not fail. */ + getrlimit (RLIMIT_STACK, &rlim); + rlim.rlim_cur = rlim.rlim_max; + setrlimit (RLIMIT_STACK, &rlim); + } +#endif /* RLIMIT_STACK */ + + /* Sets the Options. */ + option (argc, argv); + + // Initializes the key word list. + Gen_Perf table; + + // Generates and prints the Gen_Perf hash table. Don't use exit + // here, it skips the destructors. + int status = table.generate (); + + time (&clock); + tm = localtime (&clock); + printf ("/* ending time is %d:%02d:%02d */\n", tm->tm_hour, tm->tm_min, tm->tm_sec); + return status; +} diff --git a/apps/gperf/src/new.cpp b/apps/gperf/src/new.cpp new file mode 100644 index 00000000000..ebaafa16917 --- /dev/null +++ b/apps/gperf/src/new.cpp @@ -0,0 +1,75 @@ +/* Defines a buffered memory allocation abstraction that reduces calls to +// @(#)new.cpp 1.1 10/18/96 + + malloc. + Copyright (C) 1989 Free Software Foundation, Inc. + written by Douglas C. Schmidt (schmidt@ics.uci.edu) + +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 "Options.h" + +/* Determine default alignment. If your C++ compiler does not like + this then try something like #define DEFAULT_ALIGNMENT 8. */ +struct fooalign {char x; double d;}; +const int ALIGNMENT = ((char *)&((struct fooalign *) 0)->d - (char *)0); + +/* Provide an abstraction that cuts down on the number of calls to NEW + by buffering the memory pool from which strings are allocated. */ + +void * +operator new (size_t size) +{ + static char *buf_start = 0; /* Large array used to reduce calls to NEW. */ + static char *buf_end = 0; /* Indicates end of BUF_START. */ + static int buf_size = 4 * BUFSIZ; /* Size of buffer pointed to by BUF_START. */ + char *temp; + + /* Align this on correct boundaries, just to be safe... */ + size = ((size + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT; + + /* If we are about to overflow our buffer we'll just grab another + chunk of memory. Since we never free the original memory it + doesn't matter that no one points to the beginning of that + chunk. Note we use a heuristic that grows the buffer either by + size of the request or by twice the previous size, whichever is + larger. */ + + if (buf_start + size >= buf_end) + { + buf_size *= 2; + if (buf_size < size) + buf_size = size; + if (buf_start = (char *)malloc (buf_size)) + buf_end = buf_start + buf_size; + else + ACE_ERROR ((LM_ERROR, "Virtual memory failed at %s, %s in function %s\n%a", __FILE__, __LINE__, "operator new", 1)); + } + + temp = buf_start; + buf_start += size; + return temp; +} + +/* We need this deletion operator in order to make the linker happy. */ + +void +operator delete (void *ptr) +{ + // We cannot call free here, as it doesn't match the mallocs. + // free ((char *) ptr); +} |