home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume20 / gperf / part04 < prev    next >
Encoding:
Internet Message Format  |  1989-10-18  |  33.8 KB

  1. Subject:  v20i043:  Perfect hash generator for sets of key words, Part04/05
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: "Douglas C. Schmidt" <schmidt@zola.ics.uci.edu>
  7. Posting-number: Volume 20, Issue 43
  8. Archive-name: gperf/part04
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 4 (of 5)."
  17. # Contents:  cperf/src/keylist.c
  18. # Wrapped by schmidt@crimee.ics.uci.edu on Wed Oct 18 18:27:27 1989
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'cperf/src/keylist.c' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'cperf/src/keylist.c'\"
  22. else
  23. echo shar: Extracting \"'cperf/src/keylist.c'\" \(31979 characters\)
  24. sed "s/^X//" >'cperf/src/keylist.c' <<'END_OF_FILE'
  25. X/* Routines for building, ordering, and printing the keyword list.
  26. X   Copyright (C) 1989 Free Software Foundation, Inc.
  27. X   written by Douglas C. Schmidt (schmidt@ics.uci.edu)
  28. X
  29. XThis file is part of GNU GPERF.
  30. X
  31. XGNU GPERF is free software; you can redistribute it and/or modify
  32. Xit under the terms of the GNU General Public License as published by
  33. Xthe Free Software Foundation; either version 1, or (at your option)
  34. Xany later version.
  35. X
  36. XGNU GPERF is distributed in the hope that it will be useful,
  37. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  38. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  39. XGNU General Public License for more details.
  40. X
  41. XYou should have received a copy of the GNU General Public License
  42. Xalong with GNU GPERF; see the file COPYING.  If not, write to
  43. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  44. X
  45. X#include <assert.h>
  46. X#include <stdio.h>
  47. X#include "options.h"
  48. X#include "readline.h"
  49. X#include "keylist.h"
  50. X#include "hashtable.h"
  51. X#include "stderr.h"
  52. X
  53. X/* Current release version. */
  54. Xextern char *version_string;
  55. X
  56. X/* See comments in perfect.cc. */
  57. Xextern int occurrences[ALPHABET_SIZE]; 
  58. X
  59. X/* Ditto. */
  60. Xextern int asso_values[ALPHABET_SIZE];
  61. X
  62. X/* Used in function reorder, below. */
  63. Xstatic bool determined[ALPHABET_SIZE]; 
  64. X
  65. X/* Default type for generated code. */
  66. Xstatic char *default_array_type = "char *";
  67. X
  68. X/* Generated function ``in_word_set'' default return type. */
  69. Xstatic char *default_return_type = "char *";
  70. X
  71. X/* Largest positive integer value. */
  72. X#define MAX_INT ((~(unsigned)0)>>1)
  73. X
  74. X/* Most negative integer value. */
  75. X#define NEG_MAX_INT ((~(unsigned)0)^((~(unsigned)0)>>1))
  76. X
  77. X/* How wide the printed field width must be to contain the maximum hash value. */
  78. Xstatic int field_width = 2;
  79. X
  80. X/* Globally visible KEY_LIST object. */
  81. X
  82. XKEY_LIST key_list;
  83. X
  84. X/* Gathers the input stream into a buffer until one of two things occur:
  85. X
  86. X   1. We read a '%' followed by a '%'
  87. X   2. We read a '%' followed by a '}'
  88. X
  89. X   The first symbolizes the beginning of the keyword list proper,
  90. X   The second symbolizes the end of the C source code to be generated
  91. X   verbatim in the output file.
  92. X
  93. X   I assume that the keys are separated from the optional preceding struct
  94. X   declaration by a consecutive % followed by either % or } starting in 
  95. X   the first column. The code below uses an expandible buffer to scan off 
  96. X   and return a pointer to all the code (if any) appearing before the delimiter. */
  97. X
  98. Xstatic char *
  99. Xget_special_input (delimiter)
  100. X     char delimiter;
  101. X{ 
  102. X  char *xmalloc ();
  103. X  int size  = 80;
  104. X  char *buf = xmalloc (size);
  105. X  int c, i;
  106. X
  107. X  for (i = 0; (c = getchar ()) != EOF; i++)
  108. X    {
  109. X      if (c == '%')
  110. X        {
  111. X          if ((c = getchar ()) == delimiter)
  112. X            {
  113. X        
  114. X              while ((c = getchar ()) != '\n')
  115. X                ; /* Discard newline. */
  116. X              
  117. X              if (i == 0)
  118. X                return "";
  119. X              else
  120. X                {
  121. X                  buf[delimiter == '%' && buf[i - 2] == ';' ? i - 2 : i - 1] = '\0';
  122. X                  return buf;
  123. X                }
  124. X            }
  125. X          else
  126. X            ungetc (c, stdin);
  127. X        }
  128. X      else if (i >= size) /* Yikes, time to grow the buffer! */
  129. X        { 
  130. X          char *temp = xmalloc (size *= 2);
  131. X          int j;
  132. X          
  133. X          for (j = 0; j < i; j++)
  134. X            temp[j] = buf[j];
  135. X          
  136. X          free (buf);
  137. X          buf = temp;
  138. X        }
  139. X      buf[i] = c;
  140. X    }
  141. X  
  142. X  return NULL;        /* Problem here. */
  143. X}
  144. X
  145. X/* Stores any C text that must be included verbatim into the 
  146. X   generated code output. */
  147. X
  148. Xstatic char *
  149. Xsave_include_src ()
  150. X{
  151. X  int c;
  152. X  
  153. X  if ((c = getchar ()) != '%')
  154. X    {
  155. X      ungetc (c, stdin);
  156. X      return "";
  157. X    }
  158. X  else if ((c = getchar ()) != '{')
  159. X    report_error ("internal error, %c != '{' on line %d in file %s%a", c, __LINE__, __FILE__);
  160. X    /*NOT REACHED*/
  161. X  else 
  162. X    return get_special_input ('}');
  163. X}
  164. X
  165. X/* strcspn - find length of initial segment of s consisting entirely
  166. X   of characters not from reject (borrowed from Henry Spencer's
  167. X   ANSI string package). */
  168. X
  169. Xstatic int
  170. Xstrcspn (s, reject)
  171. X     char *s;
  172. X     char *reject;
  173. X{
  174. X  char *scan;
  175. X  char *rej_scan;
  176. X  int   count = 0;
  177. X
  178. X  for (scan = s; *scan; scan++) 
  179. X    {
  180. X
  181. X      for (rej_scan = reject; *rej_scan;) 
  182. X        if (*scan == *rej_scan++)
  183. X          return count;
  184. X
  185. X      count++;
  186. X    }
  187. X
  188. X  return count;
  189. X}
  190. X
  191. X/* Determines from the input file whether the user wants to build a table
  192. X   from a user-defined struct, or whether the user is content to simply
  193. X   use the default array of keys. */
  194. X
  195. Xstatic char *
  196. Xget_array_type ()
  197. X{
  198. X  return get_special_input ('%');
  199. X}  
  200. X  
  201. X/* Sets up the Return_Type, the Struct_Tag type and the Array_Type
  202. X   based upon various user Options. */
  203. X
  204. Xstatic void 
  205. Xset_output_types ()
  206. X{
  207. X  char *xmalloc ();
  208. X  
  209. X  if (OPTION_ENABLED (option, TYPE) && !(key_list.array_type = get_array_type ()))
  210. X    return;                     /* Something's wrong, bug we'll catch it later on.... */
  211. X  else if (OPTION_ENABLED (option, TYPE))        /* Yow, we've got a user-defined type... */
  212. X    {    
  213. X      int struct_tag_length = strcspn (key_list.array_type, "{\n\0");
  214. X      
  215. X      if (OPTION_ENABLED (option, POINTER))      /* And it must return a pointer... */
  216. X        {    
  217. X          key_list.return_type = xmalloc (struct_tag_length + 2);
  218. X          strncpy (key_list.return_type, key_list.array_type, struct_tag_length);
  219. X          key_list.return_type[struct_tag_length] = '\0';
  220. X          strcat (key_list.return_type, "*");
  221. X        }
  222. X      
  223. X      key_list.struct_tag = (char *) xmalloc (struct_tag_length + 1);
  224. X      strncpy (key_list.struct_tag, key_list.array_type, struct_tag_length);
  225. X      key_list.struct_tag[struct_tag_length] = '\0';
  226. X    }  
  227. X  else if (OPTION_ENABLED (option, POINTER))     /* Return a char *. */
  228. X    key_list.return_type = default_array_type;
  229. X}
  230. X
  231. X/* Reads in all keys from standard input and creates a linked list pointed
  232. X   to by Head.  This list is then quickly checked for ``links,'' i.e.,
  233. X   unhashable elements possessing identical key sets and lengths. */
  234. X
  235. Xvoid 
  236. Xread_keys ()
  237. X{
  238. X  char     *ptr;
  239. X  
  240. X  key_list.include_src = save_include_src ();
  241. X  set_output_types ();
  242. X
  243. X  /* Oops, problem with the input file. */  
  244. X  if (! (ptr = read_line ())) 
  245. X    report_error ("No words in input file, did you forget to prepend %s or use -t accidentally?\n%a", "%%");
  246. X
  247. X  /* Read in all the keywords from the input file. */
  248. X  else 
  249. X    {                      
  250. X      LIST_NODE *temp, *trail;
  251. X
  252. X      for (temp = key_list.head = make_list_node (ptr, strcspn (ptr, ",\n"));
  253. X           (ptr = read_line ()) && strcmp (ptr, "%%");
  254. X           key_list.total_keys++, temp = temp->next)
  255. X        temp->next = make_list_node (ptr, strcspn (ptr, ",\n"));
  256. X      
  257. X      /* See if any additional C code is included at end of this file. */
  258. X      if (ptr)
  259. X        key_list.additional_code = TRUE;
  260. X      {
  261. X        /* If this becomes TRUE we've got a link. */
  262. X        bool       link = FALSE;  
  263. X
  264. X        /* Hash table this number of times larger than keyword number. */
  265. X        int table_multiple = 5; 
  266. X
  267. X        /* Make large hash table for efficiency. */
  268. X        hash_table_init ((key_list.list_len = key_list.total_keys) * table_multiple); 
  269. X
  270. X        /* Test whether there are any links and also set the maximum length of
  271. X          an identifier in the keyword list. */
  272. X      
  273. X        for (temp = key_list.head, trail = NULL; temp; temp = temp->next)
  274. X          {
  275. X            LIST_NODE *ptr = retrieve (temp, OPTION_ENABLED (option, NOLENGTH));
  276. X          
  277. X            /* Check for links.  We deal with these by building an equivalence class
  278. X              of all duplicate values (i.e., links) so that only 1 keyword is
  279. X                representative of the entire collection.  This *greatly* simplifies
  280. X                  processing during later stages of the program. */
  281. X
  282. X            if (ptr)              
  283. X              {                   
  284. X                key_list.list_len--;
  285. X                trail->next = temp->next;
  286. X                temp->link  = ptr->link;
  287. X                ptr->link   = temp;
  288. X                link        = TRUE;
  289. X
  290. X                /* Complain if user hasn't enabled the duplicate option. */
  291. X                if (!OPTION_ENABLED (option, DUP))
  292. X                  report_error ("Key link: \"%s\" = \"%s\", with key set \"%s\".\n", temp->key, ptr->key, temp->key_set);
  293. X                else if (OPTION_ENABLED (option, DEBUG))
  294. X                  report_error ("Key link: \"%s\" = \"%s\", with key set \"%s\".\n", temp->key, ptr->key, temp->key_set);                
  295. X              }
  296. X            else
  297. X              trail = temp;
  298. X            
  299. X            /* Update minimum and maximum keyword length, if needed. */
  300. X            if (temp->length > key_list.max_key_len) 
  301. X              key_list.max_key_len = temp->length;
  302. X            if (temp->length < key_list.min_key_len) 
  303. X              key_list.min_key_len = temp->length;
  304. X          }
  305. X
  306. X        /* Exit program if links exists and option[DUP] not set, since we can't continue */
  307. X        if (link) 
  308. X          {
  309. X            if (OPTION_ENABLED (option, DUP))
  310. X              {
  311. X                if (!OPTION_ENABLED (option, SWITCH))
  312. X                  {
  313. X                    report_error ("turning on -S option.\n");
  314. X                    SET_OPTION (option, SWITCH);
  315. X                  }
  316. X                report_error ("Some input keys have identical hash values, examine output carefully...\n");
  317. X              }
  318. X            else
  319. X              report_error ("Some input keys have identical hash values,\ntry different key positions or use option -D.\n%a");
  320. X          }
  321. X        else if (OPTION_ENABLED (option, DUP))
  322. X          {
  323. X            /* If no links, clear the DUP option so we can use the length
  324. X              table, if output. */
  325. X            UNSET_OPTION (option, DUP);
  326. X          }
  327. X        
  328. X      }
  329. X    }
  330. X}
  331. X
  332. X/* Recursively merges two sorted lists together to form one sorted list. The
  333. X   ordering criteria is by frequency of occurrence of elements in the key set
  334. X   or by the hash value.  This is a kludge, but permits nice sharing of
  335. X   almost identical code without incurring the overhead of a function
  336. X   call comparison. */
  337. X  
  338. Xstatic 
  339. XLIST_NODE *merge (list1, list2)
  340. X     LIST_NODE *list1;
  341. X     LIST_NODE *list2;
  342. X{
  343. X  if (!list1)
  344. X    return list2;
  345. X  else if (!list2)
  346. X    return list1;
  347. X  else if (key_list.occurrence_sort && list1->occurrence < list2->occurrence
  348. X           || key_list.hash_sort && list1->hash_value > list2->hash_value)
  349. X    {
  350. X      list2->next = merge (list2->next, list1);
  351. X      return list2;
  352. X    }
  353. X  else
  354. X    {
  355. X      list1->next = merge (list1->next, list2);
  356. X      return list1;
  357. X    }
  358. X}
  359. X
  360. X/* Applies the merge sort algorithm to recursively sort the key list by
  361. X   frequency of occurrence of elements in the key set. */
  362. X  
  363. Xstatic 
  364. XLIST_NODE *merge_sort (head)
  365. X     LIST_NODE *head;
  366. X{ 
  367. X  if (!head || !head->next)
  368. X    return head;
  369. X  else
  370. X    {
  371. X      LIST_NODE *middle = head;
  372. X      LIST_NODE *temp   = head->next->next;
  373. X    
  374. X      while (temp)
  375. X        {
  376. X          temp   = temp->next;
  377. X          middle = middle->next;
  378. X          if (temp)
  379. X            temp = temp->next;
  380. X        } 
  381. X    
  382. X      temp         = middle->next;
  383. X      middle->next = NULL;
  384. X      return merge (merge_sort (head), merge_sort (temp));
  385. X    }   
  386. X}
  387. X
  388. X/* Returns the frequency of occurrence of elements in the key set. */
  389. X
  390. Xstatic int 
  391. Xget_occurrence (ptr)
  392. X     LIST_NODE *ptr;
  393. X{
  394. X  int   value = 0;
  395. X  char *temp;
  396. X
  397. X  for (temp = ptr->key_set; *temp; temp++)
  398. X    value += occurrences[*temp];
  399. X  
  400. X  return value;
  401. X}
  402. X
  403. X/* Enables the index location of all key set elements that are now 
  404. X   determined. */
  405. X  
  406. Xstatic void 
  407. Xset_determined (ptr)
  408. X     LIST_NODE *ptr;
  409. X{
  410. X  char *temp;
  411. X  
  412. X  for (temp = ptr->key_set; *temp; temp++)
  413. X    determined[*temp] = TRUE;
  414. X  
  415. X}
  416. X
  417. X/* Returns TRUE if PTR's key set is already completely determined. */
  418. X
  419. Xstatic bool 
  420. Xalready_determined (ptr)
  421. X     LIST_NODE *ptr;
  422. X{
  423. X  bool  is_determined = TRUE;
  424. X  char *temp;
  425. X
  426. X  for (temp = ptr->key_set; is_determined && *temp; temp++)
  427. X    is_determined = determined[*temp];
  428. X  
  429. X  return is_determined;
  430. X}
  431. X
  432. X/* Reorders the table by first sorting the list so that frequently occuring 
  433. X   keys appear first, and then the list is reorded so that keys whose values 
  434. X   are already determined will be placed towards the front of the list.  This
  435. X   helps prune the search time by handling inevitable collisions early in the
  436. X   search process.  See Cichelli's paper from Jan 1980 JACM for details.... */
  437. X
  438. Xvoid 
  439. Xreorder ()
  440. X{
  441. X  LIST_NODE *ptr;
  442. X
  443. X  for (ptr = key_list.head; ptr; ptr = ptr->next)
  444. X    ptr->occurrence = get_occurrence (ptr);
  445. X  
  446. X  key_list.hash_sort       = FALSE;
  447. X  key_list.occurrence_sort = TRUE;
  448. X  
  449. X  for (ptr = key_list.head = merge_sort (key_list.head); ptr->next; ptr = ptr->next)
  450. X    {
  451. X      set_determined (ptr);
  452. X    
  453. X      if (already_determined (ptr->next))
  454. X        continue;
  455. X      else
  456. X        {
  457. X          LIST_NODE *trail_ptr = ptr->next;
  458. X          LIST_NODE *run_ptr   = trail_ptr->next;
  459. X      
  460. X          for (; run_ptr; run_ptr = trail_ptr->next)
  461. X            {
  462. X        
  463. X              if (already_determined (run_ptr))
  464. X                {
  465. X                  trail_ptr->next = run_ptr->next;
  466. X                  run_ptr->next   = ptr->next;
  467. X                  ptr = ptr->next = run_ptr;
  468. X                }
  469. X              else
  470. X                trail_ptr = run_ptr;
  471. X            }
  472. X        }
  473. X    }     
  474. X}
  475. X
  476. X/* Determines the maximum and minimum hash values.  One notable feature is 
  477. X   Ira Pohl's optimal algorithm to calculate both the maximum and minimum
  478. X   items in a list in O(3n/2) time (faster than the O (2n) method). 
  479. X   Returns the maximum hash value encountered. */
  480. X  
  481. Xstatic int 
  482. Xprint_min_max ()
  483. X{
  484. X  int          min_hash_value;
  485. X  int          max_hash_value;
  486. X  LIST_NODE   *temp;
  487. X  
  488. X  if (ODD (key_list.list_len)) /* Pre-process first item, list now has an even length. */
  489. X    {              
  490. X      min_hash_value  = max_hash_value = key_list.head->hash_value;
  491. X      temp            = key_list.head->next;
  492. X    }
  493. X  else /* List is already even length, no extra work necessary. */
  494. X    {                      
  495. X      min_hash_value = MAX_INT;
  496. X      max_hash_value = NEG_MAX_INT;
  497. X      temp           = key_list.head;
  498. X    }
  499. X  
  500. X  for ( ; temp; temp = temp->next) /* Find max and min in optimal o(3n/2) time. */
  501. X    { 
  502. X      static int i;
  503. X      int key_2, key_1 = temp->hash_value;
  504. X      temp  = temp->next;
  505. X      key_2 = temp->hash_value;
  506. X      i++;
  507. X      
  508. X      if (key_1 < key_2)
  509. X        {
  510. X          if (key_1 < min_hash_value)
  511. X            min_hash_value = key_1;
  512. X          if (key_2 > max_hash_value)
  513. X            max_hash_value = key_2;
  514. X        }
  515. X      else
  516. X        {
  517. X          if (key_2 < min_hash_value)
  518. X            min_hash_value = key_2;
  519. X          if (key_1 > max_hash_value)
  520. X            max_hash_value = key_1;
  521. X        }
  522. X  }
  523. X  
  524. X  printf ("\n#define MIN_WORD_LENGTH %d\n#define MAX_WORD_LENGTH %d\
  525. X\n#define MIN_HASH_VALUE %d\n#define MAX_HASH_VALUE %d\
  526. X\n/*\n%5d keywords\n%5d is the maximum key range\n*/\n\n",
  527. X          key_list.min_key_len == MAX_INT ? key_list.max_key_len : key_list.min_key_len,
  528. X          key_list.max_key_len, min_hash_value, max_hash_value,
  529. X          key_list.total_keys, (max_hash_value - min_hash_value + 1));
  530. X  return max_hash_value;
  531. X}
  532. X
  533. X/* Generates the output using a C switch.  This trades increased search
  534. X   time for decreased table space (potentially *much* less space for
  535. X   sparse tables). It the user has specified their own struct in the
  536. X   keyword file *and* they enable the POINTER option we have extra work to
  537. X   do.  The solution here is to maintain a local static array of user
  538. X   defined struct's, as with the Print_Lookup_Function.  Then we use for
  539. X   switch statements to perform a strcmp or strncmp, returning 0 if the str 
  540. X   fails to match, and otherwise returning a pointer to appropriate index
  541. X   location in the local static array. */
  542. X
  543. X#ifdef sparc
  544. X#include <alloca.h>
  545. X#endif
  546. X
  547. Xstatic void 
  548. Xprint_switch ()
  549. X{
  550. X  char *comp_buffer;
  551. X  int   pointer_and_type_enabled = OPTION_ENABLED (option, POINTER) && OPTION_ENABLED (option, TYPE);
  552. X
  553. X  if (pointer_and_type_enabled)
  554. X    {
  555. X      comp_buffer = (char *) alloca (strlen ("*str == *resword->%s && !strncmp (str + 1, resword->%s + 1, len - 1)"
  556. X                                             + 2 * strlen (GET_KEY_NAME (option)) + 1));
  557. X      sprintf (comp_buffer, OPTION_ENABLED (option, COMP)
  558. X               ? "*str == *resword->%s && !strncmp (str + 1, resword->%s + 1, len - 1)"
  559. X               : "*str == *resword->%s && !strcmp (str + 1, resword->%s + 1)", GET_KEY_NAME (option), GET_KEY_NAME (option));
  560. X    }
  561. X  else
  562. X    comp_buffer = OPTION_ENABLED (option, COMP) 
  563. X      ? "*str == *resword && !strncmp (str + 1, resword + 1, len - 1)" 
  564. X        : "*str == *resword && !strcmp (str + 1, resword + 1)";
  565. X
  566. X  printf ("  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)\n    {\n\
  567. X      register int key = %s (str, len);\n\n\
  568. X      if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)\n        {\n",
  569. X          GET_HASH_NAME (option));
  570. X  
  571. X  /* Output each keyword as part of a switch statement indexed by hash value. */
  572. X  
  573. X  if (OPTION_ENABLED (option, POINTER) || OPTION_ENABLED (option, DUP))
  574. X    {
  575. X      LIST_NODE *temp;
  576. X
  577. X      printf ("          %s%s *resword; %s\n\n          switch (key)\n            {\n",
  578. X              OPTION_ENABLED (option, CONST) ? "const " : "",
  579. X              pointer_and_type_enabled ? key_list.struct_tag : "char", 
  580. X              OPTION_ENABLED (option, LENTABLE) && !OPTION_ENABLED (option, DUP) ? "int key_len;" : "");
  581. X
  582. X      for (temp = key_list.head; temp; temp = temp->next)
  583. X        {
  584. X          printf ("            case %*d:\n", field_width, temp->hash_value);
  585. X
  586. X          if (temp->link)
  587. X            {
  588. X              LIST_NODE *links;
  589. X
  590. X              for (links = temp; links; links = links->link)
  591. X                {
  592. X                  if (pointer_and_type_enabled)
  593. X                    printf ("              resword = &wordlist[%d];\n", links->index);
  594. X                  else
  595. X                    printf ("              resword = \"%s\";\n", links->key); 
  596. X                  printf ("              if (%s) return resword;\n", comp_buffer);
  597. X                }
  598. X              printf ("              return 0;\n");
  599. X            }
  600. X          else if (temp->next && temp->hash_value == temp->next->hash_value)
  601. X            {
  602. X
  603. X              for ( ; temp->next && temp->hash_value == temp->next->hash_value;
  604. X                   temp = temp->next)
  605. X                {
  606. X                  if (pointer_and_type_enabled)
  607. X                    printf ("              resword = &wordlist[%d];\n", temp->index);
  608. X                  else
  609. X                    printf ("              resword = \"%s\";\n", temp->key);
  610. X                  printf ("              if (%s) return resword;\n", comp_buffer);
  611. X                }
  612. X              if (pointer_and_type_enabled)
  613. X                printf ("              resword = &wordlist[%d];\n", temp->index);
  614. X              else
  615. X                printf ("              resword = \"%s\";\n", temp->key);
  616. X              printf ("              return %s ? resword : 0;\n", comp_buffer);
  617. X            }
  618. X          else 
  619. X            {
  620. X              if (pointer_and_type_enabled)
  621. X                printf ("              resword = &wordlist[%d];", temp->index);
  622. X              else 
  623. X                printf ("              resword = \"%s\";", temp->key);
  624. X              if (OPTION_ENABLED (option, LENTABLE) && !OPTION_ENABLED (option, DUP))
  625. X                printf (" key_len = %d;", temp->length);
  626. X              printf (" break;\n");
  627. X            }
  628. X        }
  629. X      printf ("            default: return 0;\n            }\n");
  630. X      printf (OPTION_ENABLED (option, LENTABLE) && !OPTION_ENABLED (option, DUP)
  631. X              ? "          if (len == key_len && %s)\n            return resword;\n"
  632. X              : "          if (%s)\n            return resword;\n", comp_buffer);
  633. X      printf ("      }\n  }\n  return 0;\n}\n");
  634. X    }
  635. X  else                          /* Nothing special required here. */
  636. X    {                        
  637. X      LIST_NODE *temp;
  638. X
  639. X      printf ("          char *s = \"\";\n\n          switch (key)\n            {\n");
  640. X      
  641. X      for (temp = key_list.head; temp; temp = temp->next)
  642. X        if (OPTION_ENABLED (option, LENTABLE))
  643. X          printf ("            case %*d: if (len == %d) s = \"%s\"; else return 0; break;\n", 
  644. X                  field_width, temp->hash_value, temp->length, temp->key);
  645. X        else
  646. X          printf ("            case %*d: s = \"%s\"; break;\n",
  647. X                  field_width, temp->hash_value, temp->key);
  648. X                      
  649. X      printf ("            default: return 0;\n            }\n          return *s == *str && !%s;\n        }\n    }\n  return 0;\n}\n", 
  650. X              OPTION_ENABLED (option, COMP) ? "strncmp (s + 1, str + 1, len - 1)" : "strcmp (s + 1, str + 1)");
  651. X    }
  652. X}
  653. X
  654. X/* Prints out a table of keyword lengths, for use with the 
  655. X   comparison code in generated function ``in_word_set.'' */
  656. X
  657. Xstatic void 
  658. Xprint_keylength_table ()
  659. X{
  660. X  int        max_column = 15;
  661. X  int        index      = 0;
  662. X  int        column     = 0;
  663. X  char      *indent     = OPTION_ENABLED (option, GLOBAL) ? "" : "  ";
  664. X  LIST_NODE *temp;
  665. X
  666. X  if (!OPTION_ENABLED (option, DUP) && !OPTION_ENABLED (option, SWITCH)) 
  667. X    {
  668. X      printf ("\n%sstatic %sunsigned %s lengthtable[] =\n%s%s{\n    ",
  669. X              indent, OPTION_ENABLED (option, CONST) ? "const " : "",
  670. X              key_list.max_key_len < 256 ? "char" :
  671. X              (key_list.max_key_len < 65536 ? "short" : "long"),
  672. X              indent, indent);
  673. X  
  674. X      for (temp = key_list.head; temp; temp = temp->next, index++)
  675. X        {
  676. X    
  677. X          if (index < temp->hash_value)
  678. X            {
  679. X      
  680. X              for ( ; index < temp->hash_value; index++)
  681. X                printf ("%3d%s", 0, ++column % (max_column - 1) ? "," : ",\n    ");
  682. X            }
  683. X    
  684. X          printf ("%3d%s", temp->length, ++column % (max_column - 1 ) ? "," : ",\n    ");
  685. X        }
  686. X  
  687. X      printf ("\n%s%s};\n\n", indent, indent);
  688. X    }
  689. X}
  690. X
  691. X/* Prints out the array containing the key words for the Perfect
  692. X   hash function. */
  693. X  
  694. Xstatic void 
  695. Xprint_keyword_table ()
  696. X{
  697. X  char      *l_brace      = *key_list.head->rest ? "{" : "";
  698. X  char      *r_brace      = *key_list.head->rest ? "}," : "";
  699. X  int        doing_switch = OPTION_ENABLED (option, SWITCH);
  700. X  char      *indent       = OPTION_ENABLED (option, GLOBAL) ? "" : "  ";
  701. X  int        index        = 0;
  702. X  LIST_NODE *temp;
  703. X
  704. X  printf ("\n%sstatic %s%s wordlist[] =\n%s%s{\n", 
  705. X          indent, OPTION_ENABLED (option, CONST) ? "const " : "",
  706. X          key_list.struct_tag, indent, indent);
  707. X  
  708. X  /* Generate an array of reserved words at appropriate locations. */
  709. X  
  710. X    for (temp = key_list.head; temp; temp = temp->next, index++)
  711. X        {
  712. X            temp->index = index;
  713. X
  714. X            if (!doing_switch && index < temp->hash_value)
  715. X                {
  716. X                    int column;
  717. X
  718. X                    printf ("      ");
  719. X      
  720. X                    for (column = 1; index < temp->hash_value; index++, column++)
  721. X                        printf ("%s\"\",%s %s", l_brace, r_brace, column % 9 ? "" : "\n      ");
  722. X      
  723. X                    if (column % 10)
  724. X                        printf ("\n");
  725. X                    else 
  726. X                        {
  727. X                            printf ("%s\"%s\", %s%s\n", l_brace, temp->key, temp->rest, r_brace);
  728. X                            continue;
  729. X                        }
  730. X                }
  731. X
  732. X            printf ("      %s\"%s\", %s%s\n", l_brace, temp->key, temp->rest, r_brace);
  733. X
  734. X            /* Deal with links specially. */
  735. X            if (temp->link)
  736. X                {
  737. X                    LIST_NODE *links;
  738. X
  739. X                    for (links = temp->link; links; links = links->link)
  740. X                        {
  741. X                            links->index = ++index;
  742. X                            printf ("      %s\"%s\", %s%s\n", l_brace, links->key, links->rest, r_brace);
  743. X                        }
  744. X                }
  745. X
  746. X        }
  747. X
  748. X  printf ("%s%s};\n\n", indent, indent);
  749. X}
  750. X
  751. X/* Generates C code for the hash function that returns the
  752. X   proper encoding for each key word. */
  753. X
  754. Xstatic void 
  755. Xprint_hash_function (max_hash_value)
  756. X     int max_hash_value;
  757. X{
  758. X  int max_column = 10;
  759. X  int count       = max_hash_value;
  760. X
  761. X  /* Calculate maximum number of digits required for MAX_HASH_VALUE. */
  762. X
  763. X  while ((count /= 10) > 0)
  764. X    field_width++;
  765. X
  766. X  if (OPTION_ENABLED (option, GNU))
  767. X    printf ("#ifdef __GNUC__\ninline\n#endif\n");
  768. X  
  769. X  printf (OPTION_ENABLED (option, ANSI) 
  770. X          ? "static int\n%s (register const char *str, register int len)\n{\n  static %sunsigned %s hash_table[] =\n    {"
  771. X          : "static int\n%s (str, len)\n     register char *str;\n     register unsigned int  len;\n{\n  static %sunsigned %s hash_table[] =\n    {",
  772. X          GET_HASH_NAME (option), OPTION_ENABLED (option, CONST) ? "const " : "",
  773. X          max_hash_value < 256 ? "char" : (max_hash_value < 65536 ? "short" : "int"));
  774. X  
  775. X  for (count = 0; count < ALPHABET_SIZE; ++count)
  776. X    {
  777. X      if (!(count % max_column))
  778. X        printf ("\n    ");
  779. X      
  780. X      printf ("%*d,", field_width, occurrences[count] ? asso_values[count] : max_hash_value);
  781. X    }
  782. X  
  783. X  /* Optimize special case of ``-k 1,$'' */
  784. X  if (OPTION_ENABLED (option, DEFAULTCHARS)) 
  785. X    printf ("\n    };\n  return %s + hash_table[str[len - 1]] + hash_table[str[0]];\n}\n\n",
  786. X            OPTION_ENABLED (option, NOLENGTH) ? "0" : "len");
  787. X  else
  788. X    {
  789. X      int key_pos;
  790. X
  791. X      RESET (option);
  792. X
  793. X      /* Get first (also highest) key position. */
  794. X      key_pos = GET (option); 
  795. X      
  796. X      /* We can perform additional optimizations here. */
  797. X      if (!OPTION_ENABLED (option, ALLCHARS) && key_pos <= key_list.min_key_len) 
  798. X        { 
  799. X          printf ("\n  };\n  return %s", OPTION_ENABLED (option, NOLENGTH) ? "0" : "len");
  800. X          
  801. X          for ( ; key_pos != EOS && key_pos != WORD_END; key_pos = GET (option))
  802. X            printf (" + hash_table[str[%d]]", key_pos - 1);
  803. X           
  804. X          printf ("%s;\n}\n\n", key_pos == WORD_END ? " + hash_table[str[len - 1]]" : "");
  805. X        }
  806. X
  807. X      /* We've got to use the correct, but brute force, technique. */
  808. X      else 
  809. X        {                    
  810. X          printf ("\n    };\n  register int hval = %s ;\n\n  switch (%s)\n    {\n      default:\n",
  811. X                  OPTION_ENABLED (option, NOLENGTH) ? "0" : "len", OPTION_ENABLED (option, NOLENGTH) ? "len" : "hval");
  812. X          
  813. X          /* User wants *all* characters considered in hash. */
  814. X          if (OPTION_ENABLED (option, ALLCHARS)) 
  815. X            { 
  816. X              int i;
  817. X
  818. X              for (i = key_list.max_key_len; i > 0; i--)
  819. X                printf ("      case %d:\n        hval += hash_table[str[%d]];\n", i, i - 1);
  820. X              
  821. X              printf ("    }\n  return hval;\n}\n\n");
  822. X            }
  823. X          else /* do the hard part... */
  824. X            {                
  825. X              count = key_pos + 1;
  826. X              
  827. X              do
  828. X                {
  829. X                  
  830. X                  while (--count > key_pos)
  831. X                    printf ("      case %d:\n", count);
  832. X                  
  833. X                  printf ("      case %d:\n        hval += hash_table[str[%d]];\n", key_pos, key_pos - 1);
  834. X                }
  835. X              while ((key_pos = GET (option)) != EOS && key_pos != WORD_END);
  836. X              
  837. X              printf ("    }\n  return hval%s ;\n}\n\n", key_pos == WORD_END ? " + hash_table[str[len - 1]]" : "");
  838. X          }
  839. X      }
  840. X  }
  841. X}
  842. X
  843. X/* Generates C code to perform the keyword lookup. */
  844. X
  845. Xstatic void 
  846. Xprint_lookup_function ()
  847. X{ 
  848. X  printf ("  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)\n    {\n\
  849. X      register int key = %s (str, len);\n\n\
  850. X      if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)\n        {\n\
  851. X          register %schar *s = wordlist[key]", 
  852. X          GET_HASH_NAME (option), OPTION_ENABLED (option, CONST) ? "const " : "");
  853. X  if (key_list.array_type != default_array_type)
  854. X    printf (".%s", GET_KEY_NAME (option));
  855. X
  856. X  printf (";\n\n          if (%s*s == *str && !%s)\n            return %s",
  857. X          OPTION_ENABLED (option, LENTABLE) ? "len == lengthtable[key]\n              && " : "",
  858. X          OPTION_ENABLED (option, COMP) ? "strncmp (str + 1, s + 1, len - 1)" : "strcmp (str + 1, s + 1)",
  859. X          OPTION_ENABLED (option, TYPE) && OPTION_ENABLED (option, POINTER) ? "&wordlist[key]" : "s");
  860. X  printf (";\n        }\n    }\n  return 0;\n}\n");
  861. X}
  862. X
  863. X/* Generates the hash function and the key word recognizer function
  864. X   based upon the user's Options. */
  865. X
  866. Xvoid 
  867. Xprint_output ()
  868. X{
  869. X  int global_table = OPTION_ENABLED (option, GLOBAL);
  870. X
  871. X  printf ("/* C code produced by gperf version %s */\n", version_string);
  872. X  print_options ();
  873. X  
  874. X  printf ("%s\n", key_list.include_src);
  875. X  
  876. X  /* Potentially output type declaration now, reference it later on.... */
  877. X  if (OPTION_ENABLED (option, TYPE) && !OPTION_ENABLED (option, NOTYPE)) 
  878. X    printf ("%s;\n", key_list.array_type);
  879. X  
  880. X  print_hash_function (print_min_max ());
  881. X  
  882. X  if (global_table)
  883. X    if (OPTION_ENABLED (option, SWITCH))
  884. X      {
  885. X        if (OPTION_ENABLED (option, LENTABLE) && OPTION_ENABLED (option, DUP))
  886. X          print_keylength_table ();
  887. X        if (OPTION_ENABLED (option, POINTER) && OPTION_ENABLED (option, TYPE))
  888. X          print_keyword_table ();
  889. X      }
  890. X    else
  891. X      {
  892. X        if (OPTION_ENABLED (option, LENTABLE))
  893. X          print_keylength_table ();
  894. X        print_keyword_table ();
  895. X      }
  896. X  /* Use the inline keyword to remove function overhead. */
  897. X  if (OPTION_ENABLED (option, GNU)) 
  898. X    printf ("#ifdef __GNUC__\ninline\n#endif\n");
  899. X  
  900. X  /* Use ANSI function prototypes. */
  901. X  printf (OPTION_ENABLED (option, ANSI)
  902. X          ? "%s%s\n%s (register const char *str, register int len)\n{\n"
  903. X          : "%s%s\n%s (str, len)\n     register char *str;\n     register unsigned int len;\n{\n", 
  904. X            OPTION_ENABLED (option, CONST) ? "const " : "", 
  905. X            key_list.return_type, GET_FUNCTION_NAME (option));
  906. X  
  907. X  /* Use the switch in place of lookup table. */
  908. X  if (OPTION_ENABLED (option, SWITCH))
  909. X    {               
  910. X      if (!global_table)
  911. X        {
  912. X          if (OPTION_ENABLED (option, LENTABLE) && OPTION_ENABLED (option, DUP))
  913. X            print_keylength_table ();
  914. X          if (OPTION_ENABLED (option, POINTER) && OPTION_ENABLED (option, TYPE)) 
  915. X            print_keyword_table ();
  916. X        }
  917. X      print_switch ();
  918. X    }
  919. X  else                /* Use the lookup table, in place of switch. */
  920. X    {           
  921. X      if (!global_table)
  922. X        {
  923. X          if (OPTION_ENABLED (option, LENTABLE))
  924. X            print_keylength_table ();
  925. X          print_keyword_table ();
  926. X        }
  927. X      print_lookup_function ();
  928. X    }
  929. X
  930. X  if (key_list.additional_code)
  931. X    {
  932. X      int c;
  933. X
  934. X      while ((c = getchar ()) != EOF)
  935. X        putchar (c);
  936. X    }
  937. X}
  938. X
  939. X/* Sorts the keys by hash value. */
  940. X
  941. Xvoid 
  942. Xsort ()
  943. X{ 
  944. X  key_list.hash_sort       = TRUE;
  945. X  key_list.occurrence_sort = FALSE;
  946. X  
  947. X  key_list.head = merge_sort (key_list.head);
  948. X}
  949. X
  950. X/* Dumps the key list to stderr stream. */
  951. X
  952. Xstatic void 
  953. Xdump () 
  954. X{      
  955. X  LIST_NODE *ptr;
  956. X
  957. X  report_error ("\nList contents are:\n(hash value, key length, index, key set, uniq set, key):\n");
  958. X  
  959. X  for (ptr = key_list.head; ptr; ptr = ptr->next)
  960. X    report_error ("      %d,      %d,     %d, %s, %s, %s\n",
  961. X                  ptr->hash_value, ptr->length, ptr->index,
  962. X                  ptr->key_set, ptr->uniq_set, ptr->key);
  963. X}
  964. X
  965. X/* Simple-minded constructor action here... */
  966. X
  967. Xvoid
  968. Xkey_list_init ()
  969. X{   
  970. X  key_list.total_keys      = 1;
  971. X  key_list.max_key_len     = NEG_MAX_INT;
  972. X  key_list.min_key_len     = MAX_INT;
  973. X  key_list.return_type     = default_return_type;
  974. X  key_list.array_type      = key_list.struct_tag  = default_array_type;
  975. X  key_list.head            = NULL;
  976. X  key_list.additional_code = FALSE;
  977. X}
  978. X
  979. X/* Returns the length of entire key list. */
  980. X
  981. Xint 
  982. Xlength () 
  983. X{ 
  984. X  return key_list.list_len;
  985. X}
  986. X
  987. X/* Returns length of longest key read. */
  988. X
  989. Xint 
  990. Xmax_key_length ()
  991. X{ 
  992. X  return key_list.max_key_len;
  993. X}
  994. X
  995. X/* DESTRUCTOR dumps diagnostics during debugging. */
  996. X
  997. Xvoid
  998. Xkey_list_destroy () 
  999. X{ 
  1000. X  if (OPTION_ENABLED (option, DEBUG))
  1001. X    {
  1002. X      report_error ("\nDumping key list information:\ntotal unique keywords = %d\
  1003. X\ntotal keywords = %d\nmaximum key length = %d.\n", 
  1004. X                    key_list.list_len, key_list.total_keys, key_list.max_key_len);
  1005. X      dump ();
  1006. X      report_error ("End dumping list.\n\n");
  1007. X    }
  1008. X}
  1009. X
  1010. END_OF_FILE
  1011. if test 31979 -ne `wc -c <'cperf/src/keylist.c'`; then
  1012.     echo shar: \"'cperf/src/keylist.c'\" unpacked with wrong size!
  1013. fi
  1014. # end of 'cperf/src/keylist.c'
  1015. fi
  1016. echo shar: End of archive 4 \(of 5\).
  1017. cp /dev/null ark4isdone
  1018. MISSING=""
  1019. for I in 1 2 3 4 5 ; do
  1020.     if test ! -f ark${I}isdone ; then
  1021.     MISSING="${MISSING} ${I}"
  1022.     fi
  1023. done
  1024. if test "${MISSING}" = "" ; then
  1025.     echo You have unpacked all 5 archives.
  1026.     rm -f ark[1-9]isdone
  1027. else
  1028.     echo You still need to unpack the following archives:
  1029.     echo "        " ${MISSING}
  1030. fi
  1031. ##  End of shell archive.
  1032. exit 0
  1033.  
  1034.