output.cc revision 228060
1228060Sbapt/* Output routines.
2228060Sbapt   Copyright (C) 1989-1998, 2000, 2002-2004, 2006-2007 Free Software Foundation, Inc.
3228060Sbapt   Written by Douglas C. Schmidt <schmidt@ics.uci.edu>
4228060Sbapt   and Bruno Haible <bruno@clisp.org>.
5228060Sbapt
6228060Sbapt   This file is part of GNU GPERF.
7228060Sbapt
8228060Sbapt   GNU GPERF is free software; you can redistribute it and/or modify
9228060Sbapt   it under the terms of the GNU General Public License as published by
10228060Sbapt   the Free Software Foundation; either version 2, or (at your option)
11228060Sbapt   any later version.
12228060Sbapt
13228060Sbapt   GNU GPERF is distributed in the hope that it will be useful,
14228060Sbapt   but WITHOUT ANY WARRANTY; without even the implied warranty of
15228060Sbapt   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16228060Sbapt   GNU General Public License for more details.
17228060Sbapt
18228060Sbapt   You should have received a copy of the GNU General Public License
19228060Sbapt   along with this program; see the file COPYING.
20228060Sbapt   If not, write to the Free Software Foundation, Inc.,
21228060Sbapt   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
22228060Sbapt
23228060Sbapt/* Specification. */
24228060Sbapt#include "output.h"
25228060Sbapt
26228060Sbapt#include <stdio.h>
27228060Sbapt#include <string.h> /* declares strncpy(), strchr() */
28228060Sbapt#include <ctype.h>  /* declares isprint() */
29228060Sbapt#include <assert.h> /* defines assert() */
30228060Sbapt#include <limits.h> /* defines SCHAR_MAX etc. */
31228060Sbapt#include "options.h"
32228060Sbapt#include "version.h"
33228060Sbapt
34228060Sbapt/* The "const " qualifier.  */
35228060Sbaptstatic const char *const_always;
36228060Sbapt
37228060Sbapt/* The "const " qualifier, for read-only arrays.  */
38228060Sbaptstatic const char *const_readonly_array;
39228060Sbapt
40228060Sbapt/* The "const " qualifier, for the array type.  */
41228060Sbaptstatic const char *const_for_struct;
42228060Sbapt
43228060Sbapt/* Returns the smallest unsigned C type capable of holding integers
44228060Sbapt   up to N.  */
45228060Sbapt
46228060Sbaptstatic const char *
47228060Sbaptsmallest_integral_type (int n)
48228060Sbapt{
49228060Sbapt  if (n <= UCHAR_MAX) return "unsigned char";
50228060Sbapt  if (n <= USHRT_MAX) return "unsigned short";
51228060Sbapt  return "unsigned int";
52228060Sbapt}
53228060Sbapt
54228060Sbapt/* Returns the smallest signed C type capable of holding integers
55228060Sbapt   from MIN to MAX.  */
56228060Sbapt
57228060Sbaptstatic const char *
58228060Sbaptsmallest_integral_type (int min, int max)
59228060Sbapt{
60228060Sbapt  if (option[ANSIC] | option[CPLUSPLUS])
61228060Sbapt    if (min >= SCHAR_MIN && max <= SCHAR_MAX) return "signed char";
62228060Sbapt  if (min >= SHRT_MIN && max <= SHRT_MAX) return "short";
63228060Sbapt  return "int";
64228060Sbapt}
65228060Sbapt
66228060Sbapt/* ------------------------------------------------------------------------- */
67228060Sbapt
68228060Sbapt/* Constructor.
69228060Sbapt   Note about the keyword list starting at head:
70228060Sbapt   - The list is ordered by increasing _hash_value.  This has been achieved
71228060Sbapt     by Search::sort().
72228060Sbapt   - Duplicates, i.e. keywords with the same _selchars set, are chained
73228060Sbapt     through the _duplicate_link pointer.  Only one representative per
74228060Sbapt     duplicate equivalence class remains on the linear keyword list.
75228060Sbapt   - Accidental duplicates, i.e. keywords for which the _asso_values[] search
76228060Sbapt     couldn't achieve different hash values, cannot occur on the linear
77228060Sbapt     keyword list.  Search::optimize would catch this mistake.
78228060Sbapt */
79228060SbaptOutput::Output (KeywordExt_List *head, const char *struct_decl,
80228060Sbapt                unsigned int struct_decl_lineno, const char *return_type,
81228060Sbapt                const char *struct_tag, const char *verbatim_declarations,
82228060Sbapt                const char *verbatim_declarations_end,
83228060Sbapt                unsigned int verbatim_declarations_lineno,
84228060Sbapt                const char *verbatim_code, const char *verbatim_code_end,
85228060Sbapt                unsigned int verbatim_code_lineno, bool charset_dependent,
86228060Sbapt                int total_keys, int max_key_len, int min_key_len,
87228060Sbapt                const Positions& positions, const unsigned int *alpha_inc,
88228060Sbapt                int total_duplicates, unsigned int alpha_size,
89228060Sbapt                const int *asso_values)
90228060Sbapt  : _head (head), _struct_decl (struct_decl),
91228060Sbapt    _struct_decl_lineno (struct_decl_lineno), _return_type (return_type),
92228060Sbapt    _struct_tag (struct_tag),
93228060Sbapt    _verbatim_declarations (verbatim_declarations),
94228060Sbapt    _verbatim_declarations_end (verbatim_declarations_end),
95228060Sbapt    _verbatim_declarations_lineno (verbatim_declarations_lineno),
96228060Sbapt    _verbatim_code (verbatim_code),
97228060Sbapt    _verbatim_code_end (verbatim_code_end),
98228060Sbapt    _verbatim_code_lineno (verbatim_code_lineno),
99228060Sbapt    _charset_dependent (charset_dependent),
100228060Sbapt    _total_keys (total_keys),
101228060Sbapt    _max_key_len (max_key_len), _min_key_len (min_key_len),
102228060Sbapt    _key_positions (positions), _alpha_inc (alpha_inc),
103228060Sbapt    _total_duplicates (total_duplicates), _alpha_size (alpha_size),
104228060Sbapt    _asso_values (asso_values)
105228060Sbapt{
106228060Sbapt}
107228060Sbapt
108228060Sbapt/* ------------------------------------------------------------------------- */
109228060Sbapt
110228060Sbapt/* Computes the minimum and maximum hash values, and stores them
111228060Sbapt   in _min_hash_value and _max_hash_value.  */
112228060Sbapt
113228060Sbaptvoid
114228060SbaptOutput::compute_min_max ()
115228060Sbapt{
116228060Sbapt  /* Since the list is already sorted by hash value all we need to do is
117228060Sbapt     to look at the first and the last element of the list.  */
118228060Sbapt
119228060Sbapt  _min_hash_value = _head->first()->_hash_value;
120228060Sbapt
121228060Sbapt  KeywordExt_List *temp;
122228060Sbapt  for (temp = _head; temp->rest(); temp = temp->rest())
123228060Sbapt    ;
124228060Sbapt  _max_hash_value = temp->first()->_hash_value;
125228060Sbapt}
126228060Sbapt
127228060Sbapt/* ------------------------------------------------------------------------- */
128228060Sbapt
129228060Sbapt/* Returns the number of different hash values.  */
130228060Sbapt
131228060Sbaptint
132228060SbaptOutput::num_hash_values () const
133228060Sbapt{
134228060Sbapt  /* Since the list is already sorted by hash value and doesn't contain
135228060Sbapt     duplicates, we can simply count the number of keywords on the list.  */
136228060Sbapt  int count = 0;
137228060Sbapt  for (KeywordExt_List *temp = _head; temp; temp = temp->rest())
138228060Sbapt    count++;
139228060Sbapt  return count;
140228060Sbapt}
141228060Sbapt
142228060Sbapt/* -------------------- Output_Constants and subclasses -------------------- */
143228060Sbapt
144228060Sbapt/* This class outputs an enumeration defining some constants.  */
145228060Sbapt
146228060Sbaptstruct Output_Constants
147228060Sbapt{
148228060Sbapt  virtual void          output_start () = 0;
149228060Sbapt  virtual void          output_item (const char *name, int value) = 0;
150228060Sbapt  virtual void          output_end () = 0;
151228060Sbapt                        Output_Constants () {}
152228060Sbapt  virtual               ~Output_Constants () {}
153228060Sbapt};
154228060Sbapt
155228060Sbapt/* This class outputs an enumeration in #define syntax.  */
156228060Sbapt
157228060Sbaptstruct Output_Defines : public Output_Constants
158228060Sbapt{
159228060Sbapt  virtual void          output_start ();
160228060Sbapt  virtual void          output_item (const char *name, int value);
161228060Sbapt  virtual void          output_end ();
162228060Sbapt                        Output_Defines () {}
163228060Sbapt  virtual               ~Output_Defines () {}
164228060Sbapt};
165228060Sbapt
166228060Sbaptvoid Output_Defines::output_start ()
167228060Sbapt{
168228060Sbapt  printf ("\n");
169228060Sbapt}
170228060Sbapt
171228060Sbaptvoid Output_Defines::output_item (const char *name, int value)
172228060Sbapt{
173228060Sbapt  printf ("#define %s %d\n", name, value);
174228060Sbapt}
175228060Sbapt
176228060Sbaptvoid Output_Defines::output_end ()
177228060Sbapt{
178228060Sbapt}
179228060Sbapt
180228060Sbapt/* This class outputs an enumeration using 'enum'.  */
181228060Sbapt
182228060Sbaptstruct Output_Enum : public Output_Constants
183228060Sbapt{
184228060Sbapt  virtual void          output_start ();
185228060Sbapt  virtual void          output_item (const char *name, int value);
186228060Sbapt  virtual void          output_end ();
187228060Sbapt                        Output_Enum (const char *indent)
188228060Sbapt                          : _indentation (indent) {}
189228060Sbapt  virtual               ~Output_Enum () {}
190228060Sbaptprivate:
191228060Sbapt  const char *_indentation;
192228060Sbapt  bool _pending_comma;
193228060Sbapt};
194228060Sbapt
195228060Sbaptvoid Output_Enum::output_start ()
196228060Sbapt{
197228060Sbapt  printf ("%senum\n"
198228060Sbapt          "%s  {\n",
199228060Sbapt          _indentation, _indentation);
200228060Sbapt  _pending_comma = false;
201228060Sbapt}
202228060Sbapt
203228060Sbaptvoid Output_Enum::output_item (const char *name, int value)
204228060Sbapt{
205228060Sbapt  if (_pending_comma)
206228060Sbapt    printf (",\n");
207228060Sbapt  printf ("%s    %s = %d", _indentation, name, value);
208228060Sbapt  _pending_comma = true;
209228060Sbapt}
210228060Sbapt
211228060Sbaptvoid Output_Enum::output_end ()
212228060Sbapt{
213228060Sbapt  if (_pending_comma)
214228060Sbapt    printf ("\n");
215228060Sbapt  printf ("%s  };\n\n", _indentation);
216228060Sbapt}
217228060Sbapt
218228060Sbapt/* Outputs the maximum and minimum hash values etc.  */
219228060Sbapt
220228060Sbaptvoid
221228060SbaptOutput::output_constants (struct Output_Constants& style) const
222228060Sbapt{
223228060Sbapt  style.output_start ();
224228060Sbapt  style.output_item ("TOTAL_KEYWORDS", _total_keys);
225228060Sbapt  style.output_item ("MIN_WORD_LENGTH", _min_key_len);
226228060Sbapt  style.output_item ("MAX_WORD_LENGTH", _max_key_len);
227228060Sbapt  style.output_item ("MIN_HASH_VALUE", _min_hash_value);
228228060Sbapt  style.output_item ("MAX_HASH_VALUE", _max_hash_value);
229228060Sbapt  style.output_end ();
230228060Sbapt}
231228060Sbapt
232228060Sbapt/* ------------------------------------------------------------------------- */
233228060Sbapt
234228060Sbapt/* We use a downcase table because when called repeatedly, the code
235228060Sbapt       gperf_downcase[c]
236228060Sbapt   is faster than
237228060Sbapt       if (c >= 'A' && c <= 'Z')
238228060Sbapt         c += 'a' - 'A';
239228060Sbapt */
240228060Sbapt#define USE_DOWNCASE_TABLE 1
241228060Sbapt
242228060Sbapt#if USE_DOWNCASE_TABLE
243228060Sbapt
244228060Sbapt/* Output gperf's ASCII-downcase table.  */
245228060Sbapt
246228060Sbaptstatic void
247228060Sbaptoutput_upperlower_table ()
248228060Sbapt{
249228060Sbapt  unsigned int c;
250228060Sbapt
251228060Sbapt  printf ("#ifndef GPERF_DOWNCASE\n"
252228060Sbapt          "#define GPERF_DOWNCASE 1\n"
253228060Sbapt          "static unsigned char gperf_downcase[256] =\n"
254228060Sbapt          "  {");
255228060Sbapt  for (c = 0; c < 256; c++)
256228060Sbapt    {
257228060Sbapt      if ((c % 15) == 0)
258228060Sbapt        printf ("\n   ");
259228060Sbapt      printf (" %3d", c >= 'A' && c <= 'Z' ? c + 'a' - 'A' : c);
260228060Sbapt      if (c < 255)
261228060Sbapt        printf (",");
262228060Sbapt    }
263228060Sbapt  printf ("\n"
264228060Sbapt          "  };\n"
265228060Sbapt          "#endif\n\n");
266228060Sbapt}
267228060Sbapt
268228060Sbapt#endif
269228060Sbapt
270228060Sbapt/* Output gperf's ASCII-case insensitive strcmp replacement.  */
271228060Sbapt
272228060Sbaptstatic void
273228060Sbaptoutput_upperlower_strcmp ()
274228060Sbapt{
275228060Sbapt  printf ("#ifndef GPERF_CASE_STRCMP\n"
276228060Sbapt          "#define GPERF_CASE_STRCMP 1\n"
277228060Sbapt          "static int\n"
278228060Sbapt          "gperf_case_strcmp ");
279228060Sbapt  printf (option[KRC] ?
280228060Sbapt               "(s1, s2)\n"
281228060Sbapt          "     register char *s1;\n"
282228060Sbapt          "     register char *s2;\n" :
283228060Sbapt          option[C] ?
284228060Sbapt               "(s1, s2)\n"
285228060Sbapt          "     register const char *s1;\n"
286228060Sbapt          "     register const char *s2;\n" :
287228060Sbapt          option[ANSIC] | option[CPLUSPLUS] ?
288228060Sbapt               "(register const char *s1, register const char *s2)\n" :
289228060Sbapt          "");
290228060Sbapt  #if USE_DOWNCASE_TABLE
291228060Sbapt  printf ("{\n"
292228060Sbapt          "  for (;;)\n"
293228060Sbapt          "    {\n"
294228060Sbapt          "      unsigned char c1 = gperf_downcase[(unsigned char)*s1++];\n"
295228060Sbapt          "      unsigned char c2 = gperf_downcase[(unsigned char)*s2++];\n"
296228060Sbapt          "      if (c1 != 0 && c1 == c2)\n"
297228060Sbapt          "        continue;\n"
298228060Sbapt          "      return (int)c1 - (int)c2;\n"
299228060Sbapt          "    }\n"
300228060Sbapt          "}\n");
301228060Sbapt  #else
302228060Sbapt  printf ("{\n"
303228060Sbapt          "  for (;;)\n"
304228060Sbapt          "    {\n"
305228060Sbapt          "      unsigned char c1 = *s1++;\n"
306228060Sbapt          "      unsigned char c2 = *s2++;\n"
307228060Sbapt          "      if (c1 >= 'A' && c1 <= 'Z')\n"
308228060Sbapt          "        c1 += 'a' - 'A';\n"
309228060Sbapt          "      if (c2 >= 'A' && c2 <= 'Z')\n"
310228060Sbapt          "        c2 += 'a' - 'A';\n"
311228060Sbapt          "      if (c1 != 0 && c1 == c2)\n"
312228060Sbapt          "        continue;\n"
313228060Sbapt          "      return (int)c1 - (int)c2;\n"
314228060Sbapt          "    }\n"
315228060Sbapt          "}\n");
316228060Sbapt  #endif
317228060Sbapt  printf ("#endif\n\n");
318228060Sbapt}
319228060Sbapt
320228060Sbapt/* Output gperf's ASCII-case insensitive strncmp replacement.  */
321228060Sbapt
322228060Sbaptstatic void
323228060Sbaptoutput_upperlower_strncmp ()
324228060Sbapt{
325228060Sbapt  printf ("#ifndef GPERF_CASE_STRNCMP\n"
326228060Sbapt          "#define GPERF_CASE_STRNCMP 1\n"
327228060Sbapt          "static int\n"
328228060Sbapt          "gperf_case_strncmp ");
329228060Sbapt  printf (option[KRC] ?
330228060Sbapt               "(s1, s2, n)\n"
331228060Sbapt          "     register char *s1;\n"
332228060Sbapt          "     register char *s2;\n"
333228060Sbapt          "     register unsigned int n;\n" :
334228060Sbapt          option[C] ?
335228060Sbapt               "(s1, s2, n)\n"
336228060Sbapt          "     register const char *s1;\n"
337228060Sbapt          "     register const char *s2;\n"
338228060Sbapt          "     register unsigned int n;\n" :
339228060Sbapt          option[ANSIC] | option[CPLUSPLUS] ?
340228060Sbapt               "(register const char *s1, register const char *s2, register unsigned int n)\n" :
341228060Sbapt          "");
342228060Sbapt  #if USE_DOWNCASE_TABLE
343228060Sbapt  printf ("{\n"
344228060Sbapt          "  for (; n > 0;)\n"
345228060Sbapt          "    {\n"
346228060Sbapt          "      unsigned char c1 = gperf_downcase[(unsigned char)*s1++];\n"
347228060Sbapt          "      unsigned char c2 = gperf_downcase[(unsigned char)*s2++];\n"
348228060Sbapt          "      if (c1 != 0 && c1 == c2)\n"
349228060Sbapt          "        {\n"
350228060Sbapt          "          n--;\n"
351228060Sbapt          "          continue;\n"
352228060Sbapt          "        }\n"
353228060Sbapt          "      return (int)c1 - (int)c2;\n"
354228060Sbapt          "    }\n"
355228060Sbapt          "  return 0;\n"
356228060Sbapt          "}\n");
357228060Sbapt  #else
358228060Sbapt  printf ("{\n"
359228060Sbapt          "  for (; n > 0;)\n"
360228060Sbapt          "    {\n"
361228060Sbapt          "      unsigned char c1 = *s1++;\n"
362228060Sbapt          "      unsigned char c2 = *s2++;\n"
363228060Sbapt          "      if (c1 >= 'A' && c1 <= 'Z')\n"
364228060Sbapt          "        c1 += 'a' - 'A';\n"
365228060Sbapt          "      if (c2 >= 'A' && c2 <= 'Z')\n"
366228060Sbapt          "        c2 += 'a' - 'A';\n"
367228060Sbapt          "      if (c1 != 0 && c1 == c2)\n"
368228060Sbapt          "        {\n"
369228060Sbapt          "          n--;\n"
370228060Sbapt          "          continue;\n"
371228060Sbapt          "        }\n"
372228060Sbapt          "      return (int)c1 - (int)c2;\n"
373228060Sbapt          "    }\n"
374228060Sbapt          "  return 0;\n"
375228060Sbapt          "}\n");
376228060Sbapt  #endif
377228060Sbapt  printf ("#endif\n\n");
378228060Sbapt}
379228060Sbapt
380228060Sbapt/* Output gperf's ASCII-case insensitive memcmp replacement.  */
381228060Sbapt
382228060Sbaptstatic void
383228060Sbaptoutput_upperlower_memcmp ()
384228060Sbapt{
385228060Sbapt  printf ("#ifndef GPERF_CASE_MEMCMP\n"
386228060Sbapt          "#define GPERF_CASE_MEMCMP 1\n"
387228060Sbapt          "static int\n"
388228060Sbapt          "gperf_case_memcmp ");
389228060Sbapt  printf (option[KRC] ?
390228060Sbapt               "(s1, s2, n)\n"
391228060Sbapt          "     register char *s1;\n"
392228060Sbapt          "     register char *s2;\n"
393228060Sbapt          "     register unsigned int n;\n" :
394228060Sbapt          option[C] ?
395228060Sbapt               "(s1, s2, n)\n"
396228060Sbapt          "     register const char *s1;\n"
397228060Sbapt          "     register const char *s2;\n"
398228060Sbapt          "     register unsigned int n;\n" :
399228060Sbapt          option[ANSIC] | option[CPLUSPLUS] ?
400228060Sbapt               "(register const char *s1, register const char *s2, register unsigned int n)\n" :
401228060Sbapt          "");
402228060Sbapt  #if USE_DOWNCASE_TABLE
403228060Sbapt  printf ("{\n"
404228060Sbapt          "  for (; n > 0;)\n"
405228060Sbapt          "    {\n"
406228060Sbapt          "      unsigned char c1 = gperf_downcase[(unsigned char)*s1++];\n"
407228060Sbapt          "      unsigned char c2 = gperf_downcase[(unsigned char)*s2++];\n"
408228060Sbapt          "      if (c1 == c2)\n"
409228060Sbapt          "        {\n"
410228060Sbapt          "          n--;\n"
411228060Sbapt          "          continue;\n"
412228060Sbapt          "        }\n"
413228060Sbapt          "      return (int)c1 - (int)c2;\n"
414228060Sbapt          "    }\n"
415228060Sbapt          "  return 0;\n"
416228060Sbapt          "}\n");
417228060Sbapt  #else
418228060Sbapt  printf ("{\n"
419228060Sbapt          "  for (; n > 0;)\n"
420228060Sbapt          "    {\n"
421228060Sbapt          "      unsigned char c1 = *s1++;\n"
422228060Sbapt          "      unsigned char c2 = *s2++;\n"
423228060Sbapt          "      if (c1 >= 'A' && c1 <= 'Z')\n"
424228060Sbapt          "        c1 += 'a' - 'A';\n"
425228060Sbapt          "      if (c2 >= 'A' && c2 <= 'Z')\n"
426228060Sbapt          "        c2 += 'a' - 'A';\n"
427228060Sbapt          "      if (c1 == c2)\n"
428228060Sbapt          "        {\n"
429228060Sbapt          "          n--;\n"
430228060Sbapt          "          continue;\n"
431228060Sbapt          "        }\n"
432228060Sbapt          "      return (int)c1 - (int)c2;\n"
433228060Sbapt          "    }\n"
434228060Sbapt          "  return 0;\n"
435228060Sbapt          "}\n");
436228060Sbapt  #endif
437228060Sbapt  printf ("#endif\n\n");
438228060Sbapt}
439228060Sbapt
440228060Sbapt/* ------------------------------------------------------------------------- */
441228060Sbapt
442228060Sbapt/* Outputs a keyword, as a string: enclosed in double quotes, escaping
443228060Sbapt   backslashes, double quote and unprintable characters.  */
444228060Sbapt
445228060Sbaptstatic void
446228060Sbaptoutput_string (const char *key, int len)
447228060Sbapt{
448228060Sbapt  putchar ('"');
449228060Sbapt  for (; len > 0; len--)
450228060Sbapt    {
451228060Sbapt      unsigned char c = static_cast<unsigned char>(*key++);
452228060Sbapt      if (isprint (c))
453228060Sbapt        {
454228060Sbapt          if (c == '"' || c == '\\')
455228060Sbapt            putchar ('\\');
456228060Sbapt          putchar (c);
457228060Sbapt        }
458228060Sbapt      else
459228060Sbapt        {
460228060Sbapt          /* Use octal escapes, not hexadecimal escapes, because some old
461228060Sbapt             C compilers didn't understand hexadecimal escapes, and because
462228060Sbapt             hexadecimal escapes are not limited to 2 digits, thus needing
463228060Sbapt             special care if the following character happens to be a digit.  */
464228060Sbapt          putchar ('\\');
465228060Sbapt          putchar ('0' + ((c >> 6) & 7));
466228060Sbapt          putchar ('0' + ((c >> 3) & 7));
467228060Sbapt          putchar ('0' + (c & 7));
468228060Sbapt        }
469228060Sbapt    }
470228060Sbapt  putchar ('"');
471228060Sbapt}
472228060Sbapt
473228060Sbapt/* ------------------------------------------------------------------------- */
474228060Sbapt
475228060Sbapt/* Outputs a #line directive, referring to the given line number.  */
476228060Sbapt
477228060Sbaptstatic void
478228060Sbaptoutput_line_directive (unsigned int lineno)
479228060Sbapt{
480228060Sbapt  const char *file_name = option.get_input_file_name ();
481228060Sbapt  if (file_name != NULL)
482228060Sbapt    {
483228060Sbapt      printf ("#line %u ", lineno);
484228060Sbapt      output_string (file_name, strlen (file_name));
485228060Sbapt      printf ("\n");
486228060Sbapt    }
487228060Sbapt}
488228060Sbapt
489228060Sbapt/* ------------------------------------------------------------------------- */
490228060Sbapt
491228060Sbapt/* Outputs a type and a const specifier (i.e. "const " or "").
492228060Sbapt   The output is terminated with a space.  */
493228060Sbapt
494228060Sbaptstatic void
495228060Sbaptoutput_const_type (const char *const_string, const char *type_string)
496228060Sbapt{
497228060Sbapt  if (type_string[strlen(type_string)-1] == '*')
498228060Sbapt    /* For pointer types, put the 'const' after the type.  */
499228060Sbapt    printf ("%s %s", type_string, const_string);
500228060Sbapt  else
501228060Sbapt    /* For scalar or struct types, put the 'const' before the type.  */
502228060Sbapt    printf ("%s%s ", const_string, type_string);
503228060Sbapt}
504228060Sbapt
505228060Sbapt/* ----------------------- Output_Expr and subclasses ----------------------- */
506228060Sbapt
507228060Sbapt/* This class outputs a general expression.  */
508228060Sbapt
509228060Sbaptstruct Output_Expr
510228060Sbapt{
511228060Sbapt  virtual void          output_expr () const = 0;
512228060Sbapt                        Output_Expr () {}
513228060Sbapt  virtual               ~Output_Expr () {}
514228060Sbapt};
515228060Sbapt
516228060Sbapt/* This class outputs an expression formed by a single string.  */
517228060Sbapt
518228060Sbaptstruct Output_Expr1 : public Output_Expr
519228060Sbapt{
520228060Sbapt  virtual void          output_expr () const;
521228060Sbapt                        Output_Expr1 (const char *piece1) : _p1 (piece1) {}
522228060Sbapt  virtual               ~Output_Expr1 () {}
523228060Sbaptprivate:
524228060Sbapt  const char *_p1;
525228060Sbapt};
526228060Sbapt
527228060Sbaptvoid Output_Expr1::output_expr () const
528228060Sbapt{
529228060Sbapt  printf ("%s", _p1);
530228060Sbapt}
531228060Sbapt
532228060Sbapt#if 0 /* unused */
533228060Sbapt
534228060Sbapt/* This class outputs an expression formed by the concatenation of two
535228060Sbapt   strings.  */
536228060Sbapt
537228060Sbaptstruct Output_Expr2 : public Output_Expr
538228060Sbapt{
539228060Sbapt  virtual void          output_expr () const;
540228060Sbapt                        Output_Expr2 (const char *piece1, const char *piece2)
541228060Sbapt                          : _p1 (piece1), _p2 (piece2) {}
542228060Sbapt  virtual               ~Output_Expr2 () {}
543228060Sbaptprivate:
544228060Sbapt  const char *_p1;
545228060Sbapt  const char *_p2;
546228060Sbapt};
547228060Sbapt
548228060Sbaptvoid Output_Expr2::output_expr () const
549228060Sbapt{
550228060Sbapt  printf ("%s%s", _p1, _p2);
551228060Sbapt}
552228060Sbapt
553228060Sbapt#endif
554228060Sbapt
555228060Sbapt/* --------------------- Output_Compare and subclasses --------------------- */
556228060Sbapt
557228060Sbapt/* This class outputs a comparison expression.  */
558228060Sbapt
559228060Sbaptstruct Output_Compare
560228060Sbapt{
561228060Sbapt  /* Outputs the comparison expression.
562228060Sbapt     expr1 outputs a simple expression of type 'const char *' referring to
563228060Sbapt     the string being looked up.  expr2 outputs a simple expression of type
564228060Sbapt     'const char *' referring to the constant string stored in the gperf
565228060Sbapt     generated hash table.  */
566228060Sbapt  virtual void          output_comparison (const Output_Expr& expr1,
567228060Sbapt                                           const Output_Expr& expr2) const = 0;
568228060Sbapt  /* Outputs the comparison expression for the first byte.
569228060Sbapt     Returns true if the this comparison is complete.  */
570228060Sbapt  bool                  output_firstchar_comparison (const Output_Expr& expr1,
571228060Sbapt                                                     const Output_Expr& expr2) const;
572228060Sbapt                        Output_Compare () {}
573228060Sbapt  virtual               ~Output_Compare () {}
574228060Sbapt};
575228060Sbapt
576228060Sbaptbool Output_Compare::output_firstchar_comparison (const Output_Expr& expr1,
577228060Sbapt                                                  const Output_Expr& expr2) const
578228060Sbapt{
579228060Sbapt  /* First, we emit a comparison of the first byte of the two strings.
580228060Sbapt     This catches most cases where the string being looked up is not in the
581228060Sbapt     hash table but happens to have the same hash code as an element of the
582228060Sbapt     hash table.  */
583228060Sbapt  if (option[UPPERLOWER])
584228060Sbapt    {
585228060Sbapt      /* Incomplete comparison, just for speedup.  */
586228060Sbapt      printf ("(((unsigned char)*");
587228060Sbapt      expr1.output_expr ();
588228060Sbapt      printf (" ^ (unsigned char)*");
589228060Sbapt      expr2.output_expr ();
590228060Sbapt      printf (") & ~32) == 0");
591228060Sbapt      return false;
592228060Sbapt    }
593228060Sbapt  else
594228060Sbapt    {
595228060Sbapt      /* Complete comparison.  */
596228060Sbapt      printf ("*");
597228060Sbapt      expr1.output_expr ();
598228060Sbapt      printf (" == *");
599228060Sbapt      expr2.output_expr ();
600228060Sbapt      return true;
601228060Sbapt    }
602228060Sbapt}
603228060Sbapt
604228060Sbapt/* This class outputs a comparison using strcmp.  */
605228060Sbapt
606228060Sbaptstruct Output_Compare_Strcmp : public Output_Compare
607228060Sbapt{
608228060Sbapt  virtual void          output_comparison (const Output_Expr& expr1,
609228060Sbapt                                           const Output_Expr& expr2) const;
610228060Sbapt                        Output_Compare_Strcmp () {}
611228060Sbapt  virtual               ~Output_Compare_Strcmp () {}
612228060Sbapt};
613228060Sbapt
614228060Sbaptvoid Output_Compare_Strcmp::output_comparison (const Output_Expr& expr1,
615228060Sbapt                                               const Output_Expr& expr2) const
616228060Sbapt{
617228060Sbapt  bool firstchar_done = output_firstchar_comparison (expr1, expr2);
618228060Sbapt  printf (" && !");
619228060Sbapt  if (option[UPPERLOWER])
620228060Sbapt    printf ("gperf_case_");
621228060Sbapt  printf ("strcmp (");
622228060Sbapt  if (firstchar_done)
623228060Sbapt    {
624228060Sbapt      expr1.output_expr ();
625228060Sbapt      printf (" + 1, ");
626228060Sbapt      expr2.output_expr ();
627228060Sbapt      printf (" + 1");
628228060Sbapt    }
629228060Sbapt  else
630228060Sbapt    {
631228060Sbapt      expr1.output_expr ();
632228060Sbapt      printf (", ");
633228060Sbapt      expr2.output_expr ();
634228060Sbapt    }
635228060Sbapt  printf (")");
636228060Sbapt}
637228060Sbapt
638228060Sbapt/* This class outputs a comparison using strncmp.
639228060Sbapt   Note that the length of expr1 will be available through the local variable
640228060Sbapt   'len'.  */
641228060Sbapt
642228060Sbaptstruct Output_Compare_Strncmp : public Output_Compare
643228060Sbapt{
644228060Sbapt  virtual void          output_comparison (const Output_Expr& expr1,
645228060Sbapt                                           const Output_Expr& expr2) const;
646228060Sbapt                        Output_Compare_Strncmp () {}
647228060Sbapt  virtual               ~Output_Compare_Strncmp () {}
648228060Sbapt};
649228060Sbapt
650228060Sbaptvoid Output_Compare_Strncmp::output_comparison (const Output_Expr& expr1,
651228060Sbapt                                                const Output_Expr& expr2) const
652228060Sbapt{
653228060Sbapt  bool firstchar_done = output_firstchar_comparison (expr1, expr2);
654228060Sbapt  printf (" && !");
655228060Sbapt  if (option[UPPERLOWER])
656228060Sbapt    printf ("gperf_case_");
657228060Sbapt  printf ("strncmp (");
658228060Sbapt  if (firstchar_done)
659228060Sbapt    {
660228060Sbapt      expr1.output_expr ();
661228060Sbapt      printf (" + 1, ");
662228060Sbapt      expr2.output_expr ();
663228060Sbapt      printf (" + 1, len - 1");
664228060Sbapt    }
665228060Sbapt  else
666228060Sbapt    {
667228060Sbapt      expr1.output_expr ();
668228060Sbapt      printf (", ");
669228060Sbapt      expr2.output_expr ();
670228060Sbapt      printf (", len");
671228060Sbapt    }
672228060Sbapt  printf (") && ");
673228060Sbapt  expr2.output_expr ();
674228060Sbapt  printf ("[len] == '\\0'");
675228060Sbapt}
676228060Sbapt
677228060Sbapt/* This class outputs a comparison using memcmp.
678228060Sbapt   Note that the length of expr1 (available through the local variable 'len')
679228060Sbapt   must be verified to be equal to the length of expr2 prior to this
680228060Sbapt   comparison.  */
681228060Sbapt
682228060Sbaptstruct Output_Compare_Memcmp : public Output_Compare
683228060Sbapt{
684228060Sbapt  virtual void          output_comparison (const Output_Expr& expr1,
685228060Sbapt                                           const Output_Expr& expr2) const;
686228060Sbapt                        Output_Compare_Memcmp () {}
687228060Sbapt  virtual               ~Output_Compare_Memcmp () {}
688228060Sbapt};
689228060Sbapt
690228060Sbaptvoid Output_Compare_Memcmp::output_comparison (const Output_Expr& expr1,
691228060Sbapt                                               const Output_Expr& expr2) const
692228060Sbapt{
693228060Sbapt  bool firstchar_done = output_firstchar_comparison (expr1, expr2);
694228060Sbapt  printf (" && !");
695228060Sbapt  if (option[UPPERLOWER])
696228060Sbapt    printf ("gperf_case_");
697228060Sbapt  printf ("memcmp (");
698228060Sbapt  if (firstchar_done)
699228060Sbapt    {
700228060Sbapt      expr1.output_expr ();
701228060Sbapt      printf (" + 1, ");
702228060Sbapt      expr2.output_expr ();
703228060Sbapt      printf (" + 1, len - 1");
704228060Sbapt    }
705228060Sbapt  else
706228060Sbapt    {
707228060Sbapt      expr1.output_expr ();
708228060Sbapt      printf (", ");
709228060Sbapt      expr2.output_expr ();
710228060Sbapt      printf (", len");
711228060Sbapt    }
712228060Sbapt  printf (")");
713228060Sbapt}
714228060Sbapt
715228060Sbapt/* ------------------------------------------------------------------------- */
716228060Sbapt
717228060Sbapt/* Generates a C expression for an asso_values[] reference.  */
718228060Sbapt
719228060Sbaptvoid
720228060SbaptOutput::output_asso_values_ref (int pos) const
721228060Sbapt{
722228060Sbapt  printf ("asso_values[");
723228060Sbapt  /* Always cast to unsigned char.  This is necessary when the alpha_inc
724228060Sbapt     is nonzero, and also avoids a gcc warning "subscript has type 'char'".  */
725228060Sbapt  printf ("(unsigned char)");
726228060Sbapt  if (pos == Positions::LASTCHAR)
727228060Sbapt    printf ("str[len - 1]");
728228060Sbapt  else
729228060Sbapt    {
730228060Sbapt      printf ("str[%d]", pos);
731228060Sbapt      if (_alpha_inc[pos])
732228060Sbapt        printf ("+%u", _alpha_inc[pos]);
733228060Sbapt    }
734228060Sbapt  printf ("]");
735228060Sbapt}
736228060Sbapt
737228060Sbapt/* Generates C code for the hash function that returns the
738228060Sbapt   proper encoding for each keyword.
739228060Sbapt   The hash function has the signature
740228060Sbapt     unsigned int <hash> (const char *str, unsigned int len).  */
741228060Sbapt
742228060Sbaptvoid
743228060SbaptOutput::output_hash_function () const
744228060Sbapt{
745228060Sbapt  /* Output the function's head.  */
746228060Sbapt  if (option[CPLUSPLUS])
747228060Sbapt    printf ("inline ");
748228060Sbapt  else if (option[KRC] | option[C] | option[ANSIC])
749228060Sbapt    printf ("#ifdef __GNUC__\n"
750228060Sbapt            "__inline\n"
751228060Sbapt            "#else\n"
752228060Sbapt            "#ifdef __cplusplus\n"
753228060Sbapt            "inline\n"
754228060Sbapt            "#endif\n"
755228060Sbapt            "#endif\n");
756228060Sbapt
757228060Sbapt  if (/* The function does not use the 'str' argument?  */
758228060Sbapt      _key_positions.get_size() == 0
759228060Sbapt      || /* The function uses 'str', but not the 'len' argument?  */
760228060Sbapt         (option[NOLENGTH]
761228060Sbapt          && _key_positions[0] < _min_key_len
762228060Sbapt          && _key_positions[_key_positions.get_size() - 1] != Positions::LASTCHAR))
763228060Sbapt    /* Pacify lint.  */
764228060Sbapt    printf ("/*ARGSUSED*/\n");
765228060Sbapt
766228060Sbapt  if (option[KRC] | option[C] | option[ANSIC])
767228060Sbapt    printf ("static ");
768228060Sbapt  printf ("unsigned int\n");
769228060Sbapt  if (option[CPLUSPLUS])
770228060Sbapt    printf ("%s::", option.get_class_name ());
771228060Sbapt  printf ("%s ", option.get_hash_name ());
772228060Sbapt  printf (option[KRC] ?
773228060Sbapt                 "(str, len)\n"
774228060Sbapt            "     register char *str;\n"
775228060Sbapt            "     register unsigned int len;\n" :
776228060Sbapt          option[C] ?
777228060Sbapt                 "(str, len)\n"
778228060Sbapt            "     register const char *str;\n"
779228060Sbapt            "     register unsigned int len;\n" :
780228060Sbapt          option[ANSIC] | option[CPLUSPLUS] ?
781228060Sbapt                 "(register const char *str, register unsigned int len)\n" :
782228060Sbapt          "");
783228060Sbapt
784228060Sbapt  /* Note that when the hash function is called, it has already been verified
785228060Sbapt     that  min_key_len <= len <= max_key_len.  */
786228060Sbapt
787228060Sbapt  /* Output the function's body.  */
788228060Sbapt  printf ("{\n");
789228060Sbapt
790228060Sbapt  /* First the asso_values array.  */
791228060Sbapt  if (_key_positions.get_size() > 0)
792228060Sbapt    {
793228060Sbapt      printf ("  static %s%s asso_values[] =\n"
794228060Sbapt              "    {",
795228060Sbapt              const_readonly_array,
796228060Sbapt              smallest_integral_type (_max_hash_value + 1));
797228060Sbapt
798228060Sbapt      const int columns = 10;
799228060Sbapt
800228060Sbapt      /* Calculate maximum number of digits required for MAX_HASH_VALUE.  */
801228060Sbapt      int field_width = 2;
802228060Sbapt      for (int trunc = _max_hash_value; (trunc /= 10) > 0;)
803228060Sbapt        field_width++;
804228060Sbapt
805228060Sbapt      for (unsigned int count = 0; count < _alpha_size; count++)
806228060Sbapt        {
807228060Sbapt          if (count > 0)
808228060Sbapt            printf (",");
809228060Sbapt          if ((count % columns) == 0)
810228060Sbapt            printf ("\n     ");
811228060Sbapt          printf ("%*d", field_width, _asso_values[count]);
812228060Sbapt        }
813228060Sbapt
814228060Sbapt      printf ("\n"
815228060Sbapt              "    };\n");
816228060Sbapt    }
817228060Sbapt
818228060Sbapt  if (_key_positions.get_size() == 0)
819228060Sbapt    {
820228060Sbapt      /* Trivial case: No key positions at all.  */
821228060Sbapt      printf ("  return %s;\n",
822228060Sbapt              option[NOLENGTH] ? "0" : "len");
823228060Sbapt    }
824228060Sbapt  else
825228060Sbapt    {
826228060Sbapt      /* Iterate through the key positions.  Remember that Positions::sort()
827228060Sbapt         has sorted them in decreasing order, with Positions::LASTCHAR coming
828228060Sbapt         last.  */
829228060Sbapt      PositionIterator iter = _key_positions.iterator(_max_key_len);
830228060Sbapt      int key_pos;
831228060Sbapt
832228060Sbapt      /* Get the highest key position.  */
833228060Sbapt      key_pos = iter.next ();
834228060Sbapt
835228060Sbapt      if (key_pos == Positions::LASTCHAR || key_pos < _min_key_len)
836228060Sbapt        {
837228060Sbapt          /* We can perform additional optimizations here:
838228060Sbapt             Write it out as a single expression. Note that the values
839228060Sbapt             are added as 'int's even though the asso_values array may
840228060Sbapt             contain 'unsigned char's or 'unsigned short's.  */
841228060Sbapt
842228060Sbapt          printf ("  return %s",
843228060Sbapt                  option[NOLENGTH] ? "" : "len + ");
844228060Sbapt
845228060Sbapt          if (_key_positions.get_size() == 2
846228060Sbapt              && _key_positions[0] == 0
847228060Sbapt              && _key_positions[1] == Positions::LASTCHAR)
848228060Sbapt            /* Optimize special case of "-k 1,$".  */
849228060Sbapt            {
850228060Sbapt              output_asso_values_ref (Positions::LASTCHAR);
851228060Sbapt              printf (" + ");
852228060Sbapt              output_asso_values_ref (0);
853228060Sbapt            }
854228060Sbapt          else
855228060Sbapt            {
856228060Sbapt              for (; key_pos != Positions::LASTCHAR; )
857228060Sbapt                {
858228060Sbapt                  output_asso_values_ref (key_pos);
859228060Sbapt                  if ((key_pos = iter.next ()) != PositionIterator::EOS)
860228060Sbapt                    printf (" + ");
861228060Sbapt                  else
862228060Sbapt                    break;
863228060Sbapt                }
864228060Sbapt
865228060Sbapt              if (key_pos == Positions::LASTCHAR)
866228060Sbapt                output_asso_values_ref (Positions::LASTCHAR);
867228060Sbapt            }
868228060Sbapt
869228060Sbapt          printf (";\n");
870228060Sbapt        }
871228060Sbapt      else
872228060Sbapt        {
873228060Sbapt          /* We've got to use the correct, but brute force, technique.  */
874228060Sbapt          printf ("  register int hval = %s;\n\n"
875228060Sbapt                  "  switch (%s)\n"
876228060Sbapt                  "    {\n"
877228060Sbapt                  "      default:\n",
878228060Sbapt                  option[NOLENGTH] ? "0" : "len",
879228060Sbapt                  option[NOLENGTH] ? "len" : "hval");
880228060Sbapt
881228060Sbapt          while (key_pos != Positions::LASTCHAR && key_pos >= _max_key_len)
882228060Sbapt            if ((key_pos = iter.next ()) == PositionIterator::EOS)
883228060Sbapt              break;
884228060Sbapt
885228060Sbapt          if (key_pos != PositionIterator::EOS && key_pos != Positions::LASTCHAR)
886228060Sbapt            {
887228060Sbapt              int i = key_pos;
888228060Sbapt              do
889228060Sbapt                {
890228060Sbapt                  if (i > key_pos)
891228060Sbapt                    printf ("      /*FALLTHROUGH*/\n"); /* Pacify lint.  */
892228060Sbapt                  for ( ; i > key_pos; i--)
893228060Sbapt                    printf ("      case %d:\n", i);
894228060Sbapt
895228060Sbapt                  printf ("        hval += ");
896228060Sbapt                  output_asso_values_ref (key_pos);
897228060Sbapt                  printf (";\n");
898228060Sbapt
899228060Sbapt                  key_pos = iter.next ();
900228060Sbapt                }
901228060Sbapt              while (key_pos != PositionIterator::EOS && key_pos != Positions::LASTCHAR);
902228060Sbapt
903228060Sbapt              if (i >= _min_key_len)
904228060Sbapt                printf ("      /*FALLTHROUGH*/\n"); /* Pacify lint.  */
905228060Sbapt              for ( ; i >= _min_key_len; i--)
906228060Sbapt                printf ("      case %d:\n", i);
907228060Sbapt            }
908228060Sbapt
909228060Sbapt          printf ("        break;\n"
910228060Sbapt                  "    }\n"
911228060Sbapt                  "  return hval");
912228060Sbapt          if (key_pos == Positions::LASTCHAR)
913228060Sbapt            {
914228060Sbapt              printf (" + ");
915228060Sbapt              output_asso_values_ref (Positions::LASTCHAR);
916228060Sbapt            }
917228060Sbapt          printf (";\n");
918228060Sbapt        }
919228060Sbapt    }
920228060Sbapt  printf ("}\n\n");
921228060Sbapt}
922228060Sbapt
923228060Sbapt/* ------------------------------------------------------------------------- */
924228060Sbapt
925228060Sbapt/* Prints out a table of keyword lengths, for use with the
926228060Sbapt   comparison code in generated function 'in_word_set'.
927228060Sbapt   Only called if option[LENTABLE].  */
928228060Sbapt
929228060Sbaptvoid
930228060SbaptOutput::output_keylength_table () const
931228060Sbapt{
932228060Sbapt  const int columns = 14;
933228060Sbapt  const char * const indent = option[GLOBAL] ? "" : "  ";
934228060Sbapt
935228060Sbapt  printf ("%sstatic %s%s %s[] =\n"
936228060Sbapt          "%s  {",
937228060Sbapt          indent, const_readonly_array,
938228060Sbapt          smallest_integral_type (_max_key_len),
939228060Sbapt          option.get_lengthtable_name (),
940228060Sbapt          indent);
941228060Sbapt
942228060Sbapt  /* Generate an array of lengths, similar to output_keyword_table.  */
943228060Sbapt  int index;
944228060Sbapt  int column;
945228060Sbapt  KeywordExt_List *temp;
946228060Sbapt
947228060Sbapt  column = 0;
948228060Sbapt  for (temp = _head, index = 0; temp; temp = temp->rest())
949228060Sbapt    {
950228060Sbapt      KeywordExt *keyword = temp->first();
951228060Sbapt
952228060Sbapt      /* If generating a switch statement, and there is no user defined type,
953228060Sbapt         we generate non-duplicates directly in the code.  Only duplicates go
954228060Sbapt         into the table.  */
955228060Sbapt      if (option[SWITCH] && !option[TYPE] && !keyword->_duplicate_link)
956228060Sbapt        continue;
957228060Sbapt
958228060Sbapt      if (index < keyword->_hash_value && !option[SWITCH] && !option[DUP])
959228060Sbapt        {
960228060Sbapt          /* Some blank entries.  */
961228060Sbapt          for ( ; index < keyword->_hash_value; index++)
962228060Sbapt            {
963228060Sbapt              if (index > 0)
964228060Sbapt                printf (",");
965228060Sbapt              if ((column++ % columns) == 0)
966228060Sbapt                printf ("\n%s   ", indent);
967228060Sbapt              printf ("%3d", 0);
968228060Sbapt            }
969228060Sbapt        }
970228060Sbapt
971228060Sbapt      if (index > 0)
972228060Sbapt        printf (",");
973228060Sbapt      if ((column++ % columns) == 0)
974228060Sbapt        printf("\n%s   ", indent);
975228060Sbapt      printf ("%3d", keyword->_allchars_length);
976228060Sbapt      index++;
977228060Sbapt
978228060Sbapt      /* Deal with duplicates specially.  */
979228060Sbapt      if (keyword->_duplicate_link) // implies option[DUP]
980228060Sbapt        for (KeywordExt *links = keyword->_duplicate_link; links; links = links->_duplicate_link)
981228060Sbapt          {
982228060Sbapt            printf (",");
983228060Sbapt            if ((column++ % columns) == 0)
984228060Sbapt              printf("\n%s   ", indent);
985228060Sbapt            printf ("%3d", links->_allchars_length);
986228060Sbapt            index++;
987228060Sbapt          }
988228060Sbapt    }
989228060Sbapt
990228060Sbapt  printf ("\n%s  };\n", indent);
991228060Sbapt  if (option[GLOBAL])
992228060Sbapt    printf ("\n");
993228060Sbapt}
994228060Sbapt
995228060Sbapt/* ------------------------------------------------------------------------- */
996228060Sbapt
997228060Sbapt/* Prints out the string pool, containing the strings of the keyword table.
998228060Sbapt   Only called if option[SHAREDLIB].  */
999228060Sbapt
1000228060Sbaptvoid
1001228060SbaptOutput::output_string_pool () const
1002228060Sbapt{
1003228060Sbapt  const char * const indent = option[TYPE] || option[GLOBAL] ? "" : "  ";
1004228060Sbapt  int index;
1005228060Sbapt  KeywordExt_List *temp;
1006228060Sbapt
1007228060Sbapt  printf ("%sstruct %s_t\n"
1008228060Sbapt          "%s  {\n",
1009228060Sbapt          indent, option.get_stringpool_name (), indent);
1010228060Sbapt  for (temp = _head, index = 0; temp; temp = temp->rest())
1011228060Sbapt    {
1012228060Sbapt      KeywordExt *keyword = temp->first();
1013228060Sbapt
1014228060Sbapt      /* If generating a switch statement, and there is no user defined type,
1015228060Sbapt         we generate non-duplicates directly in the code.  Only duplicates go
1016228060Sbapt         into the table.  */
1017228060Sbapt      if (option[SWITCH] && !option[TYPE] && !keyword->_duplicate_link)
1018228060Sbapt        continue;
1019228060Sbapt
1020228060Sbapt      if (!option[SWITCH] && !option[DUP])
1021228060Sbapt        index = keyword->_hash_value;
1022228060Sbapt
1023228060Sbapt      printf ("%s    char %s_str%d[sizeof(",
1024228060Sbapt              indent, option.get_stringpool_name (), index);
1025228060Sbapt      output_string (keyword->_allchars, keyword->_allchars_length);
1026228060Sbapt      printf (")];\n");
1027228060Sbapt
1028228060Sbapt      /* Deal with duplicates specially.  */
1029228060Sbapt      if (keyword->_duplicate_link) // implies option[DUP]
1030228060Sbapt        for (KeywordExt *links = keyword->_duplicate_link; links; links = links->_duplicate_link)
1031228060Sbapt          if (!(links->_allchars_length == keyword->_allchars_length
1032228060Sbapt                && memcmp (links->_allchars, keyword->_allchars,
1033228060Sbapt                           keyword->_allchars_length) == 0))
1034228060Sbapt            {
1035228060Sbapt              index++;
1036228060Sbapt              printf ("%s    char %s_str%d[sizeof(",
1037228060Sbapt                      indent, option.get_stringpool_name (), index);
1038228060Sbapt              output_string (links->_allchars, links->_allchars_length);
1039228060Sbapt              printf (")];\n");
1040228060Sbapt            }
1041228060Sbapt
1042228060Sbapt      index++;
1043228060Sbapt    }
1044228060Sbapt  printf ("%s  };\n",
1045228060Sbapt          indent);
1046228060Sbapt
1047228060Sbapt  printf ("%sstatic %sstruct %s_t %s_contents =\n"
1048228060Sbapt          "%s  {\n",
1049228060Sbapt          indent, const_readonly_array, option.get_stringpool_name (),
1050228060Sbapt          option.get_stringpool_name (), indent);
1051228060Sbapt  for (temp = _head, index = 0; temp; temp = temp->rest())
1052228060Sbapt    {
1053228060Sbapt      KeywordExt *keyword = temp->first();
1054228060Sbapt
1055228060Sbapt      /* If generating a switch statement, and there is no user defined type,
1056228060Sbapt         we generate non-duplicates directly in the code.  Only duplicates go
1057228060Sbapt         into the table.  */
1058228060Sbapt      if (option[SWITCH] && !option[TYPE] && !keyword->_duplicate_link)
1059228060Sbapt        continue;
1060228060Sbapt
1061228060Sbapt      if (index > 0)
1062228060Sbapt        printf (",\n");
1063228060Sbapt
1064228060Sbapt      if (!option[SWITCH] && !option[DUP])
1065228060Sbapt        index = keyword->_hash_value;
1066228060Sbapt
1067228060Sbapt      printf ("%s    ",
1068228060Sbapt              indent);
1069228060Sbapt      output_string (keyword->_allchars, keyword->_allchars_length);
1070228060Sbapt
1071228060Sbapt      /* Deal with duplicates specially.  */
1072228060Sbapt      if (keyword->_duplicate_link) // implies option[DUP]
1073228060Sbapt        for (KeywordExt *links = keyword->_duplicate_link; links; links = links->_duplicate_link)
1074228060Sbapt          if (!(links->_allchars_length == keyword->_allchars_length
1075228060Sbapt                && memcmp (links->_allchars, keyword->_allchars,
1076228060Sbapt                           keyword->_allchars_length) == 0))
1077228060Sbapt            {
1078228060Sbapt              index++;
1079228060Sbapt              printf (",\n");
1080228060Sbapt              printf ("%s    ",
1081228060Sbapt                      indent);
1082228060Sbapt              output_string (links->_allchars, links->_allchars_length);
1083228060Sbapt            }
1084228060Sbapt
1085228060Sbapt      index++;
1086228060Sbapt    }
1087228060Sbapt  if (index > 0)
1088228060Sbapt    printf ("\n");
1089228060Sbapt  printf ("%s  };\n",
1090228060Sbapt          indent);
1091228060Sbapt  printf ("%s#define %s ((%schar *) &%s_contents)\n",
1092228060Sbapt          indent, option.get_stringpool_name (), const_always,
1093228060Sbapt          option.get_stringpool_name ());
1094228060Sbapt  if (option[GLOBAL])
1095228060Sbapt    printf ("\n");
1096228060Sbapt}
1097228060Sbapt
1098228060Sbapt/* ------------------------------------------------------------------------- */
1099228060Sbapt
1100228060Sbaptstatic void
1101228060Sbaptoutput_keyword_entry (KeywordExt *temp, int stringpool_index, const char *indent)
1102228060Sbapt{
1103228060Sbapt  if (option[TYPE])
1104228060Sbapt    output_line_directive (temp->_lineno);
1105228060Sbapt  printf ("%s    ", indent);
1106228060Sbapt  if (option[TYPE])
1107228060Sbapt    printf ("{");
1108228060Sbapt  if (option[SHAREDLIB])
1109228060Sbapt    printf ("(int)(long)&((struct %s_t *)0)->%s_str%d",
1110228060Sbapt            option.get_stringpool_name (), option.get_stringpool_name (),
1111228060Sbapt            stringpool_index);
1112228060Sbapt  else
1113228060Sbapt    output_string (temp->_allchars, temp->_allchars_length);
1114228060Sbapt  if (option[TYPE])
1115228060Sbapt    {
1116228060Sbapt      if (strlen (temp->_rest) > 0)
1117228060Sbapt        printf (",%s", temp->_rest);
1118228060Sbapt      printf ("}");
1119228060Sbapt    }
1120228060Sbapt  if (option[DEBUG])
1121228060Sbapt    printf (" /* hash value = %d, index = %d */",
1122228060Sbapt            temp->_hash_value, temp->_final_index);
1123228060Sbapt}
1124228060Sbapt
1125228060Sbaptstatic void
1126228060Sbaptoutput_keyword_blank_entries (int count, const char *indent)
1127228060Sbapt{
1128228060Sbapt  int columns;
1129228060Sbapt  if (option[TYPE])
1130228060Sbapt    {
1131228060Sbapt      columns = 58 / (4 + (option[SHAREDLIB] ? 2 : option[NULLSTRINGS] ? 8 : 2)
1132228060Sbapt                        + strlen (option.get_initializer_suffix()));
1133228060Sbapt      if (columns == 0)
1134228060Sbapt        columns = 1;
1135228060Sbapt    }
1136228060Sbapt  else
1137228060Sbapt    {
1138228060Sbapt      columns = (option[SHAREDLIB] ? 9 : option[NULLSTRINGS] ? 4 : 9);
1139228060Sbapt    }
1140228060Sbapt  int column = 0;
1141228060Sbapt  for (int i = 0; i < count; i++)
1142228060Sbapt    {
1143228060Sbapt      if ((column % columns) == 0)
1144228060Sbapt        {
1145228060Sbapt          if (i > 0)
1146228060Sbapt            printf (",\n");
1147228060Sbapt          printf ("%s    ", indent);
1148228060Sbapt        }
1149228060Sbapt      else
1150228060Sbapt        {
1151228060Sbapt          if (i > 0)
1152228060Sbapt            printf (", ");
1153228060Sbapt        }
1154228060Sbapt      if (option[TYPE])
1155228060Sbapt        printf ("{");
1156228060Sbapt      if (option[SHAREDLIB])
1157228060Sbapt        printf ("-1");
1158228060Sbapt      else
1159228060Sbapt        {
1160228060Sbapt          if (option[NULLSTRINGS])
1161228060Sbapt            printf ("(char*)0");
1162228060Sbapt          else
1163228060Sbapt            printf ("\"\"");
1164228060Sbapt        }
1165228060Sbapt      if (option[TYPE])
1166228060Sbapt        printf ("%s}", option.get_initializer_suffix());
1167228060Sbapt      column++;
1168228060Sbapt    }
1169228060Sbapt}
1170228060Sbapt
1171228060Sbapt/* Prints out the array containing the keywords for the hash function.  */
1172228060Sbapt
1173228060Sbaptvoid
1174228060SbaptOutput::output_keyword_table () const
1175228060Sbapt{
1176228060Sbapt  const char *indent  = option[GLOBAL] ? "" : "  ";
1177228060Sbapt  int index;
1178228060Sbapt  KeywordExt_List *temp;
1179228060Sbapt
1180228060Sbapt  printf ("%sstatic ",
1181228060Sbapt          indent);
1182228060Sbapt  output_const_type (const_readonly_array, _wordlist_eltype);
1183228060Sbapt  printf ("%s[] =\n"
1184228060Sbapt          "%s  {\n",
1185228060Sbapt          option.get_wordlist_name (),
1186228060Sbapt          indent);
1187228060Sbapt
1188228060Sbapt  /* Generate an array of reserved words at appropriate locations.  */
1189228060Sbapt
1190228060Sbapt  for (temp = _head, index = 0; temp; temp = temp->rest())
1191228060Sbapt    {
1192228060Sbapt      KeywordExt *keyword = temp->first();
1193228060Sbapt
1194228060Sbapt      /* If generating a switch statement, and there is no user defined type,
1195228060Sbapt         we generate non-duplicates directly in the code.  Only duplicates go
1196228060Sbapt         into the table.  */
1197228060Sbapt      if (option[SWITCH] && !option[TYPE] && !keyword->_duplicate_link)
1198228060Sbapt        continue;
1199228060Sbapt
1200228060Sbapt      if (index > 0)
1201228060Sbapt        printf (",\n");
1202228060Sbapt
1203228060Sbapt      if (index < keyword->_hash_value && !option[SWITCH] && !option[DUP])
1204228060Sbapt        {
1205228060Sbapt          /* Some blank entries.  */
1206228060Sbapt          output_keyword_blank_entries (keyword->_hash_value - index, indent);
1207228060Sbapt          printf (",\n");
1208228060Sbapt          index = keyword->_hash_value;
1209228060Sbapt        }
1210228060Sbapt
1211228060Sbapt      keyword->_final_index = index;
1212228060Sbapt
1213228060Sbapt      output_keyword_entry (keyword, index, indent);
1214228060Sbapt
1215228060Sbapt      /* Deal with duplicates specially.  */
1216228060Sbapt      if (keyword->_duplicate_link) // implies option[DUP]
1217228060Sbapt        for (KeywordExt *links = keyword->_duplicate_link; links; links = links->_duplicate_link)
1218228060Sbapt          {
1219228060Sbapt            links->_final_index = ++index;
1220228060Sbapt            printf (",\n");
1221228060Sbapt            int stringpool_index =
1222228060Sbapt              (links->_allchars_length == keyword->_allchars_length
1223228060Sbapt               && memcmp (links->_allchars, keyword->_allchars,
1224228060Sbapt                          keyword->_allchars_length) == 0
1225228060Sbapt               ? keyword->_final_index
1226228060Sbapt               : links->_final_index);
1227228060Sbapt            output_keyword_entry (links, stringpool_index, indent);
1228228060Sbapt          }
1229228060Sbapt
1230228060Sbapt      index++;
1231228060Sbapt    }
1232228060Sbapt  if (index > 0)
1233228060Sbapt    printf ("\n");
1234228060Sbapt
1235228060Sbapt  printf ("%s  };\n\n", indent);
1236228060Sbapt}
1237228060Sbapt
1238228060Sbapt/* ------------------------------------------------------------------------- */
1239228060Sbapt
1240228060Sbapt/* Generates the large, sparse table that maps hash values into
1241228060Sbapt   the smaller, contiguous range of the keyword table.  */
1242228060Sbapt
1243228060Sbaptvoid
1244228060SbaptOutput::output_lookup_array () const
1245228060Sbapt{
1246228060Sbapt  if (option[DUP])
1247228060Sbapt    {
1248228060Sbapt      const int DEFAULT_VALUE = -1;
1249228060Sbapt
1250228060Sbapt      /* Because of the way output_keyword_table works, every duplicate set is
1251228060Sbapt         stored contiguously in the wordlist array.  */
1252228060Sbapt      struct duplicate_entry
1253228060Sbapt        {
1254228060Sbapt          int hash_value; /* Hash value for this particular duplicate set.  */
1255228060Sbapt          int index;      /* Index into the main keyword storage array.  */
1256228060Sbapt          int count;      /* Number of consecutive duplicates at this index.  */
1257228060Sbapt        };
1258228060Sbapt
1259228060Sbapt      duplicate_entry *duplicates = new duplicate_entry[_total_duplicates];
1260228060Sbapt      int *lookup_array = new int[_max_hash_value + 1 + 2*_total_duplicates];
1261228060Sbapt      int lookup_array_size = _max_hash_value + 1;
1262228060Sbapt      duplicate_entry *dup_ptr = &duplicates[0];
1263228060Sbapt      int *lookup_ptr = &lookup_array[_max_hash_value + 1 + 2*_total_duplicates];
1264228060Sbapt
1265228060Sbapt      while (lookup_ptr > lookup_array)
1266228060Sbapt        *--lookup_ptr = DEFAULT_VALUE;
1267228060Sbapt
1268228060Sbapt      /* Now dup_ptr = &duplicates[0] and lookup_ptr = &lookup_array[0].  */
1269228060Sbapt
1270228060Sbapt      for (KeywordExt_List *temp = _head; temp; temp = temp->rest())
1271228060Sbapt        {
1272228060Sbapt          int hash_value = temp->first()->_hash_value;
1273228060Sbapt          lookup_array[hash_value] = temp->first()->_final_index;
1274228060Sbapt          if (option[DEBUG])
1275228060Sbapt            fprintf (stderr, "keyword = %.*s, index = %d\n",
1276228060Sbapt                     temp->first()->_allchars_length, temp->first()->_allchars, temp->first()->_final_index);
1277228060Sbapt          if (temp->first()->_duplicate_link)
1278228060Sbapt            {
1279228060Sbapt              /* Start a duplicate entry.  */
1280228060Sbapt              dup_ptr->hash_value = hash_value;
1281228060Sbapt              dup_ptr->index = temp->first()->_final_index;
1282228060Sbapt              dup_ptr->count = 1;
1283228060Sbapt
1284228060Sbapt              for (KeywordExt *ptr = temp->first()->_duplicate_link; ptr; ptr = ptr->_duplicate_link)
1285228060Sbapt                {
1286228060Sbapt                  dup_ptr->count++;
1287228060Sbapt                  if (option[DEBUG])
1288228060Sbapt                    fprintf (stderr,
1289228060Sbapt                             "static linked keyword = %.*s, index = %d\n",
1290228060Sbapt                             ptr->_allchars_length, ptr->_allchars, ptr->_final_index);
1291228060Sbapt                }
1292228060Sbapt              assert (dup_ptr->count >= 2);
1293228060Sbapt              dup_ptr++;
1294228060Sbapt            }
1295228060Sbapt        }
1296228060Sbapt
1297228060Sbapt      while (dup_ptr > duplicates)
1298228060Sbapt        {
1299228060Sbapt          dup_ptr--;
1300228060Sbapt
1301228060Sbapt          if (option[DEBUG])
1302228060Sbapt            fprintf (stderr,
1303228060Sbapt                     "dup_ptr[%d]: hash_value = %d, index = %d, count = %d\n",
1304228060Sbapt                     dup_ptr - duplicates,
1305228060Sbapt                     dup_ptr->hash_value, dup_ptr->index, dup_ptr->count);
1306228060Sbapt
1307228060Sbapt          int i;
1308228060Sbapt          /* Start searching for available space towards the right part
1309228060Sbapt             of the lookup array.  */
1310228060Sbapt          for (i = dup_ptr->hash_value; i < lookup_array_size-1; i++)
1311228060Sbapt            if (lookup_array[i] == DEFAULT_VALUE
1312228060Sbapt                && lookup_array[i + 1] == DEFAULT_VALUE)
1313228060Sbapt              goto found_i;
1314228060Sbapt          /* If we didn't find it to the right look to the left instead...  */
1315228060Sbapt          for (i = dup_ptr->hash_value-1; i >= 0; i--)
1316228060Sbapt            if (lookup_array[i] == DEFAULT_VALUE
1317228060Sbapt                && lookup_array[i + 1] == DEFAULT_VALUE)
1318228060Sbapt              goto found_i;
1319228060Sbapt          /* Append to the end of lookup_array.  */
1320228060Sbapt          i = lookup_array_size;
1321228060Sbapt          lookup_array_size += 2;
1322228060Sbapt        found_i:
1323228060Sbapt          /* Put in an indirection from dup_ptr->_hash_value to i.
1324228060Sbapt             At i and i+1 store dup_ptr->_final_index and dup_ptr->count.  */
1325228060Sbapt          assert (lookup_array[dup_ptr->hash_value] == dup_ptr->index);
1326228060Sbapt          lookup_array[dup_ptr->hash_value] = - 1 - _total_keys - i;
1327228060Sbapt          lookup_array[i] = - _total_keys + dup_ptr->index;
1328228060Sbapt          lookup_array[i + 1] = - dup_ptr->count;
1329228060Sbapt          /* All these three values are <= -2, distinct from DEFAULT_VALUE.  */
1330228060Sbapt        }
1331228060Sbapt
1332228060Sbapt      /* The values of the lookup array are now known.  */
1333228060Sbapt
1334228060Sbapt      int min = INT_MAX;
1335228060Sbapt      int max = INT_MIN;
1336228060Sbapt      lookup_ptr = lookup_array + lookup_array_size;
1337228060Sbapt      while (lookup_ptr > lookup_array)
1338228060Sbapt        {
1339228060Sbapt          int val = *--lookup_ptr;
1340228060Sbapt          if (min > val)
1341228060Sbapt            min = val;
1342228060Sbapt          if (max < val)
1343228060Sbapt            max = val;
1344228060Sbapt        }
1345228060Sbapt
1346228060Sbapt      const char *indent = option[GLOBAL] ? "" : "  ";
1347228060Sbapt      printf ("%sstatic %s%s lookup[] =\n"
1348228060Sbapt              "%s  {",
1349228060Sbapt              indent, const_readonly_array, smallest_integral_type (min, max),
1350228060Sbapt              indent);
1351228060Sbapt
1352228060Sbapt      int field_width;
1353228060Sbapt      /* Calculate maximum number of digits required for MIN..MAX.  */
1354228060Sbapt      {
1355228060Sbapt        field_width = 2;
1356228060Sbapt        for (int trunc = max; (trunc /= 10) > 0;)
1357228060Sbapt          field_width++;
1358228060Sbapt      }
1359228060Sbapt      if (min < 0)
1360228060Sbapt        {
1361228060Sbapt          int neg_field_width = 2;
1362228060Sbapt          for (int trunc = -min; (trunc /= 10) > 0;)
1363228060Sbapt            neg_field_width++;
1364228060Sbapt          neg_field_width++; /* account for the minus sign */
1365228060Sbapt          if (field_width < neg_field_width)
1366228060Sbapt            field_width = neg_field_width;
1367228060Sbapt        }
1368228060Sbapt
1369228060Sbapt      const int columns = 42 / field_width;
1370228060Sbapt      int column;
1371228060Sbapt
1372228060Sbapt      column = 0;
1373228060Sbapt      for (int i = 0; i < lookup_array_size; i++)
1374228060Sbapt        {
1375228060Sbapt          if (i > 0)
1376228060Sbapt            printf (",");
1377228060Sbapt          if ((column++ % columns) == 0)
1378228060Sbapt            printf("\n%s   ", indent);
1379228060Sbapt          printf ("%*d", field_width, lookup_array[i]);
1380228060Sbapt        }
1381228060Sbapt      printf ("\n%s  };\n\n", indent);
1382228060Sbapt
1383228060Sbapt      delete[] duplicates;
1384228060Sbapt      delete[] lookup_array;
1385228060Sbapt    }
1386228060Sbapt}
1387228060Sbapt
1388228060Sbapt/* ------------------------------------------------------------------------- */
1389228060Sbapt
1390228060Sbapt/* Generate all pools needed for the lookup function.  */
1391228060Sbapt
1392228060Sbaptvoid
1393228060SbaptOutput::output_lookup_pools () const
1394228060Sbapt{
1395228060Sbapt  if (option[SWITCH])
1396228060Sbapt    {
1397228060Sbapt      if (option[TYPE] || (option[DUP] && _total_duplicates > 0))
1398228060Sbapt        output_string_pool ();
1399228060Sbapt    }
1400228060Sbapt  else
1401228060Sbapt    {
1402228060Sbapt      output_string_pool ();
1403228060Sbapt    }
1404228060Sbapt}
1405228060Sbapt
1406228060Sbapt/* Generate all the tables needed for the lookup function.  */
1407228060Sbapt
1408228060Sbaptvoid
1409228060SbaptOutput::output_lookup_tables () const
1410228060Sbapt{
1411228060Sbapt  if (option[SWITCH])
1412228060Sbapt    {
1413228060Sbapt      /* Use the switch in place of lookup table.  */
1414228060Sbapt      if (option[LENTABLE] && (option[DUP] && _total_duplicates > 0))
1415228060Sbapt        output_keylength_table ();
1416228060Sbapt      if (option[TYPE] || (option[DUP] && _total_duplicates > 0))
1417228060Sbapt        output_keyword_table ();
1418228060Sbapt    }
1419228060Sbapt  else
1420228060Sbapt    {
1421228060Sbapt      /* Use the lookup table, in place of switch.  */
1422228060Sbapt      if (option[LENTABLE])
1423228060Sbapt        output_keylength_table ();
1424228060Sbapt      output_keyword_table ();
1425228060Sbapt      output_lookup_array ();
1426228060Sbapt    }
1427228060Sbapt}
1428228060Sbapt
1429228060Sbapt/* ------------------------------------------------------------------------- */
1430228060Sbapt
1431228060Sbapt/* Output a single switch case (including duplicates).  Advance list.  */
1432228060Sbapt
1433228060Sbaptstatic KeywordExt_List *
1434228060Sbaptoutput_switch_case (KeywordExt_List *list, int indent, int *jumps_away)
1435228060Sbapt{
1436228060Sbapt  if (option[DEBUG])
1437228060Sbapt    printf ("%*s/* hash value = %4d, keyword = \"%.*s\" */\n",
1438228060Sbapt            indent, "", list->first()->_hash_value, list->first()->_allchars_length, list->first()->_allchars);
1439228060Sbapt
1440228060Sbapt  if (option[DUP] && list->first()->_duplicate_link)
1441228060Sbapt    {
1442228060Sbapt      if (option[LENTABLE])
1443228060Sbapt        printf ("%*slengthptr = &%s[%d];\n",
1444228060Sbapt                indent, "", option.get_lengthtable_name (), list->first()->_final_index);
1445228060Sbapt      printf ("%*swordptr = &%s[%d];\n",
1446228060Sbapt              indent, "", option.get_wordlist_name (), list->first()->_final_index);
1447228060Sbapt
1448228060Sbapt      int count = 0;
1449228060Sbapt      for (KeywordExt *links = list->first(); links; links = links->_duplicate_link)
1450228060Sbapt        count++;
1451228060Sbapt
1452228060Sbapt      printf ("%*swordendptr = wordptr + %d;\n"
1453228060Sbapt              "%*sgoto multicompare;\n",
1454228060Sbapt              indent, "", count,
1455228060Sbapt              indent, "");
1456228060Sbapt      *jumps_away = 1;
1457228060Sbapt    }
1458228060Sbapt  else
1459228060Sbapt    {
1460228060Sbapt      if (option[LENTABLE])
1461228060Sbapt        {
1462228060Sbapt          printf ("%*sif (len == %d)\n"
1463228060Sbapt                  "%*s  {\n",
1464228060Sbapt                  indent, "", list->first()->_allchars_length,
1465228060Sbapt                  indent, "");
1466228060Sbapt          indent += 4;
1467228060Sbapt        }
1468228060Sbapt      printf ("%*sresword = ",
1469228060Sbapt              indent, "");
1470228060Sbapt      if (option[TYPE])
1471228060Sbapt        printf ("&%s[%d]", option.get_wordlist_name (), list->first()->_final_index);
1472228060Sbapt      else
1473228060Sbapt        output_string (list->first()->_allchars, list->first()->_allchars_length);
1474228060Sbapt      printf (";\n");
1475228060Sbapt      printf ("%*sgoto compare;\n",
1476228060Sbapt              indent, "");
1477228060Sbapt      if (option[LENTABLE])
1478228060Sbapt        {
1479228060Sbapt          indent -= 4;
1480228060Sbapt          printf ("%*s  }\n",
1481228060Sbapt                  indent, "");
1482228060Sbapt        }
1483228060Sbapt      else
1484228060Sbapt        *jumps_away = 1;
1485228060Sbapt    }
1486228060Sbapt
1487228060Sbapt  return list->rest();
1488228060Sbapt}
1489228060Sbapt
1490228060Sbapt/* Output a total of size cases, grouped into num_switches switch statements,
1491228060Sbapt   where 0 < num_switches <= size.  */
1492228060Sbapt
1493228060Sbaptstatic void
1494228060Sbaptoutput_switches (KeywordExt_List *list, int num_switches, int size, int min_hash_value, int max_hash_value, int indent)
1495228060Sbapt{
1496228060Sbapt  if (option[DEBUG])
1497228060Sbapt    printf ("%*s/* know %d <= key <= %d, contains %d cases */\n",
1498228060Sbapt            indent, "", min_hash_value, max_hash_value, size);
1499228060Sbapt
1500228060Sbapt  if (num_switches > 1)
1501228060Sbapt    {
1502228060Sbapt      int part1 = num_switches / 2;
1503228060Sbapt      int part2 = num_switches - part1;
1504228060Sbapt      int size1 = static_cast<int>(static_cast<double>(size) / static_cast<double>(num_switches) * static_cast<double>(part1) + 0.5);
1505228060Sbapt      int size2 = size - size1;
1506228060Sbapt
1507228060Sbapt      KeywordExt_List *temp = list;
1508228060Sbapt      for (int count = size1; count > 0; count--)
1509228060Sbapt        temp = temp->rest();
1510228060Sbapt
1511228060Sbapt      printf ("%*sif (key < %d)\n"
1512228060Sbapt              "%*s  {\n",
1513228060Sbapt              indent, "", temp->first()->_hash_value,
1514228060Sbapt              indent, "");
1515228060Sbapt
1516228060Sbapt      output_switches (list, part1, size1, min_hash_value, temp->first()->_hash_value-1, indent+4);
1517228060Sbapt
1518228060Sbapt      printf ("%*s  }\n"
1519228060Sbapt              "%*selse\n"
1520228060Sbapt              "%*s  {\n",
1521228060Sbapt              indent, "", indent, "", indent, "");
1522228060Sbapt
1523228060Sbapt      output_switches (temp, part2, size2, temp->first()->_hash_value, max_hash_value, indent+4);
1524228060Sbapt
1525228060Sbapt      printf ("%*s  }\n",
1526228060Sbapt              indent, "");
1527228060Sbapt    }
1528228060Sbapt  else
1529228060Sbapt    {
1530228060Sbapt      /* Output a single switch.  */
1531228060Sbapt      int lowest_case_value = list->first()->_hash_value;
1532228060Sbapt      if (size == 1)
1533228060Sbapt        {
1534228060Sbapt          int jumps_away = 0;
1535228060Sbapt          assert (min_hash_value <= lowest_case_value);
1536228060Sbapt          assert (lowest_case_value <= max_hash_value);
1537228060Sbapt          if (min_hash_value == max_hash_value)
1538228060Sbapt            output_switch_case (list, indent, &jumps_away);
1539228060Sbapt          else
1540228060Sbapt            {
1541228060Sbapt              printf ("%*sif (key == %d)\n"
1542228060Sbapt                      "%*s  {\n",
1543228060Sbapt                      indent, "", lowest_case_value,
1544228060Sbapt                      indent, "");
1545228060Sbapt              output_switch_case (list, indent+4, &jumps_away);
1546228060Sbapt              printf ("%*s  }\n",
1547228060Sbapt                      indent, "");
1548228060Sbapt            }
1549228060Sbapt        }
1550228060Sbapt      else
1551228060Sbapt        {
1552228060Sbapt          if (lowest_case_value == 0)
1553228060Sbapt            printf ("%*sswitch (key)\n", indent, "");
1554228060Sbapt          else
1555228060Sbapt            printf ("%*sswitch (key - %d)\n", indent, "", lowest_case_value);
1556228060Sbapt          printf ("%*s  {\n",
1557228060Sbapt                  indent, "");
1558228060Sbapt          for (; size > 0; size--)
1559228060Sbapt            {
1560228060Sbapt              int jumps_away = 0;
1561228060Sbapt              printf ("%*s    case %d:\n",
1562228060Sbapt                      indent, "", list->first()->_hash_value - lowest_case_value);
1563228060Sbapt              list = output_switch_case (list, indent+6, &jumps_away);
1564228060Sbapt              if (!jumps_away)
1565228060Sbapt                printf ("%*s      break;\n",
1566228060Sbapt                        indent, "");
1567228060Sbapt            }
1568228060Sbapt          printf ("%*s  }\n",
1569228060Sbapt                  indent, "");
1570228060Sbapt        }
1571228060Sbapt    }
1572228060Sbapt}
1573228060Sbapt
1574228060Sbapt/* Generates C code to perform the keyword lookup.  */
1575228060Sbapt
1576228060Sbaptvoid
1577228060SbaptOutput::output_lookup_function_body (const Output_Compare& comparison) const
1578228060Sbapt{
1579228060Sbapt  printf ("  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)\n"
1580228060Sbapt          "    {\n"
1581228060Sbapt          "      register int key = %s (str, len);\n\n",
1582228060Sbapt          option.get_hash_name ());
1583228060Sbapt
1584228060Sbapt  if (option[SWITCH])
1585228060Sbapt    {
1586228060Sbapt      int switch_size = num_hash_values ();
1587228060Sbapt      int num_switches = option.get_total_switches ();
1588228060Sbapt      if (num_switches > switch_size)
1589228060Sbapt        num_switches = switch_size;
1590228060Sbapt
1591228060Sbapt      printf ("      if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)\n"
1592228060Sbapt              "        {\n");
1593228060Sbapt      if (option[DUP] && _total_duplicates > 0)
1594228060Sbapt        {
1595228060Sbapt          if (option[LENTABLE])
1596228060Sbapt            printf ("          register %s%s *lengthptr;\n",
1597228060Sbapt                    const_always, smallest_integral_type (_max_key_len));
1598228060Sbapt          printf ("          register ");
1599228060Sbapt          output_const_type (const_readonly_array, _wordlist_eltype);
1600228060Sbapt          printf ("*wordptr;\n");
1601228060Sbapt          printf ("          register ");
1602228060Sbapt          output_const_type (const_readonly_array, _wordlist_eltype);
1603228060Sbapt          printf ("*wordendptr;\n");
1604228060Sbapt        }
1605228060Sbapt      if (option[TYPE])
1606228060Sbapt        {
1607228060Sbapt          printf ("          register ");
1608228060Sbapt          output_const_type (const_readonly_array, _struct_tag);
1609228060Sbapt          printf ("*resword;\n\n");
1610228060Sbapt        }
1611228060Sbapt      else
1612228060Sbapt        printf ("          register %sresword;\n\n",
1613228060Sbapt                _struct_tag);
1614228060Sbapt
1615228060Sbapt      output_switches (_head, num_switches, switch_size, _min_hash_value, _max_hash_value, 10);
1616228060Sbapt
1617228060Sbapt      printf ("          return 0;\n");
1618228060Sbapt      if (option[DUP] && _total_duplicates > 0)
1619228060Sbapt        {
1620228060Sbapt          int indent = 8;
1621228060Sbapt          printf ("%*smulticompare:\n"
1622228060Sbapt                  "%*s  while (wordptr < wordendptr)\n"
1623228060Sbapt                  "%*s    {\n",
1624228060Sbapt                  indent, "", indent, "", indent, "");
1625228060Sbapt          if (option[LENTABLE])
1626228060Sbapt            {
1627228060Sbapt              printf ("%*s      if (len == *lengthptr)\n"
1628228060Sbapt                      "%*s        {\n",
1629228060Sbapt                      indent, "", indent, "");
1630228060Sbapt              indent += 4;
1631228060Sbapt            }
1632228060Sbapt          printf ("%*s      register %schar *s = ",
1633228060Sbapt                  indent, "", const_always);
1634228060Sbapt          if (option[TYPE])
1635228060Sbapt            printf ("wordptr->%s", option.get_slot_name ());
1636228060Sbapt          else
1637228060Sbapt            printf ("*wordptr");
1638228060Sbapt          if (option[SHAREDLIB])
1639228060Sbapt            printf (" + %s",
1640228060Sbapt                    option.get_stringpool_name ());
1641228060Sbapt          printf (";\n\n"
1642228060Sbapt                  "%*s      if (",
1643228060Sbapt                  indent, "");
1644228060Sbapt          comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("s"));
1645228060Sbapt          printf (")\n"
1646228060Sbapt                  "%*s        return %s;\n",
1647228060Sbapt                  indent, "",
1648228060Sbapt                  option[TYPE] ? "wordptr" : "s");
1649228060Sbapt          if (option[LENTABLE])
1650228060Sbapt            {
1651228060Sbapt              indent -= 4;
1652228060Sbapt              printf ("%*s        }\n",
1653228060Sbapt                      indent, "");
1654228060Sbapt            }
1655228060Sbapt          if (option[LENTABLE])
1656228060Sbapt            printf ("%*s      lengthptr++;\n",
1657228060Sbapt                    indent, "");
1658228060Sbapt          printf ("%*s      wordptr++;\n"
1659228060Sbapt                  "%*s    }\n"
1660228060Sbapt                  "%*s  return 0;\n",
1661228060Sbapt                  indent, "", indent, "", indent, "");
1662228060Sbapt        }
1663228060Sbapt      printf ("        compare:\n");
1664228060Sbapt      if (option[TYPE])
1665228060Sbapt        {
1666228060Sbapt          printf ("          {\n"
1667228060Sbapt                  "            register %schar *s = resword->%s",
1668228060Sbapt                  const_always, option.get_slot_name ());
1669228060Sbapt          if (option[SHAREDLIB])
1670228060Sbapt            printf (" + %s",
1671228060Sbapt                    option.get_stringpool_name ());
1672228060Sbapt          printf (";\n\n"
1673228060Sbapt                  "            if (");
1674228060Sbapt          comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("s"));
1675228060Sbapt          printf (")\n"
1676228060Sbapt                  "              return resword;\n"
1677228060Sbapt                  "          }\n");
1678228060Sbapt        }
1679228060Sbapt      else
1680228060Sbapt        {
1681228060Sbapt          printf ("          if (");
1682228060Sbapt          comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("resword"));
1683228060Sbapt          printf (")\n"
1684228060Sbapt                  "            return resword;\n");
1685228060Sbapt        }
1686228060Sbapt      printf ("        }\n");
1687228060Sbapt    }
1688228060Sbapt  else
1689228060Sbapt    {
1690228060Sbapt      printf ("      if (key <= MAX_HASH_VALUE && key >= 0)\n");
1691228060Sbapt
1692228060Sbapt      if (option[DUP])
1693228060Sbapt        {
1694228060Sbapt          int indent = 8;
1695228060Sbapt          printf ("%*s{\n"
1696228060Sbapt                  "%*s  register int index = lookup[key];\n\n"
1697228060Sbapt                  "%*s  if (index >= 0)\n",
1698228060Sbapt                  indent, "", indent, "", indent, "");
1699228060Sbapt          if (option[LENTABLE])
1700228060Sbapt            {
1701228060Sbapt              printf ("%*s    {\n"
1702228060Sbapt                      "%*s      if (len == %s[index])\n",
1703228060Sbapt                      indent, "", indent, "", option.get_lengthtable_name ());
1704228060Sbapt              indent += 4;
1705228060Sbapt            }
1706228060Sbapt          printf ("%*s    {\n"
1707228060Sbapt                  "%*s      register %schar *s = %s[index]",
1708228060Sbapt                  indent, "",
1709228060Sbapt                  indent, "", const_always, option.get_wordlist_name ());
1710228060Sbapt          if (option[TYPE])
1711228060Sbapt            printf (".%s", option.get_slot_name ());
1712228060Sbapt          if (option[SHAREDLIB])
1713228060Sbapt            printf (" + %s",
1714228060Sbapt                    option.get_stringpool_name ());
1715228060Sbapt          printf (";\n\n"
1716228060Sbapt                  "%*s      if (",
1717228060Sbapt                  indent, "");
1718228060Sbapt          comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("s"));
1719228060Sbapt          printf (")\n"
1720228060Sbapt                  "%*s        return ",
1721228060Sbapt                  indent, "");
1722228060Sbapt          if (option[TYPE])
1723228060Sbapt            printf ("&%s[index]", option.get_wordlist_name ());
1724228060Sbapt          else
1725228060Sbapt            printf ("s");
1726228060Sbapt          printf (";\n"
1727228060Sbapt                  "%*s    }\n",
1728228060Sbapt                  indent, "");
1729228060Sbapt          if (option[LENTABLE])
1730228060Sbapt            {
1731228060Sbapt              indent -= 4;
1732228060Sbapt              printf ("%*s    }\n", indent, "");
1733228060Sbapt            }
1734228060Sbapt          if (_total_duplicates > 0)
1735228060Sbapt            {
1736228060Sbapt              printf ("%*s  else if (index < -TOTAL_KEYWORDS)\n"
1737228060Sbapt                      "%*s    {\n"
1738228060Sbapt                      "%*s      register int offset = - 1 - TOTAL_KEYWORDS - index;\n",
1739228060Sbapt                      indent, "", indent, "", indent, "");
1740228060Sbapt              if (option[LENTABLE])
1741228060Sbapt                printf ("%*s      register %s%s *lengthptr = &%s[TOTAL_KEYWORDS + lookup[offset]];\n",
1742228060Sbapt                        indent, "", const_always, smallest_integral_type (_max_key_len),
1743228060Sbapt                        option.get_lengthtable_name ());
1744228060Sbapt              printf ("%*s      register ",
1745228060Sbapt                      indent, "");
1746228060Sbapt              output_const_type (const_readonly_array, _wordlist_eltype);
1747228060Sbapt              printf ("*wordptr = &%s[TOTAL_KEYWORDS + lookup[offset]];\n",
1748228060Sbapt                      option.get_wordlist_name ());
1749228060Sbapt              printf ("%*s      register ",
1750228060Sbapt                      indent, "");
1751228060Sbapt              output_const_type (const_readonly_array, _wordlist_eltype);
1752228060Sbapt              printf ("*wordendptr = wordptr + -lookup[offset + 1];\n\n");
1753228060Sbapt              printf ("%*s      while (wordptr < wordendptr)\n"
1754228060Sbapt                      "%*s        {\n",
1755228060Sbapt                      indent, "", indent, "");
1756228060Sbapt              if (option[LENTABLE])
1757228060Sbapt                {
1758228060Sbapt                  printf ("%*s          if (len == *lengthptr)\n"
1759228060Sbapt                          "%*s            {\n",
1760228060Sbapt                          indent, "", indent, "");
1761228060Sbapt                  indent += 4;
1762228060Sbapt                }
1763228060Sbapt              printf ("%*s          register %schar *s = ",
1764228060Sbapt                      indent, "", const_always);
1765228060Sbapt              if (option[TYPE])
1766228060Sbapt                printf ("wordptr->%s", option.get_slot_name ());
1767228060Sbapt              else
1768228060Sbapt                printf ("*wordptr");
1769228060Sbapt              if (option[SHAREDLIB])
1770228060Sbapt                printf (" + %s",
1771228060Sbapt                        option.get_stringpool_name ());
1772228060Sbapt              printf (";\n\n"
1773228060Sbapt                      "%*s          if (",
1774228060Sbapt                      indent, "");
1775228060Sbapt              comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("s"));
1776228060Sbapt              printf (")\n"
1777228060Sbapt                      "%*s            return %s;\n",
1778228060Sbapt                      indent, "",
1779228060Sbapt                      option[TYPE] ? "wordptr" : "s");
1780228060Sbapt              if (option[LENTABLE])
1781228060Sbapt                {
1782228060Sbapt                  indent -= 4;
1783228060Sbapt                  printf ("%*s            }\n",
1784228060Sbapt                          indent, "");
1785228060Sbapt                }
1786228060Sbapt              if (option[LENTABLE])
1787228060Sbapt                printf ("%*s          lengthptr++;\n",
1788228060Sbapt                        indent, "");
1789228060Sbapt              printf ("%*s          wordptr++;\n"
1790228060Sbapt                      "%*s        }\n"
1791228060Sbapt                      "%*s    }\n",
1792228060Sbapt                      indent, "", indent, "", indent, "");
1793228060Sbapt            }
1794228060Sbapt          printf ("%*s}\n",
1795228060Sbapt                  indent, "");
1796228060Sbapt        }
1797228060Sbapt      else
1798228060Sbapt        {
1799228060Sbapt          int indent = 8;
1800228060Sbapt          if (option[LENTABLE])
1801228060Sbapt            {
1802228060Sbapt              printf ("%*sif (len == %s[key])\n",
1803228060Sbapt                      indent, "", option.get_lengthtable_name ());
1804228060Sbapt              indent += 2;
1805228060Sbapt            }
1806228060Sbapt
1807228060Sbapt          if (option[SHAREDLIB])
1808228060Sbapt            {
1809228060Sbapt              if (!option[LENTABLE])
1810228060Sbapt                {
1811228060Sbapt                  printf ("%*s{\n"
1812228060Sbapt                          "%*s  register int o = %s[key]",
1813228060Sbapt                          indent, "",
1814228060Sbapt                          indent, "", option.get_wordlist_name ());
1815228060Sbapt                  if (option[TYPE])
1816228060Sbapt                    printf (".%s", option.get_slot_name ());
1817228060Sbapt                  printf (";\n"
1818228060Sbapt                          "%*s  if (o >= 0)\n"
1819228060Sbapt                          "%*s    {\n",
1820228060Sbapt                          indent, "",
1821228060Sbapt                          indent, "");
1822228060Sbapt                  indent += 4;
1823228060Sbapt                  printf ("%*s  register %schar *s = o",
1824228060Sbapt                          indent, "", const_always);
1825228060Sbapt                }
1826228060Sbapt              else
1827228060Sbapt                {
1828228060Sbapt                  /* No need for the (o >= 0) test, because the
1829228060Sbapt                     (len == lengthtable[key]) test already guarantees that
1830228060Sbapt                     key points to nonempty table entry.  */
1831228060Sbapt                  printf ("%*s{\n"
1832228060Sbapt                          "%*s  register %schar *s = %s[key]",
1833228060Sbapt                          indent, "",
1834228060Sbapt                          indent, "", const_always,
1835228060Sbapt                          option.get_wordlist_name ());
1836228060Sbapt                  if (option[TYPE])
1837228060Sbapt                    printf (".%s", option.get_slot_name ());
1838228060Sbapt                }
1839228060Sbapt              printf (" + %s",
1840228060Sbapt                      option.get_stringpool_name ());
1841228060Sbapt            }
1842228060Sbapt          else
1843228060Sbapt            {
1844228060Sbapt              printf ("%*s{\n"
1845228060Sbapt                      "%*s  register %schar *s = %s[key]",
1846228060Sbapt                      indent, "",
1847228060Sbapt                      indent, "", const_always, option.get_wordlist_name ());
1848228060Sbapt              if (option[TYPE])
1849228060Sbapt                printf (".%s", option.get_slot_name ());
1850228060Sbapt            }
1851228060Sbapt
1852228060Sbapt          printf (";\n\n"
1853228060Sbapt                  "%*s  if (",
1854228060Sbapt                  indent, "");
1855228060Sbapt          if (!option[SHAREDLIB] && option[NULLSTRINGS])
1856228060Sbapt            printf ("s && ");
1857228060Sbapt          comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("s"));
1858228060Sbapt          printf (")\n"
1859228060Sbapt                  "%*s    return ",
1860228060Sbapt                  indent, "");
1861228060Sbapt          if (option[TYPE])
1862228060Sbapt            printf ("&%s[key]", option.get_wordlist_name ());
1863228060Sbapt          else
1864228060Sbapt            printf ("s");
1865228060Sbapt          printf (";\n");
1866228060Sbapt          if (option[SHAREDLIB] && !option[LENTABLE])
1867228060Sbapt            {
1868228060Sbapt              indent -= 4;
1869228060Sbapt              printf ("%*s    }\n",
1870228060Sbapt                      indent, "");
1871228060Sbapt            }
1872228060Sbapt          printf ("%*s}\n",
1873228060Sbapt                  indent, "");
1874228060Sbapt        }
1875228060Sbapt    }
1876228060Sbapt  printf ("    }\n"
1877228060Sbapt          "  return 0;\n");
1878228060Sbapt}
1879228060Sbapt
1880228060Sbapt/* Generates C code for the lookup function.  */
1881228060Sbapt
1882228060Sbaptvoid
1883228060SbaptOutput::output_lookup_function () const
1884228060Sbapt{
1885228060Sbapt  /* Output the function's head.  */
1886228060Sbapt  if (option[KRC] | option[C] | option[ANSIC])
1887228060Sbapt    /* GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99
1888228060Sbapt       inline semantics, unless -fgnu89-inline is used.  It defines a macro
1889228060Sbapt       __GNUC_STDC_INLINE__ to indicate this situation.  */
1890228060Sbapt    printf ("#ifdef __GNUC__\n"
1891228060Sbapt            "__inline\n"
1892228060Sbapt            "#ifdef __GNUC_STDC_INLINE__\n"
1893228060Sbapt            "__attribute__ ((__gnu_inline__))\n"
1894228060Sbapt            "#endif\n"
1895228060Sbapt            "#endif\n");
1896228060Sbapt
1897228060Sbapt  printf ("%s%s\n",
1898228060Sbapt          const_for_struct, _return_type);
1899228060Sbapt  if (option[CPLUSPLUS])
1900228060Sbapt    printf ("%s::", option.get_class_name ());
1901228060Sbapt  printf ("%s ", option.get_function_name ());
1902228060Sbapt  printf (option[KRC] ?
1903228060Sbapt                 "(str, len)\n"
1904228060Sbapt            "     register char *str;\n"
1905228060Sbapt            "     register unsigned int len;\n" :
1906228060Sbapt          option[C] ?
1907228060Sbapt                 "(str, len)\n"
1908228060Sbapt            "     register const char *str;\n"
1909228060Sbapt            "     register unsigned int len;\n" :
1910228060Sbapt          option[ANSIC] | option[CPLUSPLUS] ?
1911228060Sbapt                 "(register const char *str, register unsigned int len)\n" :
1912228060Sbapt          "");
1913228060Sbapt
1914228060Sbapt  /* Output the function's body.  */
1915228060Sbapt  printf ("{\n");
1916228060Sbapt
1917228060Sbapt  if (option[ENUM] && !option[GLOBAL])
1918228060Sbapt    {
1919228060Sbapt      Output_Enum style ("  ");
1920228060Sbapt      output_constants (style);
1921228060Sbapt    }
1922228060Sbapt
1923228060Sbapt  if (option[SHAREDLIB] && !(option[GLOBAL] || option[TYPE]))
1924228060Sbapt    output_lookup_pools ();
1925228060Sbapt  if (!option[GLOBAL])
1926228060Sbapt    output_lookup_tables ();
1927228060Sbapt
1928228060Sbapt  if (option[LENTABLE])
1929228060Sbapt    output_lookup_function_body (Output_Compare_Memcmp ());
1930228060Sbapt  else
1931228060Sbapt    {
1932228060Sbapt      if (option[COMP])
1933228060Sbapt        output_lookup_function_body (Output_Compare_Strncmp ());
1934228060Sbapt      else
1935228060Sbapt        output_lookup_function_body (Output_Compare_Strcmp ());
1936228060Sbapt    }
1937228060Sbapt
1938228060Sbapt  printf ("}\n");
1939228060Sbapt}
1940228060Sbapt
1941228060Sbapt/* ------------------------------------------------------------------------- */
1942228060Sbapt
1943228060Sbapt/* Generates the hash function and the key word recognizer function
1944228060Sbapt   based upon the user's Options.  */
1945228060Sbapt
1946228060Sbaptvoid
1947228060SbaptOutput::output ()
1948228060Sbapt{
1949228060Sbapt  compute_min_max ();
1950228060Sbapt
1951228060Sbapt  if (option[C] | option[ANSIC] | option[CPLUSPLUS])
1952228060Sbapt    {
1953228060Sbapt      const_always = "const ";
1954228060Sbapt      const_readonly_array = (option[CONST] ? "const " : "");
1955228060Sbapt      const_for_struct = ((option[CONST] && option[TYPE]) ? "const " : "");
1956228060Sbapt    }
1957228060Sbapt  else
1958228060Sbapt    {
1959228060Sbapt      const_always = "";
1960228060Sbapt      const_readonly_array = "";
1961228060Sbapt      const_for_struct = "";
1962228060Sbapt    }
1963228060Sbapt
1964228060Sbapt  if (!option[TYPE])
1965228060Sbapt    {
1966228060Sbapt      _return_type = (const_always[0] ? "const char *" : "char *");
1967228060Sbapt      _struct_tag = (const_always[0] ? "const char *" : "char *");
1968228060Sbapt    }
1969228060Sbapt
1970228060Sbapt  _wordlist_eltype = (option[SHAREDLIB] && !option[TYPE] ? "int" : _struct_tag);
1971228060Sbapt
1972228060Sbapt  printf ("/* ");
1973228060Sbapt  if (option[KRC])
1974228060Sbapt    printf ("KR-C");
1975228060Sbapt  else if (option[C])
1976228060Sbapt    printf ("C");
1977228060Sbapt  else if (option[ANSIC])
1978228060Sbapt    printf ("ANSI-C");
1979228060Sbapt  else if (option[CPLUSPLUS])
1980228060Sbapt    printf ("C++");
1981228060Sbapt  printf (" code produced by gperf version %s */\n", version_string);
1982228060Sbapt  option.print_options ();
1983228060Sbapt  printf ("\n");
1984228060Sbapt  if (!option[POSITIONS])
1985228060Sbapt    {
1986228060Sbapt      printf ("/* Computed positions: -k'");
1987228060Sbapt      _key_positions.print();
1988228060Sbapt      printf ("' */\n");
1989228060Sbapt    }
1990228060Sbapt  printf ("\n");
1991228060Sbapt
1992228060Sbapt  if (_charset_dependent
1993228060Sbapt      && (_key_positions.get_size() > 0 || option[UPPERLOWER]))
1994228060Sbapt    {
1995228060Sbapt      /* The generated tables assume that the execution character set is
1996228060Sbapt         based on ISO-646, not EBCDIC.  */
1997228060Sbapt      printf ("#if !((' ' == 32) && ('!' == 33) && ('\"' == 34) && ('#' == 35) \\\n"
1998228060Sbapt              "      && ('%%' == 37) && ('&' == 38) && ('\\'' == 39) && ('(' == 40) \\\n"
1999228060Sbapt              "      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \\\n"
2000228060Sbapt              "      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \\\n"
2001228060Sbapt              "      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \\\n"
2002228060Sbapt              "      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \\\n"
2003228060Sbapt              "      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \\\n"
2004228060Sbapt              "      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \\\n"
2005228060Sbapt              "      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \\\n"
2006228060Sbapt              "      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \\\n"
2007228060Sbapt              "      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \\\n"
2008228060Sbapt              "      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \\\n"
2009228060Sbapt              "      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \\\n"
2010228060Sbapt              "      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \\\n"
2011228060Sbapt              "      && ('Z' == 90) && ('[' == 91) && ('\\\\' == 92) && (']' == 93) \\\n"
2012228060Sbapt              "      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \\\n"
2013228060Sbapt              "      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \\\n"
2014228060Sbapt              "      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \\\n"
2015228060Sbapt              "      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \\\n"
2016228060Sbapt              "      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \\\n"
2017228060Sbapt              "      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \\\n"
2018228060Sbapt              "      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \\\n"
2019228060Sbapt              "      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))\n"
2020228060Sbapt              "/* The character set is not based on ISO-646.  */\n");
2021228060Sbapt      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");
2022228060Sbapt      printf ("#endif\n\n");
2023228060Sbapt    }
2024228060Sbapt
2025228060Sbapt  if (_verbatim_declarations < _verbatim_declarations_end)
2026228060Sbapt    {
2027228060Sbapt      output_line_directive (_verbatim_declarations_lineno);
2028228060Sbapt      fwrite (_verbatim_declarations, 1,
2029228060Sbapt              _verbatim_declarations_end - _verbatim_declarations, stdout);
2030228060Sbapt    }
2031228060Sbapt
2032228060Sbapt  if (option[TYPE] && !option[NOTYPE]) /* Output type declaration now, reference it later on.... */
2033228060Sbapt    {
2034228060Sbapt      output_line_directive (_struct_decl_lineno);
2035228060Sbapt      printf ("%s\n", _struct_decl);
2036228060Sbapt    }
2037228060Sbapt
2038228060Sbapt  if (option[INCLUDE])
2039228060Sbapt    printf ("#include <string.h>\n"); /* Declare strlen(), strcmp(), strncmp(). */
2040228060Sbapt
2041228060Sbapt  if (!option[ENUM])
2042228060Sbapt    {
2043228060Sbapt      Output_Defines style;
2044228060Sbapt      output_constants (style);
2045228060Sbapt    }
2046228060Sbapt  else if (option[GLOBAL])
2047228060Sbapt    {
2048228060Sbapt      Output_Enum style ("");
2049228060Sbapt      output_constants (style);
2050228060Sbapt    }
2051228060Sbapt
2052228060Sbapt  printf ("/* maximum key range = %d, duplicates = %d */\n\n",
2053228060Sbapt          _max_hash_value - _min_hash_value + 1, _total_duplicates);
2054228060Sbapt
2055228060Sbapt  if (option[UPPERLOWER])
2056228060Sbapt    {
2057228060Sbapt      #if USE_DOWNCASE_TABLE
2058228060Sbapt      output_upperlower_table ();
2059228060Sbapt      #endif
2060228060Sbapt
2061228060Sbapt      if (option[LENTABLE])
2062228060Sbapt        output_upperlower_memcmp ();
2063228060Sbapt      else
2064228060Sbapt        {
2065228060Sbapt          if (option[COMP])
2066228060Sbapt            output_upperlower_strncmp ();
2067228060Sbapt          else
2068228060Sbapt            output_upperlower_strcmp ();
2069228060Sbapt        }
2070228060Sbapt    }
2071228060Sbapt
2072228060Sbapt  if (option[CPLUSPLUS])
2073228060Sbapt    printf ("class %s\n"
2074228060Sbapt            "{\n"
2075228060Sbapt            "private:\n"
2076228060Sbapt            "  static inline unsigned int %s (const char *str, unsigned int len);\n"
2077228060Sbapt            "public:\n"
2078228060Sbapt            "  static %s%s%s (const char *str, unsigned int len);\n"
2079228060Sbapt            "};\n"
2080228060Sbapt            "\n",
2081228060Sbapt            option.get_class_name (), option.get_hash_name (),
2082228060Sbapt            const_for_struct, _return_type, option.get_function_name ());
2083228060Sbapt
2084228060Sbapt  output_hash_function ();
2085228060Sbapt
2086228060Sbapt  if (option[SHAREDLIB] && (option[GLOBAL] || option[TYPE]))
2087228060Sbapt    output_lookup_pools ();
2088228060Sbapt  if (option[GLOBAL])
2089228060Sbapt    output_lookup_tables ();
2090228060Sbapt
2091228060Sbapt  output_lookup_function ();
2092228060Sbapt
2093228060Sbapt  if (_verbatim_code < _verbatim_code_end)
2094228060Sbapt    {
2095228060Sbapt      output_line_directive (_verbatim_code_lineno);
2096228060Sbapt      fwrite (_verbatim_code, 1, _verbatim_code_end - _verbatim_code, stdout);
2097228060Sbapt    }
2098228060Sbapt
2099228060Sbapt  fflush (stdout);
2100228060Sbapt}
2101