mirror of
https://git.savannah.gnu.org/git/gperf.git
synced 2025-12-02 21:19:24 +00:00
Rework the options handling.
This commit is contained in:
47
ChangeLog
47
ChangeLog
@@ -1,3 +1,50 @@
|
|||||||
|
2002-10-14 Bruno Haible <bruno@clisp.org>
|
||||||
|
|
||||||
|
* src/options.h (Positions): New class.
|
||||||
|
(PositionIterator): New class.
|
||||||
|
(Options::parse_options): Renamed from Options::operator().
|
||||||
|
(Options::get_asso_max, Options::set_asso_max): Move to class Key_List.
|
||||||
|
(Options::reset, Options::get): Remove, replaced by class
|
||||||
|
PositionIterator.
|
||||||
|
(Options::get_initial_asso_value): Renamed from Options::initial_value.
|
||||||
|
(Options::key_sort): Remove, replaced by Positions::sort.
|
||||||
|
(Options): Make all fields and methods non-static.
|
||||||
|
* src/options.icc (Positions::Positions, Positions::operator[],
|
||||||
|
Positions::get_size, Positions::pointer, Positions::set_size,
|
||||||
|
Positions::sort, PositionIterator::PositionIterator,
|
||||||
|
PositionIterator::next): New methods.
|
||||||
|
(Options::get_initial_asso_value): Renamed from Options::initial_value.
|
||||||
|
(Options::get_size_multiple): New method.
|
||||||
|
(Options::get_key_positions): New method.
|
||||||
|
(Options::get_max_keysig_size): Implement using _key_positions.
|
||||||
|
* src/options.cc (Options::long_usage): Split big string into small
|
||||||
|
pieces.
|
||||||
|
(PositionStringParser): Prefix field names with _.
|
||||||
|
(Options::Options): Update.
|
||||||
|
(Options::~Options): Fix explanation of of _size_multiple. Don't print
|
||||||
|
_key_positions if it is effectively ignored.
|
||||||
|
(Options::parse_options): Renamed from Options::operator(). Update.
|
||||||
|
* src/key-list.h (Key_List): New field _size. New methods get_asso_max,
|
||||||
|
set_asso_max, get_max_keysig_size.
|
||||||
|
* src/key-list.cc (Key_List::read_keys): Don't make side effects on
|
||||||
|
options.
|
||||||
|
(Key_List::dump): Use Key_List::get_max_keysig_size() instead of
|
||||||
|
Options::get_max_keysig_size().
|
||||||
|
(Key_List::get_max_keysig_size): New function.
|
||||||
|
* src/hash-table.cc (Hash_Table::~Hash_Table): Compute the field
|
||||||
|
width on the fly if option[ALLCHARS].
|
||||||
|
* src/gen-perf.cc (Gen_Perf::Gen_Perf): Update,
|
||||||
|
Use Options::get_size_multiple() instead of Options::get_asso_max().
|
||||||
|
Use Key_List::get_asso_max() instead of Options::get_asso_max(). Use
|
||||||
|
Key_List::get_max_keysig_size() instead of
|
||||||
|
Options::get_max_keysig_size().
|
||||||
|
(Gen_Perf::affects_prev): Likewise.
|
||||||
|
(Gen_Perf::change): Likewise.
|
||||||
|
* src/keyword.cc: Update.
|
||||||
|
* src/main.cc: Update.
|
||||||
|
* src/output.cc: Update.
|
||||||
|
* tests/test-6.exp: Update.
|
||||||
|
|
||||||
2002-10-13 Bruno Haible <bruno@clisp.org>
|
2002-10-13 Bruno Haible <bruno@clisp.org>
|
||||||
|
|
||||||
* src/bool-array.*: Some polishing.
|
* src/bool-array.*: Some polishing.
|
||||||
|
|||||||
@@ -43,17 +43,17 @@ Gen_Perf::Gen_Perf ()
|
|||||||
Key_List::read_keys ();
|
Key_List::read_keys ();
|
||||||
if (option[ORDER])
|
if (option[ORDER])
|
||||||
reorder ();
|
reorder ();
|
||||||
asso_value_max = option.get_asso_max ();
|
|
||||||
non_linked_length = Key_List::keyword_list_length ();
|
|
||||||
_num_done = 1;
|
_num_done = 1;
|
||||||
_fewest_collisions = 0;
|
_fewest_collisions = 0;
|
||||||
|
asso_value_max = option.get_size_multiple ();
|
||||||
|
non_linked_length = Key_List::keyword_list_length ();
|
||||||
if (asso_value_max == 0)
|
if (asso_value_max == 0)
|
||||||
asso_value_max = non_linked_length;
|
asso_value_max = non_linked_length;
|
||||||
else if (asso_value_max > 0)
|
else if (asso_value_max > 0)
|
||||||
asso_value_max *= non_linked_length;
|
asso_value_max *= non_linked_length;
|
||||||
else /* if (asso_value_max < 0) */
|
else /* if (asso_value_max < 0) */
|
||||||
asso_value_max = non_linked_length / -asso_value_max;
|
asso_value_max = non_linked_length / -asso_value_max;
|
||||||
option.set_asso_max (POW (asso_value_max));
|
set_asso_max (POW (asso_value_max));
|
||||||
|
|
||||||
if (option[RANDOM])
|
if (option[RANDOM])
|
||||||
{
|
{
|
||||||
@@ -64,14 +64,14 @@ Gen_Perf::Gen_Perf ()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int asso_value = option.initial_value ();
|
int asso_value = option.get_initial_asso_value ();
|
||||||
|
|
||||||
if (asso_value) /* Initialize array if user requests non-zero default. */
|
if (asso_value) /* Initialize array if user requests non-zero default. */
|
||||||
for (int i = ALPHA_SIZE - 1; i >= 0; i--)
|
for (int i = ALPHA_SIZE - 1; i >= 0; i--)
|
||||||
_asso_values[i] = asso_value & option.get_asso_max () - 1;
|
_asso_values[i] = asso_value & get_asso_max () - 1;
|
||||||
}
|
}
|
||||||
_max_hash_value = Key_List::max_key_length () + option.get_asso_max () *
|
_max_hash_value = Key_List::max_key_length () + get_asso_max () *
|
||||||
option.get_max_keysig_size ();
|
get_max_keysig_size ();
|
||||||
_collision_detector = new Bool_Array (_max_hash_value + 1);
|
_collision_detector = new Bool_Array (_max_hash_value + 1);
|
||||||
|
|
||||||
if (option[DEBUG])
|
if (option[DEBUG])
|
||||||
@@ -172,7 +172,7 @@ Gen_Perf::affects_prev (char c, KeywordExt *curr)
|
|||||||
{
|
{
|
||||||
int original_char = _asso_values[(unsigned char)c];
|
int original_char = _asso_values[(unsigned char)c];
|
||||||
int total_iterations = !option[FAST]
|
int total_iterations = !option[FAST]
|
||||||
? option.get_asso_max () : option.get_iterations () ? option.get_iterations () : keyword_list_length ();
|
? get_asso_max () : option.get_iterations () ? option.get_iterations () : keyword_list_length ();
|
||||||
|
|
||||||
/* Try all legal associated values. */
|
/* Try all legal associated values. */
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ Gen_Perf::affects_prev (char c, KeywordExt *curr)
|
|||||||
|
|
||||||
_asso_values[(unsigned char)c] =
|
_asso_values[(unsigned char)c] =
|
||||||
(_asso_values[(unsigned char)c] + (option.get_jump () ? option.get_jump () : rand ()))
|
(_asso_values[(unsigned char)c] + (option.get_jump () ? option.get_jump () : rand ()))
|
||||||
& (option.get_asso_max () - 1);
|
& (get_asso_max () - 1);
|
||||||
|
|
||||||
/* Iteration Number array is a win, O(1) intialization time! */
|
/* Iteration Number array is a win, O(1) intialization time! */
|
||||||
_collision_detector->clear ();
|
_collision_detector->clear ();
|
||||||
@@ -221,7 +221,7 @@ Gen_Perf::change (KeywordExt *prior, KeywordExt *curr)
|
|||||||
int union_set_length;
|
int union_set_length;
|
||||||
|
|
||||||
if (!union_set)
|
if (!union_set)
|
||||||
union_set = new char [2 * option.get_max_keysig_size ()];
|
union_set = new char [2 * get_max_keysig_size ()];
|
||||||
|
|
||||||
if (option[DEBUG])
|
if (option[DEBUG])
|
||||||
{
|
{
|
||||||
@@ -265,7 +265,7 @@ Gen_Perf::change (KeywordExt *prior, KeywordExt *curr)
|
|||||||
if (option[DEBUG])
|
if (option[DEBUG])
|
||||||
{
|
{
|
||||||
fprintf (stderr, "** collision not resolved after %d iterations, %d duplicates remain, continuing...\n",
|
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 () : keyword_list_length (),
|
!option[FAST] ? get_asso_max () : option.get_iterations () ? option.get_iterations () : keyword_list_length (),
|
||||||
_fewest_collisions + _total_duplicates);
|
_fewest_collisions + _total_duplicates);
|
||||||
fflush (stderr);
|
fflush (stderr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,18 @@ Hash_Table::~Hash_Table ()
|
|||||||
{
|
{
|
||||||
if (option[DEBUG])
|
if (option[DEBUG])
|
||||||
{
|
{
|
||||||
int field_width = option.get_max_keysig_size ();
|
int field_width;
|
||||||
|
|
||||||
|
if (option[ALLCHARS])
|
||||||
|
{
|
||||||
|
field_width = 0;
|
||||||
|
for (int i = _size - 1; i >= 0; i--)
|
||||||
|
if (_table[i])
|
||||||
|
if (field_width < _table[i]->_selchars_length)
|
||||||
|
field_width = _table[i]->_selchars_length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
field_width = option.get_max_keysig_size ();
|
||||||
|
|
||||||
fprintf (stderr,
|
fprintf (stderr,
|
||||||
"\ndumping the hash table\n"
|
"\ndumping the hash table\n"
|
||||||
|
|||||||
@@ -449,8 +449,6 @@ Key_List::read_keys ()
|
|||||||
fprintf (stderr, "Empty input key is not allowed.\nTo recognize an empty input key, your code should check for\nlen == 0 before calling the gperf generated lookup function.\n");
|
fprintf (stderr, "Empty input key is not allowed.\nTo recognize an empty input key, your code should check for\nlen == 0 before calling the gperf generated lookup function.\n");
|
||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
if (option[ALLCHARS])
|
|
||||||
option.set_keysig_size (_max_key_len);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -624,7 +622,7 @@ Key_List::sort ()
|
|||||||
void
|
void
|
||||||
Key_List::dump ()
|
Key_List::dump ()
|
||||||
{
|
{
|
||||||
int field_width = option.get_max_keysig_size ();
|
int field_width = get_max_keysig_size ();
|
||||||
|
|
||||||
fprintf (stderr, "\nList contents are:\n(hash value, key length, index, %*s, keyword):\n",
|
fprintf (stderr, "\nList contents are:\n(hash value, key length, index, %*s, keyword):\n",
|
||||||
field_width, "selchars");
|
field_width, "selchars");
|
||||||
@@ -667,3 +665,10 @@ Key_List::max_key_length ()
|
|||||||
return _max_key_len;
|
return _max_key_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns number of key positions. */
|
||||||
|
|
||||||
|
int
|
||||||
|
Key_List::get_max_keysig_size ()
|
||||||
|
{
|
||||||
|
return option[ALLCHARS] ? _max_key_len : option.get_max_keysig_size ();
|
||||||
|
}
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ private:
|
|||||||
int _list_len; /* Length of head's Key_List, not counting duplicates. */
|
int _list_len; /* Length of head's Key_List, not counting duplicates. */
|
||||||
protected:
|
protected:
|
||||||
int _total_keys; /* Total number of keys, counting duplicates. */
|
int _total_keys; /* Total number of keys, counting duplicates. */
|
||||||
|
int _size; /* Range of the hash table. */
|
||||||
private:
|
private:
|
||||||
static int _determined[MAX_ALPHA_SIZE]; /* Used in function reorder, below. */
|
static int _determined[MAX_ALPHA_SIZE]; /* Used in function reorder, below. */
|
||||||
static int get_occurrence (KeywordExt *ptr);
|
static int get_occurrence (KeywordExt *ptr);
|
||||||
@@ -79,6 +80,9 @@ public:
|
|||||||
void reorder ();
|
void reorder ();
|
||||||
void sort ();
|
void sort ();
|
||||||
void read_keys ();
|
void read_keys ();
|
||||||
|
int get_max_keysig_size ();
|
||||||
|
void set_asso_max (int r) { _size = r; }
|
||||||
|
int get_asso_max () { return _size; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -65,21 +65,21 @@ void KeywordExt::init_selchars (Vectors *v)
|
|||||||
char *key_set =
|
char *key_set =
|
||||||
new char[(option[ALLCHARS] ? _allchars_length : option.get_max_keysig_size ())];
|
new char[(option[ALLCHARS] ? _allchars_length : option.get_max_keysig_size ())];
|
||||||
char *ptr = key_set;
|
char *ptr = key_set;
|
||||||
int i;
|
|
||||||
|
|
||||||
if (option[ALLCHARS])
|
if (option[ALLCHARS])
|
||||||
/* Use all the character positions in the KEY. */
|
/* Use all the character positions in the KEY. */
|
||||||
for (i = _allchars_length; i > 0; k++, ptr++, i--)
|
for (int i = _allchars_length; i > 0; k++, ptr++, i--)
|
||||||
v->_occurrences[(unsigned char)(*ptr = *k)]++;
|
v->_occurrences[(unsigned char)(*ptr = *k)]++;
|
||||||
else
|
else
|
||||||
/* Only use those character positions specified by the user. */
|
/* Only use those character positions specified by the user. */
|
||||||
{
|
{
|
||||||
/* Iterate through the list of key_positions, initializing occurrences
|
/* Iterate through the list of key_positions, initializing occurrences
|
||||||
table and selchars (via char * pointer ptr). */
|
table and selchars (via char * pointer ptr). */
|
||||||
|
PositionIterator iter (option.get_key_positions ());
|
||||||
|
|
||||||
for (option.reset (); (i = option.get ()) != EOS; )
|
for (int i; (i = iter.next ()) != PositionIterator::EOS; )
|
||||||
{
|
{
|
||||||
if (i == WORD_END)
|
if (i == Positions::LASTCHAR)
|
||||||
/* Special notation for last KEY position, i.e. '$'. */
|
/* Special notation for last KEY position, i.e. '$'. */
|
||||||
*ptr = _allchars[_allchars_length - 1];
|
*ptr = _allchars[_allchars_length - 1];
|
||||||
else if (i <= _allchars_length)
|
else if (i <= _allchars_length)
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ int
|
|||||||
main (int argc, char *argv[])
|
main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
/* Sets the Options. */
|
/* Sets the Options. */
|
||||||
option (argc, argv);
|
option.parse_options (argc, argv);
|
||||||
|
|
||||||
/* Initializes the key word list. */
|
/* Initializes the key word list. */
|
||||||
Gen_Perf generate_table;
|
Gen_Perf generate_table;
|
||||||
|
|||||||
394
src/options.cc
394
src/options.cc
@@ -27,122 +27,125 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
|
|||||||
#include "vectors.h"
|
#include "vectors.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
/* Global option coordinator for the entire program. */
|
/* Global option coordinator for the entire program. */
|
||||||
Options option;
|
Options option;
|
||||||
|
|
||||||
/* Records the program name. */
|
/* Records the program name. */
|
||||||
const char *program_name;
|
const char *program_name;
|
||||||
|
|
||||||
/* Size to jump on a collision. */
|
/* Size to jump on a collision. */
|
||||||
static const int DEFAULT_JUMP_VALUE = 5;
|
static const int DEFAULT_JUMP_VALUE = 5;
|
||||||
|
|
||||||
/* Default name for generated lookup function. */
|
/* Default name for generated lookup function. */
|
||||||
static const char *const DEFAULT_NAME = "in_word_set";
|
static const char *const DEFAULT_NAME = "in_word_set";
|
||||||
|
|
||||||
/* Default name for the key component. */
|
/* Default name for the key component. */
|
||||||
static const char *const DEFAULT_KEY = "name";
|
static const char *const DEFAULT_KEY = "name";
|
||||||
|
|
||||||
/* Default struct initializer suffix. */
|
/* Default struct initializer suffix. */
|
||||||
static const char *const DEFAULT_INITIALIZER_SUFFIX = "";
|
static const char *const DEFAULT_INITIALIZER_SUFFIX = "";
|
||||||
|
|
||||||
/* Default name for the generated class. */
|
/* Default name for the generated class. */
|
||||||
static const char *const DEFAULT_CLASS_NAME = "Perfect_Hash";
|
static const char *const DEFAULT_CLASS_NAME = "Perfect_Hash";
|
||||||
|
|
||||||
/* Default name for generated hash function. */
|
/* Default name for generated hash function. */
|
||||||
static const char *const DEFAULT_HASH_NAME = "hash";
|
static const char *const DEFAULT_HASH_NAME = "hash";
|
||||||
|
|
||||||
/* Default name for generated hash table array. */
|
/* Default name for generated hash table array. */
|
||||||
static const char *const DEFAULT_WORDLIST_NAME = "wordlist";
|
static const char *const DEFAULT_WORDLIST_NAME = "wordlist";
|
||||||
|
|
||||||
/* Default delimiters that separate keywords from their attributes. */
|
/* Default delimiters that separate keywords from their attributes. */
|
||||||
static const char *const DEFAULT_DELIMITERS = ",\n";
|
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::_initializer_suffix;
|
|
||||||
const char *Options::_class_name;
|
|
||||||
const char *Options::_hash_name;
|
|
||||||
const char *Options::_wordlist_name;
|
|
||||||
const char *Options::_delimiters;
|
|
||||||
char Options::_key_positions[MAX_KEY_POS];
|
|
||||||
|
|
||||||
/* Prints program usage to given stream. */
|
/* Prints program usage to given stream. */
|
||||||
|
|
||||||
void
|
void
|
||||||
Options::short_usage (FILE * strm)
|
Options::short_usage (FILE * stream) const
|
||||||
{
|
{
|
||||||
fprintf (strm, "Usage: %s [-cCdDef[num]F<initializers>GhH<hashname>i<init>Ijk<keys>K<keyname>lL<language>nN<function name>ors<size>S<switches>tTvW<wordlistname>Z<class name>7] [input-file]\n"
|
fprintf (stream, "Usage: %s [-cCdDef[num]F<initializers>GhH<hashname>i<init>Ijk<keys>K<keyname>lL<language>nN<function name>ors<size>S<switches>tTvW<wordlistname>Z<class name>7] [input-file]\n"
|
||||||
"Try `%s --help' for more information.\n",
|
"Try '%s --help' for more information.\n",
|
||||||
program_name, program_name);
|
program_name, program_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Options::long_usage (FILE * strm)
|
Options::long_usage (FILE * stream) const
|
||||||
{
|
{
|
||||||
fprintf (strm,
|
fprintf (stream,
|
||||||
"GNU `gperf' generates perfect hash functions.\n"
|
"GNU 'gperf' generates perfect hash functions.\n");
|
||||||
"\n"
|
fprintf (stream, "\n");
|
||||||
"Usage: %s [OPTION]... [INPUT-FILE]\n"
|
fprintf (stream,
|
||||||
"\n"
|
"Usage: %s [OPTION]... [INPUT-FILE]\n",
|
||||||
|
program_name);
|
||||||
|
fprintf (stream, "\n");
|
||||||
|
fprintf (stream,
|
||||||
"If a long option shows an argument as mandatory, then it is mandatory\n"
|
"If a long option shows an argument as mandatory, then it is mandatory\n"
|
||||||
"for the equivalent short option also.\n"
|
"for the equivalent short option also.\n");
|
||||||
"\n"
|
fprintf (stream, "\n");
|
||||||
"Input file interpretation:\n"
|
fprintf (stream,
|
||||||
|
"Input file interpretation:\n");
|
||||||
|
fprintf (stream,
|
||||||
" -e, --delimiters=DELIMITER-LIST\n"
|
" -e, --delimiters=DELIMITER-LIST\n"
|
||||||
" Allow user to provide a string containing delimiters\n"
|
" Allow user to provide a string containing delimiters\n"
|
||||||
" used to separate keywords from their attributes.\n"
|
" used to separate keywords from their attributes.\n"
|
||||||
" Default is \",\\n\".\n"
|
" Default is \",\\n\".\n");
|
||||||
|
fprintf (stream,
|
||||||
" -t, --struct-type Allows the user to include a structured type\n"
|
" -t, --struct-type Allows the user to include a structured type\n"
|
||||||
" declaration for generated code. Any text before %%%%\n"
|
" declaration for generated code. Any text before %%%%\n"
|
||||||
" is considered part of the type declaration. Key\n"
|
" is considered part of the type declaration. Key\n"
|
||||||
" words and additional fields may follow this, one\n"
|
" words and additional fields may follow this, one\n"
|
||||||
" group of fields per line.\n"
|
" group of fields per line.\n");
|
||||||
"\n"
|
fprintf (stream, "\n");
|
||||||
"Language for the output code:\n"
|
fprintf (stream,
|
||||||
|
"Language for the output code:\n");
|
||||||
|
fprintf (stream,
|
||||||
" -L, --language=LANGUAGE-NAME\n"
|
" -L, --language=LANGUAGE-NAME\n"
|
||||||
" Generates code in the specified language. Languages\n"
|
" Generates code in the specified language. Languages\n"
|
||||||
" handled are currently C++, ANSI-C, C, and KR-C. The\n"
|
" handled are currently C++, ANSI-C, C, and KR-C. The\n"
|
||||||
" default is C.\n"
|
" default is C.\n");
|
||||||
"\n"
|
fprintf (stream, "\n");
|
||||||
"Details in the output code:\n"
|
fprintf (stream,
|
||||||
|
"Details in the output code:\n");
|
||||||
|
fprintf (stream,
|
||||||
" -K, --slot-name=NAME Select name of the keyword component in the keyword\n"
|
" -K, --slot-name=NAME Select name of the keyword component in the keyword\n"
|
||||||
" structure.\n"
|
" structure.\n");
|
||||||
|
fprintf (stream,
|
||||||
" -F, --initializer-suffix=INITIALIZERS\n"
|
" -F, --initializer-suffix=INITIALIZERS\n"
|
||||||
" Initializers for additional components in the keyword\n"
|
" Initializers for additional components in the keyword\n"
|
||||||
" structure.\n"
|
" structure.\n");
|
||||||
|
fprintf (stream,
|
||||||
" -H, --hash-fn-name=NAME\n"
|
" -H, --hash-fn-name=NAME\n"
|
||||||
" Specify name of generated hash function. Default is\n"
|
" Specify name of generated hash function. Default is\n"
|
||||||
" `hash'.\n"
|
" 'hash'.\n");
|
||||||
|
fprintf (stream,
|
||||||
" -N, --lookup-fn-name=NAME\n"
|
" -N, --lookup-fn-name=NAME\n"
|
||||||
" Specify name of generated lookup function. Default\n"
|
" Specify name of generated lookup function. Default\n"
|
||||||
" name is `in_word_set'.\n"
|
" name is 'in_word_set'.\n");
|
||||||
|
fprintf (stream,
|
||||||
" -Z, --class-name=NAME Specify name of generated C++ class. Default name is\n"
|
" -Z, --class-name=NAME Specify name of generated C++ class. Default name is\n"
|
||||||
" `Perfect_Hash'.\n"
|
" 'Perfect_Hash'.\n");
|
||||||
" -7, --seven-bit Assume 7-bit characters.\n"
|
fprintf (stream,
|
||||||
|
" -7, --seven-bit Assume 7-bit characters.\n");
|
||||||
|
fprintf (stream,
|
||||||
" -c, --compare-strncmp Generate comparison code using strncmp rather than\n"
|
" -c, --compare-strncmp Generate comparison code using strncmp rather than\n"
|
||||||
" strcmp.\n"
|
" strcmp.\n");
|
||||||
|
fprintf (stream,
|
||||||
" -C, --readonly-tables Make the contents of generated lookup tables\n"
|
" -C, --readonly-tables Make the contents of generated lookup tables\n"
|
||||||
" constant, i.e., readonly.\n"
|
" constant, i.e., readonly.\n");
|
||||||
|
fprintf (stream,
|
||||||
" -E, --enum Define constant values using an enum local to the\n"
|
" -E, --enum Define constant values using an enum local to the\n"
|
||||||
" lookup function rather than with defines.\n"
|
" lookup function rather than with defines.\n");
|
||||||
|
fprintf (stream,
|
||||||
" -I, --includes Include the necessary system include file <string.h>\n"
|
" -I, --includes Include the necessary system include file <string.h>\n"
|
||||||
" at the beginning of the code.\n"
|
" at the beginning of the code.\n");
|
||||||
|
fprintf (stream,
|
||||||
" -G, --global Generate the static table of keywords as a static\n"
|
" -G, --global Generate the static table of keywords as a static\n"
|
||||||
" global variable, rather than hiding it inside of the\n"
|
" global variable, rather than hiding it inside of the\n"
|
||||||
" lookup function (which is the default behavior).\n"
|
" lookup function (which is the default behavior).\n");
|
||||||
|
fprintf (stream,
|
||||||
" -W, --word-array-name=NAME\n"
|
" -W, --word-array-name=NAME\n"
|
||||||
" Specify name of word list array. Default name is\n"
|
" Specify name of word list array. Default name is\n"
|
||||||
" `wordlist'.\n"
|
" 'wordlist'.\n");
|
||||||
|
fprintf (stream,
|
||||||
" -S, --switch=COUNT Causes the generated C code to use a switch\n"
|
" -S, --switch=COUNT Causes the generated C code to use a switch\n"
|
||||||
" statement scheme, rather than an array lookup table.\n"
|
" statement scheme, rather than an array lookup table.\n"
|
||||||
" This can lead to a reduction in both time and space\n"
|
" This can lead to a reduction in both time and space\n"
|
||||||
@@ -152,13 +155,16 @@ Options::long_usage (FILE * strm)
|
|||||||
" elements, a value of 2 generates 2 tables with 1/2\n"
|
" elements, a value of 2 generates 2 tables with 1/2\n"
|
||||||
" the elements in each table, etc. If COUNT is very\n"
|
" the elements in each table, etc. If COUNT is very\n"
|
||||||
" large, say 1000000, the generated C code does a\n"
|
" large, say 1000000, the generated C code does a\n"
|
||||||
" binary search.\n"
|
" binary search.\n");
|
||||||
|
fprintf (stream,
|
||||||
" -T, --omit-struct-type\n"
|
" -T, --omit-struct-type\n"
|
||||||
" Prevents the transfer of the type declaration to the\n"
|
" Prevents the transfer of the type declaration to the\n"
|
||||||
" output file. Use this option if the type is already\n"
|
" output file. Use this option if the type is already\n"
|
||||||
" defined elsewhere.\n"
|
" defined elsewhere.\n");
|
||||||
"\n"
|
fprintf (stream, "\n");
|
||||||
"Algorithm employed by gperf:\n"
|
fprintf (stream,
|
||||||
|
"Algorithm employed by gperf:\n");
|
||||||
|
fprintf (stream,
|
||||||
" -k, --key-positions=KEYS\n"
|
" -k, --key-positions=KEYS\n"
|
||||||
" Select the key positions used in the hash function.\n"
|
" Select the key positions used in the hash function.\n"
|
||||||
" The allowable choices range between 1-%d, inclusive.\n"
|
" The allowable choices range between 1-%d, inclusive.\n"
|
||||||
@@ -166,59 +172,71 @@ Options::long_usage (FILE * strm)
|
|||||||
" used, and key positions may occur in any order.\n"
|
" used, and key positions may occur in any order.\n"
|
||||||
" Also, the meta-character '*' causes the generated\n"
|
" Also, the meta-character '*' causes the generated\n"
|
||||||
" hash function to consider ALL key positions, and $\n"
|
" hash function to consider ALL key positions, and $\n"
|
||||||
" indicates the ``final character'' of a key, e.g.,\n"
|
" indicates the \"final character\" of a key, e.g.,\n"
|
||||||
" $,1,2,4,6-10.\n"
|
" $,1,2,4,6-10.\n",
|
||||||
|
Positions::MAX_KEY_POS - 1);
|
||||||
|
fprintf (stream,
|
||||||
" -l, --compare-strlen Compare key lengths before trying a string\n"
|
" -l, --compare-strlen Compare key lengths before trying a string\n"
|
||||||
" comparison. This helps cut down on the number of\n"
|
" comparison. This helps cut down on the number of\n"
|
||||||
" string comparisons made during the lookup.\n"
|
" string comparisons made during the lookup.\n");
|
||||||
|
fprintf (stream,
|
||||||
" -D, --duplicates Handle keywords that hash to duplicate values. This\n"
|
" -D, --duplicates Handle keywords that hash to duplicate values. This\n"
|
||||||
" is useful for certain highly redundant keyword sets.\n"
|
" is useful for certain highly redundant keyword sets.\n");
|
||||||
" -f, --fast=ITERATIONS Generate the gen-perf.hash function ``fast''. This\n"
|
fprintf (stream,
|
||||||
|
" -f, --fast=ITERATIONS Generate the gen-perf.hash function \"fast\". This\n"
|
||||||
" decreases gperf's running time at the cost of\n"
|
" decreases gperf's running time at the cost of\n"
|
||||||
" minimizing generated table size. The numeric\n"
|
" minimizing generated table size. The numeric\n"
|
||||||
" argument represents the number of times to iterate\n"
|
" argument represents the number of times to iterate\n"
|
||||||
" when resolving a collision. `0' means ``iterate by\n"
|
" when resolving a collision. '0' means \"iterate by\n"
|
||||||
" the number of keywords''.\n"
|
" the number of keywords\".\n");
|
||||||
|
fprintf (stream,
|
||||||
" -i, --initial-asso=N Provide an initial value for the associate values\n"
|
" -i, --initial-asso=N Provide an initial value for the associate values\n"
|
||||||
" array. Default is 0. Setting this value larger helps\n"
|
" array. Default is 0. Setting this value larger helps\n"
|
||||||
" inflate the size of the final table.\n"
|
" inflate the size of the final table.\n");
|
||||||
" -j, --jump=JUMP-VALUE Affects the ``jump value'', i.e., how far to advance\n"
|
fprintf (stream,
|
||||||
|
" -j, --jump=JUMP-VALUE Affects the \"jump value\", i.e., how far to advance\n"
|
||||||
" the associated character value upon collisions. Must\n"
|
" the associated character value upon collisions. Must\n"
|
||||||
" be an odd number, default is %d.\n"
|
" be an odd number, default is %d.\n",
|
||||||
|
DEFAULT_JUMP_VALUE);
|
||||||
|
fprintf (stream,
|
||||||
" -n, --no-strlen Do not include the length of the keyword when\n"
|
" -n, --no-strlen Do not include the length of the keyword when\n"
|
||||||
" computing the hash function.\n"
|
" computing the hash function.\n");
|
||||||
|
fprintf (stream,
|
||||||
" -o, --occurrence-sort Reorders input keys by frequency of occurrence of\n"
|
" -o, --occurrence-sort Reorders input keys by frequency of occurrence of\n"
|
||||||
" the key sets. This should decrease the search time\n"
|
" the key sets. This should decrease the search time\n"
|
||||||
" dramatically.\n"
|
" dramatically.\n");
|
||||||
|
fprintf (stream,
|
||||||
" -r, --random Utilizes randomness to initialize the associated\n"
|
" -r, --random Utilizes randomness to initialize the associated\n"
|
||||||
" values table.\n"
|
" values table.\n");
|
||||||
|
fprintf (stream,
|
||||||
" -s, --size-multiple=N Affects the size of the generated hash table. The\n"
|
" -s, --size-multiple=N Affects the size of the generated hash table. The\n"
|
||||||
" numeric argument N indicates ``how many times larger\n"
|
" numeric argument N indicates \"how many times larger\n"
|
||||||
" or smaller'' the associated value range should be,\n"
|
" or smaller\" the associated value range should be,\n"
|
||||||
" in relationship to the number of keys, e.g. a value\n"
|
" in relationship to the number of keys, e.g. a value\n"
|
||||||
" of 3 means ``allow the maximum associated value to\n"
|
" of 3 means \"allow the maximum associated value to\n"
|
||||||
" be about 3 times larger than the number of input\n"
|
" be about 3 times larger than the number of input\n"
|
||||||
" keys.'' Conversely, a value of -3 means ``make the\n"
|
" keys\". Conversely, a value of -3 means \"make the\n"
|
||||||
" maximum associated value about 3 times smaller than\n"
|
" maximum associated value about 3 times smaller than\n"
|
||||||
" the number of input keys. A larger table should\n"
|
" the number of input keys\". A larger table should\n"
|
||||||
" decrease the time required for an unsuccessful\n"
|
" decrease the time required for an unsuccessful\n"
|
||||||
" search, at the expense of extra table space. Default\n"
|
" search, at the expense of extra table space. Default\n"
|
||||||
" value is 1.\n"
|
" value is 1.\n");
|
||||||
"\n"
|
fprintf (stream, "\n");
|
||||||
|
fprintf (stream,
|
||||||
"Informative output:\n"
|
"Informative output:\n"
|
||||||
" -h, --help Print this message.\n"
|
" -h, --help Print this message.\n"
|
||||||
" -v, --version Print the gperf version number.\n"
|
" -v, --version Print the gperf version number.\n"
|
||||||
" -d, --debug Enables the debugging option (produces verbose\n"
|
" -d, --debug Enables the debugging option (produces verbose\n"
|
||||||
" output to the standard error).\n"
|
" output to the standard error).\n");
|
||||||
"\n"
|
fprintf (stream, "\n");
|
||||||
"Report bugs to <bug-gnu-utils@gnu.org>.\n"
|
fprintf (stream,
|
||||||
, program_name, MAX_KEY_POS - 1, DEFAULT_JUMP_VALUE);
|
"Report bugs to <bug-gnu-utils@gnu.org>.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Output command-line Options. */
|
/* Prints the given options. */
|
||||||
|
|
||||||
void
|
void
|
||||||
Options::print_options ()
|
Options::print_options () const
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -228,7 +246,7 @@ Options::print_options ()
|
|||||||
{
|
{
|
||||||
const char *arg = _argument_vector[i];
|
const char *arg = _argument_vector[i];
|
||||||
|
|
||||||
/* Escape arg if it contains shell metacharacters. */
|
/* Escape arg if it contains shell metacharacters. */
|
||||||
if (*arg == '-')
|
if (*arg == '-')
|
||||||
{
|
{
|
||||||
putchar (*arg);
|
putchar (*arg);
|
||||||
@@ -278,110 +296,96 @@ Options::print_options ()
|
|||||||
class PositionStringParser
|
class PositionStringParser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PositionStringParser (const char *s, int lo, int hi, int word_end, int bad_val, int key_end);
|
PositionStringParser (const char *str, int low_bound, int high_bound, int end_word_marker, int error_value, int end_marker);
|
||||||
int nextPosition ();
|
int nextPosition ();
|
||||||
private:
|
private:
|
||||||
const char *str; /* A pointer to the string provided by the user. */
|
/* A pointer to the string provided by the user. */
|
||||||
int end; /* Value returned after last key is processed. */
|
const char * _str;
|
||||||
int end_word; /* A value marking the abstract ``end of word'' ( usually '$'). */
|
/* Smallest possible value, inclusive. */
|
||||||
int error_value; /* Error value returned when input is syntactically erroneous. */
|
int const _low_bound;
|
||||||
int hi_bound; /* Greatest possible value, inclusive. */
|
/* Greatest possible value, inclusive. */
|
||||||
int lo_bound; /* Smallest possible value, inclusive. */
|
int const _high_bound;
|
||||||
int size;
|
/* A value marking the abstract "end of word" ( usually '$'). */
|
||||||
int curr_value;
|
int const _end_word_marker;
|
||||||
int upper_bound;
|
/* Error value returned when input is syntactically erroneous. */
|
||||||
|
int const _error_value;
|
||||||
|
/* Value returned after last key is processed. */
|
||||||
|
int const _end_marker;
|
||||||
|
int _size;
|
||||||
|
int _curr_value;
|
||||||
|
int _upper_bound;
|
||||||
};
|
};
|
||||||
|
|
||||||
PositionStringParser::PositionStringParser (const char *s, int lo, int hi, int word_end, int bad_val, int key_end)
|
PositionStringParser::PositionStringParser (const char *str, int low_bound, int high_bound, int end_word_marker, int error_value, int end_marker)
|
||||||
: str (s), end (key_end), end_word (word_end), error_value (bad_val), hi_bound (hi), lo_bound (lo),
|
: _str (str),
|
||||||
size (0), curr_value (0), upper_bound (0)
|
_low_bound (low_bound),
|
||||||
|
_high_bound (high_bound),
|
||||||
|
_end_word_marker (end_word_marker),
|
||||||
|
_error_value (error_value),
|
||||||
|
_end_marker (end_marker),
|
||||||
|
_size (0),
|
||||||
|
_curr_value (0),
|
||||||
|
_upper_bound (0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int PositionStringParser::nextPosition ()
|
int PositionStringParser::nextPosition ()
|
||||||
{
|
{
|
||||||
if (size)
|
if (_size)
|
||||||
{
|
{
|
||||||
if (++curr_value >= upper_bound)
|
if (++_curr_value >= _upper_bound)
|
||||||
size = 0;
|
_size = 0;
|
||||||
return curr_value;
|
return _curr_value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while (*str)
|
while (*_str)
|
||||||
switch (*str)
|
switch (*_str)
|
||||||
{
|
{
|
||||||
default: return error_value;
|
default: return _error_value;
|
||||||
case ',': str++; break;
|
case ',': _str++; break;
|
||||||
case '$': str++; return end_word;
|
case '$': _str++; return _end_word_marker;
|
||||||
case '0': case '1': case '2': case '3': case '4':
|
case '0': case '1': case '2': case '3': case '4':
|
||||||
case '5': case '6': case '7': case '8': case '9':
|
case '5': case '6': case '7': case '8': case '9':
|
||||||
for (curr_value = 0; isdigit ((unsigned char)(*str)); str++)
|
for (_curr_value = 0; isdigit ((unsigned char)(*_str)); _str++)
|
||||||
curr_value = curr_value * 10 + (*str - '0');
|
_curr_value = _curr_value * 10 + (*_str - '0');
|
||||||
|
|
||||||
if (*str == '-')
|
if (*_str == '-')
|
||||||
{
|
{
|
||||||
|
|
||||||
for (size = 1, upper_bound = 0;
|
for (_size = 1, _upper_bound = 0;
|
||||||
isdigit ((unsigned char)(*++str));
|
isdigit ((unsigned char)(*++_str));
|
||||||
upper_bound = upper_bound * 10 + (*str - '0'));
|
_upper_bound = _upper_bound * 10 + (*_str - '0'));
|
||||||
|
|
||||||
if (upper_bound <= curr_value || upper_bound > hi_bound)
|
if (_upper_bound <= _curr_value || _upper_bound > _high_bound)
|
||||||
return error_value;
|
return _error_value;
|
||||||
}
|
}
|
||||||
return curr_value >= lo_bound && curr_value <= hi_bound
|
return _curr_value >= _low_bound && _curr_value <= _high_bound
|
||||||
? curr_value : error_value;
|
? _curr_value : _error_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return end;
|
return _end_marker;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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)
|
|
||||||
{
|
|
||||||
/* Bubble sort. */
|
|
||||||
for (int i = 1; i < len; i++)
|
|
||||||
{
|
|
||||||
int j;
|
|
||||||
int tmp;
|
|
||||||
|
|
||||||
for (j = i, tmp = base[j]; j > 0 && tmp >= base[j - 1]; j--)
|
|
||||||
if ((base[j] = base[j - 1]) == tmp) /* oh no, a duplicate!!! */
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
base[j] = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sets the default Options. */
|
/* Sets the default Options. */
|
||||||
|
|
||||||
Options::Options ()
|
Options::Options ()
|
||||||
|
: _option_word (DEFAULTCHARS | C),
|
||||||
|
_iterations (0),
|
||||||
|
_jump (DEFAULT_JUMP_VALUE),
|
||||||
|
_initial_asso_value (0),
|
||||||
|
_total_switches (1),
|
||||||
|
_size_multiple (1),
|
||||||
|
_function_name (DEFAULT_NAME),
|
||||||
|
_key_name (DEFAULT_KEY),
|
||||||
|
_initializer_suffix (DEFAULT_INITIALIZER_SUFFIX),
|
||||||
|
_class_name (DEFAULT_CLASS_NAME),
|
||||||
|
_hash_name (DEFAULT_HASH_NAME),
|
||||||
|
_wordlist_name (DEFAULT_WORDLIST_NAME),
|
||||||
|
_delimiters (DEFAULT_DELIMITERS),
|
||||||
|
_key_positions (1, Positions::LASTCHAR)
|
||||||
{
|
{
|
||||||
_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;
|
|
||||||
_initializer_suffix = DEFAULT_INITIALIZER_SUFFIX;
|
|
||||||
_hash_name = DEFAULT_HASH_NAME;
|
|
||||||
_wordlist_name = DEFAULT_WORDLIST_NAME;
|
|
||||||
_class_name = DEFAULT_CLASS_NAME;
|
|
||||||
_size = 1;
|
|
||||||
_total_switches = 1;
|
|
||||||
_iterations = 0;
|
|
||||||
_initial_asso_value = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dumps option status when debug is set. */
|
/* Dumps option status when debug is set. */
|
||||||
@@ -390,8 +394,6 @@ Options::~Options ()
|
|||||||
{
|
{
|
||||||
if (_option_word & DEBUG)
|
if (_option_word & DEBUG)
|
||||||
{
|
{
|
||||||
char *ptr;
|
|
||||||
|
|
||||||
fprintf (stderr, "\ndumping Options:"
|
fprintf (stderr, "\ndumping Options:"
|
||||||
"\nDEBUG is.......: %s"
|
"\nDEBUG is.......: %s"
|
||||||
"\nORDER is.......: %s"
|
"\nORDER is.......: %s"
|
||||||
@@ -421,7 +423,7 @@ Options::~Options ()
|
|||||||
"\nkey name = %s"
|
"\nkey name = %s"
|
||||||
"\ninitializer suffix = %s"
|
"\ninitializer suffix = %s"
|
||||||
"\njump value = %d"
|
"\njump value = %d"
|
||||||
"\nmax associated value = %d"
|
"\nhash table size multiplier = %d"
|
||||||
"\ninitial associated value = %d"
|
"\ninitial associated value = %d"
|
||||||
"\ndelimiters = %s"
|
"\ndelimiters = %s"
|
||||||
"\nnumber of switch statements = %d\n",
|
"\nnumber of switch statements = %d\n",
|
||||||
@@ -448,19 +450,22 @@ Options::~Options ()
|
|||||||
_option_word & SEVENBIT ? "enabled" : "disabled",
|
_option_word & SEVENBIT ? "enabled" : "disabled",
|
||||||
_iterations,
|
_iterations,
|
||||||
_function_name, _hash_name, _wordlist_name, _key_name,
|
_function_name, _hash_name, _wordlist_name, _key_name,
|
||||||
_initializer_suffix, _jump, _size - 1, _initial_asso_value,
|
_initializer_suffix, _jump, _size_multiple, _initial_asso_value,
|
||||||
_delimiters, _total_switches);
|
_delimiters, _total_switches);
|
||||||
if (_option_word & ALLCHARS)
|
if (_option_word & ALLCHARS)
|
||||||
fprintf (stderr, "all characters are used in the hash function\n");
|
fprintf (stderr, "all characters are used in the hash function\n");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf (stderr, "maximum keysig size = %d\nkey positions are: \n",
|
||||||
|
_key_positions.get_size());
|
||||||
|
|
||||||
fprintf (stderr, "maximum keysig size = %d\nkey positions are: \n",
|
PositionIterator iter (_key_positions);
|
||||||
_total_keysig_size);
|
for (int pos; (pos = iter.next()) != PositionIterator::EOS; )
|
||||||
|
if (pos == Positions::LASTCHAR)
|
||||||
for (ptr = _key_positions; *ptr != EOS; ptr++)
|
fprintf (stderr, "$\n");
|
||||||
if (*ptr == WORD_END)
|
else
|
||||||
fprintf (stderr, "$\n");
|
fprintf (stderr, "%d\n", pos);
|
||||||
else
|
}
|
||||||
fprintf (stderr, "%d\n", *ptr);
|
|
||||||
|
|
||||||
fprintf (stderr, "finished dumping Options\n");
|
fprintf (stderr, "finished dumping Options\n");
|
||||||
}
|
}
|
||||||
@@ -505,7 +510,7 @@ static const struct option long_options[] =
|
|||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
Options::operator() (int argc, char *argv[])
|
Options::parse_options (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int option_char;
|
int option_char;
|
||||||
|
|
||||||
@@ -615,43 +620,52 @@ Options::operator() (int argc, char *argv[])
|
|||||||
case 'k': /* Sets key positions used for hash function. */
|
case 'k': /* Sets key positions used for hash function. */
|
||||||
{
|
{
|
||||||
const int BAD_VALUE = -1;
|
const int BAD_VALUE = -1;
|
||||||
|
const int EOS = PositionIterator::EOS;
|
||||||
int value;
|
int value;
|
||||||
PositionStringParser sparser (/*getopt*/optarg, 1, MAX_KEY_POS - 1, WORD_END, BAD_VALUE, EOS);
|
PositionStringParser sparser (/*getopt*/optarg, 1, Positions::MAX_KEY_POS - 1, Positions::LASTCHAR, BAD_VALUE, EOS);
|
||||||
|
|
||||||
if (/*getopt*/optarg [0] == '*') /* Use all the characters for hashing!!!! */
|
if (/*getopt*/optarg [0] == '*') /* Use all the characters for hashing!!!! */
|
||||||
_option_word = (_option_word & ~DEFAULTCHARS) | ALLCHARS;
|
_option_word = (_option_word & ~DEFAULTCHARS) | ALLCHARS;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *key_pos;
|
unsigned char *key_positions = _key_positions.pointer();
|
||||||
|
unsigned char *key_pos;
|
||||||
|
|
||||||
for (key_pos = _key_positions; (value = sparser.nextPosition()) != EOS; key_pos++)
|
for (key_pos = key_positions; (value = sparser.nextPosition()) != EOS; key_pos++)
|
||||||
if (value == BAD_VALUE)
|
if (value == BAD_VALUE)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "Illegal key value or range, use 1,2,3-%d,'$' or '*'.\n",
|
fprintf (stderr, "Illegal key value or range, use 1,2,3-%d,'$' or '*'.\n",
|
||||||
MAX_KEY_POS - 1);
|
Positions::MAX_KEY_POS - 1);
|
||||||
short_usage (stderr);
|
short_usage (stderr);
|
||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
*key_pos = value;;
|
*key_pos = value;
|
||||||
|
|
||||||
*key_pos = EOS;
|
*key_pos = EOS;
|
||||||
|
|
||||||
if (! (_total_keysig_size = (key_pos - _key_positions)))
|
unsigned int total_keysig_size = key_pos - key_positions;
|
||||||
|
if (total_keysig_size == 0)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "No keys selected.\n");
|
fprintf (stderr, "No keys selected.\n");
|
||||||
short_usage (stderr);
|
short_usage (stderr);
|
||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
else if (! key_sort (_key_positions, _total_keysig_size))
|
_key_positions.set_size (total_keysig_size);
|
||||||
|
|
||||||
|
/* Sorts the key positions *IN REVERSE ORDER!!*
|
||||||
|
This makes further routines more efficient. Especially
|
||||||
|
when generating code. */
|
||||||
|
if (! _key_positions.sort())
|
||||||
{
|
{
|
||||||
fprintf (stderr, "Duplicate keys selected\n");
|
fprintf (stderr, "Duplicate keys selected\n");
|
||||||
short_usage (stderr);
|
short_usage (stderr);
|
||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_total_keysig_size != 2
|
if (!(_key_positions.get_size() == 2
|
||||||
|| (_key_positions[0] != 1 || _key_positions[1] != WORD_END))
|
&& _key_positions[0] == 1
|
||||||
|
&& _key_positions[1] == Positions::LASTCHAR))
|
||||||
_option_word &= ~DEFAULTCHARS;
|
_option_word &= ~DEFAULTCHARS;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -710,8 +724,8 @@ Options::operator() (int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
case 's': /* Range of associated values, determines size of final table. */
|
case 's': /* Range of associated values, determines size of final table. */
|
||||||
{
|
{
|
||||||
if (abs (_size = atoi (/*getopt*/optarg)) > 50)
|
if (abs (_size_multiple = atoi (/*getopt*/optarg)) > 50)
|
||||||
fprintf (stderr, "%d is excessive, did you really mean this?! (try `%s --help' for help)\n", _size, program_name);
|
fprintf (stderr, "%d is excessive, did you really mean this?! (try `%s --help' for help)\n", _size_multiple, program_name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'S': /* Generate switch statement output, rather than lookup table. */
|
case 'S': /* Generate switch statement output, rather than lookup table. */
|
||||||
|
|||||||
313
src/options.h
313
src/options.h
@@ -22,56 +22,139 @@ 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. */
|
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
|
||||||
|
|
||||||
/* This module provides a uniform interface to the various options available
|
/* This module provides a uniform interface to the various options available
|
||||||
to a user of the gperf hash function generator. In addition to the
|
to a user of the gperf hash function generator. */
|
||||||
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
|
#ifndef options_h
|
||||||
#define options_h 1
|
#define options_h 1
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
/* Enumerate the potential debugging Options. */
|
/* Enumeration of the possible boolean options. */
|
||||||
|
|
||||||
enum Option_Type
|
enum Option_Type
|
||||||
{
|
{
|
||||||
DEBUG = 01, /* Enable debugging (prints diagnostics to stderr). */
|
/* Enable debugging (prints diagnostics to stderr). */
|
||||||
ORDER = 02, /* Apply ordering heuristic to speed-up search time. */
|
DEBUG = 1 << 0,
|
||||||
ALLCHARS = 04, /* Use all characters in hash function. */
|
|
||||||
TYPE = 010, /* Handle user-defined type structured keyword input. */
|
/* Apply ordering heuristic to speed-up search time. */
|
||||||
RANDOM = 020, /* Randomly initialize the associated values table. */
|
ORDER = 1 << 1,
|
||||||
DEFAULTCHARS = 040, /* Make default char positions be 1,$ (end of keyword). */
|
|
||||||
SWITCH = 0100, /* Generate switch output to save space. */
|
/* Use all characters in hash function. */
|
||||||
NOLENGTH = 0200, /* Don't include keyword length in hash computations. */
|
ALLCHARS = 1 << 2,
|
||||||
LENTABLE = 0400, /* Generate a length table for string comparison. */
|
|
||||||
DUP = 01000, /* Handle duplicate hash values for keywords. */
|
/* Handle user-defined type structured keyword input. */
|
||||||
FAST = 02000, /* Generate the hash function ``fast.'' */
|
TYPE = 1 << 3,
|
||||||
NOTYPE = 04000, /* Don't include user-defined type definition in output -- it's already defined elsewhere. */
|
|
||||||
COMP = 010000, /* Generate strncmp rather than strcmp. */
|
/* Randomly initialize the associated values table. */
|
||||||
GLOBAL = 020000, /* Make the keyword table a global variable. */
|
RANDOM = 1 << 4,
|
||||||
CONST = 040000, /* Make the generated tables readonly (const). */
|
|
||||||
KRC = 0100000, /* Generate K&R C code: no prototypes, no const. */
|
/* Make default char positions be 1,$ (end of keyword). */
|
||||||
C = 0200000, /* Generate C code: no prototypes, but const (user can #define it away). */
|
DEFAULTCHARS = 1 << 5,
|
||||||
ANSIC = 0400000, /* Generate ISO/ANSI C code: prototypes and const, but no class. */
|
|
||||||
CPLUSPLUS = 01000000, /* Generate C++ code: prototypes, const, class, inline, enum. */
|
/* Generate switch output to save space. */
|
||||||
ENUM = 02000000, /* Use enum for constants. */
|
SWITCH = 1 << 6,
|
||||||
INCLUDE = 04000000, /* Generate #include statements. */
|
|
||||||
SEVENBIT = 010000000 /* Assume 7-bit, not 8-bit, characters. */
|
/* Don't include keyword length in hash computations. */
|
||||||
|
NOLENGTH = 1 << 7,
|
||||||
|
|
||||||
|
/* Generate a length table for string comparison. */
|
||||||
|
LENTABLE = 1 << 8,
|
||||||
|
|
||||||
|
/* Handle duplicate hash values for keywords. */
|
||||||
|
DUP = 1 << 9,
|
||||||
|
|
||||||
|
/* Generate the hash function "fast". */
|
||||||
|
FAST = 1 << 10,
|
||||||
|
|
||||||
|
/* Don't include user-defined type definition in output -- it's already
|
||||||
|
defined elsewhere. */
|
||||||
|
NOTYPE = 1 << 11,
|
||||||
|
|
||||||
|
/* Generate strncmp rather than strcmp. */
|
||||||
|
COMP = 1 << 12,
|
||||||
|
|
||||||
|
/* Make the keyword table a global variable. */
|
||||||
|
GLOBAL = 1 << 13,
|
||||||
|
|
||||||
|
/* Make the generated tables readonly (const). */
|
||||||
|
CONST = 1 << 14,
|
||||||
|
|
||||||
|
/* Generate K&R C code: no prototypes, no const. */
|
||||||
|
KRC = 1 << 15,
|
||||||
|
|
||||||
|
/* Generate C code: no prototypes, but const (user can #define it away). */
|
||||||
|
C = 1 << 16,
|
||||||
|
|
||||||
|
/* Generate ISO/ANSI C code: prototypes and const, but no class. */
|
||||||
|
ANSIC = 1 << 17,
|
||||||
|
|
||||||
|
/* Generate C++ code: prototypes, const, class, inline, enum. */
|
||||||
|
CPLUSPLUS = 1 << 18,
|
||||||
|
|
||||||
|
/* Use enum for constants. */
|
||||||
|
ENUM = 1 << 19,
|
||||||
|
|
||||||
|
/* Generate #include statements. */
|
||||||
|
INCLUDE = 1 << 20,
|
||||||
|
|
||||||
|
/* Assume 7-bit, not 8-bit, characters. */
|
||||||
|
SEVENBIT = 1 << 21
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Define some useful constants (these don't really belong here, but I'm
|
/* This class denotes a set of key positions. */
|
||||||
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
|
class Positions
|
||||||
{
|
{
|
||||||
MAX_KEY_POS = 128 - 1, /* Max size of each word's key set. */
|
friend class PositionIterator;
|
||||||
WORD_START = 1, /* Signals the start of a word. */
|
public:
|
||||||
WORD_END = 0, /* Signals the end of a word. */
|
/* Denotes the last char of a keyword, depending on the keyword's length. */
|
||||||
EOS = MAX_KEY_POS /* Signals end of the key list. */
|
static const int LASTCHAR = 0;
|
||||||
|
|
||||||
|
/* Maximum size of the set. */
|
||||||
|
static const int MAX_KEY_POS = 127;
|
||||||
|
|
||||||
|
/* Constructors. */
|
||||||
|
Positions ();
|
||||||
|
Positions (int key1);
|
||||||
|
Positions (int key1, int key2);
|
||||||
|
|
||||||
|
/* Accessors. */
|
||||||
|
int operator[] (unsigned int index) const;
|
||||||
|
unsigned int get_size () const;
|
||||||
|
|
||||||
|
/* Write access. */
|
||||||
|
unsigned char * pointer ();
|
||||||
|
void set_size (unsigned int size);
|
||||||
|
|
||||||
|
/* Sorts the array in reverse order.
|
||||||
|
Returns 1 if there are no duplicates, 0 otherwise. */
|
||||||
|
int sort ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* Number of positions, excluding the terminating PositionIterator::EOS. */
|
||||||
|
unsigned int _size;
|
||||||
|
/* Array of positions. 1 for the first char, 2 for the second char etc.,
|
||||||
|
LASTCHAR for the last char. PositionIterator::EOS past the end. */
|
||||||
|
unsigned char _positions[MAX_KEY_POS];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This class denotes an iterator through a set of key positions. */
|
||||||
|
|
||||||
|
class PositionIterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/* Initializes an iterator through POSITIONS. */
|
||||||
|
PositionIterator (Positions const& positions);
|
||||||
|
|
||||||
|
/* End of iteration marker. */
|
||||||
|
static const int EOS = Positions::MAX_KEY_POS;
|
||||||
|
|
||||||
|
/* Retrieves the next position, or EOS past the end. */
|
||||||
|
int next ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Positions& _set;
|
||||||
|
int _index;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Class manager for gperf program Options. */
|
/* Class manager for gperf program Options. */
|
||||||
@@ -79,54 +162,122 @@ enum
|
|||||||
class Options
|
class Options
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Options ();
|
/* Constructor. */
|
||||||
~Options ();
|
Options ();
|
||||||
int operator[] (Option_Type option);
|
|
||||||
void operator() (int argc, char *argv[]);
|
/* Destructor. */
|
||||||
static void print_options ();
|
~Options ();
|
||||||
static void set_asso_max (int r);
|
|
||||||
static int get_asso_max ();
|
/* Parses the options given in the command-line arguments. */
|
||||||
static void reset ();
|
void parse_options (int argc, char *argv[]);
|
||||||
static int get ();
|
|
||||||
static int get_iterations ();
|
/* Prints the given options. */
|
||||||
static int get_max_keysig_size ();
|
void print_options () const;
|
||||||
static void set_keysig_size (int);
|
|
||||||
static int get_jump ();
|
/* Accessors. */
|
||||||
static int initial_value ();
|
|
||||||
static int get_total_switches ();
|
/* Tests a given boolean option. Returns 1 if set, 0 otherwise. */
|
||||||
static const char *get_function_name ();
|
int operator[] (Option_Type option) const;
|
||||||
static const char *get_key_name ();
|
|
||||||
static const char *get_initializer_suffix ();
|
/* Returns the iterations value. */
|
||||||
static const char *get_class_name ();
|
int get_iterations () const;
|
||||||
static const char *get_hash_name ();
|
|
||||||
static const char *get_wordlist_name ();
|
/* Returns the jump value. */
|
||||||
static const char *get_delimiter ();
|
int get_jump () const;
|
||||||
|
|
||||||
|
/* Returns the initial associated character value. */
|
||||||
|
int get_initial_asso_value () const;
|
||||||
|
|
||||||
|
/* Returns the total number of switch statements to generate. */
|
||||||
|
int get_total_switches () const;
|
||||||
|
|
||||||
|
/* Returns the factor by which to multiply the generated table's size. */
|
||||||
|
int get_size_multiple () const;
|
||||||
|
|
||||||
|
/* Returns the generated function name. */
|
||||||
|
const char * get_function_name () const;
|
||||||
|
|
||||||
|
/* Returns the keyword key name. */
|
||||||
|
const char * get_key_name () const;
|
||||||
|
|
||||||
|
/* Returns the struct initializer suffix. */
|
||||||
|
const char * get_initializer_suffix () const;
|
||||||
|
|
||||||
|
/* Returns the generated class name. */
|
||||||
|
const char * get_class_name () const;
|
||||||
|
|
||||||
|
/* Returns the hash function name. */
|
||||||
|
const char * get_hash_name () const;
|
||||||
|
|
||||||
|
/* Returns the hash table array name. */
|
||||||
|
const char * get_wordlist_name () const;
|
||||||
|
|
||||||
|
/* Returns the string used to delimit keywords from other attributes. */
|
||||||
|
const char * get_delimiter () const;
|
||||||
|
|
||||||
|
/* Returns key positions. */
|
||||||
|
const Positions& get_key_positions () const;
|
||||||
|
|
||||||
|
/* Returns total distinct key positions. */
|
||||||
|
int get_max_keysig_size () const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static int _option_word; /* Holds the user-specified Options. */
|
/* Prints program usage to given stream. */
|
||||||
static int _total_switches; /* Number of switch statements to generate. */
|
void short_usage (FILE * stream) const;
|
||||||
static int _total_keysig_size; /* Total number of distinct key_positions. */
|
|
||||||
static int _size; /* Range of the hash table. */
|
/* Prints program usage to given stream. */
|
||||||
static int _key_pos; /* Tracks current key position for Iterator. */
|
void long_usage (FILE * stream) const;
|
||||||
static int _jump; /* Jump length when trying alternative values. */
|
|
||||||
static int _initial_asso_value; /* Initial value for asso_values table. */
|
/* Records count of command-line arguments. */
|
||||||
static int _argument_count; /* Records count of command-line arguments. */
|
int _argument_count;
|
||||||
static int _iterations; /* Amount to iterate when a collision occurs. */
|
|
||||||
static char **_argument_vector; /* Stores a pointer to command-line vector. */
|
/* Stores a pointer to command-line argument vector. */
|
||||||
static const char *_function_name; /* Names used for generated lookup function. */
|
char **_argument_vector;
|
||||||
static const char *_key_name; /* Name used for keyword key. */
|
|
||||||
static const char *_initializer_suffix; /* Suffix for empty struct initializers. */
|
/* Holds the boolean options. */
|
||||||
static const char *_class_name; /* Name used for generated C++ class. */
|
int _option_word;
|
||||||
static const char *_hash_name; /* Name used for generated hash function. */
|
|
||||||
static const char *_wordlist_name; /* Name used for hash table array. */
|
/* Amount to iterate when a collision occurs. */
|
||||||
static const char *_delimiters; /* Separates keywords from other attributes. */
|
int _iterations;
|
||||||
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. */
|
/* Jump length when trying alternative values. */
|
||||||
static void short_usage (FILE * strm); /* Prints proper program usage. */
|
int _jump;
|
||||||
static void long_usage (FILE * strm); /* Prints proper program usage. */
|
|
||||||
|
/* Initial value for asso_values table. */
|
||||||
|
int _initial_asso_value;
|
||||||
|
|
||||||
|
/* Number of switch statements to generate. */
|
||||||
|
int _total_switches;
|
||||||
|
|
||||||
|
/* Factor by which to multiply the generated table's size. */
|
||||||
|
int _size_multiple;
|
||||||
|
|
||||||
|
/* Names used for generated lookup function. */
|
||||||
|
const char *_function_name;
|
||||||
|
|
||||||
|
/* Name used for keyword key. */
|
||||||
|
const char *_key_name;
|
||||||
|
|
||||||
|
/* Suffix for empty struct initializers. */
|
||||||
|
const char *_initializer_suffix;
|
||||||
|
|
||||||
|
/* Name used for generated C++ class. */
|
||||||
|
const char *_class_name;
|
||||||
|
|
||||||
|
/* Name used for generated hash function. */
|
||||||
|
const char *_hash_name;
|
||||||
|
|
||||||
|
/* Name used for hash table array. */
|
||||||
|
const char *_wordlist_name;
|
||||||
|
|
||||||
|
/* Separates keywords from other attributes. */
|
||||||
|
const char *_delimiters;
|
||||||
|
|
||||||
|
/* Contains user-specified key choices. */
|
||||||
|
Positions _key_positions;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Global option coordinator for the entire program. */
|
/* Global option coordinator for the entire program. */
|
||||||
extern Options option;
|
extern Options option;
|
||||||
|
|
||||||
#ifdef __OPTIMIZE__
|
#ifdef __OPTIMIZE__
|
||||||
|
|||||||
239
src/options.icc
239
src/options.icc
@@ -19,128 +19,193 @@ 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
|
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. */
|
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
|
||||||
|
|
||||||
/* TRUE if option enable, else FALSE. */
|
INLINE
|
||||||
|
Positions::Positions ()
|
||||||
|
: _size (0)
|
||||||
|
{
|
||||||
|
_positions[0] = PositionIterator::EOS;
|
||||||
|
}
|
||||||
|
|
||||||
|
INLINE
|
||||||
|
Positions::Positions (int key1)
|
||||||
|
: _size (1)
|
||||||
|
{
|
||||||
|
_positions[0] = key1;
|
||||||
|
_positions[1] = PositionIterator::EOS;
|
||||||
|
}
|
||||||
|
|
||||||
|
INLINE
|
||||||
|
Positions::Positions (int key1, int key2)
|
||||||
|
: _size (2)
|
||||||
|
{
|
||||||
|
_positions[0] = key1;
|
||||||
|
_positions[1] = key2;
|
||||||
|
_positions[2] = PositionIterator::EOS;
|
||||||
|
}
|
||||||
|
|
||||||
INLINE int
|
INLINE int
|
||||||
Options::operator[] (Option_Type option)
|
Positions::operator[] (unsigned int index) const
|
||||||
{
|
{
|
||||||
return _option_word & option;
|
return _positions[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initializes the key Iterator. */
|
INLINE unsigned int
|
||||||
INLINE void
|
Positions::get_size () const
|
||||||
Options::reset ()
|
|
||||||
{
|
|
||||||
_key_pos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns current key_position and advance index. */
|
|
||||||
INLINE int
|
|
||||||
Options::get ()
|
|
||||||
{
|
|
||||||
return _key_positions[_key_pos++];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sets the size of the table size. */
|
|
||||||
INLINE void
|
|
||||||
Options::set_asso_max (int r)
|
|
||||||
{
|
|
||||||
_size = r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns the size of the table size. */
|
|
||||||
INLINE int
|
|
||||||
Options::get_asso_max ()
|
|
||||||
{
|
{
|
||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns total distinct key positions. */
|
INLINE unsigned char *
|
||||||
INLINE int
|
Positions::pointer ()
|
||||||
Options::get_max_keysig_size ()
|
|
||||||
{
|
{
|
||||||
return _total_keysig_size;
|
return _positions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sets total distinct key positions. */
|
|
||||||
INLINE void
|
INLINE void
|
||||||
Options::set_keysig_size (int size)
|
Positions::set_size (unsigned int size)
|
||||||
{
|
{
|
||||||
_total_keysig_size = size;
|
_size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the jump value. */
|
/* Sorts the array in reverse order.
|
||||||
|
Returns 1 if there are no duplicates, 0 otherwise. */
|
||||||
INLINE int
|
INLINE int
|
||||||
Options::get_jump ()
|
Positions::sort ()
|
||||||
{
|
{
|
||||||
return _jump;
|
/* Bubble sort. */
|
||||||
|
int duplicate_free = 1;
|
||||||
|
unsigned char *base = _positions;
|
||||||
|
unsigned int len = _size;
|
||||||
|
|
||||||
|
for (unsigned int i = 1; i < len; i++)
|
||||||
|
{
|
||||||
|
unsigned int j;
|
||||||
|
int tmp;
|
||||||
|
|
||||||
|
for (j = i, tmp = base[j]; j > 0 && tmp >= base[j - 1]; j--)
|
||||||
|
if ((base[j] = base[j - 1]) == tmp) /* oh no, a duplicate!!! */
|
||||||
|
duplicate_free = 0;
|
||||||
|
|
||||||
|
base[j] = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return duplicate_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the generated function name. */
|
INLINE
|
||||||
INLINE const char *
|
PositionIterator::PositionIterator (Positions const& positions)
|
||||||
Options::get_function_name ()
|
: _set (positions),
|
||||||
|
_index (0)
|
||||||
{
|
{
|
||||||
return _function_name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the keyword key name. */
|
|
||||||
INLINE const char *
|
|
||||||
Options::get_key_name ()
|
|
||||||
{
|
|
||||||
return _key_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns the struct initializer suffix. */
|
|
||||||
INLINE const char *
|
|
||||||
Options::get_initializer_suffix ()
|
|
||||||
{
|
|
||||||
return _initializer_suffix;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns the hash function name. */
|
|
||||||
INLINE const char *
|
|
||||||
Options::get_hash_name ()
|
|
||||||
{
|
|
||||||
return _hash_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns the hash table array name. */
|
|
||||||
INLINE const char *
|
|
||||||
Options::get_wordlist_name ()
|
|
||||||
{
|
|
||||||
return _wordlist_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns the generated class name. */
|
|
||||||
INLINE const char *
|
|
||||||
Options::get_class_name ()
|
|
||||||
{
|
|
||||||
return _class_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns the initial associated character value. */
|
|
||||||
INLINE int
|
INLINE int
|
||||||
Options::initial_value ()
|
PositionIterator::next ()
|
||||||
{
|
{
|
||||||
return _initial_asso_value;
|
return _set._positions[_index++];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the iterations value. */
|
/* Tests a given boolean option. Returns 1 if set, 0 otherwise. */
|
||||||
INLINE int
|
INLINE int
|
||||||
Options::get_iterations ()
|
Options::operator[] (Option_Type option) const
|
||||||
|
{
|
||||||
|
return _option_word & option;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the iterations value. */
|
||||||
|
INLINE int
|
||||||
|
Options::get_iterations () const
|
||||||
{
|
{
|
||||||
return _iterations;
|
return _iterations;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the string used to delimit keywords from other attributes. */
|
/* Returns the jump value. */
|
||||||
|
INLINE int
|
||||||
|
Options::get_jump () const
|
||||||
|
{
|
||||||
|
return _jump;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the initial associated character value. */
|
||||||
|
INLINE int
|
||||||
|
Options::get_initial_asso_value () const
|
||||||
|
{
|
||||||
|
return _initial_asso_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the total number of switch statements to generate. */
|
||||||
|
INLINE int
|
||||||
|
Options::get_total_switches () const
|
||||||
|
{
|
||||||
|
return _total_switches;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the factor by which to multiply the generated table's size. */
|
||||||
|
INLINE int
|
||||||
|
Options::get_size_multiple () const
|
||||||
|
{
|
||||||
|
return _size_multiple;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the generated function name. */
|
||||||
INLINE const char *
|
INLINE const char *
|
||||||
Options::get_delimiter ()
|
Options::get_function_name () const
|
||||||
|
{
|
||||||
|
return _function_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the keyword key name. */
|
||||||
|
INLINE const char *
|
||||||
|
Options::get_key_name () const
|
||||||
|
{
|
||||||
|
return _key_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the struct initializer suffix. */
|
||||||
|
INLINE const char *
|
||||||
|
Options::get_initializer_suffix () const
|
||||||
|
{
|
||||||
|
return _initializer_suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the generated class name. */
|
||||||
|
INLINE const char *
|
||||||
|
Options::get_class_name () const
|
||||||
|
{
|
||||||
|
return _class_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the hash function name. */
|
||||||
|
INLINE const char *
|
||||||
|
Options::get_hash_name () const
|
||||||
|
{
|
||||||
|
return _hash_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the hash table array name. */
|
||||||
|
INLINE const char *
|
||||||
|
Options::get_wordlist_name () const
|
||||||
|
{
|
||||||
|
return _wordlist_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the string used to delimit keywords from other attributes. */
|
||||||
|
INLINE const char *
|
||||||
|
Options::get_delimiter () const
|
||||||
{
|
{
|
||||||
return _delimiters;
|
return _delimiters;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Gets the total number of switch statements to generate. */
|
/* Returns key positions. */
|
||||||
INLINE int
|
INLINE const Positions&
|
||||||
Options::get_total_switches ()
|
Options::get_key_positions () const
|
||||||
{
|
{
|
||||||
return _total_switches;
|
return _key_positions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns total distinct key positions. */
|
||||||
|
INLINE int
|
||||||
|
Options::get_max_keysig_size () const
|
||||||
|
{
|
||||||
|
return _key_positions.get_size();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -470,16 +470,34 @@ Output::output_hash_function ()
|
|||||||
printf (" return %sasso_values[%sstr[len - 1]] + asso_values[%sstr[0]];\n",
|
printf (" return %sasso_values[%sstr[len - 1]] + asso_values[%sstr[0]];\n",
|
||||||
option[NOLENGTH] ? "" : "len + ",
|
option[NOLENGTH] ? "" : "len + ",
|
||||||
char_to_index, char_to_index);
|
char_to_index, char_to_index);
|
||||||
|
else if (option[ALLCHARS])
|
||||||
|
{
|
||||||
|
/* User wants *all* characters considered in hash. */
|
||||||
|
printf (" register int hval = %s;\n\n"
|
||||||
|
" switch (%s)\n"
|
||||||
|
" {\n"
|
||||||
|
" default:\n",
|
||||||
|
option[NOLENGTH] ? "0" : "len",
|
||||||
|
option[NOLENGTH] ? "len" : "hval");
|
||||||
|
|
||||||
|
for (int i = _max_key_len; i > 0; i--)
|
||||||
|
printf (" case %d:\n"
|
||||||
|
" hval += asso_values[%sstr[%d]];\n",
|
||||||
|
i, char_to_index, i - 1);
|
||||||
|
|
||||||
|
printf (" break;\n"
|
||||||
|
" }\n"
|
||||||
|
" return hval;\n");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
PositionIterator iter (option.get_key_positions());
|
||||||
int key_pos;
|
int key_pos;
|
||||||
|
|
||||||
option.reset ();
|
|
||||||
|
|
||||||
/* Get first (also highest) key position. */
|
/* Get first (also highest) key position. */
|
||||||
key_pos = option.get ();
|
key_pos = iter.next ();
|
||||||
|
|
||||||
if (!option[ALLCHARS] && (key_pos == WORD_END || key_pos <= _min_key_len))
|
if (key_pos == Positions::LASTCHAR || key_pos <= _min_key_len)
|
||||||
{
|
{
|
||||||
/* We can perform additional optimizations here:
|
/* We can perform additional optimizations here:
|
||||||
Write it out as a single expression. Note that the values
|
Write it out as a single expression. Note that the values
|
||||||
@@ -489,16 +507,16 @@ Output::output_hash_function ()
|
|||||||
printf (" return %s",
|
printf (" return %s",
|
||||||
option[NOLENGTH] ? "" : "len + ");
|
option[NOLENGTH] ? "" : "len + ");
|
||||||
|
|
||||||
for (; key_pos != WORD_END; )
|
for (; key_pos != Positions::LASTCHAR; )
|
||||||
{
|
{
|
||||||
printf ("asso_values[%sstr[%d]]", char_to_index, key_pos - 1);
|
printf ("asso_values[%sstr[%d]]", char_to_index, key_pos - 1);
|
||||||
if ((key_pos = option.get ()) != EOS)
|
if ((key_pos = iter.next ()) != PositionIterator::EOS)
|
||||||
printf (" + ");
|
printf (" + ");
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key_pos == WORD_END)
|
if (key_pos == Positions::LASTCHAR)
|
||||||
printf ("asso_values[%sstr[len - 1]]", char_to_index);
|
printf ("asso_values[%sstr[len - 1]]", char_to_index);
|
||||||
|
|
||||||
printf (";\n");
|
printf (";\n");
|
||||||
@@ -513,50 +531,35 @@ Output::output_hash_function ()
|
|||||||
option[NOLENGTH] ? "0" : "len",
|
option[NOLENGTH] ? "0" : "len",
|
||||||
option[NOLENGTH] ? "len" : "hval");
|
option[NOLENGTH] ? "len" : "hval");
|
||||||
|
|
||||||
/* User wants *all* characters considered in hash. */
|
while (key_pos != Positions::LASTCHAR && key_pos > _max_key_len)
|
||||||
if (option[ALLCHARS])
|
if ((key_pos = iter.next ()) == PositionIterator::EOS)
|
||||||
{
|
break;
|
||||||
for (int i = _max_key_len; i > 0; i--)
|
|
||||||
printf (" case %d:\n"
|
|
||||||
" hval += asso_values[%sstr[%d]];\n",
|
|
||||||
i, char_to_index, i - 1);
|
|
||||||
|
|
||||||
printf (" break;\n"
|
if (key_pos != PositionIterator::EOS && key_pos != Positions::LASTCHAR)
|
||||||
" }\n"
|
|
||||||
" return hval;\n");
|
|
||||||
}
|
|
||||||
else /* do the hard part... */
|
|
||||||
{
|
{
|
||||||
while (key_pos != WORD_END && key_pos > _max_key_len)
|
int i = key_pos;
|
||||||
if ((key_pos = option.get ()) == EOS)
|
do
|
||||||
break;
|
|
||||||
|
|
||||||
if (key_pos != EOS && key_pos != WORD_END)
|
|
||||||
{
|
{
|
||||||
int i = key_pos;
|
for ( ; i >= key_pos; i--)
|
||||||
do
|
|
||||||
{
|
|
||||||
for ( ; i >= key_pos; i--)
|
|
||||||
printf (" case %d:\n", i);
|
|
||||||
|
|
||||||
printf (" hval += asso_values[%sstr[%d]];\n",
|
|
||||||
char_to_index, key_pos - 1);
|
|
||||||
|
|
||||||
key_pos = option.get ();
|
|
||||||
}
|
|
||||||
while (key_pos != EOS && key_pos != WORD_END);
|
|
||||||
|
|
||||||
for ( ; i >= _min_key_len; i--)
|
|
||||||
printf (" case %d:\n", i);
|
printf (" case %d:\n", i);
|
||||||
}
|
|
||||||
|
|
||||||
printf (" break;\n"
|
printf (" hval += asso_values[%sstr[%d]];\n",
|
||||||
" }\n"
|
char_to_index, key_pos - 1);
|
||||||
" return hval");
|
|
||||||
if (key_pos == WORD_END)
|
key_pos = iter.next ();
|
||||||
printf (" + asso_values[%sstr[len - 1]]", char_to_index);
|
}
|
||||||
printf (";\n");
|
while (key_pos != PositionIterator::EOS && key_pos != Positions::LASTCHAR);
|
||||||
|
|
||||||
|
for ( ; i >= _min_key_len; i--)
|
||||||
|
printf (" case %d:\n", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printf (" break;\n"
|
||||||
|
" }\n"
|
||||||
|
" return hval");
|
||||||
|
if (key_pos == Positions::LASTCHAR)
|
||||||
|
printf (" + asso_values[%sstr[len - 1]]", char_to_index);
|
||||||
|
printf (";\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf ("}\n\n");
|
printf ("}\n\n");
|
||||||
@@ -1432,7 +1435,7 @@ Output::output ()
|
|||||||
else if (option[CPLUSPLUS])
|
else if (option[CPLUSPLUS])
|
||||||
printf ("C++");
|
printf ("C++");
|
||||||
printf (" code produced by gperf version %s */\n", version_string);
|
printf (" code produced by gperf version %s */\n", version_string);
|
||||||
Options::print_options ();
|
option.print_options ();
|
||||||
|
|
||||||
printf ("%s\n", _include_src);
|
printf ("%s\n", _include_src);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
GNU `gperf' generates perfect hash functions.
|
GNU 'gperf' generates perfect hash functions.
|
||||||
|
|
||||||
Usage: ../src/gperf [OPTION]... [INPUT-FILE]
|
Usage: ../src/gperf [OPTION]... [INPUT-FILE]
|
||||||
|
|
||||||
@@ -30,12 +30,12 @@ Details in the output code:
|
|||||||
structure.
|
structure.
|
||||||
-H, --hash-fn-name=NAME
|
-H, --hash-fn-name=NAME
|
||||||
Specify name of generated hash function. Default is
|
Specify name of generated hash function. Default is
|
||||||
`hash'.
|
'hash'.
|
||||||
-N, --lookup-fn-name=NAME
|
-N, --lookup-fn-name=NAME
|
||||||
Specify name of generated lookup function. Default
|
Specify name of generated lookup function. Default
|
||||||
name is `in_word_set'.
|
name is 'in_word_set'.
|
||||||
-Z, --class-name=NAME Specify name of generated C++ class. Default name is
|
-Z, --class-name=NAME Specify name of generated C++ class. Default name is
|
||||||
`Perfect_Hash'.
|
'Perfect_Hash'.
|
||||||
-7, --seven-bit Assume 7-bit characters.
|
-7, --seven-bit Assume 7-bit characters.
|
||||||
-c, --compare-strncmp Generate comparison code using strncmp rather than
|
-c, --compare-strncmp Generate comparison code using strncmp rather than
|
||||||
strcmp.
|
strcmp.
|
||||||
@@ -50,7 +50,7 @@ Details in the output code:
|
|||||||
lookup function (which is the default behavior).
|
lookup function (which is the default behavior).
|
||||||
-W, --word-array-name=NAME
|
-W, --word-array-name=NAME
|
||||||
Specify name of word list array. Default name is
|
Specify name of word list array. Default name is
|
||||||
`wordlist'.
|
'wordlist'.
|
||||||
-S, --switch=COUNT Causes the generated C code to use a switch
|
-S, --switch=COUNT Causes the generated C code to use a switch
|
||||||
statement scheme, rather than an array lookup table.
|
statement scheme, rather than an array lookup table.
|
||||||
This can lead to a reduction in both time and space
|
This can lead to a reduction in both time and space
|
||||||
@@ -74,23 +74,23 @@ Algorithm employed by gperf:
|
|||||||
used, and key positions may occur in any order.
|
used, and key positions may occur in any order.
|
||||||
Also, the meta-character '*' causes the generated
|
Also, the meta-character '*' causes the generated
|
||||||
hash function to consider ALL key positions, and $
|
hash function to consider ALL key positions, and $
|
||||||
indicates the ``final character'' of a key, e.g.,
|
indicates the "final character" of a key, e.g.,
|
||||||
$,1,2,4,6-10.
|
$,1,2,4,6-10.
|
||||||
-l, --compare-strlen Compare key lengths before trying a string
|
-l, --compare-strlen Compare key lengths before trying a string
|
||||||
comparison. This helps cut down on the number of
|
comparison. This helps cut down on the number of
|
||||||
string comparisons made during the lookup.
|
string comparisons made during the lookup.
|
||||||
-D, --duplicates Handle keywords that hash to duplicate values. This
|
-D, --duplicates Handle keywords that hash to duplicate values. This
|
||||||
is useful for certain highly redundant keyword sets.
|
is useful for certain highly redundant keyword sets.
|
||||||
-f, --fast=ITERATIONS Generate the gen-perf.hash function ``fast''. This
|
-f, --fast=ITERATIONS Generate the gen-perf.hash function "fast". This
|
||||||
decreases gperf's running time at the cost of
|
decreases gperf's running time at the cost of
|
||||||
minimizing generated table size. The numeric
|
minimizing generated table size. The numeric
|
||||||
argument represents the number of times to iterate
|
argument represents the number of times to iterate
|
||||||
when resolving a collision. `0' means ``iterate by
|
when resolving a collision. '0' means "iterate by
|
||||||
the number of keywords''.
|
the number of keywords".
|
||||||
-i, --initial-asso=N Provide an initial value for the associate values
|
-i, --initial-asso=N Provide an initial value for the associate values
|
||||||
array. Default is 0. Setting this value larger helps
|
array. Default is 0. Setting this value larger helps
|
||||||
inflate the size of the final table.
|
inflate the size of the final table.
|
||||||
-j, --jump=JUMP-VALUE Affects the ``jump value'', i.e., how far to advance
|
-j, --jump=JUMP-VALUE Affects the "jump value", i.e., how far to advance
|
||||||
the associated character value upon collisions. Must
|
the associated character value upon collisions. Must
|
||||||
be an odd number, default is 5.
|
be an odd number, default is 5.
|
||||||
-n, --no-strlen Do not include the length of the keyword when
|
-n, --no-strlen Do not include the length of the keyword when
|
||||||
@@ -101,14 +101,14 @@ Algorithm employed by gperf:
|
|||||||
-r, --random Utilizes randomness to initialize the associated
|
-r, --random Utilizes randomness to initialize the associated
|
||||||
values table.
|
values table.
|
||||||
-s, --size-multiple=N Affects the size of the generated hash table. The
|
-s, --size-multiple=N Affects the size of the generated hash table. The
|
||||||
numeric argument N indicates ``how many times larger
|
numeric argument N indicates "how many times larger
|
||||||
or smaller'' the associated value range should be,
|
or smaller" the associated value range should be,
|
||||||
in relationship to the number of keys, e.g. a value
|
in relationship to the number of keys, e.g. a value
|
||||||
of 3 means ``allow the maximum associated value to
|
of 3 means "allow the maximum associated value to
|
||||||
be about 3 times larger than the number of input
|
be about 3 times larger than the number of input
|
||||||
keys.'' Conversely, a value of -3 means ``make the
|
keys". Conversely, a value of -3 means "make the
|
||||||
maximum associated value about 3 times smaller than
|
maximum associated value about 3 times smaller than
|
||||||
the number of input keys. A larger table should
|
the number of input keys". A larger table should
|
||||||
decrease the time required for an unsuccessful
|
decrease the time required for an unsuccessful
|
||||||
search, at the expense of extra table space. Default
|
search, at the expense of extra table space. Default
|
||||||
value is 1.
|
value is 1.
|
||||||
|
|||||||
Reference in New Issue
Block a user