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:
173
src/output.cc
173
src/output.cc
@@ -40,7 +40,8 @@ static const char *const_readonly_array;
|
||||
/* The "const " qualifier, for the array type. */
|
||||
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 *
|
||||
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,
|
||||
const char *return_type, const char *struct_tag,
|
||||
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
|
||||
list is already sorted by hash value all we need to do is
|
||||
find the final item! */
|
||||
/* Recognizing duplicates. */
|
||||
|
||||
/* 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
|
||||
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;
|
||||
for (temp = _head; temp->rest(); temp = temp->rest())
|
||||
;
|
||||
|
||||
_min_hash_value = _head->first()->_hash_value;
|
||||
_max_hash_value = temp->first()->_hash_value;
|
||||
}
|
||||
|
||||
@@ -107,6 +141,8 @@ Output::compute_min_max ()
|
||||
int
|
||||
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;
|
||||
KeywordExt_List *temp;
|
||||
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
|
||||
{
|
||||
virtual void output_start ();
|
||||
virtual void output_item (const char *name, int value);
|
||||
virtual void output_end ();
|
||||
Output_Enum (const char *indent) : indentation (indent) {}
|
||||
Output_Enum (const char *indent) : _indentation (indent) {}
|
||||
virtual ~Output_Enum () {}
|
||||
private:
|
||||
const char *indentation;
|
||||
int pending_comma;
|
||||
const char *_indentation;
|
||||
bool _pending_comma;
|
||||
};
|
||||
|
||||
void Output_Enum::output_start ()
|
||||
{
|
||||
printf ("%senum\n"
|
||||
"%s {\n",
|
||||
indentation, indentation);
|
||||
pending_comma = 0;
|
||||
_indentation, _indentation);
|
||||
_pending_comma = false;
|
||||
}
|
||||
|
||||
void Output_Enum::output_item (const char *name, int value)
|
||||
{
|
||||
if (pending_comma)
|
||||
if (_pending_comma)
|
||||
printf (",\n");
|
||||
printf ("%s %s = %d", indentation, name, value);
|
||||
pending_comma = 1;
|
||||
printf ("%s %s = %d", _indentation, name, value);
|
||||
_pending_comma = true;
|
||||
}
|
||||
|
||||
void Output_Enum::output_end ()
|
||||
{
|
||||
if (pending_comma)
|
||||
if (_pending_comma)
|
||||
printf ("\n");
|
||||
printf ("%s };\n\n", indentation);
|
||||
printf ("%s };\n\n", _indentation);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
||||
static void
|
||||
output_const_type (const char *const_string, const char *type_string)
|
||||
{
|
||||
if (type_string[strlen(type_string)-1] == '*')
|
||||
/* For pointer types, put the 'const' after the type. */
|
||||
printf ("%s %s", type_string, const_string);
|
||||
else
|
||||
/* For scalar or struct types, put the 'const' before the type. */
|
||||
printf ("%s%s ", const_string, type_string);
|
||||
}
|
||||
|
||||
@@ -274,15 +312,15 @@ struct Output_Expr
|
||||
struct Output_Expr1 : public Output_Expr
|
||||
{
|
||||
virtual void output_expr () const;
|
||||
Output_Expr1 (const char *piece1) : p1 (piece1) {}
|
||||
Output_Expr1 (const char *piece1) : _p1 (piece1) {}
|
||||
virtual ~Output_Expr1 () {}
|
||||
private:
|
||||
const char *p1;
|
||||
const char *_p1;
|
||||
};
|
||||
|
||||
void Output_Expr1::output_expr () const
|
||||
{
|
||||
printf ("%s", p1);
|
||||
printf ("%s", _p1);
|
||||
}
|
||||
|
||||
#if 0 /* unused */
|
||||
@@ -294,16 +332,16 @@ struct Output_Expr2 : public Output_Expr
|
||||
{
|
||||
virtual void output_expr () const;
|
||||
Output_Expr2 (const char *piece1, const char *piece2)
|
||||
: p1 (piece1), p2 (piece2) {}
|
||||
: _p1 (piece1), _p2 (piece2) {}
|
||||
virtual ~Output_Expr2 () {}
|
||||
private:
|
||||
const char *p1;
|
||||
const char *p2;
|
||||
const char *_p1;
|
||||
const char *_p2;
|
||||
};
|
||||
|
||||
void Output_Expr2::output_expr () const
|
||||
{
|
||||
printf ("%s%s", p1, p2);
|
||||
printf ("%s%s", _p1, _p2);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -314,6 +352,11 @@ void Output_Expr2::output_expr () const
|
||||
|
||||
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,
|
||||
const Output_Expr& expr2) const = 0;
|
||||
Output_Compare () {}
|
||||
@@ -346,7 +389,7 @@ void Output_Compare_Strcmp::output_comparison (const Output_Expr& expr1,
|
||||
|
||||
/* This class outputs a comparison using strncmp.
|
||||
Note that the length of expr1 will be available through the local variable
|
||||
`len'. */
|
||||
'len'. */
|
||||
|
||||
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.
|
||||
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
|
||||
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
|
||||
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
|
||||
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. */
|
||||
if (option[CPLUSPLUS])
|
||||
printf ("inline ");
|
||||
@@ -452,16 +489,24 @@ Output::output_hash_function ()
|
||||
printf ("{\n");
|
||||
|
||||
/* First the asso_values array. */
|
||||
{
|
||||
printf (" static %s%s asso_values[] =\n"
|
||||
" {",
|
||||
const_readonly_array,
|
||||
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++)
|
||||
{
|
||||
if (count > 0)
|
||||
printf (",");
|
||||
if (!(count % max_column))
|
||||
if ((count % columns) == 0)
|
||||
printf ("\n ");
|
||||
printf ("%*d", field_width,
|
||||
_occurrences[count] ? _asso_values[count] : _max_hash_value + 1);
|
||||
@@ -469,16 +514,9 @@ Output::output_hash_function ()
|
||||
|
||||
printf ("\n"
|
||||
" };\n");
|
||||
}
|
||||
|
||||
/* Optimize special case of ``-k 1,$'' */
|
||||
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])
|
||||
if (option[ALLCHARS])
|
||||
{
|
||||
/* User wants *all* characters considered in hash. */
|
||||
printf (" register int hval = %s;\n\n"
|
||||
@@ -499,22 +537,33 @@ Output::output_hash_function ()
|
||||
}
|
||||
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());
|
||||
int key_pos;
|
||||
|
||||
/* Get first (also highest) key position. */
|
||||
/* Get the highest key position. */
|
||||
key_pos = iter.next ();
|
||||
|
||||
if (key_pos == Positions::LASTCHAR || key_pos <= _min_key_len)
|
||||
{
|
||||
/* We can perform additional optimizations here:
|
||||
Write it out as a single expression. Note that the values
|
||||
are added as `int's even though the asso_values array may
|
||||
contain `unsigned char's or `unsigned short's. */
|
||||
are added as 'int's even though the asso_values array may
|
||||
contain 'unsigned char's or 'unsigned short's. */
|
||||
|
||||
printf (" return %s",
|
||||
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; )
|
||||
{
|
||||
printf ("asso_values[%sstr[%d]]", char_to_index, key_pos - 1);
|
||||
@@ -526,6 +575,7 @@ Output::output_hash_function ()
|
||||
|
||||
if (key_pos == Positions::LASTCHAR)
|
||||
printf ("asso_values[%sstr[len - 1]]", char_to_index);
|
||||
}
|
||||
|
||||
printf (";\n");
|
||||
}
|
||||
@@ -576,16 +626,14 @@ Output::output_hash_function ()
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* 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
|
||||
Output::output_keylength_table ()
|
||||
{
|
||||
const int columns = 14;
|
||||
int index;
|
||||
int column;
|
||||
const char *indent = option[GLOBAL] ? "" : " ";
|
||||
KeywordExt_List *temp;
|
||||
const char * const indent = option[GLOBAL] ? "" : " ";
|
||||
|
||||
printf ("%sstatic %s%s lengthtable[] =\n%s {",
|
||||
indent, const_readonly_array,
|
||||
@@ -593,10 +641,16 @@ Output::output_keylength_table ()
|
||||
indent);
|
||||
|
||||
/* Generate an array of lengths, similar to output_keyword_table. */
|
||||
int index;
|
||||
int column;
|
||||
KeywordExt_List *temp;
|
||||
|
||||
column = 0;
|
||||
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]
|
||||
&& !(temp->first()->_duplicate_link
|
||||
|| (temp->rest() && temp->first()->_hash_value == temp->rest()->first()->_hash_value)))
|
||||
@@ -620,20 +674,19 @@ Output::output_keylength_table ()
|
||||
if ((column++ % columns) == 0)
|
||||
printf("\n%s ", indent);
|
||||
printf ("%3d", temp->first()->_allchars_length);
|
||||
index++;
|
||||
|
||||
/* Deal with links specially. */
|
||||
/* Deal with duplicates specially. */
|
||||
if (temp->first()->_duplicate_link) // implies option[DUP]
|
||||
for (KeywordExt *links = temp->first()->_duplicate_link; links; links = links->_duplicate_link)
|
||||
{
|
||||
++index;
|
||||
printf (",");
|
||||
if ((column++ % columns) == 0)
|
||||
printf("\n%s ", indent);
|
||||
printf ("%3d", links->_allchars_length);
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
printf ("\n%s };\n", indent);
|
||||
if (option[GLOBAL])
|
||||
@@ -737,7 +790,7 @@ Output::output_keyword_table ()
|
||||
|
||||
output_keyword_entry (temp->first(), indent);
|
||||
|
||||
/* Deal with links specially. */
|
||||
/* Deal with duplicates specially. */
|
||||
if (temp->first()->_duplicate_link) // implies option[DUP]
|
||||
for (KeywordExt *links = temp->first()->_duplicate_link; links; links = links->_duplicate_link)
|
||||
{
|
||||
|
||||
28
src/output.h
28
src/output.h
@@ -35,14 +35,40 @@ struct Output_Compare;
|
||||
class Output
|
||||
{
|
||||
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 ();
|
||||
private:
|
||||
|
||||
/* Computes the minimum and maximum hash values, and stores them
|
||||
in _min_hash_value and _max_hash_value. */
|
||||
void compute_min_max ();
|
||||
|
||||
/* Returns the number of different hash values. */
|
||||
int num_hash_values ();
|
||||
|
||||
/* Outputs the maximum and minimum hash values etc. */
|
||||
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 ();
|
||||
|
||||
/* 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_keyword_table ();
|
||||
void output_lookup_array ();
|
||||
void output_lookup_tables ();
|
||||
|
||||
Reference in New Issue
Block a user