1
0
mirror of https://git.savannah.gnu.org/git/gperf.git synced 2025-12-02 21:19:24 +00:00

Comments.

This commit is contained in:
Bruno Haible
2003-01-08 12:30:46 +00:00
parent cd08b4d519
commit e19dee4b44
2 changed files with 217 additions and 138 deletions

View File

@@ -40,7 +40,8 @@ static const char *const_readonly_array;
/* The "const " qualifier, for the array type. */ /* The "const " qualifier, for the array type. */
static const char *const_for_struct; static const char *const_for_struct;
/* Returns the smallest unsigned C type capable of holding integers up to N. */ /* Returns the smallest unsigned C type capable of holding integers
up to N. */
static const char * static const char *
smallest_integral_type (int n) smallest_integral_type (int n)
@@ -67,7 +68,24 @@ static const char *char_to_index;
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
/* Constructor. */ /* Constructor.
Note about the keyword list starting at head:
- The list is ordered by increasing _hash_value. This has been achieved
by Search::sort().
- Duplicates, i.e. keywords with the same _selchars set, are chained
through the _duplicate_link pointer. This chain goes in the same
direction as the list order, i.e. from earlier list positions to
later list positions. This property has been achieved by
Search::prepare() and has been preserved through Search::reorder()
and Search::sort() (because the sorting criteria cannot distinguish
keywords with the same _selchars, and Search::merge_sort() is a stable
sorting algorithm).
- Therefore, since duplicates have the same _hash_value, duplicates
have been sorted together by Search::sort(), and form blocks of
consecutive list elements. The _duplicate_link of every element
of a duplicate block (except the last element) points to the next
element in this block.
*/
Output::Output (KeywordExt_List *head, const char *array_type, Output::Output (KeywordExt_List *head, const char *array_type,
const char *return_type, const char *struct_tag, const char *return_type, const char *struct_tag,
bool additional_code, const char *include_src, bool additional_code, const char *include_src,
@@ -85,18 +103,34 @@ Output::Output (KeywordExt_List *head, const char *array_type,
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
/* Computes the maximum and minimum hash values. Since the /* Recognizing duplicates. */
list is already sorted by hash value all we need to do is
find the final item! */ /* Returns true for a duplicate keyword, excluding the first element of a
duplicate block. */
inline bool
is_redundant_duplicate (KeywordExt_List *elem)
{
/* Compare the hash values of this element and the next one. */
return (elem->rest() != NULL
&& elem->first()->_hash_value == elem->rest()->first()->_hash_value);
}
/* ------------------------------------------------------------------------- */
/* Computes the minimum and maximum hash values, and stores them
in _min_hash_value and _max_hash_value. */
void void
Output::compute_min_max () Output::compute_min_max ()
{ {
/* Since the list is already sorted by hash value all we need to do is
to look at the first and the last element of the list. */
_min_hash_value = _head->first()->_hash_value;
KeywordExt_List *temp; KeywordExt_List *temp;
for (temp = _head; temp->rest(); temp = temp->rest()) for (temp = _head; temp->rest(); temp = temp->rest())
; ;
_min_hash_value = _head->first()->_hash_value;
_max_hash_value = temp->first()->_hash_value; _max_hash_value = temp->first()->_hash_value;
} }
@@ -107,6 +141,8 @@ Output::compute_min_max ()
int int
Output::num_hash_values () Output::num_hash_values ()
{ {
/* Since the list is already sorted by hash value we can count the
different hash values in a single pass through the list. */
int count = 1; int count = 1;
KeywordExt_List *temp; KeywordExt_List *temp;
int value; int value;
@@ -160,41 +196,41 @@ void Output_Defines::output_end ()
{ {
} }
/* This class outputs an enumeration using `enum'. */ /* This class outputs an enumeration using 'enum'. */
struct Output_Enum : public Output_Constants struct Output_Enum : public Output_Constants
{ {
virtual void output_start (); virtual void output_start ();
virtual void output_item (const char *name, int value); virtual void output_item (const char *name, int value);
virtual void output_end (); virtual void output_end ();
Output_Enum (const char *indent) : indentation (indent) {} Output_Enum (const char *indent) : _indentation (indent) {}
virtual ~Output_Enum () {} virtual ~Output_Enum () {}
private: private:
const char *indentation; const char *_indentation;
int pending_comma; bool _pending_comma;
}; };
void Output_Enum::output_start () void Output_Enum::output_start ()
{ {
printf ("%senum\n" printf ("%senum\n"
"%s {\n", "%s {\n",
indentation, indentation); _indentation, _indentation);
pending_comma = 0; _pending_comma = false;
} }
void Output_Enum::output_item (const char *name, int value) void Output_Enum::output_item (const char *name, int value)
{ {
if (pending_comma) if (_pending_comma)
printf (",\n"); printf (",\n");
printf ("%s %s = %d", indentation, name, value); printf ("%s %s = %d", _indentation, name, value);
pending_comma = 1; _pending_comma = true;
} }
void Output_Enum::output_end () void Output_Enum::output_end ()
{ {
if (pending_comma) if (_pending_comma)
printf ("\n"); printf ("\n");
printf ("%s };\n\n", indentation); printf ("%s };\n\n", _indentation);
} }
/* Outputs the maximum and minimum hash values etc. */ /* Outputs the maximum and minimum hash values etc. */
@@ -246,15 +282,17 @@ output_string (const char *key, int len)
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
/* Outputs a type and a const specifier. /* Outputs a type and a const specifier (i.e. "const " or "").
The output is terminated with a space. */ The output is terminated with a space. */
static void static void
output_const_type (const char *const_string, const char *type_string) output_const_type (const char *const_string, const char *type_string)
{ {
if (type_string[strlen(type_string)-1] == '*') if (type_string[strlen(type_string)-1] == '*')
/* For pointer types, put the 'const' after the type. */
printf ("%s %s", type_string, const_string); printf ("%s %s", type_string, const_string);
else else
/* For scalar or struct types, put the 'const' before the type. */
printf ("%s%s ", const_string, type_string); printf ("%s%s ", const_string, type_string);
} }
@@ -274,15 +312,15 @@ struct Output_Expr
struct Output_Expr1 : public Output_Expr struct Output_Expr1 : public Output_Expr
{ {
virtual void output_expr () const; virtual void output_expr () const;
Output_Expr1 (const char *piece1) : p1 (piece1) {} Output_Expr1 (const char *piece1) : _p1 (piece1) {}
virtual ~Output_Expr1 () {} virtual ~Output_Expr1 () {}
private: private:
const char *p1; const char *_p1;
}; };
void Output_Expr1::output_expr () const void Output_Expr1::output_expr () const
{ {
printf ("%s", p1); printf ("%s", _p1);
} }
#if 0 /* unused */ #if 0 /* unused */
@@ -294,16 +332,16 @@ struct Output_Expr2 : public Output_Expr
{ {
virtual void output_expr () const; virtual void output_expr () const;
Output_Expr2 (const char *piece1, const char *piece2) Output_Expr2 (const char *piece1, const char *piece2)
: p1 (piece1), p2 (piece2) {} : _p1 (piece1), _p2 (piece2) {}
virtual ~Output_Expr2 () {} virtual ~Output_Expr2 () {}
private: private:
const char *p1; const char *_p1;
const char *p2; const char *_p2;
}; };
void Output_Expr2::output_expr () const void Output_Expr2::output_expr () const
{ {
printf ("%s%s", p1, p2); printf ("%s%s", _p1, _p2);
} }
#endif #endif
@@ -314,6 +352,11 @@ void Output_Expr2::output_expr () const
struct Output_Compare struct Output_Compare
{ {
/* Outputs the comparison expression.
expr1 outputs a simple expression of type 'const char *' referring to
the string being looked up. expr2 outputs a simple expression of type
'const char *' referring to the constant string stored in the gperf
generated hash table. */
virtual void output_comparison (const Output_Expr& expr1, virtual void output_comparison (const Output_Expr& expr1,
const Output_Expr& expr2) const = 0; const Output_Expr& expr2) const = 0;
Output_Compare () {} Output_Compare () {}
@@ -346,7 +389,7 @@ void Output_Compare_Strcmp::output_comparison (const Output_Expr& expr1,
/* This class outputs a comparison using strncmp. /* This class outputs a comparison using strncmp.
Note that the length of expr1 will be available through the local variable Note that the length of expr1 will be available through the local variable
`len'. */ 'len'. */
struct Output_Compare_Strncmp : public Output_Compare struct Output_Compare_Strncmp : public Output_Compare
{ {
@@ -373,7 +416,7 @@ void Output_Compare_Strncmp::output_comparison (const Output_Expr& expr1,
} }
/* This class outputs a comparison using memcmp. /* This class outputs a comparison using memcmp.
Note that the length of expr1 (available through the local variable `len') Note that the length of expr1 (available through the local variable 'len')
must be verified to be equal to the length of expr2 prior to this must be verified to be equal to the length of expr2 prior to this
comparison. */ comparison. */
@@ -402,19 +445,13 @@ void Output_Compare_Memcmp::output_comparison (const Output_Expr& expr1,
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
/* Generates C code for the hash function that returns the /* Generates C code for the hash function that returns the
proper encoding for each key word. */ proper encoding for each keyword.
The hash function has the signature
unsigned int <hash> (const char *str, unsigned int len). */
void void
Output::output_hash_function () Output::output_hash_function ()
{ {
const int max_column = 10;
int field_width;
/* Calculate maximum number of digits required for MAX_HASH_VALUE. */
field_width = 2;
for (int trunc = _max_hash_value; (trunc /= 10) > 0;)
field_width++;
/* Output the function's head. */ /* Output the function's head. */
if (option[CPLUSPLUS]) if (option[CPLUSPLUS])
printf ("inline "); printf ("inline ");
@@ -452,16 +489,24 @@ Output::output_hash_function ()
printf ("{\n"); printf ("{\n");
/* First the asso_values array. */ /* First the asso_values array. */
{
printf (" static %s%s asso_values[] =\n" printf (" static %s%s asso_values[] =\n"
" {", " {",
const_readonly_array, const_readonly_array,
smallest_integral_type (_max_hash_value + 1)); smallest_integral_type (_max_hash_value + 1));
const int columns = 10;
/* Calculate maximum number of digits required for MAX_HASH_VALUE. */
int field_width = 2;
for (int trunc = _max_hash_value; (trunc /= 10) > 0;)
field_width++;
for (int count = 0; count < _alpha_size; count++) for (int count = 0; count < _alpha_size; count++)
{ {
if (count > 0) if (count > 0)
printf (","); printf (",");
if (!(count % max_column)) if ((count % columns) == 0)
printf ("\n "); printf ("\n ");
printf ("%*d", field_width, printf ("%*d", field_width,
_occurrences[count] ? _asso_values[count] : _max_hash_value + 1); _occurrences[count] ? _asso_values[count] : _max_hash_value + 1);
@@ -469,16 +514,9 @@ Output::output_hash_function ()
printf ("\n" printf ("\n"
" };\n"); " };\n");
}
/* Optimize special case of ``-k 1,$'' */ if (option[ALLCHARS])
if (!option[ALLCHARS]
&& option.get_key_positions().get_size() == 2
&& option.get_key_positions()[0] == 1
&& option.get_key_positions()[1] == Positions::LASTCHAR)
printf (" return %sasso_values[%sstr[len - 1]] + asso_values[%sstr[0]];\n",
option[NOLENGTH] ? "" : "len + ",
char_to_index, char_to_index);
else if (option[ALLCHARS])
{ {
/* User wants *all* characters considered in hash. */ /* User wants *all* characters considered in hash. */
printf (" register int hval = %s;\n\n" printf (" register int hval = %s;\n\n"
@@ -499,22 +537,33 @@ Output::output_hash_function ()
} }
else else
{ {
/* Iterate through the key positions. Remember that Positions::sort()
has sorted them in decreasing order, with Positions::LASTCHAR coming
last. */
PositionIterator iter (option.get_key_positions()); PositionIterator iter (option.get_key_positions());
int key_pos; int key_pos;
/* Get first (also highest) key position. */ /* Get the highest key position. */
key_pos = iter.next (); key_pos = iter.next ();
if (key_pos == Positions::LASTCHAR || 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
are added as `int's even though the asso_values array may are added as 'int's even though the asso_values array may
contain `unsigned char's or `unsigned short's. */ contain 'unsigned char's or 'unsigned short's. */
printf (" return %s", printf (" return %s",
option[NOLENGTH] ? "" : "len + "); option[NOLENGTH] ? "" : "len + ");
if (option.get_key_positions().get_size() == 2
&& option.get_key_positions()[0] == 1
&& option.get_key_positions()[1] == Positions::LASTCHAR)
/* Optimize special case of "-k 1,$". */
printf ("asso_values[%sstr[len - 1]] + asso_values[%sstr[0]]",
char_to_index, char_to_index);
else
{
for (; key_pos != Positions::LASTCHAR; ) 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);
@@ -526,6 +575,7 @@ Output::output_hash_function ()
if (key_pos == Positions::LASTCHAR) 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");
} }
@@ -576,16 +626,14 @@ Output::output_hash_function ()
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
/* Prints out a table of keyword lengths, for use with the /* Prints out a table of keyword lengths, for use with the
comparison code in generated function ``in_word_set''. */ comparison code in generated function 'in_word_set'.
Only called if option[LENTABLE]. */
void void
Output::output_keylength_table () Output::output_keylength_table ()
{ {
const int columns = 14; const int columns = 14;
int index; const char * const indent = option[GLOBAL] ? "" : " ";
int column;
const char *indent = option[GLOBAL] ? "" : " ";
KeywordExt_List *temp;
printf ("%sstatic %s%s lengthtable[] =\n%s {", printf ("%sstatic %s%s lengthtable[] =\n%s {",
indent, const_readonly_array, indent, const_readonly_array,
@@ -593,10 +641,16 @@ Output::output_keylength_table ()
indent); indent);
/* Generate an array of lengths, similar to output_keyword_table. */ /* Generate an array of lengths, similar to output_keyword_table. */
int index;
int column;
KeywordExt_List *temp;
column = 0; column = 0;
for (temp = _head, index = 0; temp; temp = temp->rest()) for (temp = _head, index = 0; temp; temp = temp->rest())
{ {
/* If generating a switch statement, and there is no user defined type,
we generate non-duplicates directly in the code. Only duplicates go
into the table. */
if (option[SWITCH] && !option[TYPE] if (option[SWITCH] && !option[TYPE]
&& !(temp->first()->_duplicate_link && !(temp->first()->_duplicate_link
|| (temp->rest() && temp->first()->_hash_value == temp->rest()->first()->_hash_value))) || (temp->rest() && temp->first()->_hash_value == temp->rest()->first()->_hash_value)))
@@ -620,20 +674,19 @@ Output::output_keylength_table ()
if ((column++ % columns) == 0) if ((column++ % columns) == 0)
printf("\n%s ", indent); printf("\n%s ", indent);
printf ("%3d", temp->first()->_allchars_length); printf ("%3d", temp->first()->_allchars_length);
index++;
/* Deal with links specially. */ /* Deal with duplicates specially. */
if (temp->first()->_duplicate_link) // implies option[DUP] if (temp->first()->_duplicate_link) // implies option[DUP]
for (KeywordExt *links = temp->first()->_duplicate_link; links; links = links->_duplicate_link) for (KeywordExt *links = temp->first()->_duplicate_link; links; links = links->_duplicate_link)
{ {
++index;
printf (","); printf (",");
if ((column++ % columns) == 0) if ((column++ % columns) == 0)
printf("\n%s ", indent); printf("\n%s ", indent);
printf ("%3d", links->_allchars_length); printf ("%3d", links->_allchars_length);
}
index++; index++;
} }
}
printf ("\n%s };\n", indent); printf ("\n%s };\n", indent);
if (option[GLOBAL]) if (option[GLOBAL])
@@ -696,7 +749,7 @@ output_keyword_blank_entries (int count, const char *indent)
} }
} }
/* Prints out the array containing the key words for the hash function. */ /* Prints out the array containing the keywords for the hash function. */
void void
Output::output_keyword_table () Output::output_keyword_table ()
@@ -737,7 +790,7 @@ Output::output_keyword_table ()
output_keyword_entry (temp->first(), indent); output_keyword_entry (temp->first(), indent);
/* Deal with links specially. */ /* Deal with duplicates specially. */
if (temp->first()->_duplicate_link) // implies option[DUP] if (temp->first()->_duplicate_link) // implies option[DUP]
for (KeywordExt *links = temp->first()->_duplicate_link; links; links = links->_duplicate_link) for (KeywordExt *links = temp->first()->_duplicate_link; links; links = links->_duplicate_link)
{ {

View File

@@ -35,14 +35,40 @@ struct Output_Compare;
class Output class Output
{ {
public: public:
Output (KeywordExt_List *head, const char *array_type, const char *return_type, const char *struct_tag, bool additional_code, const char *include_src, int total_keys, int total_duplicates, int max_key_len, int min_key_len, int alpha_size, const int *occurrences, const int *asso_values); /* Constructor. */
Output (KeywordExt_List *head,
const char *array_type,
const char *return_type,
const char *struct_tag,
bool additional_code,
const char *include_src,
int total_keys,
int total_duplicates,
int max_key_len, int min_key_len,
int alpha_size,
const int *occurrences,
const int *asso_values);
void output (); void output ();
private: private:
/* Computes the minimum and maximum hash values, and stores them
in _min_hash_value and _max_hash_value. */
void compute_min_max (); void compute_min_max ();
/* Returns the number of different hash values. */
int num_hash_values (); int num_hash_values ();
/* Outputs the maximum and minimum hash values etc. */
void output_constants (struct Output_Constants&); void output_constants (struct Output_Constants&);
/* Generates C code for the hash function that returns the
proper encoding for each keyword. */
void output_hash_function (); void output_hash_function ();
/* Prints out a table of keyword lengths, for use with the
comparison code in generated function 'in_word_set'. */
void output_keylength_table (); void output_keylength_table ();
void output_keyword_table (); void output_keyword_table ();
void output_lookup_array (); void output_lookup_array ();
void output_lookup_tables (); void output_lookup_tables ();