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" 775260386Spfg " register unsigned int len;\n" : 776228060Sbapt option[C] ? 777228060Sbapt "(str, len)\n" 778228060Sbapt " register const char *str;\n" 779260386Spfg " register unsigned int len;\n" : 780228060Sbapt option[ANSIC] | option[CPLUSPLUS] ? 781260386Spfg "(register const char *str, register unsigned int len)\n" : 782260386Spfg ""); 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", 878260386Spfg 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]) 1109258115Spfg 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" 1903260386Spfg " register unsigned int len;\n" : 1904228060Sbapt option[C] ? 1905228060Sbapt "(str, len)\n" 1906228060Sbapt " register const char *str;\n" 1907260386Spfg " register unsigned int len;\n" : 1908228060Sbapt option[ANSIC] | option[CPLUSPLUS] ? 1909260386Spfg "(register const char *str, register unsigned int len)\n" : 1910260386Spfg ""); 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 2036258115Spfg if (option[INCLUDE]) { 2037228060Sbapt printf ("#include <string.h>\n"); /* Declare strlen(), strcmp(), strncmp(). */ 2038258115Spfg if (option[SHAREDLIB]) 2039258115Spfg printf("#include <stddef.h>\n"); /* Declare offsetof() */ 2040258115Spfg } 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" 2077260386Spfg " static inline unsigned int %s (const char *str, unsigned int len);\n" 2078228060Sbapt "public:\n" 2079260386Spfg " static %s%s%s (const char *str, unsigned int len);\n" 2080228060Sbapt "};\n" 2081228060Sbapt "\n", 2082260386Spfg option.get_class_name (), option.get_hash_name (), 2083260386Spfg 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