mirror of
https://git.savannah.gnu.org/git/gperf.git
synced 2025-12-02 13:09:22 +00:00
Comments.
This commit is contained in:
327
src/output.cc
327
src/output.cc
@@ -31,16 +31,17 @@
|
|||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
/* The "const " qualifier. */
|
/* The "const " qualifier. */
|
||||||
static const char *const_always;
|
static const char *const_always;
|
||||||
|
|
||||||
/* The "const " qualifier, for read-only arrays. */
|
/* The "const " qualifier, for read-only arrays. */
|
||||||
static const char *const_readonly_array;
|
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)
|
||||||
@@ -51,7 +52,7 @@ smallest_integral_type (int n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the smallest signed C type capable of holding integers
|
/* Returns the smallest signed C type capable of holding integers
|
||||||
from MIN to MAX. */
|
from MIN to MAX. */
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
smallest_integral_type (int min, int max)
|
smallest_integral_type (int min, int max)
|
||||||
@@ -62,12 +63,29 @@ smallest_integral_type (int min, int max)
|
|||||||
return "int";
|
return "int";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A cast from `char' to a valid array index. */
|
/* A cast from `char' to a valid array index. */
|
||||||
static const char *char_to_index;
|
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,28 +103,46 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/* Returns the number of different hash values. */
|
/* Returns the number of different hash values. */
|
||||||
|
|
||||||
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;
|
||||||
@@ -124,7 +160,7 @@ Output::num_hash_values ()
|
|||||||
|
|
||||||
/* -------------------- Output_Constants and subclasses -------------------- */
|
/* -------------------- Output_Constants and subclasses -------------------- */
|
||||||
|
|
||||||
/* This class outputs an enumeration defining some constants. */
|
/* This class outputs an enumeration defining some constants. */
|
||||||
|
|
||||||
struct Output_Constants
|
struct Output_Constants
|
||||||
{
|
{
|
||||||
@@ -135,7 +171,7 @@ struct Output_Constants
|
|||||||
virtual ~Output_Constants () {}
|
virtual ~Output_Constants () {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This class outputs an enumeration in #define syntax. */
|
/* This class outputs an enumeration in #define syntax. */
|
||||||
|
|
||||||
struct Output_Defines : public Output_Constants
|
struct Output_Defines : public Output_Constants
|
||||||
{
|
{
|
||||||
@@ -160,44 +196,44 @@ 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. */
|
||||||
|
|
||||||
void
|
void
|
||||||
Output::output_constants (struct Output_Constants& style)
|
Output::output_constants (struct Output_Constants& style)
|
||||||
@@ -214,7 +250,7 @@ Output::output_constants (struct Output_Constants& style)
|
|||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/* Outputs a keyword, as a string: enclosed in double quotes, escaping
|
/* Outputs a keyword, as a string: enclosed in double quotes, escaping
|
||||||
backslashes, double quote and unprintable characters. */
|
backslashes, double quote and unprintable characters. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
output_string (const char *key, int len)
|
output_string (const char *key, int len)
|
||||||
@@ -234,7 +270,7 @@ output_string (const char *key, int len)
|
|||||||
/* Use octal escapes, not hexadecimal escapes, because some old
|
/* Use octal escapes, not hexadecimal escapes, because some old
|
||||||
C compilers didn't understand hexadecimal escapes, and because
|
C compilers didn't understand hexadecimal escapes, and because
|
||||||
hexadecimal escapes are not limited to 2 digits, thus needing
|
hexadecimal escapes are not limited to 2 digits, thus needing
|
||||||
special care if the following character happens to be a digit. */
|
special care if the following character happens to be a digit. */
|
||||||
putchar ('\\');
|
putchar ('\\');
|
||||||
putchar ('0' + ((c >> 6) & 7));
|
putchar ('0' + ((c >> 6) & 7));
|
||||||
putchar ('0' + ((c >> 3) & 7));
|
putchar ('0' + ((c >> 3) & 7));
|
||||||
@@ -246,21 +282,23 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------- Output_Expr and subclasses ----------------------- */
|
/* ----------------------- Output_Expr and subclasses ----------------------- */
|
||||||
|
|
||||||
/* This class outputs a general expression. */
|
/* This class outputs a general expression. */
|
||||||
|
|
||||||
struct Output_Expr
|
struct Output_Expr
|
||||||
{
|
{
|
||||||
@@ -269,58 +307,63 @@ struct Output_Expr
|
|||||||
virtual ~Output_Expr () {}
|
virtual ~Output_Expr () {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This class outputs an expression formed by a single string. */
|
/* This class outputs an expression formed by a single string. */
|
||||||
|
|
||||||
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 */
|
||||||
|
|
||||||
/* This class outputs an expression formed by the concatenation of two
|
/* This class outputs an expression formed by the concatenation of two
|
||||||
strings. */
|
strings. */
|
||||||
|
|
||||||
struct Output_Expr2 : public Output_Expr
|
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
|
||||||
|
|
||||||
/* --------------------- Output_Compare and subclasses --------------------- */
|
/* --------------------- Output_Compare and subclasses --------------------- */
|
||||||
|
|
||||||
/* This class outputs a comparison expression. */
|
/* This class outputs a comparison expression. */
|
||||||
|
|
||||||
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 () {}
|
||||||
virtual ~Output_Compare () {}
|
virtual ~Output_Compare () {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This class outputs a comparison using strcmp. */
|
/* This class outputs a comparison using strcmp. */
|
||||||
|
|
||||||
struct Output_Compare_Strcmp : public Output_Compare
|
struct Output_Compare_Strcmp : public 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,9 +416,9 @@ 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. */
|
||||||
|
|
||||||
struct Output_Compare_Memcmp : public Output_Compare
|
struct Output_Compare_Memcmp : public Output_Compare
|
||||||
{
|
{
|
||||||
@@ -402,20 +445,14 @@ 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;
|
/* Output the function's head. */
|
||||||
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])
|
if (option[CPLUSPLUS])
|
||||||
printf ("inline ");
|
printf ("inline ");
|
||||||
else if (option[KRC] | option[C] | option[ANSIC])
|
else if (option[KRC] | option[C] | option[ANSIC])
|
||||||
@@ -446,39 +483,40 @@ Output::output_hash_function ()
|
|||||||
"");
|
"");
|
||||||
|
|
||||||
/* Note that when the hash function is called, it has already been verified
|
/* Note that when the hash function is called, it has already been verified
|
||||||
that min_key_len <= len <= max_key_len. */
|
that min_key_len <= len <= max_key_len. */
|
||||||
|
|
||||||
/* Output the function's body. */
|
/* Output the function's body. */
|
||||||
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,
|
" {",
|
||||||
smallest_integral_type (_max_hash_value + 1));
|
const_readonly_array,
|
||||||
|
smallest_integral_type (_max_hash_value + 1));
|
||||||
|
|
||||||
for (int count = 0; count < _alpha_size; count++)
|
const int columns = 10;
|
||||||
{
|
|
||||||
if (count > 0)
|
|
||||||
printf (",");
|
|
||||||
if (!(count % max_column))
|
|
||||||
printf ("\n ");
|
|
||||||
printf ("%*d", field_width,
|
|
||||||
_occurrences[count] ? _asso_values[count] : _max_hash_value + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf ("\n"
|
/* Calculate maximum number of digits required for MAX_HASH_VALUE. */
|
||||||
" };\n");
|
int field_width = 2;
|
||||||
|
for (int trunc = _max_hash_value; (trunc /= 10) > 0;)
|
||||||
|
field_width++;
|
||||||
|
|
||||||
/* Optimize special case of ``-k 1,$'' */
|
for (int count = 0; count < _alpha_size; count++)
|
||||||
if (!option[ALLCHARS]
|
{
|
||||||
&& option.get_key_positions().get_size() == 2
|
if (count > 0)
|
||||||
&& option.get_key_positions()[0] == 1
|
printf (",");
|
||||||
&& option.get_key_positions()[1] == Positions::LASTCHAR)
|
if ((count % columns) == 0)
|
||||||
printf (" return %sasso_values[%sstr[len - 1]] + asso_values[%sstr[0]];\n",
|
printf ("\n ");
|
||||||
option[NOLENGTH] ? "" : "len + ",
|
printf ("%*d", field_width,
|
||||||
char_to_index, char_to_index);
|
_occurrences[count] ? _asso_values[count] : _max_hash_value + 1);
|
||||||
else if (option[ALLCHARS])
|
}
|
||||||
|
|
||||||
|
printf ("\n"
|
||||||
|
" };\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
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,39 +537,51 @@ 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 + ");
|
||||||
|
|
||||||
for (; key_pos != Positions::LASTCHAR; )
|
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
|
||||||
{
|
{
|
||||||
printf ("asso_values[%sstr[%d]]", char_to_index, key_pos - 1);
|
for (; key_pos != Positions::LASTCHAR; )
|
||||||
if ((key_pos = iter.next ()) != PositionIterator::EOS)
|
{
|
||||||
printf (" + ");
|
printf ("asso_values[%sstr[%d]]", char_to_index, key_pos - 1);
|
||||||
else
|
if ((key_pos = iter.next ()) != PositionIterator::EOS)
|
||||||
break;
|
printf (" + ");
|
||||||
}
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
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");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* We've got to use the correct, but brute force, technique. */
|
/* We've got to use the correct, but brute force, technique. */
|
||||||
printf (" register int hval = %s;\n\n"
|
printf (" register int hval = %s;\n\n"
|
||||||
" switch (%s)\n"
|
" switch (%s)\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
@@ -576,27 +626,31 @@ 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,
|
||||||
smallest_integral_type (_max_key_len),
|
smallest_integral_type (_max_key_len),
|
||||||
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)))
|
||||||
@@ -604,7 +658,7 @@ Output::output_keylength_table ()
|
|||||||
|
|
||||||
if (index < temp->first()->_hash_value && !option[SWITCH] && !option[DUP])
|
if (index < temp->first()->_hash_value && !option[SWITCH] && !option[DUP])
|
||||||
{
|
{
|
||||||
/* Some blank entries. */
|
/* Some blank entries. */
|
||||||
for ( ; index < temp->first()->_hash_value; index++)
|
for ( ; index < temp->first()->_hash_value; index++)
|
||||||
{
|
{
|
||||||
if (index > 0)
|
if (index > 0)
|
||||||
@@ -620,19 +674,18 @@ 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);
|
||||||
@@ -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 ()
|
||||||
@@ -713,7 +766,7 @@ Output::output_keyword_table ()
|
|||||||
option.get_wordlist_name (),
|
option.get_wordlist_name (),
|
||||||
indent);
|
indent);
|
||||||
|
|
||||||
/* Generate an array of reserved words at appropriate locations. */
|
/* Generate an array of reserved words at appropriate locations. */
|
||||||
|
|
||||||
for (temp = _head, index = 0; temp; temp = temp->rest())
|
for (temp = _head, index = 0; temp; temp = temp->rest())
|
||||||
{
|
{
|
||||||
@@ -727,7 +780,7 @@ Output::output_keyword_table ()
|
|||||||
|
|
||||||
if (index < temp->first()->_hash_value && !option[SWITCH] && !option[DUP])
|
if (index < temp->first()->_hash_value && !option[SWITCH] && !option[DUP])
|
||||||
{
|
{
|
||||||
/* Some blank entries. */
|
/* Some blank entries. */
|
||||||
output_keyword_blank_entries (temp->first()->_hash_value - index, indent);
|
output_keyword_blank_entries (temp->first()->_hash_value - index, indent);
|
||||||
printf (",\n");
|
printf (",\n");
|
||||||
index = temp->first()->_hash_value;
|
index = temp->first()->_hash_value;
|
||||||
@@ -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)
|
||||||
{
|
{
|
||||||
@@ -757,7 +810,7 @@ Output::output_keyword_table ()
|
|||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/* Generates the large, sparse table that maps hash values into
|
/* Generates the large, sparse table that maps hash values into
|
||||||
the smaller, contiguous range of the keyword table. */
|
the smaller, contiguous range of the keyword table. */
|
||||||
|
|
||||||
void
|
void
|
||||||
Output::output_lookup_array ()
|
Output::output_lookup_array ()
|
||||||
@@ -767,12 +820,12 @@ Output::output_lookup_array ()
|
|||||||
const int DEFAULT_VALUE = -1;
|
const int DEFAULT_VALUE = -1;
|
||||||
|
|
||||||
/* Because of the way output_keyword_table works, every duplicate set is
|
/* Because of the way output_keyword_table works, every duplicate set is
|
||||||
stored contiguously in the wordlist array. */
|
stored contiguously in the wordlist array. */
|
||||||
struct duplicate_entry
|
struct duplicate_entry
|
||||||
{
|
{
|
||||||
int hash_value; /* Hash value for this particular duplicate set. */
|
int hash_value; /* Hash value for this particular duplicate set. */
|
||||||
int index; /* Index into the main keyword storage array. */
|
int index; /* Index into the main keyword storage array. */
|
||||||
int count; /* Number of consecutive duplicates at this index. */
|
int count; /* Number of consecutive duplicates at this index. */
|
||||||
};
|
};
|
||||||
|
|
||||||
duplicate_entry *duplicates = new duplicate_entry[_total_duplicates];
|
duplicate_entry *duplicates = new duplicate_entry[_total_duplicates];
|
||||||
@@ -784,7 +837,7 @@ Output::output_lookup_array ()
|
|||||||
while (lookup_ptr > lookup_array)
|
while (lookup_ptr > lookup_array)
|
||||||
*--lookup_ptr = DEFAULT_VALUE;
|
*--lookup_ptr = DEFAULT_VALUE;
|
||||||
|
|
||||||
/* Now dup_ptr = &duplicates[0] and lookup_ptr = &lookup_array[0]. */
|
/* Now dup_ptr = &duplicates[0] and lookup_ptr = &lookup_array[0]. */
|
||||||
|
|
||||||
for (KeywordExt_List *temp = _head; temp; temp = temp->rest())
|
for (KeywordExt_List *temp = _head; temp; temp = temp->rest())
|
||||||
{
|
{
|
||||||
@@ -796,7 +849,7 @@ Output::output_lookup_array ()
|
|||||||
if (temp->first()->_duplicate_link
|
if (temp->first()->_duplicate_link
|
||||||
|| (temp->rest() && hash_value == temp->rest()->first()->_hash_value))
|
|| (temp->rest() && hash_value == temp->rest()->first()->_hash_value))
|
||||||
{
|
{
|
||||||
/* Start a duplicate entry. */
|
/* Start a duplicate entry. */
|
||||||
dup_ptr->hash_value = hash_value;
|
dup_ptr->hash_value = hash_value;
|
||||||
dup_ptr->index = temp->first()->_final_index;
|
dup_ptr->index = temp->first()->_final_index;
|
||||||
dup_ptr->count = 1;
|
dup_ptr->count = 1;
|
||||||
@@ -839,30 +892,30 @@ Output::output_lookup_array ()
|
|||||||
|
|
||||||
int i;
|
int i;
|
||||||
/* Start searching for available space towards the right part
|
/* Start searching for available space towards the right part
|
||||||
of the lookup array. */
|
of the lookup array. */
|
||||||
for (i = dup_ptr->hash_value; i < lookup_array_size-1; i++)
|
for (i = dup_ptr->hash_value; i < lookup_array_size-1; i++)
|
||||||
if (lookup_array[i] == DEFAULT_VALUE
|
if (lookup_array[i] == DEFAULT_VALUE
|
||||||
&& lookup_array[i + 1] == DEFAULT_VALUE)
|
&& lookup_array[i + 1] == DEFAULT_VALUE)
|
||||||
goto found_i;
|
goto found_i;
|
||||||
/* If we didn't find it to the right look to the left instead... */
|
/* If we didn't find it to the right look to the left instead... */
|
||||||
for (i = dup_ptr->hash_value-1; i >= 0; i--)
|
for (i = dup_ptr->hash_value-1; i >= 0; i--)
|
||||||
if (lookup_array[i] == DEFAULT_VALUE
|
if (lookup_array[i] == DEFAULT_VALUE
|
||||||
&& lookup_array[i + 1] == DEFAULT_VALUE)
|
&& lookup_array[i + 1] == DEFAULT_VALUE)
|
||||||
goto found_i;
|
goto found_i;
|
||||||
/* Append to the end of lookup_array. */
|
/* Append to the end of lookup_array. */
|
||||||
i = lookup_array_size;
|
i = lookup_array_size;
|
||||||
lookup_array_size += 2;
|
lookup_array_size += 2;
|
||||||
found_i:
|
found_i:
|
||||||
/* Put in an indirection from dup_ptr->_hash_value to i.
|
/* Put in an indirection from dup_ptr->_hash_value to i.
|
||||||
At i and i+1 store dup_ptr->_final_index and dup_ptr->count. */
|
At i and i+1 store dup_ptr->_final_index and dup_ptr->count. */
|
||||||
assert (lookup_array[dup_ptr->hash_value] == dup_ptr->index);
|
assert (lookup_array[dup_ptr->hash_value] == dup_ptr->index);
|
||||||
lookup_array[dup_ptr->hash_value] = - 1 - _total_keys - i;
|
lookup_array[dup_ptr->hash_value] = - 1 - _total_keys - i;
|
||||||
lookup_array[i] = - _total_keys + dup_ptr->index;
|
lookup_array[i] = - _total_keys + dup_ptr->index;
|
||||||
lookup_array[i + 1] = - dup_ptr->count;
|
lookup_array[i + 1] = - dup_ptr->count;
|
||||||
/* All these three values are <= -2, distinct from DEFAULT_VALUE. */
|
/* All these three values are <= -2, distinct from DEFAULT_VALUE. */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The values of the lookup array are now known. */
|
/* The values of the lookup array are now known. */
|
||||||
|
|
||||||
int min = INT_MAX;
|
int min = INT_MAX;
|
||||||
int max = INT_MIN;
|
int max = INT_MIN;
|
||||||
@@ -883,7 +936,7 @@ Output::output_lookup_array ()
|
|||||||
indent);
|
indent);
|
||||||
|
|
||||||
int field_width;
|
int field_width;
|
||||||
/* Calculate maximum number of digits required for MIN..MAX. */
|
/* Calculate maximum number of digits required for MIN..MAX. */
|
||||||
{
|
{
|
||||||
field_width = 2;
|
field_width = 2;
|
||||||
for (int trunc = max; (trunc /= 10) > 0;)
|
for (int trunc = max; (trunc /= 10) > 0;)
|
||||||
@@ -920,14 +973,14 @@ Output::output_lookup_array ()
|
|||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/* Generate all the tables needed for the lookup function. */
|
/* Generate all the tables needed for the lookup function. */
|
||||||
|
|
||||||
void
|
void
|
||||||
Output::output_lookup_tables ()
|
Output::output_lookup_tables ()
|
||||||
{
|
{
|
||||||
if (option[SWITCH])
|
if (option[SWITCH])
|
||||||
{
|
{
|
||||||
/* Use the switch in place of lookup table. */
|
/* Use the switch in place of lookup table. */
|
||||||
if (option[LENTABLE] && (option[DUP] && _total_duplicates > 0))
|
if (option[LENTABLE] && (option[DUP] && _total_duplicates > 0))
|
||||||
output_keylength_table ();
|
output_keylength_table ();
|
||||||
if (option[TYPE] || (option[DUP] && _total_duplicates > 0))
|
if (option[TYPE] || (option[DUP] && _total_duplicates > 0))
|
||||||
@@ -935,7 +988,7 @@ Output::output_lookup_tables ()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Use the lookup table, in place of switch. */
|
/* Use the lookup table, in place of switch. */
|
||||||
if (option[LENTABLE])
|
if (option[LENTABLE])
|
||||||
output_keylength_table ();
|
output_keylength_table ();
|
||||||
output_keyword_table ();
|
output_keyword_table ();
|
||||||
@@ -945,7 +998,7 @@ Output::output_lookup_tables ()
|
|||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/* Output a single switch case (including duplicates). Advance list. */
|
/* Output a single switch case (including duplicates). Advance list. */
|
||||||
|
|
||||||
static KeywordExt_List *
|
static KeywordExt_List *
|
||||||
output_switch_case (KeywordExt_List *list, int indent, int *jumps_away)
|
output_switch_case (KeywordExt_List *list, int indent, int *jumps_away)
|
||||||
@@ -1015,7 +1068,7 @@ output_switch_case (KeywordExt_List *list, int indent, int *jumps_away)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Output a total of size cases, grouped into num_switches switch statements,
|
/* Output a total of size cases, grouped into num_switches switch statements,
|
||||||
where 0 < num_switches <= size. */
|
where 0 < num_switches <= size. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
output_switches (KeywordExt_List *list, int num_switches, int size, int min_hash_value, int max_hash_value, int indent)
|
output_switches (KeywordExt_List *list, int num_switches, int size, int min_hash_value, int max_hash_value, int indent)
|
||||||
@@ -1058,7 +1111,7 @@ output_switches (KeywordExt_List *list, int num_switches, int size, int min_hash
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Output a single switch. */
|
/* Output a single switch. */
|
||||||
int lowest_case_value = list->first()->_hash_value;
|
int lowest_case_value = list->first()->_hash_value;
|
||||||
if (size == 1)
|
if (size == 1)
|
||||||
{
|
{
|
||||||
@@ -1102,7 +1155,7 @@ output_switches (KeywordExt_List *list, int num_switches, int size, int min_hash
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generates C code to perform the keyword lookup. */
|
/* Generates C code to perform the keyword lookup. */
|
||||||
|
|
||||||
void
|
void
|
||||||
Output::output_lookup_function_body (const Output_Compare& comparison)
|
Output::output_lookup_function_body (const Output_Compare& comparison)
|
||||||
@@ -1349,12 +1402,12 @@ Output::output_lookup_function_body (const Output_Compare& comparison)
|
|||||||
" return 0;\n");
|
" return 0;\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generates C code for the lookup function. */
|
/* Generates C code for the lookup function. */
|
||||||
|
|
||||||
void
|
void
|
||||||
Output::output_lookup_function ()
|
Output::output_lookup_function ()
|
||||||
{
|
{
|
||||||
/* Output the function's head. */
|
/* Output the function's head. */
|
||||||
if (option[KRC] | option[C] | option[ANSIC])
|
if (option[KRC] | option[C] | option[ANSIC])
|
||||||
printf ("#ifdef __GNUC__\n"
|
printf ("#ifdef __GNUC__\n"
|
||||||
"__inline\n"
|
"__inline\n"
|
||||||
@@ -1377,7 +1430,7 @@ Output::output_lookup_function ()
|
|||||||
"(register const char *str, register unsigned int len)\n" :
|
"(register const char *str, register unsigned int len)\n" :
|
||||||
"");
|
"");
|
||||||
|
|
||||||
/* Output the function's body. */
|
/* Output the function's body. */
|
||||||
printf ("{\n");
|
printf ("{\n");
|
||||||
|
|
||||||
if (option[ENUM] && !option[GLOBAL])
|
if (option[ENUM] && !option[GLOBAL])
|
||||||
@@ -1405,7 +1458,7 @@ Output::output_lookup_function ()
|
|||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/* Generates the hash function and the key word recognizer function
|
/* Generates the hash function and the key word recognizer function
|
||||||
based upon the user's Options. */
|
based upon the user's Options. */
|
||||||
|
|
||||||
void
|
void
|
||||||
Output::output ()
|
Output::output ()
|
||||||
|
|||||||
28
src/output.h
28
src/output.h
@@ -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 ();
|
||||||
|
|||||||
Reference in New Issue
Block a user