| Index: gperf/src/gperf/3.0.1/gperf-3.0.1-src/src/output.cc
|
| ===================================================================
|
| --- gperf/src/gperf/3.0.1/gperf-3.0.1-src/src/output.cc (revision 0)
|
| +++ gperf/src/gperf/3.0.1/gperf-3.0.1-src/src/output.cc (revision 0)
|
| @@ -0,0 +1,2082 @@
|
| +/* Output routines.
|
| + Copyright (C) 1989-1998, 2000, 2002-2003 Free Software Foundation, Inc.
|
| + Written by Douglas C. Schmidt <schmidt@ics.uci.edu>
|
| + and Bruno Haible <bruno@clisp.org>.
|
| +
|
| + This file is part of GNU GPERF.
|
| +
|
| + GNU GPERF is free software; you can redistribute it and/or modify
|
| + it under the terms of the GNU General Public License as published by
|
| + the Free Software Foundation; either version 2, or (at your option)
|
| + any later version.
|
| +
|
| + GNU GPERF is distributed in the hope that it will be useful,
|
| + but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| + GNU General Public License for more details.
|
| +
|
| + You should have received a copy of the GNU General Public License
|
| + along with this program; see the file COPYING.
|
| + If not, write to the Free Software Foundation, Inc.,
|
| + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
| +
|
| +/* Specification. */
|
| +#include "output.h"
|
| +
|
| +#include <stdio.h>
|
| +#include <string.h> /* declares strncpy(), strchr() */
|
| +#include <ctype.h> /* declares isprint() */
|
| +#include <assert.h> /* defines assert() */
|
| +#include <limits.h> /* defines SCHAR_MAX etc. */
|
| +#include "options.h"
|
| +#include "version.h"
|
| +
|
| +/* The "const " qualifier. */
|
| +static const char *const_always;
|
| +
|
| +/* The "const " qualifier, for read-only arrays. */
|
| +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. */
|
| +
|
| +static const char *
|
| +smallest_integral_type (int n)
|
| +{
|
| + if (n <= UCHAR_MAX) return "unsigned char";
|
| + if (n <= USHRT_MAX) return "unsigned short";
|
| + return "unsigned int";
|
| +}
|
| +
|
| +/* Returns the smallest signed C type capable of holding integers
|
| + from MIN to MAX. */
|
| +
|
| +static const char *
|
| +smallest_integral_type (int min, int max)
|
| +{
|
| + if (option[ANSIC] | option[CPLUSPLUS])
|
| + if (min >= SCHAR_MIN && max <= SCHAR_MAX) return "signed char";
|
| + if (min >= SHRT_MIN && max <= SHRT_MAX) return "short";
|
| + return "int";
|
| +}
|
| +
|
| +/* ------------------------------------------------------------------------- */
|
| +
|
| +/* 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. Only one representative per
|
| + duplicate equivalence class remains on the linear keyword list.
|
| + - Accidental duplicates, i.e. keywords for which the _asso_values[] search
|
| + couldn't achieve different hash values, cannot occur on the linear
|
| + keyword list. Search::optimize would catch this mistake.
|
| + */
|
| +Output::Output (KeywordExt_List *head, const char *struct_decl,
|
| + unsigned int struct_decl_lineno, const char *return_type,
|
| + const char *struct_tag, const char *verbatim_declarations,
|
| + const char *verbatim_declarations_end,
|
| + unsigned int verbatim_declarations_lineno,
|
| + const char *verbatim_code, const char *verbatim_code_end,
|
| + unsigned int verbatim_code_lineno, bool charset_dependent,
|
| + int total_keys, int max_key_len, int min_key_len,
|
| + const Positions& positions, const unsigned int *alpha_inc,
|
| + int total_duplicates, unsigned int alpha_size,
|
| + const int *asso_values)
|
| + : _head (head), _struct_decl (struct_decl),
|
| + _struct_decl_lineno (struct_decl_lineno), _return_type (return_type),
|
| + _struct_tag (struct_tag),
|
| + _verbatim_declarations (verbatim_declarations),
|
| + _verbatim_declarations_end (verbatim_declarations_end),
|
| + _verbatim_declarations_lineno (verbatim_declarations_lineno),
|
| + _verbatim_code (verbatim_code),
|
| + _verbatim_code_end (verbatim_code_end),
|
| + _verbatim_code_lineno (verbatim_code_lineno),
|
| + _charset_dependent (charset_dependent),
|
| + _total_keys (total_keys),
|
| + _max_key_len (max_key_len), _min_key_len (min_key_len),
|
| + _key_positions (positions), _alpha_inc (alpha_inc),
|
| + _total_duplicates (total_duplicates), _alpha_size (alpha_size),
|
| + _asso_values (asso_values)
|
| +{
|
| +}
|
| +
|
| +/* ------------------------------------------------------------------------- */
|
| +
|
| +/* 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())
|
| + ;
|
| + _max_hash_value = temp->first()->_hash_value;
|
| +}
|
| +
|
| +/* ------------------------------------------------------------------------- */
|
| +
|
| +/* Returns the number of different hash values. */
|
| +
|
| +int
|
| +Output::num_hash_values () const
|
| +{
|
| + /* Since the list is already sorted by hash value and doesn't contain
|
| + duplicates, we can simply count the number of keywords on the list. */
|
| + int count = 0;
|
| + for (KeywordExt_List *temp = _head; temp; temp = temp->rest())
|
| + count++;
|
| + return count;
|
| +}
|
| +
|
| +/* -------------------- Output_Constants and subclasses -------------------- */
|
| +
|
| +/* This class outputs an enumeration defining some constants. */
|
| +
|
| +struct Output_Constants
|
| +{
|
| + virtual void output_start () = 0;
|
| + virtual void output_item (const char *name, int value) = 0;
|
| + virtual void output_end () = 0;
|
| + Output_Constants () {}
|
| + virtual ~Output_Constants () {}
|
| +};
|
| +
|
| +/* This class outputs an enumeration in #define syntax. */
|
| +
|
| +struct Output_Defines : public Output_Constants
|
| +{
|
| + virtual void output_start ();
|
| + virtual void output_item (const char *name, int value);
|
| + virtual void output_end ();
|
| + Output_Defines () {}
|
| + virtual ~Output_Defines () {}
|
| +};
|
| +
|
| +void Output_Defines::output_start ()
|
| +{
|
| + printf ("\n");
|
| +}
|
| +
|
| +void Output_Defines::output_item (const char *name, int value)
|
| +{
|
| + printf ("#define %s %d\n", name, value);
|
| +}
|
| +
|
| +void Output_Defines::output_end ()
|
| +{
|
| +}
|
| +
|
| +/* 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) {}
|
| + virtual ~Output_Enum () {}
|
| +private:
|
| + const char *_indentation;
|
| + bool _pending_comma;
|
| +};
|
| +
|
| +void Output_Enum::output_start ()
|
| +{
|
| + printf ("%senum\n"
|
| + "%s {\n",
|
| + _indentation, _indentation);
|
| + _pending_comma = false;
|
| +}
|
| +
|
| +void Output_Enum::output_item (const char *name, int value)
|
| +{
|
| + if (_pending_comma)
|
| + printf (",\n");
|
| + printf ("%s %s = %d", _indentation, name, value);
|
| + _pending_comma = true;
|
| +}
|
| +
|
| +void Output_Enum::output_end ()
|
| +{
|
| + if (_pending_comma)
|
| + printf ("\n");
|
| + printf ("%s };\n\n", _indentation);
|
| +}
|
| +
|
| +/* Outputs the maximum and minimum hash values etc. */
|
| +
|
| +void
|
| +Output::output_constants (struct Output_Constants& style) const
|
| +{
|
| + style.output_start ();
|
| + style.output_item ("TOTAL_KEYWORDS", _total_keys);
|
| + style.output_item ("MIN_WORD_LENGTH", _min_key_len);
|
| + style.output_item ("MAX_WORD_LENGTH", _max_key_len);
|
| + style.output_item ("MIN_HASH_VALUE", _min_hash_value);
|
| + style.output_item ("MAX_HASH_VALUE", _max_hash_value);
|
| + style.output_end ();
|
| +}
|
| +
|
| +/* ------------------------------------------------------------------------- */
|
| +
|
| +/* We use a downcase table because when called repeatedly, the code
|
| + gperf_downcase[c]
|
| + is faster than
|
| + if (c >= 'A' && c <= 'Z')
|
| + c += 'a' - 'A';
|
| + */
|
| +#define USE_DOWNCASE_TABLE 1
|
| +
|
| +#if USE_DOWNCASE_TABLE
|
| +
|
| +/* Output gperf's ASCII-downcase table. */
|
| +
|
| +static void
|
| +output_upperlower_table ()
|
| +{
|
| + unsigned int c;
|
| +
|
| + printf ("#ifndef GPERF_DOWNCASE\n"
|
| + "#define GPERF_DOWNCASE 1\n"
|
| + "static unsigned char gperf_downcase[256] =\n"
|
| + " {");
|
| + for (c = 0; c < 256; c++)
|
| + {
|
| + if ((c % 15) == 0)
|
| + printf ("\n ");
|
| + printf (" %3d", c >= 'A' && c <= 'Z' ? c + 'a' - 'A' : c);
|
| + if (c < 255)
|
| + printf (",");
|
| + }
|
| + printf ("\n"
|
| + " };\n"
|
| + "#endif\n\n");
|
| +}
|
| +
|
| +#endif
|
| +
|
| +/* Output gperf's ASCII-case insensitive strcmp replacement. */
|
| +
|
| +static void
|
| +output_upperlower_strcmp ()
|
| +{
|
| + printf ("#ifndef GPERF_CASE_STRCMP\n"
|
| + "#define GPERF_CASE_STRCMP 1\n"
|
| + "static int\n"
|
| + "gperf_case_strcmp ");
|
| + printf (option[KRC] ?
|
| + "(s1, s2)\n"
|
| + " register char *s1;\n"
|
| + " register char *s2;\n" :
|
| + option[C] ?
|
| + "(s1, s2)\n"
|
| + " register const char *s1;\n"
|
| + " register const char *s2;\n" :
|
| + option[ANSIC] | option[CPLUSPLUS] ?
|
| + "(register const char *s1, register const char *s2)\n" :
|
| + "");
|
| + #if USE_DOWNCASE_TABLE
|
| + printf ("{\n"
|
| + " for (;;)\n"
|
| + " {\n"
|
| + " unsigned char c1 = gperf_downcase[(unsigned char)*s1++];\n"
|
| + " unsigned char c2 = gperf_downcase[(unsigned char)*s2++];\n"
|
| + " if (c1 != 0 && c1 == c2)\n"
|
| + " continue;\n"
|
| + " return (int)c1 - (int)c2;\n"
|
| + " }\n"
|
| + "}\n");
|
| + #else
|
| + printf ("{\n"
|
| + " for (;;)\n"
|
| + " {\n"
|
| + " unsigned char c1 = *s1++;\n"
|
| + " unsigned char c2 = *s2++;\n"
|
| + " if (c1 >= 'A' && c1 <= 'Z')\n"
|
| + " c1 += 'a' - 'A';\n"
|
| + " if (c2 >= 'A' && c2 <= 'Z')\n"
|
| + " c2 += 'a' - 'A';\n"
|
| + " if (c1 != 0 && c1 == c2)\n"
|
| + " continue;\n"
|
| + " return (int)c1 - (int)c2;\n"
|
| + " }\n"
|
| + "}\n");
|
| + #endif
|
| + printf ("#endif\n\n");
|
| +}
|
| +
|
| +/* Output gperf's ASCII-case insensitive strncmp replacement. */
|
| +
|
| +static void
|
| +output_upperlower_strncmp ()
|
| +{
|
| + printf ("#ifndef GPERF_CASE_STRNCMP\n"
|
| + "#define GPERF_CASE_STRNCMP 1\n"
|
| + "static int\n"
|
| + "gperf_case_strncmp ");
|
| + printf (option[KRC] ?
|
| + "(s1, s2, n)\n"
|
| + " register char *s1;\n"
|
| + " register char *s2;\n"
|
| + " register unsigned int n;\n" :
|
| + option[C] ?
|
| + "(s1, s2, n)\n"
|
| + " register const char *s1;\n"
|
| + " register const char *s2;\n"
|
| + " register unsigned int n;\n" :
|
| + option[ANSIC] | option[CPLUSPLUS] ?
|
| + "(register const char *s1, register const char *s2, register unsigned int n)\n" :
|
| + "");
|
| + #if USE_DOWNCASE_TABLE
|
| + printf ("{\n"
|
| + " for (; n > 0;)\n"
|
| + " {\n"
|
| + " unsigned char c1 = gperf_downcase[(unsigned char)*s1++];\n"
|
| + " unsigned char c2 = gperf_downcase[(unsigned char)*s2++];\n"
|
| + " if (c1 != 0 && c1 == c2)\n"
|
| + " {\n"
|
| + " n--;\n"
|
| + " continue;\n"
|
| + " }\n"
|
| + " return (int)c1 - (int)c2;\n"
|
| + " }\n"
|
| + " return 0;\n"
|
| + "}\n");
|
| + #else
|
| + printf ("{\n"
|
| + " for (; n > 0;)\n"
|
| + " {\n"
|
| + " unsigned char c1 = *s1++;\n"
|
| + " unsigned char c2 = *s2++;\n"
|
| + " if (c1 >= 'A' && c1 <= 'Z')\n"
|
| + " c1 += 'a' - 'A';\n"
|
| + " if (c2 >= 'A' && c2 <= 'Z')\n"
|
| + " c2 += 'a' - 'A';\n"
|
| + " if (c1 != 0 && c1 == c2)\n"
|
| + " {\n"
|
| + " n--;\n"
|
| + " continue;\n"
|
| + " }\n"
|
| + " return (int)c1 - (int)c2;\n"
|
| + " }\n"
|
| + " return 0;\n"
|
| + "}\n");
|
| + #endif
|
| + printf ("#endif\n\n");
|
| +}
|
| +
|
| +/* Output gperf's ASCII-case insensitive memcmp replacement. */
|
| +
|
| +static void
|
| +output_upperlower_memcmp ()
|
| +{
|
| + printf ("#ifndef GPERF_CASE_MEMCMP\n"
|
| + "#define GPERF_CASE_MEMCMP 1\n"
|
| + "static int\n"
|
| + "gperf_case_memcmp ");
|
| + printf (option[KRC] ?
|
| + "(s1, s2, n)\n"
|
| + " register char *s1;\n"
|
| + " register char *s2;\n"
|
| + " register unsigned int n;\n" :
|
| + option[C] ?
|
| + "(s1, s2, n)\n"
|
| + " register const char *s1;\n"
|
| + " register const char *s2;\n"
|
| + " register unsigned int n;\n" :
|
| + option[ANSIC] | option[CPLUSPLUS] ?
|
| + "(register const char *s1, register const char *s2, register unsigned int n)\n" :
|
| + "");
|
| + #if USE_DOWNCASE_TABLE
|
| + printf ("{\n"
|
| + " for (; n > 0;)\n"
|
| + " {\n"
|
| + " unsigned char c1 = gperf_downcase[(unsigned char)*s1++];\n"
|
| + " unsigned char c2 = gperf_downcase[(unsigned char)*s2++];\n"
|
| + " if (c1 == c2)\n"
|
| + " {\n"
|
| + " n--;\n"
|
| + " continue;\n"
|
| + " }\n"
|
| + " return (int)c1 - (int)c2;\n"
|
| + " }\n"
|
| + " return 0;\n"
|
| + "}\n");
|
| + #else
|
| + printf ("{\n"
|
| + " for (; n > 0;)\n"
|
| + " {\n"
|
| + " unsigned char c1 = *s1++;\n"
|
| + " unsigned char c2 = *s2++;\n"
|
| + " if (c1 >= 'A' && c1 <= 'Z')\n"
|
| + " c1 += 'a' - 'A';\n"
|
| + " if (c2 >= 'A' && c2 <= 'Z')\n"
|
| + " c2 += 'a' - 'A';\n"
|
| + " if (c1 == c2)\n"
|
| + " {\n"
|
| + " n--;\n"
|
| + " continue;\n"
|
| + " }\n"
|
| + " return (int)c1 - (int)c2;\n"
|
| + " }\n"
|
| + " return 0;\n"
|
| + "}\n");
|
| + #endif
|
| + printf ("#endif\n\n");
|
| +}
|
| +
|
| +/* ------------------------------------------------------------------------- */
|
| +
|
| +/* Outputs a keyword, as a string: enclosed in double quotes, escaping
|
| + backslashes, double quote and unprintable characters. */
|
| +
|
| +static void
|
| +output_string (const char *key, int len)
|
| +{
|
| + putchar ('"');
|
| + for (; len > 0; len--)
|
| + {
|
| + unsigned char c = static_cast<unsigned char>(*key++);
|
| + if (isprint (c))
|
| + {
|
| + if (c == '"' || c == '\\')
|
| + putchar ('\\');
|
| + putchar (c);
|
| + }
|
| + else
|
| + {
|
| + /* Use octal escapes, not hexadecimal escapes, because some old
|
| + C compilers didn't understand hexadecimal escapes, and because
|
| + hexadecimal escapes are not limited to 2 digits, thus needing
|
| + special care if the following character happens to be a digit. */
|
| + putchar ('\\');
|
| + putchar ('0' + ((c >> 6) & 7));
|
| + putchar ('0' + ((c >> 3) & 7));
|
| + putchar ('0' + (c & 7));
|
| + }
|
| + }
|
| + putchar ('"');
|
| +}
|
| +
|
| +/* ------------------------------------------------------------------------- */
|
| +
|
| +/* 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);
|
| +}
|
| +
|
| +/* ----------------------- Output_Expr and subclasses ----------------------- */
|
| +
|
| +/* This class outputs a general expression. */
|
| +
|
| +struct Output_Expr
|
| +{
|
| + virtual void output_expr () const = 0;
|
| + Output_Expr () {}
|
| + virtual ~Output_Expr () {}
|
| +};
|
| +
|
| +/* This class outputs an expression formed by a single string. */
|
| +
|
| +struct Output_Expr1 : public Output_Expr
|
| +{
|
| + virtual void output_expr () const;
|
| + Output_Expr1 (const char *piece1) : _p1 (piece1) {}
|
| + virtual ~Output_Expr1 () {}
|
| +private:
|
| + const char *_p1;
|
| +};
|
| +
|
| +void Output_Expr1::output_expr () const
|
| +{
|
| + printf ("%s", _p1);
|
| +}
|
| +
|
| +#if 0 /* unused */
|
| +
|
| +/* This class outputs an expression formed by the concatenation of two
|
| + strings. */
|
| +
|
| +struct Output_Expr2 : public Output_Expr
|
| +{
|
| + virtual void output_expr () const;
|
| + Output_Expr2 (const char *piece1, const char *piece2)
|
| + : _p1 (piece1), _p2 (piece2) {}
|
| + virtual ~Output_Expr2 () {}
|
| +private:
|
| + const char *_p1;
|
| + const char *_p2;
|
| +};
|
| +
|
| +void Output_Expr2::output_expr () const
|
| +{
|
| + printf ("%s%s", _p1, _p2);
|
| +}
|
| +
|
| +#endif
|
| +
|
| +/* --------------------- Output_Compare and subclasses --------------------- */
|
| +
|
| +/* This class outputs a comparison expression. */
|
| +
|
| +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;
|
| + /* Outputs the comparison expression for the first byte.
|
| + Returns true if the this comparison is complete. */
|
| + bool output_firstchar_comparison (const Output_Expr& expr1,
|
| + const Output_Expr& expr2) const;
|
| + Output_Compare () {}
|
| + virtual ~Output_Compare () {}
|
| +};
|
| +
|
| +bool Output_Compare::output_firstchar_comparison (const Output_Expr& expr1,
|
| + const Output_Expr& expr2) const
|
| +{
|
| + /* First, we emit a comparison of the first byte of the two strings.
|
| + This catches most cases where the string being looked up is not in the
|
| + hash table but happens to have the same hash code as an element of the
|
| + hash table. */
|
| + if (option[UPPERLOWER])
|
| + {
|
| + /* Incomplete comparison, just for speedup. */
|
| + printf ("(((unsigned char)*");
|
| + expr1.output_expr ();
|
| + printf (" ^ (unsigned char)*");
|
| + expr2.output_expr ();
|
| + printf (") & ~32) == 0");
|
| + return false;
|
| + }
|
| + else
|
| + {
|
| + /* Complete comparison. */
|
| + printf ("*");
|
| + expr1.output_expr ();
|
| + printf (" == *");
|
| + expr2.output_expr ();
|
| + return true;
|
| + }
|
| +}
|
| +
|
| +/* This class outputs a comparison using strcmp. */
|
| +
|
| +struct Output_Compare_Strcmp : public Output_Compare
|
| +{
|
| + virtual void output_comparison (const Output_Expr& expr1,
|
| + const Output_Expr& expr2) const;
|
| + Output_Compare_Strcmp () {}
|
| + virtual ~Output_Compare_Strcmp () {}
|
| +};
|
| +
|
| +void Output_Compare_Strcmp::output_comparison (const Output_Expr& expr1,
|
| + const Output_Expr& expr2) const
|
| +{
|
| + bool firstchar_done = output_firstchar_comparison (expr1, expr2);
|
| + printf (" && !");
|
| + if (option[UPPERLOWER])
|
| + printf ("gperf_case_");
|
| + printf ("strcmp (");
|
| + if (firstchar_done)
|
| + {
|
| + expr1.output_expr ();
|
| + printf (" + 1, ");
|
| + expr2.output_expr ();
|
| + printf (" + 1");
|
| + }
|
| + else
|
| + {
|
| + expr1.output_expr ();
|
| + printf (", ");
|
| + expr2.output_expr ();
|
| + }
|
| + printf (")");
|
| +}
|
| +
|
| +/* This class outputs a comparison using strncmp.
|
| + Note that the length of expr1 will be available through the local variable
|
| + 'len'. */
|
| +
|
| +struct Output_Compare_Strncmp : public Output_Compare
|
| +{
|
| + virtual void output_comparison (const Output_Expr& expr1,
|
| + const Output_Expr& expr2) const;
|
| + Output_Compare_Strncmp () {}
|
| + virtual ~Output_Compare_Strncmp () {}
|
| +};
|
| +
|
| +void Output_Compare_Strncmp::output_comparison (const Output_Expr& expr1,
|
| + const Output_Expr& expr2) const
|
| +{
|
| + bool firstchar_done = output_firstchar_comparison (expr1, expr2);
|
| + printf (" && !");
|
| + if (option[UPPERLOWER])
|
| + printf ("gperf_case_");
|
| + printf ("strncmp (");
|
| + if (firstchar_done)
|
| + {
|
| + expr1.output_expr ();
|
| + printf (" + 1, ");
|
| + expr2.output_expr ();
|
| + printf (" + 1, len - 1");
|
| + }
|
| + else
|
| + {
|
| + expr1.output_expr ();
|
| + printf (", ");
|
| + expr2.output_expr ();
|
| + printf (", len");
|
| + }
|
| + printf (") && ");
|
| + expr2.output_expr ();
|
| + printf ("[len] == '\\0'");
|
| +}
|
| +
|
| +/* This class outputs a comparison using memcmp.
|
| + 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. */
|
| +
|
| +struct Output_Compare_Memcmp : public Output_Compare
|
| +{
|
| + virtual void output_comparison (const Output_Expr& expr1,
|
| + const Output_Expr& expr2) const;
|
| + Output_Compare_Memcmp () {}
|
| + virtual ~Output_Compare_Memcmp () {}
|
| +};
|
| +
|
| +void Output_Compare_Memcmp::output_comparison (const Output_Expr& expr1,
|
| + const Output_Expr& expr2) const
|
| +{
|
| + bool firstchar_done = output_firstchar_comparison (expr1, expr2);
|
| + printf (" && !");
|
| + if (option[UPPERLOWER])
|
| + printf ("gperf_case_");
|
| + printf ("memcmp (");
|
| + if (firstchar_done)
|
| + {
|
| + expr1.output_expr ();
|
| + printf (" + 1, ");
|
| + expr2.output_expr ();
|
| + printf (" + 1, len - 1");
|
| + }
|
| + else
|
| + {
|
| + expr1.output_expr ();
|
| + printf (", ");
|
| + expr2.output_expr ();
|
| + printf (", len");
|
| + }
|
| + printf (")");
|
| +}
|
| +
|
| +/* ------------------------------------------------------------------------- */
|
| +
|
| +/* Generates a C expression for an asso_values[] reference. */
|
| +
|
| +void
|
| +Output::output_asso_values_ref (int pos) const
|
| +{
|
| + printf ("asso_values[");
|
| + /* Always cast to unsigned char. This is necessary when the alpha_inc
|
| + is nonzero, and also avoids a gcc warning "subscript has type 'char'". */
|
| + printf ("(unsigned char)");
|
| + if (pos == Positions::LASTCHAR)
|
| + printf ("str[len - 1]");
|
| + else
|
| + {
|
| + printf ("str[%d]", pos);
|
| + if (_alpha_inc[pos])
|
| + printf ("+%u", _alpha_inc[pos]);
|
| + }
|
| + printf ("]");
|
| +}
|
| +
|
| +/* Generates C code for the hash function that returns the
|
| + 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
|
| +{
|
| + /* Output the function's head. */
|
| + if (option[CPLUSPLUS])
|
| + printf ("inline ");
|
| + else if (option[KRC] | option[C] | option[ANSIC])
|
| + printf ("#ifdef __GNUC__\n"
|
| + "__inline\n"
|
| + "#else\n"
|
| + "#ifdef __cplusplus\n"
|
| + "inline\n"
|
| + "#endif\n"
|
| + "#endif\n");
|
| +
|
| + if (/* The function does not use the 'str' argument? */
|
| + _key_positions.get_size() == 0
|
| + || /* The function uses 'str', but not the 'len' argument? */
|
| + (option[NOLENGTH]
|
| + && _key_positions[0] < _min_key_len
|
| + && _key_positions[_key_positions.get_size() - 1] != Positions::LASTCHAR))
|
| + /* Pacify lint. */
|
| + printf ("/*ARGSUSED*/\n");
|
| +
|
| + if (option[KRC] | option[C] | option[ANSIC])
|
| + printf ("static ");
|
| + printf ("unsigned int\n");
|
| + if (option[CPLUSPLUS])
|
| + printf ("%s::", option.get_class_name ());
|
| + printf ("%s ", option.get_hash_name ());
|
| + printf (option[KRC] ?
|
| + "(str, len)\n"
|
| + " register char *str;\n"
|
| + " register unsigned int len;\n" :
|
| + option[C] ?
|
| + "(str, len)\n"
|
| + " register const char *str;\n"
|
| + " register unsigned int len;\n" :
|
| + option[ANSIC] | option[CPLUSPLUS] ?
|
| + "(register const char *str, register unsigned int len)\n" :
|
| + "");
|
| +
|
| + /* Note that when the hash function is called, it has already been verified
|
| + that min_key_len <= len <= max_key_len. */
|
| +
|
| + /* Output the function's body. */
|
| + printf ("{\n");
|
| +
|
| + /* First the asso_values array. */
|
| + if (_key_positions.get_size() > 0)
|
| + {
|
| + 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 (unsigned int count = 0; count < _alpha_size; count++)
|
| + {
|
| + if (count > 0)
|
| + printf (",");
|
| + if ((count % columns) == 0)
|
| + printf ("\n ");
|
| + printf ("%*d", field_width, _asso_values[count]);
|
| + }
|
| +
|
| + printf ("\n"
|
| + " };\n");
|
| + }
|
| +
|
| + if (_key_positions.get_size() == 0)
|
| + {
|
| + /* Trivial case: No key positions at all. */
|
| + printf (" return %s;\n",
|
| + option[NOLENGTH] ? "0" : "len");
|
| + }
|
| + else
|
| + {
|
| + /* Iterate through the key positions. Remember that Positions::sort()
|
| + has sorted them in decreasing order, with Positions::LASTCHAR coming
|
| + last. */
|
| + PositionIterator iter = _key_positions.iterator(_max_key_len);
|
| + int key_pos;
|
| +
|
| + /* 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. */
|
| +
|
| + printf (" return %s",
|
| + option[NOLENGTH] ? "" : "len + ");
|
| +
|
| + if (_key_positions.get_size() == 2
|
| + && _key_positions[0] == 0
|
| + && _key_positions[1] == Positions::LASTCHAR)
|
| + /* Optimize special case of "-k 1,$". */
|
| + {
|
| + output_asso_values_ref (Positions::LASTCHAR);
|
| + printf (" + ");
|
| + output_asso_values_ref (0);
|
| + }
|
| + else
|
| + {
|
| + for (; key_pos != Positions::LASTCHAR; )
|
| + {
|
| + output_asso_values_ref (key_pos);
|
| + if ((key_pos = iter.next ()) != PositionIterator::EOS)
|
| + printf (" + ");
|
| + else
|
| + break;
|
| + }
|
| +
|
| + if (key_pos == Positions::LASTCHAR)
|
| + output_asso_values_ref (Positions::LASTCHAR);
|
| + }
|
| +
|
| + printf (";\n");
|
| + }
|
| + else
|
| + {
|
| + /* We've got to use the correct, but brute force, technique. */
|
| + printf (" register int hval = %s;\n\n"
|
| + " switch (%s)\n"
|
| + " {\n"
|
| + " default:\n",
|
| + option[NOLENGTH] ? "0" : "len",
|
| + option[NOLENGTH] ? "len" : "hval");
|
| +
|
| + while (key_pos != Positions::LASTCHAR && key_pos >= _max_key_len)
|
| + if ((key_pos = iter.next ()) == PositionIterator::EOS)
|
| + break;
|
| +
|
| + if (key_pos != PositionIterator::EOS && key_pos != Positions::LASTCHAR)
|
| + {
|
| + int i = key_pos;
|
| + do
|
| + {
|
| + if (i > key_pos)
|
| + printf (" /*FALLTHROUGH*/\n"); /* Pacify lint. */
|
| + for ( ; i > key_pos; i--)
|
| + printf (" case %d:\n", i);
|
| +
|
| + printf (" hval += ");
|
| + output_asso_values_ref (key_pos);
|
| + printf (";\n");
|
| +
|
| + key_pos = iter.next ();
|
| + }
|
| + while (key_pos != PositionIterator::EOS && key_pos != Positions::LASTCHAR);
|
| +
|
| + if (i >= _min_key_len)
|
| + printf (" /*FALLTHROUGH*/\n"); /* Pacify lint. */
|
| + for ( ; i >= _min_key_len; i--)
|
| + printf (" case %d:\n", i);
|
| + }
|
| +
|
| + printf (" break;\n"
|
| + " }\n"
|
| + " return hval");
|
| + if (key_pos == Positions::LASTCHAR)
|
| + {
|
| + printf (" + ");
|
| + output_asso_values_ref (Positions::LASTCHAR);
|
| + }
|
| + printf (";\n");
|
| + }
|
| + }
|
| + printf ("}\n\n");
|
| +}
|
| +
|
| +/* ------------------------------------------------------------------------- */
|
| +
|
| +/* Prints out a table of keyword lengths, for use with the
|
| + comparison code in generated function 'in_word_set'.
|
| + Only called if option[LENTABLE]. */
|
| +
|
| +void
|
| +Output::output_keylength_table () const
|
| +{
|
| + const int columns = 14;
|
| + const char * const indent = option[GLOBAL] ? "" : " ";
|
| +
|
| + printf ("%sstatic %s%s lengthtable[] =\n%s {",
|
| + indent, const_readonly_array,
|
| + smallest_integral_type (_max_key_len),
|
| + 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())
|
| + {
|
| + KeywordExt *keyword = temp->first();
|
| +
|
| + /* 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] && !keyword->_duplicate_link)
|
| + continue;
|
| +
|
| + if (index < keyword->_hash_value && !option[SWITCH] && !option[DUP])
|
| + {
|
| + /* Some blank entries. */
|
| + for ( ; index < keyword->_hash_value; index++)
|
| + {
|
| + if (index > 0)
|
| + printf (",");
|
| + if ((column++ % columns) == 0)
|
| + printf ("\n%s ", indent);
|
| + printf ("%3d", 0);
|
| + }
|
| + }
|
| +
|
| + if (index > 0)
|
| + printf (",");
|
| + if ((column++ % columns) == 0)
|
| + printf("\n%s ", indent);
|
| + printf ("%3d", keyword->_allchars_length);
|
| + index++;
|
| +
|
| + /* Deal with duplicates specially. */
|
| + if (keyword->_duplicate_link) // implies option[DUP]
|
| + for (KeywordExt *links = keyword->_duplicate_link; links; links = links->_duplicate_link)
|
| + {
|
| + printf (",");
|
| + if ((column++ % columns) == 0)
|
| + printf("\n%s ", indent);
|
| + printf ("%3d", links->_allchars_length);
|
| + index++;
|
| + }
|
| + }
|
| +
|
| + printf ("\n%s };\n", indent);
|
| + if (option[GLOBAL])
|
| + printf ("\n");
|
| +}
|
| +
|
| +/* ------------------------------------------------------------------------- */
|
| +
|
| +/* Prints out the string pool, containing the strings of the keyword table.
|
| + Only called if option[SHAREDLIB]. */
|
| +
|
| +void
|
| +Output::output_string_pool () const
|
| +{
|
| + const char * const indent = option[TYPE] || option[GLOBAL] ? "" : " ";
|
| + int index;
|
| + KeywordExt_List *temp;
|
| +
|
| + printf ("%sstruct %s_t\n"
|
| + "%s {\n",
|
| + indent, option.get_stringpool_name (), indent);
|
| + for (temp = _head, index = 0; temp; temp = temp->rest())
|
| + {
|
| + KeywordExt *keyword = temp->first();
|
| +
|
| + /* 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] && !keyword->_duplicate_link)
|
| + continue;
|
| +
|
| + if (!option[SWITCH] && !option[DUP])
|
| + index = keyword->_hash_value;
|
| +
|
| + printf ("%s char %s_str%d[sizeof(",
|
| + indent, option.get_stringpool_name (), index);
|
| + output_string (keyword->_allchars, keyword->_allchars_length);
|
| + printf (")];\n");
|
| +
|
| + /* Deal with duplicates specially. */
|
| + if (keyword->_duplicate_link) // implies option[DUP]
|
| + for (KeywordExt *links = keyword->_duplicate_link; links; links = links->_duplicate_link)
|
| + if (!(links->_allchars_length == keyword->_allchars_length
|
| + && memcmp (links->_allchars, keyword->_allchars,
|
| + keyword->_allchars_length) == 0))
|
| + {
|
| + index++;
|
| + printf ("%s char %s_str%d[sizeof(",
|
| + indent, option.get_stringpool_name (), index);
|
| + output_string (links->_allchars, links->_allchars_length);
|
| + printf (")];\n");
|
| + }
|
| +
|
| + index++;
|
| + }
|
| + printf ("%s };\n",
|
| + indent);
|
| +
|
| + printf ("%sstatic %sstruct %s_t %s_contents =\n"
|
| + "%s {\n",
|
| + indent, const_readonly_array, option.get_stringpool_name (),
|
| + option.get_stringpool_name (), indent);
|
| + for (temp = _head, index = 0; temp; temp = temp->rest())
|
| + {
|
| + KeywordExt *keyword = temp->first();
|
| +
|
| + /* 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] && !keyword->_duplicate_link)
|
| + continue;
|
| +
|
| + if (index > 0)
|
| + printf (",\n");
|
| +
|
| + if (!option[SWITCH] && !option[DUP])
|
| + index = keyword->_hash_value;
|
| +
|
| + printf ("%s ",
|
| + indent);
|
| + output_string (keyword->_allchars, keyword->_allchars_length);
|
| +
|
| + /* Deal with duplicates specially. */
|
| + if (keyword->_duplicate_link) // implies option[DUP]
|
| + for (KeywordExt *links = keyword->_duplicate_link; links; links = links->_duplicate_link)
|
| + if (!(links->_allchars_length == keyword->_allchars_length
|
| + && memcmp (links->_allchars, keyword->_allchars,
|
| + keyword->_allchars_length) == 0))
|
| + {
|
| + index++;
|
| + printf (",\n");
|
| + printf ("%s ",
|
| + indent);
|
| + output_string (links->_allchars, links->_allchars_length);
|
| + }
|
| +
|
| + index++;
|
| + }
|
| + if (index > 0)
|
| + printf ("\n");
|
| + printf ("%s };\n",
|
| + indent);
|
| + printf ("%s#define %s ((%schar *) &%s_contents)\n",
|
| + indent, option.get_stringpool_name (), const_always,
|
| + option.get_stringpool_name ());
|
| + if (option[GLOBAL])
|
| + printf ("\n");
|
| +}
|
| +
|
| +/* ------------------------------------------------------------------------- */
|
| +
|
| +static void
|
| +output_keyword_entry (KeywordExt *temp, int stringpool_index, const char *indent)
|
| +{
|
| + if (option[TYPE] && option.get_input_file_name ())
|
| + printf ("#line %u \"%s\"\n",
|
| + temp->_lineno, option.get_input_file_name ());
|
| + printf ("%s ", indent);
|
| + if (option[TYPE])
|
| + printf ("{");
|
| + if (option[SHAREDLIB])
|
| + printf ("(int)(long)&((struct %s_t *)0)->%s_str%d",
|
| + option.get_stringpool_name (), option.get_stringpool_name (),
|
| + stringpool_index);
|
| + else
|
| + output_string (temp->_allchars, temp->_allchars_length);
|
| + if (option[TYPE])
|
| + {
|
| + if (strlen (temp->_rest) > 0)
|
| + printf (",%s", temp->_rest);
|
| + printf ("}");
|
| + }
|
| + if (option[DEBUG])
|
| + printf (" /* hash value = %d, index = %d */",
|
| + temp->_hash_value, temp->_final_index);
|
| +}
|
| +
|
| +static void
|
| +output_keyword_blank_entries (int count, const char *indent)
|
| +{
|
| + int columns;
|
| + if (option[TYPE])
|
| + {
|
| + columns = 58 / (4 + (option[SHAREDLIB] ? 2 : option[NULLSTRINGS] ? 8 : 2)
|
| + + strlen (option.get_initializer_suffix()));
|
| + if (columns == 0)
|
| + columns = 1;
|
| + }
|
| + else
|
| + {
|
| + columns = (option[SHAREDLIB] ? 9 : option[NULLSTRINGS] ? 4 : 9);
|
| + }
|
| + int column = 0;
|
| + for (int i = 0; i < count; i++)
|
| + {
|
| + if ((column % columns) == 0)
|
| + {
|
| + if (i > 0)
|
| + printf (",\n");
|
| + printf ("%s ", indent);
|
| + }
|
| + else
|
| + {
|
| + if (i > 0)
|
| + printf (", ");
|
| + }
|
| + if (option[TYPE])
|
| + printf ("{");
|
| + if (option[SHAREDLIB])
|
| + printf ("-1");
|
| + else
|
| + {
|
| + if (option[NULLSTRINGS])
|
| + printf ("(char*)0");
|
| + else
|
| + printf ("\"\"");
|
| + }
|
| + if (option[TYPE])
|
| + printf ("%s}", option.get_initializer_suffix());
|
| + column++;
|
| + }
|
| +}
|
| +
|
| +/* Prints out the array containing the keywords for the hash function. */
|
| +
|
| +void
|
| +Output::output_keyword_table () const
|
| +{
|
| + const char *indent = option[GLOBAL] ? "" : " ";
|
| + int index;
|
| + KeywordExt_List *temp;
|
| +
|
| + printf ("%sstatic ",
|
| + indent);
|
| + output_const_type (const_readonly_array, _wordlist_eltype);
|
| + printf ("%s[] =\n"
|
| + "%s {\n",
|
| + option.get_wordlist_name (),
|
| + indent);
|
| +
|
| + /* Generate an array of reserved words at appropriate locations. */
|
| +
|
| + for (temp = _head, index = 0; temp; temp = temp->rest())
|
| + {
|
| + KeywordExt *keyword = temp->first();
|
| +
|
| + /* 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] && !keyword->_duplicate_link)
|
| + continue;
|
| +
|
| + if (index > 0)
|
| + printf (",\n");
|
| +
|
| + if (index < keyword->_hash_value && !option[SWITCH] && !option[DUP])
|
| + {
|
| + /* Some blank entries. */
|
| + output_keyword_blank_entries (keyword->_hash_value - index, indent);
|
| + printf (",\n");
|
| + index = keyword->_hash_value;
|
| + }
|
| +
|
| + keyword->_final_index = index;
|
| +
|
| + output_keyword_entry (keyword, index, indent);
|
| +
|
| + /* Deal with duplicates specially. */
|
| + if (keyword->_duplicate_link) // implies option[DUP]
|
| + for (KeywordExt *links = keyword->_duplicate_link; links; links = links->_duplicate_link)
|
| + {
|
| + links->_final_index = ++index;
|
| + printf (",\n");
|
| + int stringpool_index =
|
| + (links->_allchars_length == keyword->_allchars_length
|
| + && memcmp (links->_allchars, keyword->_allchars,
|
| + keyword->_allchars_length) == 0
|
| + ? keyword->_final_index
|
| + : links->_final_index);
|
| + output_keyword_entry (links, stringpool_index, indent);
|
| + }
|
| +
|
| + index++;
|
| + }
|
| + if (index > 0)
|
| + printf ("\n");
|
| +
|
| + printf ("%s };\n\n", indent);
|
| +}
|
| +
|
| +/* ------------------------------------------------------------------------- */
|
| +
|
| +/* Generates the large, sparse table that maps hash values into
|
| + the smaller, contiguous range of the keyword table. */
|
| +
|
| +void
|
| +Output::output_lookup_array () const
|
| +{
|
| + if (option[DUP])
|
| + {
|
| + const int DEFAULT_VALUE = -1;
|
| +
|
| + /* Because of the way output_keyword_table works, every duplicate set is
|
| + stored contiguously in the wordlist array. */
|
| + struct duplicate_entry
|
| + {
|
| + int hash_value; /* Hash value for this particular duplicate set. */
|
| + int index; /* Index into the main keyword storage array. */
|
| + int count; /* Number of consecutive duplicates at this index. */
|
| + };
|
| +
|
| + duplicate_entry *duplicates = new duplicate_entry[_total_duplicates];
|
| + int *lookup_array = new int[_max_hash_value + 1 + 2*_total_duplicates];
|
| + int lookup_array_size = _max_hash_value + 1;
|
| + duplicate_entry *dup_ptr = &duplicates[0];
|
| + int *lookup_ptr = &lookup_array[_max_hash_value + 1 + 2*_total_duplicates];
|
| +
|
| + while (lookup_ptr > lookup_array)
|
| + *--lookup_ptr = DEFAULT_VALUE;
|
| +
|
| + /* Now dup_ptr = &duplicates[0] and lookup_ptr = &lookup_array[0]. */
|
| +
|
| + for (KeywordExt_List *temp = _head; temp; temp = temp->rest())
|
| + {
|
| + int hash_value = temp->first()->_hash_value;
|
| + lookup_array[hash_value] = temp->first()->_final_index;
|
| + if (option[DEBUG])
|
| + fprintf (stderr, "keyword = %.*s, index = %d\n",
|
| + temp->first()->_allchars_length, temp->first()->_allchars, temp->first()->_final_index);
|
| + if (temp->first()->_duplicate_link)
|
| + {
|
| + /* Start a duplicate entry. */
|
| + dup_ptr->hash_value = hash_value;
|
| + dup_ptr->index = temp->first()->_final_index;
|
| + dup_ptr->count = 1;
|
| +
|
| + for (KeywordExt *ptr = temp->first()->_duplicate_link; ptr; ptr = ptr->_duplicate_link)
|
| + {
|
| + dup_ptr->count++;
|
| + if (option[DEBUG])
|
| + fprintf (stderr,
|
| + "static linked keyword = %.*s, index = %d\n",
|
| + ptr->_allchars_length, ptr->_allchars, ptr->_final_index);
|
| + }
|
| + assert (dup_ptr->count >= 2);
|
| + dup_ptr++;
|
| + }
|
| + }
|
| +
|
| + while (dup_ptr > duplicates)
|
| + {
|
| + dup_ptr--;
|
| +
|
| + if (option[DEBUG])
|
| + fprintf (stderr,
|
| + "dup_ptr[%d]: hash_value = %d, index = %d, count = %d\n",
|
| + dup_ptr - duplicates,
|
| + dup_ptr->hash_value, dup_ptr->index, dup_ptr->count);
|
| +
|
| + int i;
|
| + /* Start searching for available space towards the right part
|
| + of the lookup array. */
|
| + for (i = dup_ptr->hash_value; i < lookup_array_size-1; i++)
|
| + if (lookup_array[i] == DEFAULT_VALUE
|
| + && lookup_array[i + 1] == DEFAULT_VALUE)
|
| + goto found_i;
|
| + /* If we didn't find it to the right look to the left instead... */
|
| + for (i = dup_ptr->hash_value-1; i >= 0; i--)
|
| + if (lookup_array[i] == DEFAULT_VALUE
|
| + && lookup_array[i + 1] == DEFAULT_VALUE)
|
| + goto found_i;
|
| + /* Append to the end of lookup_array. */
|
| + i = lookup_array_size;
|
| + lookup_array_size += 2;
|
| + found_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. */
|
| + assert (lookup_array[dup_ptr->hash_value] == dup_ptr->index);
|
| + lookup_array[dup_ptr->hash_value] = - 1 - _total_keys - i;
|
| + lookup_array[i] = - _total_keys + dup_ptr->index;
|
| + lookup_array[i + 1] = - dup_ptr->count;
|
| + /* All these three values are <= -2, distinct from DEFAULT_VALUE. */
|
| + }
|
| +
|
| + /* The values of the lookup array are now known. */
|
| +
|
| + int min = INT_MAX;
|
| + int max = INT_MIN;
|
| + lookup_ptr = lookup_array + lookup_array_size;
|
| + while (lookup_ptr > lookup_array)
|
| + {
|
| + int val = *--lookup_ptr;
|
| + if (min > val)
|
| + min = val;
|
| + if (max < val)
|
| + max = val;
|
| + }
|
| +
|
| + const char *indent = option[GLOBAL] ? "" : " ";
|
| + printf ("%sstatic %s%s lookup[] =\n"
|
| + "%s {",
|
| + indent, const_readonly_array, smallest_integral_type (min, max),
|
| + indent);
|
| +
|
| + int field_width;
|
| + /* Calculate maximum number of digits required for MIN..MAX. */
|
| + {
|
| + field_width = 2;
|
| + for (int trunc = max; (trunc /= 10) > 0;)
|
| + field_width++;
|
| + }
|
| + if (min < 0)
|
| + {
|
| + int neg_field_width = 2;
|
| + for (int trunc = -min; (trunc /= 10) > 0;)
|
| + neg_field_width++;
|
| + neg_field_width++; /* account for the minus sign */
|
| + if (field_width < neg_field_width)
|
| + field_width = neg_field_width;
|
| + }
|
| +
|
| + const int columns = 42 / field_width;
|
| + int column;
|
| +
|
| + column = 0;
|
| + for (int i = 0; i < lookup_array_size; i++)
|
| + {
|
| + if (i > 0)
|
| + printf (",");
|
| + if ((column++ % columns) == 0)
|
| + printf("\n%s ", indent);
|
| + printf ("%*d", field_width, lookup_array[i]);
|
| + }
|
| + printf ("\n%s };\n\n", indent);
|
| +
|
| + delete[] duplicates;
|
| + delete[] lookup_array;
|
| + }
|
| +}
|
| +
|
| +/* ------------------------------------------------------------------------- */
|
| +
|
| +/* Generate all pools needed for the lookup function. */
|
| +
|
| +void
|
| +Output::output_lookup_pools () const
|
| +{
|
| + if (option[SWITCH])
|
| + {
|
| + if (option[TYPE] || (option[DUP] && _total_duplicates > 0))
|
| + output_string_pool ();
|
| + }
|
| + else
|
| + {
|
| + output_string_pool ();
|
| + }
|
| +}
|
| +
|
| +/* Generate all the tables needed for the lookup function. */
|
| +
|
| +void
|
| +Output::output_lookup_tables () const
|
| +{
|
| + if (option[SWITCH])
|
| + {
|
| + /* Use the switch in place of lookup table. */
|
| + if (option[LENTABLE] && (option[DUP] && _total_duplicates > 0))
|
| + output_keylength_table ();
|
| + if (option[TYPE] || (option[DUP] && _total_duplicates > 0))
|
| + output_keyword_table ();
|
| + }
|
| + else
|
| + {
|
| + /* Use the lookup table, in place of switch. */
|
| + if (option[LENTABLE])
|
| + output_keylength_table ();
|
| + output_keyword_table ();
|
| + output_lookup_array ();
|
| + }
|
| +}
|
| +
|
| +/* ------------------------------------------------------------------------- */
|
| +
|
| +/* Output a single switch case (including duplicates). Advance list. */
|
| +
|
| +static KeywordExt_List *
|
| +output_switch_case (KeywordExt_List *list, int indent, int *jumps_away)
|
| +{
|
| + if (option[DEBUG])
|
| + printf ("%*s/* hash value = %4d, keyword = \"%.*s\" */\n",
|
| + indent, "", list->first()->_hash_value, list->first()->_allchars_length, list->first()->_allchars);
|
| +
|
| + if (option[DUP] && list->first()->_duplicate_link)
|
| + {
|
| + if (option[LENTABLE])
|
| + printf ("%*slengthptr = &lengthtable[%d];\n",
|
| + indent, "", list->first()->_final_index);
|
| + printf ("%*swordptr = &%s[%d];\n",
|
| + indent, "", option.get_wordlist_name (), list->first()->_final_index);
|
| +
|
| + int count = 0;
|
| + for (KeywordExt *links = list->first(); links; links = links->_duplicate_link)
|
| + count++;
|
| +
|
| + printf ("%*swordendptr = wordptr + %d;\n"
|
| + "%*sgoto multicompare;\n",
|
| + indent, "", count,
|
| + indent, "");
|
| + *jumps_away = 1;
|
| + }
|
| + else
|
| + {
|
| + if (option[LENTABLE])
|
| + {
|
| + printf ("%*sif (len == %d)\n"
|
| + "%*s {\n",
|
| + indent, "", list->first()->_allchars_length,
|
| + indent, "");
|
| + indent += 4;
|
| + }
|
| + printf ("%*sresword = ",
|
| + indent, "");
|
| + if (option[TYPE])
|
| + printf ("&%s[%d]", option.get_wordlist_name (), list->first()->_final_index);
|
| + else
|
| + output_string (list->first()->_allchars, list->first()->_allchars_length);
|
| + printf (";\n");
|
| + printf ("%*sgoto compare;\n",
|
| + indent, "");
|
| + if (option[LENTABLE])
|
| + {
|
| + indent -= 4;
|
| + printf ("%*s }\n",
|
| + indent, "");
|
| + }
|
| + else
|
| + *jumps_away = 1;
|
| + }
|
| +
|
| + return list->rest();
|
| +}
|
| +
|
| +/* Output a total of size cases, grouped into num_switches switch statements,
|
| + where 0 < num_switches <= size. */
|
| +
|
| +static void
|
| +output_switches (KeywordExt_List *list, int num_switches, int size, int min_hash_value, int max_hash_value, int indent)
|
| +{
|
| + if (option[DEBUG])
|
| + printf ("%*s/* know %d <= key <= %d, contains %d cases */\n",
|
| + indent, "", min_hash_value, max_hash_value, size);
|
| +
|
| + if (num_switches > 1)
|
| + {
|
| + int part1 = num_switches / 2;
|
| + int part2 = num_switches - part1;
|
| + int size1 = static_cast<int>(static_cast<double>(size) / static_cast<double>(num_switches) * static_cast<double>(part1) + 0.5);
|
| + int size2 = size - size1;
|
| +
|
| + KeywordExt_List *temp = list;
|
| + for (int count = size1; count > 0; count--)
|
| + temp = temp->rest();
|
| +
|
| + printf ("%*sif (key < %d)\n"
|
| + "%*s {\n",
|
| + indent, "", temp->first()->_hash_value,
|
| + indent, "");
|
| +
|
| + output_switches (list, part1, size1, min_hash_value, temp->first()->_hash_value-1, indent+4);
|
| +
|
| + printf ("%*s }\n"
|
| + "%*selse\n"
|
| + "%*s {\n",
|
| + indent, "", indent, "", indent, "");
|
| +
|
| + output_switches (temp, part2, size2, temp->first()->_hash_value, max_hash_value, indent+4);
|
| +
|
| + printf ("%*s }\n",
|
| + indent, "");
|
| + }
|
| + else
|
| + {
|
| + /* Output a single switch. */
|
| + int lowest_case_value = list->first()->_hash_value;
|
| + if (size == 1)
|
| + {
|
| + int jumps_away = 0;
|
| + assert (min_hash_value <= lowest_case_value);
|
| + assert (lowest_case_value <= max_hash_value);
|
| + if (min_hash_value == max_hash_value)
|
| + output_switch_case (list, indent, &jumps_away);
|
| + else
|
| + {
|
| + printf ("%*sif (key == %d)\n"
|
| + "%*s {\n",
|
| + indent, "", lowest_case_value,
|
| + indent, "");
|
| + output_switch_case (list, indent+4, &jumps_away);
|
| + printf ("%*s }\n",
|
| + indent, "");
|
| + }
|
| + }
|
| + else
|
| + {
|
| + if (lowest_case_value == 0)
|
| + printf ("%*sswitch (key)\n", indent, "");
|
| + else
|
| + printf ("%*sswitch (key - %d)\n", indent, "", lowest_case_value);
|
| + printf ("%*s {\n",
|
| + indent, "");
|
| + for (; size > 0; size--)
|
| + {
|
| + int jumps_away = 0;
|
| + printf ("%*s case %d:\n",
|
| + indent, "", list->first()->_hash_value - lowest_case_value);
|
| + list = output_switch_case (list, indent+6, &jumps_away);
|
| + if (!jumps_away)
|
| + printf ("%*s break;\n",
|
| + indent, "");
|
| + }
|
| + printf ("%*s }\n",
|
| + indent, "");
|
| + }
|
| + }
|
| +}
|
| +
|
| +/* Generates C code to perform the keyword lookup. */
|
| +
|
| +void
|
| +Output::output_lookup_function_body (const Output_Compare& comparison) const
|
| +{
|
| + printf (" if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)\n"
|
| + " {\n"
|
| + " register int key = %s (str, len);\n\n",
|
| + option.get_hash_name ());
|
| +
|
| + if (option[SWITCH])
|
| + {
|
| + int switch_size = num_hash_values ();
|
| + int num_switches = option.get_total_switches ();
|
| + if (num_switches > switch_size)
|
| + num_switches = switch_size;
|
| +
|
| + printf (" if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)\n"
|
| + " {\n");
|
| + if (option[DUP] && _total_duplicates > 0)
|
| + {
|
| + if (option[LENTABLE])
|
| + printf (" register %s%s *lengthptr;\n",
|
| + const_always, smallest_integral_type (_max_key_len));
|
| + printf (" register ");
|
| + output_const_type (const_readonly_array, _wordlist_eltype);
|
| + printf ("*wordptr;\n");
|
| + printf (" register ");
|
| + output_const_type (const_readonly_array, _wordlist_eltype);
|
| + printf ("*wordendptr;\n");
|
| + }
|
| + if (option[TYPE])
|
| + {
|
| + printf (" register ");
|
| + output_const_type (const_readonly_array, _struct_tag);
|
| + printf ("*resword;\n\n");
|
| + }
|
| + else
|
| + printf (" register %sresword;\n\n",
|
| + _struct_tag);
|
| +
|
| + output_switches (_head, num_switches, switch_size, _min_hash_value, _max_hash_value, 10);
|
| +
|
| + printf (" return 0;\n");
|
| + if (option[DUP] && _total_duplicates > 0)
|
| + {
|
| + int indent = 8;
|
| + printf ("%*smulticompare:\n"
|
| + "%*s while (wordptr < wordendptr)\n"
|
| + "%*s {\n",
|
| + indent, "", indent, "", indent, "");
|
| + if (option[LENTABLE])
|
| + {
|
| + printf ("%*s if (len == *lengthptr)\n"
|
| + "%*s {\n",
|
| + indent, "", indent, "");
|
| + indent += 4;
|
| + }
|
| + printf ("%*s register %schar *s = ",
|
| + indent, "", const_always);
|
| + if (option[TYPE])
|
| + printf ("wordptr->%s", option.get_slot_name ());
|
| + else
|
| + printf ("*wordptr");
|
| + if (option[SHAREDLIB])
|
| + printf (" + %s",
|
| + option.get_stringpool_name ());
|
| + printf (";\n\n"
|
| + "%*s if (",
|
| + indent, "");
|
| + comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("s"));
|
| + printf (")\n"
|
| + "%*s return %s;\n",
|
| + indent, "",
|
| + option[TYPE] ? "wordptr" : "s");
|
| + if (option[LENTABLE])
|
| + {
|
| + indent -= 4;
|
| + printf ("%*s }\n",
|
| + indent, "");
|
| + }
|
| + if (option[LENTABLE])
|
| + printf ("%*s lengthptr++;\n",
|
| + indent, "");
|
| + printf ("%*s wordptr++;\n"
|
| + "%*s }\n"
|
| + "%*s return 0;\n",
|
| + indent, "", indent, "", indent, "");
|
| + }
|
| + printf (" compare:\n");
|
| + if (option[TYPE])
|
| + {
|
| + printf (" {\n"
|
| + " register %schar *s = resword->%s",
|
| + const_always, option.get_slot_name ());
|
| + if (option[SHAREDLIB])
|
| + printf (" + %s",
|
| + option.get_stringpool_name ());
|
| + printf (";\n\n"
|
| + " if (");
|
| + comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("s"));
|
| + printf (")\n"
|
| + " return resword;\n"
|
| + " }\n");
|
| + }
|
| + else
|
| + {
|
| + printf (" if (");
|
| + comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("resword"));
|
| + printf (")\n"
|
| + " return resword;\n");
|
| + }
|
| + printf (" }\n");
|
| + }
|
| + else
|
| + {
|
| + printf (" if (key <= MAX_HASH_VALUE && key >= 0)\n");
|
| +
|
| + if (option[DUP])
|
| + {
|
| + int indent = 8;
|
| + printf ("%*s{\n"
|
| + "%*s register int index = lookup[key];\n\n"
|
| + "%*s if (index >= 0)\n",
|
| + indent, "", indent, "", indent, "");
|
| + if (option[LENTABLE])
|
| + {
|
| + printf ("%*s {\n"
|
| + "%*s if (len == lengthtable[index])\n",
|
| + indent, "", indent, "");
|
| + indent += 4;
|
| + }
|
| + printf ("%*s {\n"
|
| + "%*s register %schar *s = %s[index]",
|
| + indent, "",
|
| + indent, "", const_always, option.get_wordlist_name ());
|
| + if (option[TYPE])
|
| + printf (".%s", option.get_slot_name ());
|
| + if (option[SHAREDLIB])
|
| + printf (" + %s",
|
| + option.get_stringpool_name ());
|
| + printf (";\n\n"
|
| + "%*s if (",
|
| + indent, "");
|
| + comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("s"));
|
| + printf (")\n"
|
| + "%*s return ",
|
| + indent, "");
|
| + if (option[TYPE])
|
| + printf ("&%s[index]", option.get_wordlist_name ());
|
| + else
|
| + printf ("s");
|
| + printf (";\n"
|
| + "%*s }\n",
|
| + indent, "");
|
| + if (option[LENTABLE])
|
| + {
|
| + indent -= 4;
|
| + printf ("%*s }\n", indent, "");
|
| + }
|
| + if (_total_duplicates > 0)
|
| + {
|
| + printf ("%*s else if (index < -TOTAL_KEYWORDS)\n"
|
| + "%*s {\n"
|
| + "%*s register int offset = - 1 - TOTAL_KEYWORDS - index;\n",
|
| + indent, "", indent, "", indent, "");
|
| + if (option[LENTABLE])
|
| + printf ("%*s register %s%s *lengthptr = &lengthtable[TOTAL_KEYWORDS + lookup[offset]];\n",
|
| + indent, "", const_always, smallest_integral_type (_max_key_len));
|
| + printf ("%*s register ",
|
| + indent, "");
|
| + output_const_type (const_readonly_array, _wordlist_eltype);
|
| + printf ("*wordptr = &%s[TOTAL_KEYWORDS + lookup[offset]];\n",
|
| + option.get_wordlist_name ());
|
| + printf ("%*s register ",
|
| + indent, "");
|
| + output_const_type (const_readonly_array, _wordlist_eltype);
|
| + printf ("*wordendptr = wordptr + -lookup[offset + 1];\n\n");
|
| + printf ("%*s while (wordptr < wordendptr)\n"
|
| + "%*s {\n",
|
| + indent, "", indent, "");
|
| + if (option[LENTABLE])
|
| + {
|
| + printf ("%*s if (len == *lengthptr)\n"
|
| + "%*s {\n",
|
| + indent, "", indent, "");
|
| + indent += 4;
|
| + }
|
| + printf ("%*s register %schar *s = ",
|
| + indent, "", const_always);
|
| + if (option[TYPE])
|
| + printf ("wordptr->%s", option.get_slot_name ());
|
| + else
|
| + printf ("*wordptr");
|
| + if (option[SHAREDLIB])
|
| + printf (" + %s",
|
| + option.get_stringpool_name ());
|
| + printf (";\n\n"
|
| + "%*s if (",
|
| + indent, "");
|
| + comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("s"));
|
| + printf (")\n"
|
| + "%*s return %s;\n",
|
| + indent, "",
|
| + option[TYPE] ? "wordptr" : "s");
|
| + if (option[LENTABLE])
|
| + {
|
| + indent -= 4;
|
| + printf ("%*s }\n",
|
| + indent, "");
|
| + }
|
| + if (option[LENTABLE])
|
| + printf ("%*s lengthptr++;\n",
|
| + indent, "");
|
| + printf ("%*s wordptr++;\n"
|
| + "%*s }\n"
|
| + "%*s }\n",
|
| + indent, "", indent, "", indent, "");
|
| + }
|
| + printf ("%*s}\n",
|
| + indent, "");
|
| + }
|
| + else
|
| + {
|
| + int indent = 8;
|
| + if (option[LENTABLE])
|
| + {
|
| + printf ("%*sif (len == lengthtable[key])\n",
|
| + indent, "");
|
| + indent += 2;
|
| + }
|
| +
|
| + if (option[SHAREDLIB])
|
| + {
|
| + if (!option[LENTABLE])
|
| + {
|
| + printf ("%*s{\n"
|
| + "%*s register int o = %s[key]",
|
| + indent, "",
|
| + indent, "", option.get_wordlist_name ());
|
| + if (option[TYPE])
|
| + printf (".%s", option.get_slot_name ());
|
| + printf (";\n"
|
| + "%*s if (o >= 0)\n"
|
| + "%*s {\n",
|
| + indent, "",
|
| + indent, "");
|
| + indent += 4;
|
| + printf ("%*s register %schar *s = o",
|
| + indent, "", const_always);
|
| + }
|
| + else
|
| + {
|
| + /* No need for the (o >= 0) test, because the
|
| + (len == lengthtable[key]) test already guarantees that
|
| + key points to nonempty table entry. */
|
| + printf ("%*s{\n"
|
| + "%*s register %schar *s = %s[key]",
|
| + indent, "",
|
| + indent, "", const_always,
|
| + option.get_wordlist_name ());
|
| + if (option[TYPE])
|
| + printf (".%s", option.get_slot_name ());
|
| + }
|
| + printf (" + %s",
|
| + option.get_stringpool_name ());
|
| + }
|
| + else
|
| + {
|
| + printf ("%*s{\n"
|
| + "%*s register %schar *s = %s[key]",
|
| + indent, "",
|
| + indent, "", const_always, option.get_wordlist_name ());
|
| + if (option[TYPE])
|
| + printf (".%s", option.get_slot_name ());
|
| + }
|
| +
|
| + printf (";\n\n"
|
| + "%*s if (",
|
| + indent, "");
|
| + if (!option[SHAREDLIB] && option[NULLSTRINGS])
|
| + printf ("s && ");
|
| + comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("s"));
|
| + printf (")\n"
|
| + "%*s return ",
|
| + indent, "");
|
| + if (option[TYPE])
|
| + printf ("&%s[key]", option.get_wordlist_name ());
|
| + else
|
| + printf ("s");
|
| + printf (";\n");
|
| + if (option[SHAREDLIB] && !option[LENTABLE])
|
| + {
|
| + indent -= 4;
|
| + printf ("%*s }\n",
|
| + indent, "");
|
| + }
|
| + printf ("%*s}\n",
|
| + indent, "");
|
| + }
|
| + }
|
| + printf (" }\n"
|
| + " return 0;\n");
|
| +}
|
| +
|
| +/* Generates C code for the lookup function. */
|
| +
|
| +void
|
| +Output::output_lookup_function () const
|
| +{
|
| + /* Output the function's head. */
|
| + if (option[KRC] | option[C] | option[ANSIC])
|
| + printf ("#ifdef __GNUC__\n"
|
| + "__inline\n"
|
| + "#endif\n");
|
| +
|
| + printf ("%s%s\n",
|
| + const_for_struct, _return_type);
|
| + if (option[CPLUSPLUS])
|
| + printf ("%s::", option.get_class_name ());
|
| + printf ("%s ", option.get_function_name ());
|
| + printf (option[KRC] ?
|
| + "(str, len)\n"
|
| + " register char *str;\n"
|
| + " register unsigned int len;\n" :
|
| + option[C] ?
|
| + "(str, len)\n"
|
| + " register const char *str;\n"
|
| + " register unsigned int len;\n" :
|
| + option[ANSIC] | option[CPLUSPLUS] ?
|
| + "(register const char *str, register unsigned int len)\n" :
|
| + "");
|
| +
|
| + /* Output the function's body. */
|
| + printf ("{\n");
|
| +
|
| + if (option[ENUM] && !option[GLOBAL])
|
| + {
|
| + Output_Enum style (" ");
|
| + output_constants (style);
|
| + }
|
| +
|
| + if (option[SHAREDLIB] && !(option[GLOBAL] || option[TYPE]))
|
| + output_lookup_pools ();
|
| + if (!option[GLOBAL])
|
| + output_lookup_tables ();
|
| +
|
| + if (option[LENTABLE])
|
| + output_lookup_function_body (Output_Compare_Memcmp ());
|
| + else
|
| + {
|
| + if (option[COMP])
|
| + output_lookup_function_body (Output_Compare_Strncmp ());
|
| + else
|
| + output_lookup_function_body (Output_Compare_Strcmp ());
|
| + }
|
| +
|
| + printf ("}\n");
|
| +}
|
| +
|
| +/* ------------------------------------------------------------------------- */
|
| +
|
| +/* Generates the hash function and the key word recognizer function
|
| + based upon the user's Options. */
|
| +
|
| +void
|
| +Output::output ()
|
| +{
|
| + compute_min_max ();
|
| +
|
| + if (option[C] | option[ANSIC] | option[CPLUSPLUS])
|
| + {
|
| + const_always = "const ";
|
| + const_readonly_array = (option[CONST] ? "const " : "");
|
| + const_for_struct = ((option[CONST] && option[TYPE]) ? "const " : "");
|
| + }
|
| + else
|
| + {
|
| + const_always = "";
|
| + const_readonly_array = "";
|
| + const_for_struct = "";
|
| + }
|
| +
|
| + if (!option[TYPE])
|
| + {
|
| + _return_type = (const_always[0] ? "const char *" : "char *");
|
| + _struct_tag = (const_always[0] ? "const char *" : "char *");
|
| + }
|
| +
|
| + _wordlist_eltype = (option[SHAREDLIB] && !option[TYPE] ? "int" : _struct_tag);
|
| +
|
| + printf ("/* ");
|
| + if (option[KRC])
|
| + printf ("KR-C");
|
| + else if (option[C])
|
| + printf ("C");
|
| + else if (option[ANSIC])
|
| + printf ("ANSI-C");
|
| + else if (option[CPLUSPLUS])
|
| + printf ("C++");
|
| + printf (" code produced by gperf version %s */\n", version_string);
|
| + option.print_options ();
|
| + printf ("\n");
|
| + if (!option[POSITIONS])
|
| + {
|
| + printf ("/* Computed positions: -k'");
|
| + _key_positions.print();
|
| + printf ("' */\n");
|
| + }
|
| + printf ("\n");
|
| +
|
| + if (_charset_dependent
|
| + && (_key_positions.get_size() > 0 || option[UPPERLOWER]))
|
| + {
|
| + /* The generated tables assume that the execution character set is
|
| + based on ISO-646, not EBCDIC. */
|
| + printf ("#if !((' ' == 32) && ('!' == 33) && ('\"' == 34) && ('#' == 35) \\\n"
|
| + " && ('%%' == 37) && ('&' == 38) && ('\\'' == 39) && ('(' == 40) \\\n"
|
| + " && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \\\n"
|
| + " && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \\\n"
|
| + " && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \\\n"
|
| + " && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \\\n"
|
| + " && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \\\n"
|
| + " && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \\\n"
|
| + " && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \\\n"
|
| + " && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \\\n"
|
| + " && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \\\n"
|
| + " && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \\\n"
|
| + " && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \\\n"
|
| + " && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \\\n"
|
| + " && ('Z' == 90) && ('[' == 91) && ('\\\\' == 92) && (']' == 93) \\\n"
|
| + " && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \\\n"
|
| + " && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \\\n"
|
| + " && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \\\n"
|
| + " && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \\\n"
|
| + " && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \\\n"
|
| + " && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \\\n"
|
| + " && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \\\n"
|
| + " && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))\n"
|
| + "/* The character set is not based on ISO-646. */\n");
|
| + printf ("%s \"gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>.\"\n", option[KRC] || option[C] ? "error" : "#error");
|
| + printf ("#endif\n\n");
|
| + }
|
| +
|
| + if (_verbatim_declarations < _verbatim_declarations_end)
|
| + {
|
| + if (option.get_input_file_name ())
|
| + printf ("#line %u \"%s\"\n",
|
| + _verbatim_declarations_lineno, option.get_input_file_name ());
|
| + fwrite (_verbatim_declarations, 1,
|
| + _verbatim_declarations_end - _verbatim_declarations, stdout);
|
| + }
|
| +
|
| + if (option[TYPE] && !option[NOTYPE]) /* Output type declaration now, reference it later on.... */
|
| + {
|
| + if (option.get_input_file_name ())
|
| + printf ("#line %u \"%s\"\n",
|
| + _struct_decl_lineno, option.get_input_file_name ());
|
| + printf ("%s\n", _struct_decl);
|
| + }
|
| +
|
| + if (option[INCLUDE])
|
| + printf ("#include <string.h>\n"); /* Declare strlen(), strcmp(), strncmp(). */
|
| +
|
| + if (!option[ENUM])
|
| + {
|
| + Output_Defines style;
|
| + output_constants (style);
|
| + }
|
| + else if (option[GLOBAL])
|
| + {
|
| + Output_Enum style ("");
|
| + output_constants (style);
|
| + }
|
| +
|
| + printf ("/* maximum key range = %d, duplicates = %d */\n\n",
|
| + _max_hash_value - _min_hash_value + 1, _total_duplicates);
|
| +
|
| + if (option[UPPERLOWER])
|
| + {
|
| + #if USE_DOWNCASE_TABLE
|
| + output_upperlower_table ();
|
| + #endif
|
| +
|
| + if (option[LENTABLE])
|
| + output_upperlower_memcmp ();
|
| + else
|
| + {
|
| + if (option[COMP])
|
| + output_upperlower_strncmp ();
|
| + else
|
| + output_upperlower_strcmp ();
|
| + }
|
| + }
|
| +
|
| + if (option[CPLUSPLUS])
|
| + printf ("class %s\n"
|
| + "{\n"
|
| + "private:\n"
|
| + " static inline unsigned int %s (const char *str, unsigned int len);\n"
|
| + "public:\n"
|
| + " static %s%s%s (const char *str, unsigned int len);\n"
|
| + "};\n"
|
| + "\n",
|
| + option.get_class_name (), option.get_hash_name (),
|
| + const_for_struct, _return_type, option.get_function_name ());
|
| +
|
| + output_hash_function ();
|
| +
|
| + if (option[SHAREDLIB] && (option[GLOBAL] || option[TYPE]))
|
| + output_lookup_pools ();
|
| + if (option[GLOBAL])
|
| + output_lookup_tables ();
|
| +
|
| + output_lookup_function ();
|
| +
|
| + if (_verbatim_code < _verbatim_code_end)
|
| + {
|
| + if (option.get_input_file_name ())
|
| + printf ("#line %u \"%s\"\n",
|
| + _verbatim_code_lineno, option.get_input_file_name ());
|
| + fwrite (_verbatim_code, 1, _verbatim_code_end - _verbatim_code, stdout);
|
| + }
|
| +
|
| + fflush (stdout);
|
| +}
|
|
|
| Property changes on: gperf\src\gperf\3.0.1\gperf-3.0.1-src\src\output.cc
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|