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])
1109259320Spfg    printf("offsetof(struct %s_t, %s_str%d)", option.get_stringpool_name (), option.get_stringpool_name (), stringpool_index);
1110228060Sbapt  else
1111228060Sbapt    output_string (temp->_allchars, temp->_allchars_length);
1112228060Sbapt  if (option[TYPE])
1113228060Sbapt    {
1114228060Sbapt      if (strlen (temp->_rest) > 0)
1115228060Sbapt        printf (",%s", temp->_rest);
1116228060Sbapt      printf ("}");
1117228060Sbapt    }
1118228060Sbapt  if (option[DEBUG])
1119228060Sbapt    printf (" /* hash value = %d, index = %d */",
1120228060Sbapt            temp->_hash_value, temp->_final_index);
1121228060Sbapt}
1122228060Sbapt
1123228060Sbaptstatic void
1124228060Sbaptoutput_keyword_blank_entries (int count, const char *indent)
1125228060Sbapt{
1126228060Sbapt  int columns;
1127228060Sbapt  if (option[TYPE])
1128228060Sbapt    {
1129228060Sbapt      columns = 58 / (4 + (option[SHAREDLIB] ? 2 : option[NULLSTRINGS] ? 8 : 2)
1130228060Sbapt                        + strlen (option.get_initializer_suffix()));
1131228060Sbapt      if (columns == 0)
1132228060Sbapt        columns = 1;
1133228060Sbapt    }
1134228060Sbapt  else
1135228060Sbapt    {
1136228060Sbapt      columns = (option[SHAREDLIB] ? 9 : option[NULLSTRINGS] ? 4 : 9);
1137228060Sbapt    }
1138228060Sbapt  int column = 0;
1139228060Sbapt  for (int i = 0; i < count; i++)
1140228060Sbapt    {
1141228060Sbapt      if ((column % columns) == 0)
1142228060Sbapt        {
1143228060Sbapt          if (i > 0)
1144228060Sbapt            printf (",\n");
1145228060Sbapt          printf ("%s    ", indent);
1146228060Sbapt        }
1147228060Sbapt      else
1148228060Sbapt        {
1149228060Sbapt          if (i > 0)
1150228060Sbapt            printf (", ");
1151228060Sbapt        }
1152228060Sbapt      if (option[TYPE])
1153228060Sbapt        printf ("{");
1154228060Sbapt      if (option[SHAREDLIB])
1155228060Sbapt        printf ("-1");
1156228060Sbapt      else
1157228060Sbapt        {
1158228060Sbapt          if (option[NULLSTRINGS])
1159228060Sbapt            printf ("(char*)0");
1160228060Sbapt          else
1161228060Sbapt            printf ("\"\"");
1162228060Sbapt        }
1163228060Sbapt      if (option[TYPE])
1164228060Sbapt        printf ("%s}", option.get_initializer_suffix());
1165228060Sbapt      column++;
1166228060Sbapt    }
1167228060Sbapt}
1168228060Sbapt
1169228060Sbapt/* Prints out the array containing the keywords for the hash function.  */
1170228060Sbapt
1171228060Sbaptvoid
1172228060SbaptOutput::output_keyword_table () const
1173228060Sbapt{
1174228060Sbapt  const char *indent  = option[GLOBAL] ? "" : "  ";
1175228060Sbapt  int index;
1176228060Sbapt  KeywordExt_List *temp;
1177228060Sbapt
1178228060Sbapt  printf ("%sstatic ",
1179228060Sbapt          indent);
1180228060Sbapt  output_const_type (const_readonly_array, _wordlist_eltype);
1181228060Sbapt  printf ("%s[] =\n"
1182228060Sbapt          "%s  {\n",
1183228060Sbapt          option.get_wordlist_name (),
1184228060Sbapt          indent);
1185228060Sbapt
1186228060Sbapt  /* Generate an array of reserved words at appropriate locations.  */
1187228060Sbapt
1188228060Sbapt  for (temp = _head, index = 0; temp; temp = temp->rest())
1189228060Sbapt    {
1190228060Sbapt      KeywordExt *keyword = temp->first();
1191228060Sbapt
1192228060Sbapt      /* If generating a switch statement, and there is no user defined type,
1193228060Sbapt         we generate non-duplicates directly in the code.  Only duplicates go
1194228060Sbapt         into the table.  */
1195228060Sbapt      if (option[SWITCH] && !option[TYPE] && !keyword->_duplicate_link)
1196228060Sbapt        continue;
1197228060Sbapt
1198228060Sbapt      if (index > 0)
1199228060Sbapt        printf (",\n");
1200228060Sbapt
1201228060Sbapt      if (index < keyword->_hash_value && !option[SWITCH] && !option[DUP])
1202228060Sbapt        {
1203228060Sbapt          /* Some blank entries.  */
1204228060Sbapt          output_keyword_blank_entries (keyword->_hash_value - index, indent);
1205228060Sbapt          printf (",\n");
1206228060Sbapt          index = keyword->_hash_value;
1207228060Sbapt        }
1208228060Sbapt
1209228060Sbapt      keyword->_final_index = index;
1210228060Sbapt
1211228060Sbapt      output_keyword_entry (keyword, index, indent);
1212228060Sbapt
1213228060Sbapt      /* Deal with duplicates specially.  */
1214228060Sbapt      if (keyword->_duplicate_link) // implies option[DUP]
1215228060Sbapt        for (KeywordExt *links = keyword->_duplicate_link; links; links = links->_duplicate_link)
1216228060Sbapt          {
1217228060Sbapt            links->_final_index = ++index;
1218228060Sbapt            printf (",\n");
1219228060Sbapt            int stringpool_index =
1220228060Sbapt              (links->_allchars_length == keyword->_allchars_length
1221228060Sbapt               && memcmp (links->_allchars, keyword->_allchars,
1222228060Sbapt                          keyword->_allchars_length) == 0
1223228060Sbapt               ? keyword->_final_index
1224228060Sbapt               : links->_final_index);
1225228060Sbapt            output_keyword_entry (links, stringpool_index, indent);
1226228060Sbapt          }
1227228060Sbapt
1228228060Sbapt      index++;
1229228060Sbapt    }
1230228060Sbapt  if (index > 0)
1231228060Sbapt    printf ("\n");
1232228060Sbapt
1233228060Sbapt  printf ("%s  };\n\n", indent);
1234228060Sbapt}
1235228060Sbapt
1236228060Sbapt/* ------------------------------------------------------------------------- */
1237228060Sbapt
1238228060Sbapt/* Generates the large, sparse table that maps hash values into
1239228060Sbapt   the smaller, contiguous range of the keyword table.  */
1240228060Sbapt
1241228060Sbaptvoid
1242228060SbaptOutput::output_lookup_array () const
1243228060Sbapt{
1244228060Sbapt  if (option[DUP])
1245228060Sbapt    {
1246228060Sbapt      const int DEFAULT_VALUE = -1;
1247228060Sbapt
1248228060Sbapt      /* Because of the way output_keyword_table works, every duplicate set is
1249228060Sbapt         stored contiguously in the wordlist array.  */
1250228060Sbapt      struct duplicate_entry
1251228060Sbapt        {
1252228060Sbapt          int hash_value; /* Hash value for this particular duplicate set.  */
1253228060Sbapt          int index;      /* Index into the main keyword storage array.  */
1254228060Sbapt          int count;      /* Number of consecutive duplicates at this index.  */
1255228060Sbapt        };
1256228060Sbapt
1257228060Sbapt      duplicate_entry *duplicates = new duplicate_entry[_total_duplicates];
1258228060Sbapt      int *lookup_array = new int[_max_hash_value + 1 + 2*_total_duplicates];
1259228060Sbapt      int lookup_array_size = _max_hash_value + 1;
1260228060Sbapt      duplicate_entry *dup_ptr = &duplicates[0];
1261228060Sbapt      int *lookup_ptr = &lookup_array[_max_hash_value + 1 + 2*_total_duplicates];
1262228060Sbapt
1263228060Sbapt      while (lookup_ptr > lookup_array)
1264228060Sbapt        *--lookup_ptr = DEFAULT_VALUE;
1265228060Sbapt
1266228060Sbapt      /* Now dup_ptr = &duplicates[0] and lookup_ptr = &lookup_array[0].  */
1267228060Sbapt
1268228060Sbapt      for (KeywordExt_List *temp = _head; temp; temp = temp->rest())
1269228060Sbapt        {
1270228060Sbapt          int hash_value = temp->first()->_hash_value;
1271228060Sbapt          lookup_array[hash_value] = temp->first()->_final_index;
1272228060Sbapt          if (option[DEBUG])
1273228060Sbapt            fprintf (stderr, "keyword = %.*s, index = %d\n",
1274228060Sbapt                     temp->first()->_allchars_length, temp->first()->_allchars, temp->first()->_final_index);
1275228060Sbapt          if (temp->first()->_duplicate_link)
1276228060Sbapt            {
1277228060Sbapt              /* Start a duplicate entry.  */
1278228060Sbapt              dup_ptr->hash_value = hash_value;
1279228060Sbapt              dup_ptr->index = temp->first()->_final_index;
1280228060Sbapt              dup_ptr->count = 1;
1281228060Sbapt
1282228060Sbapt              for (KeywordExt *ptr = temp->first()->_duplicate_link; ptr; ptr = ptr->_duplicate_link)
1283228060Sbapt                {
1284228060Sbapt                  dup_ptr->count++;
1285228060Sbapt                  if (option[DEBUG])
1286228060Sbapt                    fprintf (stderr,
1287228060Sbapt                             "static linked keyword = %.*s, index = %d\n",
1288228060Sbapt                             ptr->_allchars_length, ptr->_allchars, ptr->_final_index);
1289228060Sbapt                }
1290228060Sbapt              assert (dup_ptr->count >= 2);
1291228060Sbapt              dup_ptr++;
1292228060Sbapt            }
1293228060Sbapt        }
1294228060Sbapt
1295228060Sbapt      while (dup_ptr > duplicates)
1296228060Sbapt        {
1297228060Sbapt          dup_ptr--;
1298228060Sbapt
1299228060Sbapt          if (option[DEBUG])
1300228060Sbapt            fprintf (stderr,
1301228604Sdim                     "dup_ptr[%td]: hash_value = %d, index = %d, count = %d\n",
1302228060Sbapt                     dup_ptr - duplicates,
1303228060Sbapt                     dup_ptr->hash_value, dup_ptr->index, dup_ptr->count);
1304228060Sbapt
1305228060Sbapt          int i;
1306228060Sbapt          /* Start searching for available space towards the right part
1307228060Sbapt             of the lookup array.  */
1308228060Sbapt          for (i = dup_ptr->hash_value; i < lookup_array_size-1; i++)
1309228060Sbapt            if (lookup_array[i] == DEFAULT_VALUE
1310228060Sbapt                && lookup_array[i + 1] == DEFAULT_VALUE)
1311228060Sbapt              goto found_i;
1312228060Sbapt          /* If we didn't find it to the right look to the left instead...  */
1313228060Sbapt          for (i = dup_ptr->hash_value-1; i >= 0; i--)
1314228060Sbapt            if (lookup_array[i] == DEFAULT_VALUE
1315228060Sbapt                && lookup_array[i + 1] == DEFAULT_VALUE)
1316228060Sbapt              goto found_i;
1317228060Sbapt          /* Append to the end of lookup_array.  */
1318228060Sbapt          i = lookup_array_size;
1319228060Sbapt          lookup_array_size += 2;
1320228060Sbapt        found_i:
1321228060Sbapt          /* Put in an indirection from dup_ptr->_hash_value to i.
1322228060Sbapt             At i and i+1 store dup_ptr->_final_index and dup_ptr->count.  */
1323228060Sbapt          assert (lookup_array[dup_ptr->hash_value] == dup_ptr->index);
1324228060Sbapt          lookup_array[dup_ptr->hash_value] = - 1 - _total_keys - i;
1325228060Sbapt          lookup_array[i] = - _total_keys + dup_ptr->index;
1326228060Sbapt          lookup_array[i + 1] = - dup_ptr->count;
1327228060Sbapt          /* All these three values are <= -2, distinct from DEFAULT_VALUE.  */
1328228060Sbapt        }
1329228060Sbapt
1330228060Sbapt      /* The values of the lookup array are now known.  */
1331228060Sbapt
1332228060Sbapt      int min = INT_MAX;
1333228060Sbapt      int max = INT_MIN;
1334228060Sbapt      lookup_ptr = lookup_array + lookup_array_size;
1335228060Sbapt      while (lookup_ptr > lookup_array)
1336228060Sbapt        {
1337228060Sbapt          int val = *--lookup_ptr;
1338228060Sbapt          if (min > val)
1339228060Sbapt            min = val;
1340228060Sbapt          if (max < val)
1341228060Sbapt            max = val;
1342228060Sbapt        }
1343228060Sbapt
1344228060Sbapt      const char *indent = option[GLOBAL] ? "" : "  ";
1345228060Sbapt      printf ("%sstatic %s%s lookup[] =\n"
1346228060Sbapt              "%s  {",
1347228060Sbapt              indent, const_readonly_array, smallest_integral_type (min, max),
1348228060Sbapt              indent);
1349228060Sbapt
1350228060Sbapt      int field_width;
1351228060Sbapt      /* Calculate maximum number of digits required for MIN..MAX.  */
1352228060Sbapt      {
1353228060Sbapt        field_width = 2;
1354228060Sbapt        for (int trunc = max; (trunc /= 10) > 0;)
1355228060Sbapt          field_width++;
1356228060Sbapt      }
1357228060Sbapt      if (min < 0)
1358228060Sbapt        {
1359228060Sbapt          int neg_field_width = 2;
1360228060Sbapt          for (int trunc = -min; (trunc /= 10) > 0;)
1361228060Sbapt            neg_field_width++;
1362228060Sbapt          neg_field_width++; /* account for the minus sign */
1363228060Sbapt          if (field_width < neg_field_width)
1364228060Sbapt            field_width = neg_field_width;
1365228060Sbapt        }
1366228060Sbapt
1367228060Sbapt      const int columns = 42 / field_width;
1368228060Sbapt      int column;
1369228060Sbapt
1370228060Sbapt      column = 0;
1371228060Sbapt      for (int i = 0; i < lookup_array_size; i++)
1372228060Sbapt        {
1373228060Sbapt          if (i > 0)
1374228060Sbapt            printf (",");
1375228060Sbapt          if ((column++ % columns) == 0)
1376228060Sbapt            printf("\n%s   ", indent);
1377228060Sbapt          printf ("%*d", field_width, lookup_array[i]);
1378228060Sbapt        }
1379228060Sbapt      printf ("\n%s  };\n\n", indent);
1380228060Sbapt
1381228060Sbapt      delete[] duplicates;
1382228060Sbapt      delete[] lookup_array;
1383228060Sbapt    }
1384228060Sbapt}
1385228060Sbapt
1386228060Sbapt/* ------------------------------------------------------------------------- */
1387228060Sbapt
1388228060Sbapt/* Generate all pools needed for the lookup function.  */
1389228060Sbapt
1390228060Sbaptvoid
1391228060SbaptOutput::output_lookup_pools () const
1392228060Sbapt{
1393228060Sbapt  if (option[SWITCH])
1394228060Sbapt    {
1395228060Sbapt      if (option[TYPE] || (option[DUP] && _total_duplicates > 0))
1396228060Sbapt        output_string_pool ();
1397228060Sbapt    }
1398228060Sbapt  else
1399228060Sbapt    {
1400228060Sbapt      output_string_pool ();
1401228060Sbapt    }
1402228060Sbapt}
1403228060Sbapt
1404228060Sbapt/* Generate all the tables needed for the lookup function.  */
1405228060Sbapt
1406228060Sbaptvoid
1407228060SbaptOutput::output_lookup_tables () const
1408228060Sbapt{
1409228060Sbapt  if (option[SWITCH])
1410228060Sbapt    {
1411228060Sbapt      /* Use the switch in place of lookup table.  */
1412228060Sbapt      if (option[LENTABLE] && (option[DUP] && _total_duplicates > 0))
1413228060Sbapt        output_keylength_table ();
1414228060Sbapt      if (option[TYPE] || (option[DUP] && _total_duplicates > 0))
1415228060Sbapt        output_keyword_table ();
1416228060Sbapt    }
1417228060Sbapt  else
1418228060Sbapt    {
1419228060Sbapt      /* Use the lookup table, in place of switch.  */
1420228060Sbapt      if (option[LENTABLE])
1421228060Sbapt        output_keylength_table ();
1422228060Sbapt      output_keyword_table ();
1423228060Sbapt      output_lookup_array ();
1424228060Sbapt    }
1425228060Sbapt}
1426228060Sbapt
1427228060Sbapt/* ------------------------------------------------------------------------- */
1428228060Sbapt
1429228060Sbapt/* Output a single switch case (including duplicates).  Advance list.  */
1430228060Sbapt
1431228060Sbaptstatic KeywordExt_List *
1432228060Sbaptoutput_switch_case (KeywordExt_List *list, int indent, int *jumps_away)
1433228060Sbapt{
1434228060Sbapt  if (option[DEBUG])
1435228060Sbapt    printf ("%*s/* hash value = %4d, keyword = \"%.*s\" */\n",
1436228060Sbapt            indent, "", list->first()->_hash_value, list->first()->_allchars_length, list->first()->_allchars);
1437228060Sbapt
1438228060Sbapt  if (option[DUP] && list->first()->_duplicate_link)
1439228060Sbapt    {
1440228060Sbapt      if (option[LENTABLE])
1441228060Sbapt        printf ("%*slengthptr = &%s[%d];\n",
1442228060Sbapt                indent, "", option.get_lengthtable_name (), list->first()->_final_index);
1443228060Sbapt      printf ("%*swordptr = &%s[%d];\n",
1444228060Sbapt              indent, "", option.get_wordlist_name (), list->first()->_final_index);
1445228060Sbapt
1446228060Sbapt      int count = 0;
1447228060Sbapt      for (KeywordExt *links = list->first(); links; links = links->_duplicate_link)
1448228060Sbapt        count++;
1449228060Sbapt
1450228060Sbapt      printf ("%*swordendptr = wordptr + %d;\n"
1451228060Sbapt              "%*sgoto multicompare;\n",
1452228060Sbapt              indent, "", count,
1453228060Sbapt              indent, "");
1454228060Sbapt      *jumps_away = 1;
1455228060Sbapt    }
1456228060Sbapt  else
1457228060Sbapt    {
1458228060Sbapt      if (option[LENTABLE])
1459228060Sbapt        {
1460228060Sbapt          printf ("%*sif (len == %d)\n"
1461228060Sbapt                  "%*s  {\n",
1462228060Sbapt                  indent, "", list->first()->_allchars_length,
1463228060Sbapt                  indent, "");
1464228060Sbapt          indent += 4;
1465228060Sbapt        }
1466228060Sbapt      printf ("%*sresword = ",
1467228060Sbapt              indent, "");
1468228060Sbapt      if (option[TYPE])
1469228060Sbapt        printf ("&%s[%d]", option.get_wordlist_name (), list->first()->_final_index);
1470228060Sbapt      else
1471228060Sbapt        output_string (list->first()->_allchars, list->first()->_allchars_length);
1472228060Sbapt      printf (";\n");
1473228060Sbapt      printf ("%*sgoto compare;\n",
1474228060Sbapt              indent, "");
1475228060Sbapt      if (option[LENTABLE])
1476228060Sbapt        {
1477228060Sbapt          indent -= 4;
1478228060Sbapt          printf ("%*s  }\n",
1479228060Sbapt                  indent, "");
1480228060Sbapt        }
1481228060Sbapt      else
1482228060Sbapt        *jumps_away = 1;
1483228060Sbapt    }
1484228060Sbapt
1485228060Sbapt  return list->rest();
1486228060Sbapt}
1487228060Sbapt
1488228060Sbapt/* Output a total of size cases, grouped into num_switches switch statements,
1489228060Sbapt   where 0 < num_switches <= size.  */
1490228060Sbapt
1491228060Sbaptstatic void
1492228060Sbaptoutput_switches (KeywordExt_List *list, int num_switches, int size, int min_hash_value, int max_hash_value, int indent)
1493228060Sbapt{
1494228060Sbapt  if (option[DEBUG])
1495228060Sbapt    printf ("%*s/* know %d <= key <= %d, contains %d cases */\n",
1496228060Sbapt            indent, "", min_hash_value, max_hash_value, size);
1497228060Sbapt
1498228060Sbapt  if (num_switches > 1)
1499228060Sbapt    {
1500228060Sbapt      int part1 = num_switches / 2;
1501228060Sbapt      int part2 = num_switches - part1;
1502228060Sbapt      int size1 = static_cast<int>(static_cast<double>(size) / static_cast<double>(num_switches) * static_cast<double>(part1) + 0.5);
1503228060Sbapt      int size2 = size - size1;
1504228060Sbapt
1505228060Sbapt      KeywordExt_List *temp = list;
1506228060Sbapt      for (int count = size1; count > 0; count--)
1507228060Sbapt        temp = temp->rest();
1508228060Sbapt
1509228060Sbapt      printf ("%*sif (key < %d)\n"
1510228060Sbapt              "%*s  {\n",
1511228060Sbapt              indent, "", temp->first()->_hash_value,
1512228060Sbapt              indent, "");
1513228060Sbapt
1514228060Sbapt      output_switches (list, part1, size1, min_hash_value, temp->first()->_hash_value-1, indent+4);
1515228060Sbapt
1516228060Sbapt      printf ("%*s  }\n"
1517228060Sbapt              "%*selse\n"
1518228060Sbapt              "%*s  {\n",
1519228060Sbapt              indent, "", indent, "", indent, "");
1520228060Sbapt
1521228060Sbapt      output_switches (temp, part2, size2, temp->first()->_hash_value, max_hash_value, indent+4);
1522228060Sbapt
1523228060Sbapt      printf ("%*s  }\n",
1524228060Sbapt              indent, "");
1525228060Sbapt    }
1526228060Sbapt  else
1527228060Sbapt    {
1528228060Sbapt      /* Output a single switch.  */
1529228060Sbapt      int lowest_case_value = list->first()->_hash_value;
1530228060Sbapt      if (size == 1)
1531228060Sbapt        {
1532228060Sbapt          int jumps_away = 0;
1533228060Sbapt          assert (min_hash_value <= lowest_case_value);
1534228060Sbapt          assert (lowest_case_value <= max_hash_value);
1535228060Sbapt          if (min_hash_value == max_hash_value)
1536228060Sbapt            output_switch_case (list, indent, &jumps_away);
1537228060Sbapt          else
1538228060Sbapt            {
1539228060Sbapt              printf ("%*sif (key == %d)\n"
1540228060Sbapt                      "%*s  {\n",
1541228060Sbapt                      indent, "", lowest_case_value,
1542228060Sbapt                      indent, "");
1543228060Sbapt              output_switch_case (list, indent+4, &jumps_away);
1544228060Sbapt              printf ("%*s  }\n",
1545228060Sbapt                      indent, "");
1546228060Sbapt            }
1547228060Sbapt        }
1548228060Sbapt      else
1549228060Sbapt        {
1550228060Sbapt          if (lowest_case_value == 0)
1551228060Sbapt            printf ("%*sswitch (key)\n", indent, "");
1552228060Sbapt          else
1553228060Sbapt            printf ("%*sswitch (key - %d)\n", indent, "", lowest_case_value);
1554228060Sbapt          printf ("%*s  {\n",
1555228060Sbapt                  indent, "");
1556228060Sbapt          for (; size > 0; size--)
1557228060Sbapt            {
1558228060Sbapt              int jumps_away = 0;
1559228060Sbapt              printf ("%*s    case %d:\n",
1560228060Sbapt                      indent, "", list->first()->_hash_value - lowest_case_value);
1561228060Sbapt              list = output_switch_case (list, indent+6, &jumps_away);
1562228060Sbapt              if (!jumps_away)
1563228060Sbapt                printf ("%*s      break;\n",
1564228060Sbapt                        indent, "");
1565228060Sbapt            }
1566228060Sbapt          printf ("%*s  }\n",
1567228060Sbapt                  indent, "");
1568228060Sbapt        }
1569228060Sbapt    }
1570228060Sbapt}
1571228060Sbapt
1572228060Sbapt/* Generates C code to perform the keyword lookup.  */
1573228060Sbapt
1574228060Sbaptvoid
1575228060SbaptOutput::output_lookup_function_body (const Output_Compare& comparison) const
1576228060Sbapt{
1577228060Sbapt  printf ("  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)\n"
1578228060Sbapt          "    {\n"
1579228060Sbapt          "      register int key = %s (str, len);\n\n",
1580228060Sbapt          option.get_hash_name ());
1581228060Sbapt
1582228060Sbapt  if (option[SWITCH])
1583228060Sbapt    {
1584228060Sbapt      int switch_size = num_hash_values ();
1585228060Sbapt      int num_switches = option.get_total_switches ();
1586228060Sbapt      if (num_switches > switch_size)
1587228060Sbapt        num_switches = switch_size;
1588228060Sbapt
1589228060Sbapt      printf ("      if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)\n"
1590228060Sbapt              "        {\n");
1591228060Sbapt      if (option[DUP] && _total_duplicates > 0)
1592228060Sbapt        {
1593228060Sbapt          if (option[LENTABLE])
1594228060Sbapt            printf ("          register %s%s *lengthptr;\n",
1595228060Sbapt                    const_always, smallest_integral_type (_max_key_len));
1596228060Sbapt          printf ("          register ");
1597228060Sbapt          output_const_type (const_readonly_array, _wordlist_eltype);
1598228060Sbapt          printf ("*wordptr;\n");
1599228060Sbapt          printf ("          register ");
1600228060Sbapt          output_const_type (const_readonly_array, _wordlist_eltype);
1601228060Sbapt          printf ("*wordendptr;\n");
1602228060Sbapt        }
1603228060Sbapt      if (option[TYPE])
1604228060Sbapt        {
1605228060Sbapt          printf ("          register ");
1606228060Sbapt          output_const_type (const_readonly_array, _struct_tag);
1607228060Sbapt          printf ("*resword;\n\n");
1608228060Sbapt        }
1609228060Sbapt      else
1610228060Sbapt        printf ("          register %sresword;\n\n",
1611228060Sbapt                _struct_tag);
1612228060Sbapt
1613228060Sbapt      output_switches (_head, num_switches, switch_size, _min_hash_value, _max_hash_value, 10);
1614228060Sbapt
1615228060Sbapt      printf ("          return 0;\n");
1616228060Sbapt      if (option[DUP] && _total_duplicates > 0)
1617228060Sbapt        {
1618228060Sbapt          int indent = 8;
1619228060Sbapt          printf ("%*smulticompare:\n"
1620228060Sbapt                  "%*s  while (wordptr < wordendptr)\n"
1621228060Sbapt                  "%*s    {\n",
1622228060Sbapt                  indent, "", indent, "", indent, "");
1623228060Sbapt          if (option[LENTABLE])
1624228060Sbapt            {
1625228060Sbapt              printf ("%*s      if (len == *lengthptr)\n"
1626228060Sbapt                      "%*s        {\n",
1627228060Sbapt                      indent, "", indent, "");
1628228060Sbapt              indent += 4;
1629228060Sbapt            }
1630228060Sbapt          printf ("%*s      register %schar *s = ",
1631228060Sbapt                  indent, "", const_always);
1632228060Sbapt          if (option[TYPE])
1633228060Sbapt            printf ("wordptr->%s", option.get_slot_name ());
1634228060Sbapt          else
1635228060Sbapt            printf ("*wordptr");
1636228060Sbapt          if (option[SHAREDLIB])
1637228060Sbapt            printf (" + %s",
1638228060Sbapt                    option.get_stringpool_name ());
1639228060Sbapt          printf (";\n\n"
1640228060Sbapt                  "%*s      if (",
1641228060Sbapt                  indent, "");
1642228060Sbapt          comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("s"));
1643228060Sbapt          printf (")\n"
1644228060Sbapt                  "%*s        return %s;\n",
1645228060Sbapt                  indent, "",
1646228060Sbapt                  option[TYPE] ? "wordptr" : "s");
1647228060Sbapt          if (option[LENTABLE])
1648228060Sbapt            {
1649228060Sbapt              indent -= 4;
1650228060Sbapt              printf ("%*s        }\n",
1651228060Sbapt                      indent, "");
1652228060Sbapt            }
1653228060Sbapt          if (option[LENTABLE])
1654228060Sbapt            printf ("%*s      lengthptr++;\n",
1655228060Sbapt                    indent, "");
1656228060Sbapt          printf ("%*s      wordptr++;\n"
1657228060Sbapt                  "%*s    }\n"
1658228060Sbapt                  "%*s  return 0;\n",
1659228060Sbapt                  indent, "", indent, "", indent, "");
1660228060Sbapt        }
1661228060Sbapt      printf ("        compare:\n");
1662228060Sbapt      if (option[TYPE])
1663228060Sbapt        {
1664228060Sbapt          printf ("          {\n"
1665228060Sbapt                  "            register %schar *s = resword->%s",
1666228060Sbapt                  const_always, option.get_slot_name ());
1667228060Sbapt          if (option[SHAREDLIB])
1668228060Sbapt            printf (" + %s",
1669228060Sbapt                    option.get_stringpool_name ());
1670228060Sbapt          printf (";\n\n"
1671228060Sbapt                  "            if (");
1672228060Sbapt          comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("s"));
1673228060Sbapt          printf (")\n"
1674228060Sbapt                  "              return resword;\n"
1675228060Sbapt                  "          }\n");
1676228060Sbapt        }
1677228060Sbapt      else
1678228060Sbapt        {
1679228060Sbapt          printf ("          if (");
1680228060Sbapt          comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("resword"));
1681228060Sbapt          printf (")\n"
1682228060Sbapt                  "            return resword;\n");
1683228060Sbapt        }
1684228060Sbapt      printf ("        }\n");
1685228060Sbapt    }
1686228060Sbapt  else
1687228060Sbapt    {
1688228060Sbapt      printf ("      if (key <= MAX_HASH_VALUE && key >= 0)\n");
1689228060Sbapt
1690228060Sbapt      if (option[DUP])
1691228060Sbapt        {
1692228060Sbapt          int indent = 8;
1693228060Sbapt          printf ("%*s{\n"
1694228060Sbapt                  "%*s  register int index = lookup[key];\n\n"
1695228060Sbapt                  "%*s  if (index >= 0)\n",
1696228060Sbapt                  indent, "", indent, "", indent, "");
1697228060Sbapt          if (option[LENTABLE])
1698228060Sbapt            {
1699228060Sbapt              printf ("%*s    {\n"
1700228060Sbapt                      "%*s      if (len == %s[index])\n",
1701228060Sbapt                      indent, "", indent, "", option.get_lengthtable_name ());
1702228060Sbapt              indent += 4;
1703228060Sbapt            }
1704228060Sbapt          printf ("%*s    {\n"
1705228060Sbapt                  "%*s      register %schar *s = %s[index]",
1706228060Sbapt                  indent, "",
1707228060Sbapt                  indent, "", const_always, option.get_wordlist_name ());
1708228060Sbapt          if (option[TYPE])
1709228060Sbapt            printf (".%s", option.get_slot_name ());
1710228060Sbapt          if (option[SHAREDLIB])
1711228060Sbapt            printf (" + %s",
1712228060Sbapt                    option.get_stringpool_name ());
1713228060Sbapt          printf (";\n\n"
1714228060Sbapt                  "%*s      if (",
1715228060Sbapt                  indent, "");
1716228060Sbapt          comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("s"));
1717228060Sbapt          printf (")\n"
1718228060Sbapt                  "%*s        return ",
1719228060Sbapt                  indent, "");
1720228060Sbapt          if (option[TYPE])
1721228060Sbapt            printf ("&%s[index]", option.get_wordlist_name ());
1722228060Sbapt          else
1723228060Sbapt            printf ("s");
1724228060Sbapt          printf (";\n"
1725228060Sbapt                  "%*s    }\n",
1726228060Sbapt                  indent, "");
1727228060Sbapt          if (option[LENTABLE])
1728228060Sbapt            {
1729228060Sbapt              indent -= 4;
1730228060Sbapt              printf ("%*s    }\n", indent, "");
1731228060Sbapt            }
1732228060Sbapt          if (_total_duplicates > 0)
1733228060Sbapt            {
1734228060Sbapt              printf ("%*s  else if (index < -TOTAL_KEYWORDS)\n"
1735228060Sbapt                      "%*s    {\n"
1736228060Sbapt                      "%*s      register int offset = - 1 - TOTAL_KEYWORDS - index;\n",
1737228060Sbapt                      indent, "", indent, "", indent, "");
1738228060Sbapt              if (option[LENTABLE])
1739228060Sbapt                printf ("%*s      register %s%s *lengthptr = &%s[TOTAL_KEYWORDS + lookup[offset]];\n",
1740228060Sbapt                        indent, "", const_always, smallest_integral_type (_max_key_len),
1741228060Sbapt                        option.get_lengthtable_name ());
1742228060Sbapt              printf ("%*s      register ",
1743228060Sbapt                      indent, "");
1744228060Sbapt              output_const_type (const_readonly_array, _wordlist_eltype);
1745228060Sbapt              printf ("*wordptr = &%s[TOTAL_KEYWORDS + lookup[offset]];\n",
1746228060Sbapt                      option.get_wordlist_name ());
1747228060Sbapt              printf ("%*s      register ",
1748228060Sbapt                      indent, "");
1749228060Sbapt              output_const_type (const_readonly_array, _wordlist_eltype);
1750228060Sbapt              printf ("*wordendptr = wordptr + -lookup[offset + 1];\n\n");
1751228060Sbapt              printf ("%*s      while (wordptr < wordendptr)\n"
1752228060Sbapt                      "%*s        {\n",
1753228060Sbapt                      indent, "", indent, "");
1754228060Sbapt              if (option[LENTABLE])
1755228060Sbapt                {
1756228060Sbapt                  printf ("%*s          if (len == *lengthptr)\n"
1757228060Sbapt                          "%*s            {\n",
1758228060Sbapt                          indent, "", indent, "");
1759228060Sbapt                  indent += 4;
1760228060Sbapt                }
1761228060Sbapt              printf ("%*s          register %schar *s = ",
1762228060Sbapt                      indent, "", const_always);
1763228060Sbapt              if (option[TYPE])
1764228060Sbapt                printf ("wordptr->%s", option.get_slot_name ());
1765228060Sbapt              else
1766228060Sbapt                printf ("*wordptr");
1767228060Sbapt              if (option[SHAREDLIB])
1768228060Sbapt                printf (" + %s",
1769228060Sbapt                        option.get_stringpool_name ());
1770228060Sbapt              printf (";\n\n"
1771228060Sbapt                      "%*s          if (",
1772228060Sbapt                      indent, "");
1773228060Sbapt              comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("s"));
1774228060Sbapt              printf (")\n"
1775228060Sbapt                      "%*s            return %s;\n",
1776228060Sbapt                      indent, "",
1777228060Sbapt                      option[TYPE] ? "wordptr" : "s");
1778228060Sbapt              if (option[LENTABLE])
1779228060Sbapt                {
1780228060Sbapt                  indent -= 4;
1781228060Sbapt                  printf ("%*s            }\n",
1782228060Sbapt                          indent, "");
1783228060Sbapt                }
1784228060Sbapt              if (option[LENTABLE])
1785228060Sbapt                printf ("%*s          lengthptr++;\n",
1786228060Sbapt                        indent, "");
1787228060Sbapt              printf ("%*s          wordptr++;\n"
1788228060Sbapt                      "%*s        }\n"
1789228060Sbapt                      "%*s    }\n",
1790228060Sbapt                      indent, "", indent, "", indent, "");
1791228060Sbapt            }
1792228060Sbapt          printf ("%*s}\n",
1793228060Sbapt                  indent, "");
1794228060Sbapt        }
1795228060Sbapt      else
1796228060Sbapt        {
1797228060Sbapt          int indent = 8;
1798228060Sbapt          if (option[LENTABLE])
1799228060Sbapt            {
1800228060Sbapt              printf ("%*sif (len == %s[key])\n",
1801228060Sbapt                      indent, "", option.get_lengthtable_name ());
1802228060Sbapt              indent += 2;
1803228060Sbapt            }
1804228060Sbapt
1805228060Sbapt          if (option[SHAREDLIB])
1806228060Sbapt            {
1807228060Sbapt              if (!option[LENTABLE])
1808228060Sbapt                {
1809228060Sbapt                  printf ("%*s{\n"
1810228060Sbapt                          "%*s  register int o = %s[key]",
1811228060Sbapt                          indent, "",
1812228060Sbapt                          indent, "", option.get_wordlist_name ());
1813228060Sbapt                  if (option[TYPE])
1814228060Sbapt                    printf (".%s", option.get_slot_name ());
1815228060Sbapt                  printf (";\n"
1816228060Sbapt                          "%*s  if (o >= 0)\n"
1817228060Sbapt                          "%*s    {\n",
1818228060Sbapt                          indent, "",
1819228060Sbapt                          indent, "");
1820228060Sbapt                  indent += 4;
1821228060Sbapt                  printf ("%*s  register %schar *s = o",
1822228060Sbapt                          indent, "", const_always);
1823228060Sbapt                }
1824228060Sbapt              else
1825228060Sbapt                {
1826228060Sbapt                  /* No need for the (o >= 0) test, because the
1827228060Sbapt                     (len == lengthtable[key]) test already guarantees that
1828228060Sbapt                     key points to nonempty table entry.  */
1829228060Sbapt                  printf ("%*s{\n"
1830228060Sbapt                          "%*s  register %schar *s = %s[key]",
1831228060Sbapt                          indent, "",
1832228060Sbapt                          indent, "", const_always,
1833228060Sbapt                          option.get_wordlist_name ());
1834228060Sbapt                  if (option[TYPE])
1835228060Sbapt                    printf (".%s", option.get_slot_name ());
1836228060Sbapt                }
1837228060Sbapt              printf (" + %s",
1838228060Sbapt                      option.get_stringpool_name ());
1839228060Sbapt            }
1840228060Sbapt          else
1841228060Sbapt            {
1842228060Sbapt              printf ("%*s{\n"
1843228060Sbapt                      "%*s  register %schar *s = %s[key]",
1844228060Sbapt                      indent, "",
1845228060Sbapt                      indent, "", const_always, option.get_wordlist_name ());
1846228060Sbapt              if (option[TYPE])
1847228060Sbapt                printf (".%s", option.get_slot_name ());
1848228060Sbapt            }
1849228060Sbapt
1850228060Sbapt          printf (";\n\n"
1851228060Sbapt                  "%*s  if (",
1852228060Sbapt                  indent, "");
1853228060Sbapt          if (!option[SHAREDLIB] && option[NULLSTRINGS])
1854228060Sbapt            printf ("s && ");
1855228060Sbapt          comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("s"));
1856228060Sbapt          printf (")\n"
1857228060Sbapt                  "%*s    return ",
1858228060Sbapt                  indent, "");
1859228060Sbapt          if (option[TYPE])
1860228060Sbapt            printf ("&%s[key]", option.get_wordlist_name ());
1861228060Sbapt          else
1862228060Sbapt            printf ("s");
1863228060Sbapt          printf (";\n");
1864228060Sbapt          if (option[SHAREDLIB] && !option[LENTABLE])
1865228060Sbapt            {
1866228060Sbapt              indent -= 4;
1867228060Sbapt              printf ("%*s    }\n",
1868228060Sbapt                      indent, "");
1869228060Sbapt            }
1870228060Sbapt          printf ("%*s}\n",
1871228060Sbapt                  indent, "");
1872228060Sbapt        }
1873228060Sbapt    }
1874228060Sbapt  printf ("    }\n"
1875228060Sbapt          "  return 0;\n");
1876228060Sbapt}
1877228060Sbapt
1878228060Sbapt/* Generates C code for the lookup function.  */
1879228060Sbapt
1880228060Sbaptvoid
1881228060SbaptOutput::output_lookup_function () const
1882228060Sbapt{
1883228060Sbapt  /* Output the function's head.  */
1884228060Sbapt  if (option[KRC] | option[C] | option[ANSIC])
1885228060Sbapt    /* GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99
1886228060Sbapt       inline semantics, unless -fgnu89-inline is used.  It defines a macro
1887228060Sbapt       __GNUC_STDC_INLINE__ to indicate this situation.  */
1888228060Sbapt    printf ("#ifdef __GNUC__\n"
1889228060Sbapt            "__inline\n"
1890228060Sbapt            "#ifdef __GNUC_STDC_INLINE__\n"
1891228060Sbapt            "__attribute__ ((__gnu_inline__))\n"
1892228060Sbapt            "#endif\n"
1893228060Sbapt            "#endif\n");
1894228060Sbapt
1895228060Sbapt  printf ("%s%s\n",
1896228060Sbapt          const_for_struct, _return_type);
1897228060Sbapt  if (option[CPLUSPLUS])
1898228060Sbapt    printf ("%s::", option.get_class_name ());
1899228060Sbapt  printf ("%s ", option.get_function_name ());
1900228060Sbapt  printf (option[KRC] ?
1901228060Sbapt                 "(str, len)\n"
1902228060Sbapt            "     register char *str;\n"
1903228060Sbapt            "     register unsigned int len;\n" :
1904228060Sbapt          option[C] ?
1905228060Sbapt                 "(str, len)\n"
1906228060Sbapt            "     register const char *str;\n"
1907228060Sbapt            "     register unsigned int len;\n" :
1908228060Sbapt          option[ANSIC] | option[CPLUSPLUS] ?
1909228060Sbapt                 "(register const char *str, register unsigned int len)\n" :
1910228060Sbapt          "");
1911228060Sbapt
1912228060Sbapt  /* Output the function's body.  */
1913228060Sbapt  printf ("{\n");
1914228060Sbapt
1915228060Sbapt  if (option[ENUM] && !option[GLOBAL])
1916228060Sbapt    {
1917228060Sbapt      Output_Enum style ("  ");
1918228060Sbapt      output_constants (style);
1919228060Sbapt    }
1920228060Sbapt
1921228060Sbapt  if (option[SHAREDLIB] && !(option[GLOBAL] || option[TYPE]))
1922228060Sbapt    output_lookup_pools ();
1923228060Sbapt  if (!option[GLOBAL])
1924228060Sbapt    output_lookup_tables ();
1925228060Sbapt
1926228060Sbapt  if (option[LENTABLE])
1927228060Sbapt    output_lookup_function_body (Output_Compare_Memcmp ());
1928228060Sbapt  else
1929228060Sbapt    {
1930228060Sbapt      if (option[COMP])
1931228060Sbapt        output_lookup_function_body (Output_Compare_Strncmp ());
1932228060Sbapt      else
1933228060Sbapt        output_lookup_function_body (Output_Compare_Strcmp ());
1934228060Sbapt    }
1935228060Sbapt
1936228060Sbapt  printf ("}\n");
1937228060Sbapt}
1938228060Sbapt
1939228060Sbapt/* ------------------------------------------------------------------------- */
1940228060Sbapt
1941228060Sbapt/* Generates the hash function and the key word recognizer function
1942228060Sbapt   based upon the user's Options.  */
1943228060Sbapt
1944228060Sbaptvoid
1945228060SbaptOutput::output ()
1946228060Sbapt{
1947228060Sbapt  compute_min_max ();
1948228060Sbapt
1949228060Sbapt  if (option[C] | option[ANSIC] | option[CPLUSPLUS])
1950228060Sbapt    {
1951228060Sbapt      const_always = "const ";
1952228060Sbapt      const_readonly_array = (option[CONST] ? "const " : "");
1953228060Sbapt      const_for_struct = ((option[CONST] && option[TYPE]) ? "const " : "");
1954228060Sbapt    }
1955228060Sbapt  else
1956228060Sbapt    {
1957228060Sbapt      const_always = "";
1958228060Sbapt      const_readonly_array = "";
1959228060Sbapt      const_for_struct = "";
1960228060Sbapt    }
1961228060Sbapt
1962228060Sbapt  if (!option[TYPE])
1963228060Sbapt    {
1964228060Sbapt      _return_type = (const_always[0] ? "const char *" : "char *");
1965228060Sbapt      _struct_tag = (const_always[0] ? "const char *" : "char *");
1966228060Sbapt    }
1967228060Sbapt
1968228060Sbapt  _wordlist_eltype = (option[SHAREDLIB] && !option[TYPE] ? "int" : _struct_tag);
1969228060Sbapt
1970228060Sbapt  printf ("/* ");
1971228060Sbapt  if (option[KRC])
1972228060Sbapt    printf ("KR-C");
1973228060Sbapt  else if (option[C])
1974228060Sbapt    printf ("C");
1975228060Sbapt  else if (option[ANSIC])
1976228060Sbapt    printf ("ANSI-C");
1977228060Sbapt  else if (option[CPLUSPLUS])
1978228060Sbapt    printf ("C++");
1979228060Sbapt  printf (" code produced by gperf version %s */\n", version_string);
1980228060Sbapt  option.print_options ();
1981228060Sbapt  printf ("\n");
1982228060Sbapt  if (!option[POSITIONS])
1983228060Sbapt    {
1984228060Sbapt      printf ("/* Computed positions: -k'");
1985228060Sbapt      _key_positions.print();
1986228060Sbapt      printf ("' */\n");
1987228060Sbapt    }
1988228060Sbapt  printf ("\n");
1989228060Sbapt
1990228060Sbapt  if (_charset_dependent
1991228060Sbapt      && (_key_positions.get_size() > 0 || option[UPPERLOWER]))
1992228060Sbapt    {
1993228060Sbapt      /* The generated tables assume that the execution character set is
1994228060Sbapt         based on ISO-646, not EBCDIC.  */
1995228060Sbapt      printf ("#if !((' ' == 32) && ('!' == 33) && ('\"' == 34) && ('#' == 35) \\\n"
1996228060Sbapt              "      && ('%%' == 37) && ('&' == 38) && ('\\'' == 39) && ('(' == 40) \\\n"
1997228060Sbapt              "      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \\\n"
1998228060Sbapt              "      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \\\n"
1999228060Sbapt              "      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \\\n"
2000228060Sbapt              "      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \\\n"
2001228060Sbapt              "      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \\\n"
2002228060Sbapt              "      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \\\n"
2003228060Sbapt              "      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \\\n"
2004228060Sbapt              "      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \\\n"
2005228060Sbapt              "      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \\\n"
2006228060Sbapt              "      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \\\n"
2007228060Sbapt              "      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \\\n"
2008228060Sbapt              "      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \\\n"
2009228060Sbapt              "      && ('Z' == 90) && ('[' == 91) && ('\\\\' == 92) && (']' == 93) \\\n"
2010228060Sbapt              "      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \\\n"
2011228060Sbapt              "      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \\\n"
2012228060Sbapt              "      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \\\n"
2013228060Sbapt              "      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \\\n"
2014228060Sbapt              "      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \\\n"
2015228060Sbapt              "      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \\\n"
2016228060Sbapt              "      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \\\n"
2017228060Sbapt              "      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))\n"
2018228060Sbapt              "/* The character set is not based on ISO-646.  */\n");
2019228060Sbapt      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");
2020228060Sbapt      printf ("#endif\n\n");
2021228060Sbapt    }
2022228060Sbapt
2023228060Sbapt  if (_verbatim_declarations < _verbatim_declarations_end)
2024228060Sbapt    {
2025228060Sbapt      output_line_directive (_verbatim_declarations_lineno);
2026228060Sbapt      fwrite (_verbatim_declarations, 1,
2027228060Sbapt              _verbatim_declarations_end - _verbatim_declarations, stdout);
2028228060Sbapt    }
2029228060Sbapt
2030228060Sbapt  if (option[TYPE] && !option[NOTYPE]) /* Output type declaration now, reference it later on.... */
2031228060Sbapt    {
2032228060Sbapt      output_line_directive (_struct_decl_lineno);
2033228060Sbapt      printf ("%s\n", _struct_decl);
2034228060Sbapt    }
2035228060Sbapt
2036259320Spfg  if (option[INCLUDE]) {
2037228060Sbapt    printf ("#include <string.h>\n"); /* Declare strlen(), strcmp(), strncmp(). */
2038259320Spfg    if (option[SHAREDLIB])
2039259320Spfg      printf("#include <stddef.h>\n"); /* Declare offsetof() */
2040259320Spfg  }
2041228060Sbapt
2042228060Sbapt  if (!option[ENUM])
2043228060Sbapt    {
2044228060Sbapt      Output_Defines style;
2045228060Sbapt      output_constants (style);
2046228060Sbapt    }
2047228060Sbapt  else if (option[GLOBAL])
2048228060Sbapt    {
2049228060Sbapt      Output_Enum style ("");
2050228060Sbapt      output_constants (style);
2051228060Sbapt    }
2052228060Sbapt
2053228060Sbapt  printf ("/* maximum key range = %d, duplicates = %d */\n\n",
2054228060Sbapt          _max_hash_value - _min_hash_value + 1, _total_duplicates);
2055228060Sbapt
2056228060Sbapt  if (option[UPPERLOWER])
2057228060Sbapt    {
2058228060Sbapt      #if USE_DOWNCASE_TABLE
2059228060Sbapt      output_upperlower_table ();
2060228060Sbapt      #endif
2061228060Sbapt
2062228060Sbapt      if (option[LENTABLE])
2063228060Sbapt        output_upperlower_memcmp ();
2064228060Sbapt      else
2065228060Sbapt        {
2066228060Sbapt          if (option[COMP])
2067228060Sbapt            output_upperlower_strncmp ();
2068228060Sbapt          else
2069228060Sbapt            output_upperlower_strcmp ();
2070228060Sbapt        }
2071228060Sbapt    }
2072228060Sbapt
2073228060Sbapt  if (option[CPLUSPLUS])
2074228060Sbapt    printf ("class %s\n"
2075228060Sbapt            "{\n"
2076228060Sbapt            "private:\n"
2077228060Sbapt            "  static inline unsigned int %s (const char *str, unsigned int len);\n"
2078228060Sbapt            "public:\n"
2079228060Sbapt            "  static %s%s%s (const char *str, unsigned int len);\n"
2080228060Sbapt            "};\n"
2081228060Sbapt            "\n",
2082228060Sbapt            option.get_class_name (), option.get_hash_name (),
2083228060Sbapt            const_for_struct, _return_type, option.get_function_name ());
2084228060Sbapt
2085228060Sbapt  output_hash_function ();
2086228060Sbapt
2087228060Sbapt  if (option[SHAREDLIB] && (option[GLOBAL] || option[TYPE]))
2088228060Sbapt    output_lookup_pools ();
2089228060Sbapt  if (option[GLOBAL])
2090228060Sbapt    output_lookup_tables ();
2091228060Sbapt
2092228060Sbapt  output_lookup_function ();
2093228060Sbapt
2094228060Sbapt  if (_verbatim_code < _verbatim_code_end)
2095228060Sbapt    {
2096228060Sbapt      output_line_directive (_verbatim_code_lineno);
2097228060Sbapt      fwrite (_verbatim_code, 1, _verbatim_code_end - _verbatim_code, stdout);
2098228060Sbapt    }
2099228060Sbapt
2100228060Sbapt  fflush (stdout);
2101228060Sbapt}
2102