1 | /* Output routines. |
2 | Copyright (C) 1989-1998, 2000, 2002-2004, 2006-2007, 2009, 2011-2012, 2016 Free Software Foundation, Inc. |
3 | Written by Douglas C. Schmidt <schmidt@ics.uci.edu> |
4 | and Bruno Haible <bruno@clisp.org>. |
5 | |
6 | This file is part of GNU GPERF. |
7 | |
8 | This program is free software: you can redistribute it and/or modify |
9 | it under the terms of the GNU General Public License as published by |
10 | the Free Software Foundation; either version 3 of the License, or |
11 | (at your option) any later version. |
12 | |
13 | This program is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | GNU General Public License for more details. |
17 | |
18 | You should have received a copy of the GNU General Public License |
19 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
20 | |
21 | /* Specification. */ |
22 | #include "output.h" |
23 | |
24 | #include <stdio.h> |
25 | #include <string.h> /* declares strncpy(), strchr() */ |
26 | #include <ctype.h> /* declares isprint() */ |
27 | #include <assert.h> /* defines assert() */ |
28 | #include <limits.h> /* defines SCHAR_MAX etc. */ |
29 | #include "options.h" |
30 | #include "version.h" |
31 | #include "config.h" |
32 | |
33 | /* ============================== Portability ============================== */ |
34 | |
35 | /* Dynamically allocated array with dynamic extent: |
36 | |
37 | Example: |
38 | DYNAMIC_ARRAY (my_array, int, n); |
39 | ... |
40 | FREE_DYNAMIC_ARRAY (my_array); |
41 | |
42 | Attention: depending on your implementation my_array is either the array |
43 | itself or a pointer to the array! Always use my_array only as expression! |
44 | */ |
45 | #if HAVE_DYNAMIC_ARRAY |
46 | #define DYNAMIC_ARRAY(var,eltype,size) eltype var[size] |
47 | #define FREE_DYNAMIC_ARRAY(var) |
48 | #else |
49 | #define DYNAMIC_ARRAY(var,eltype,size) eltype *var = new eltype[size] |
50 | #define FREE_DYNAMIC_ARRAY(var) delete[] var |
51 | #endif |
52 | |
53 | /* ========================================================================= */ |
54 | |
55 | /* The "register " storage-class specifier. */ |
56 | static const char *register_scs; |
57 | |
58 | /* The "const " qualifier. */ |
59 | static const char *const_always; |
60 | |
61 | /* The "const " qualifier, for read-only arrays. */ |
62 | static const char *const_readonly_array; |
63 | |
64 | /* The "const " qualifier, for the array type. */ |
65 | static const char *const_for_struct; |
66 | |
67 | /* Returns the smallest unsigned C type capable of holding integers |
68 | up to N. */ |
69 | |
70 | static const char * |
71 | smallest_integral_type (int n) |
72 | { |
73 | if (n <= UCHAR_MAX) return "unsigned char" ; |
74 | if (n <= USHRT_MAX) return "unsigned short" ; |
75 | return "unsigned int" ; |
76 | } |
77 | |
78 | /* Returns the smallest signed C type capable of holding integers |
79 | from MIN to MAX. */ |
80 | |
81 | static const char * |
82 | smallest_integral_type (int min, int max) |
83 | { |
84 | if (option[ANSIC] | option[CPLUSPLUS]) |
85 | if (min >= SCHAR_MIN && max <= SCHAR_MAX) return "signed char" ; |
86 | if (min >= SHRT_MIN && max <= SHRT_MAX) return "short" ; |
87 | return "int" ; |
88 | } |
89 | |
90 | /* ------------------------------------------------------------------------- */ |
91 | |
92 | /* Constructor. |
93 | Note about the keyword list starting at head: |
94 | - The list is ordered by increasing _hash_value. This has been achieved |
95 | by Search::sort(). |
96 | - Duplicates, i.e. keywords with the same _selchars set, are chained |
97 | through the _duplicate_link pointer. Only one representative per |
98 | duplicate equivalence class remains on the linear keyword list. |
99 | - Accidental duplicates, i.e. keywords for which the _asso_values[] search |
100 | couldn't achieve different hash values, cannot occur on the linear |
101 | keyword list. Search::optimize would catch this mistake. |
102 | */ |
103 | Output::Output (KeywordExt_List *head, const char *struct_decl, |
104 | unsigned int struct_decl_lineno, const char *return_type, |
105 | const char *struct_tag, const char *verbatim_declarations, |
106 | const char *verbatim_declarations_end, |
107 | unsigned int verbatim_declarations_lineno, |
108 | const char *verbatim_code, const char *verbatim_code_end, |
109 | unsigned int verbatim_code_lineno, bool charset_dependent, |
110 | int total_keys, int max_key_len, int min_key_len, |
111 | bool hash_includes_len, const Positions& positions, |
112 | const unsigned int *alpha_inc, int total_duplicates, |
113 | unsigned int alpha_size, const int *asso_values) |
114 | : _head (head), _struct_decl (struct_decl), |
115 | _struct_decl_lineno (struct_decl_lineno), _return_type (return_type), |
116 | _struct_tag (struct_tag), |
117 | _verbatim_declarations (verbatim_declarations), |
118 | _verbatim_declarations_end (verbatim_declarations_end), |
119 | _verbatim_declarations_lineno (verbatim_declarations_lineno), |
120 | _verbatim_code (verbatim_code), |
121 | _verbatim_code_end (verbatim_code_end), |
122 | _verbatim_code_lineno (verbatim_code_lineno), |
123 | _charset_dependent (charset_dependent), |
124 | _total_keys (total_keys), |
125 | _max_key_len (max_key_len), _min_key_len (min_key_len), |
126 | _hash_includes_len (hash_includes_len), |
127 | _key_positions (positions), _alpha_inc (alpha_inc), |
128 | _total_duplicates (total_duplicates), _alpha_size (alpha_size), |
129 | _asso_values (asso_values) |
130 | { |
131 | } |
132 | |
133 | /* ------------------------------------------------------------------------- */ |
134 | |
135 | /* Computes the minimum and maximum hash values, and stores them |
136 | in _min_hash_value and _max_hash_value. */ |
137 | |
138 | void |
139 | Output::compute_min_max () |
140 | { |
141 | /* Since the list is already sorted by hash value all we need to do is |
142 | to look at the first and the last element of the list. */ |
143 | |
144 | _min_hash_value = _head->first()->_hash_value; |
145 | |
146 | KeywordExt_List *temp; |
147 | for (temp = _head; temp->rest(); temp = temp->rest()) |
148 | ; |
149 | _max_hash_value = temp->first()->_hash_value; |
150 | } |
151 | |
152 | /* ------------------------------------------------------------------------- */ |
153 | |
154 | /* Returns the number of different hash values. */ |
155 | |
156 | int |
157 | Output::num_hash_values () const |
158 | { |
159 | /* Since the list is already sorted by hash value and doesn't contain |
160 | duplicates, we can simply count the number of keywords on the list. */ |
161 | int count = 0; |
162 | for (KeywordExt_List *temp = _head; temp; temp = temp->rest()) |
163 | count++; |
164 | return count; |
165 | } |
166 | |
167 | /* -------------------- Output_Constants and subclasses -------------------- */ |
168 | |
169 | /* This class outputs an enumeration defining some constants. */ |
170 | |
171 | struct Output_Constants |
172 | { |
173 | virtual void output_start () = 0; |
174 | virtual void output_item (const char *name, int value) = 0; |
175 | virtual void output_end () = 0; |
176 | Output_Constants () {} |
177 | virtual ~Output_Constants () {} |
178 | }; |
179 | |
180 | /* This class outputs an enumeration in #define syntax. */ |
181 | |
182 | struct Output_Defines : public Output_Constants |
183 | { |
184 | virtual void output_start (); |
185 | virtual void output_item (const char *name, int value); |
186 | virtual void output_end (); |
187 | Output_Defines () {} |
188 | virtual ~Output_Defines () {} |
189 | }; |
190 | |
191 | void Output_Defines::output_start () |
192 | { |
193 | printf ("\n" ); |
194 | } |
195 | |
196 | void Output_Defines::output_item (const char *name, int value) |
197 | { |
198 | printf ("#define %s %d\n" , name, value); |
199 | } |
200 | |
201 | void Output_Defines::output_end () |
202 | { |
203 | } |
204 | |
205 | /* This class outputs an enumeration using 'enum'. */ |
206 | |
207 | struct Output_Enum : public Output_Constants |
208 | { |
209 | virtual void output_start (); |
210 | virtual void output_item (const char *name, int value); |
211 | virtual void output_end (); |
212 | Output_Enum (const char *indent) |
213 | : _indentation (indent) {} |
214 | virtual ~Output_Enum () {} |
215 | private: |
216 | const char *_indentation; |
217 | bool _pending_comma; |
218 | }; |
219 | |
220 | void Output_Enum::output_start () |
221 | { |
222 | printf ("%senum\n" |
223 | "%s {\n" , |
224 | _indentation, _indentation); |
225 | _pending_comma = false; |
226 | } |
227 | |
228 | void Output_Enum::output_item (const char *name, int value) |
229 | { |
230 | if (_pending_comma) |
231 | printf (",\n" ); |
232 | printf ("%s %s = %d" , _indentation, name, value); |
233 | _pending_comma = true; |
234 | } |
235 | |
236 | void Output_Enum::output_end () |
237 | { |
238 | if (_pending_comma) |
239 | printf ("\n" ); |
240 | printf ("%s };\n\n" , _indentation); |
241 | } |
242 | |
243 | /* Outputs a constant in the given style. */ |
244 | |
245 | static void |
246 | output_constant (struct Output_Constants& style, const char *name, int value) |
247 | { |
248 | const char *prefix = option.get_constants_prefix (); |
249 | DYNAMIC_ARRAY (combined_name, char, strlen (prefix) + strlen (name) + 1); |
250 | strcpy (combined_name, prefix); |
251 | strcpy (combined_name + strlen (prefix), name); |
252 | style.output_item (combined_name, value); |
253 | FREE_DYNAMIC_ARRAY (combined_name); |
254 | } |
255 | |
256 | /* Outputs the maximum and minimum hash values etc. */ |
257 | |
258 | void |
259 | Output::output_constants (struct Output_Constants& style) const |
260 | { |
261 | style.output_start (); |
262 | output_constant (style, "TOTAL_KEYWORDS" , _total_keys); |
263 | output_constant (style, "MIN_WORD_LENGTH" , _min_key_len); |
264 | output_constant (style, "MAX_WORD_LENGTH" , _max_key_len); |
265 | output_constant (style, "MIN_HASH_VALUE" , _min_hash_value); |
266 | output_constant (style, "MAX_HASH_VALUE" , _max_hash_value); |
267 | style.output_end (); |
268 | } |
269 | |
270 | /* ------------------------------------------------------------------------- */ |
271 | |
272 | /* We use a downcase table because when called repeatedly, the code |
273 | gperf_downcase[c] |
274 | is faster than |
275 | if (c >= 'A' && c <= 'Z') |
276 | c += 'a' - 'A'; |
277 | */ |
278 | #define USE_DOWNCASE_TABLE 1 |
279 | |
280 | #if USE_DOWNCASE_TABLE |
281 | |
282 | /* Output gperf's ASCII-downcase table. */ |
283 | |
284 | static void |
285 | output_upperlower_table () |
286 | { |
287 | unsigned int c; |
288 | |
289 | printf ("#ifndef GPERF_DOWNCASE\n" |
290 | "#define GPERF_DOWNCASE 1\n" |
291 | "static unsigned char gperf_downcase[256] =\n" |
292 | " {" ); |
293 | for (c = 0; c < 256; c++) |
294 | { |
295 | if ((c % 15) == 0) |
296 | printf ("\n " ); |
297 | printf (" %3d" , c >= 'A' && c <= 'Z' ? c + 'a' - 'A' : c); |
298 | if (c < 255) |
299 | printf ("," ); |
300 | } |
301 | printf ("\n" |
302 | " };\n" |
303 | "#endif\n\n" ); |
304 | } |
305 | |
306 | #endif |
307 | |
308 | /* Output gperf's ASCII-case insensitive strcmp replacement. */ |
309 | |
310 | static void |
311 | output_upperlower_strcmp () |
312 | { |
313 | printf ("#ifndef GPERF_CASE_STRCMP\n" |
314 | "#define GPERF_CASE_STRCMP 1\n" |
315 | "static int\n" |
316 | "gperf_case_strcmp " ); |
317 | printf (option[KRC] ? |
318 | "(s1, s2)\n" |
319 | " %schar *s1;\n" |
320 | " %schar *s2;\n" : |
321 | option[C] ? |
322 | "(s1, s2)\n" |
323 | " %sconst char *s1;\n" |
324 | " %sconst char *s2;\n" : |
325 | option[ANSIC] | option[CPLUSPLUS] ? |
326 | "(%sconst char *s1, %sconst char *s2)\n" : |
327 | "" , |
328 | register_scs, register_scs); |
329 | #if USE_DOWNCASE_TABLE |
330 | printf ("{\n" |
331 | " for (;;)\n" |
332 | " {\n" |
333 | " unsigned char c1 = gperf_downcase[(unsigned char)*s1++];\n" |
334 | " unsigned char c2 = gperf_downcase[(unsigned char)*s2++];\n" |
335 | " if (c1 != 0 && c1 == c2)\n" |
336 | " continue;\n" |
337 | " return (int)c1 - (int)c2;\n" |
338 | " }\n" |
339 | "}\n" ); |
340 | #else |
341 | printf ("{\n" |
342 | " for (;;)\n" |
343 | " {\n" |
344 | " unsigned char c1 = *s1++;\n" |
345 | " unsigned char c2 = *s2++;\n" |
346 | " if (c1 >= 'A' && c1 <= 'Z')\n" |
347 | " c1 += 'a' - 'A';\n" |
348 | " if (c2 >= 'A' && c2 <= 'Z')\n" |
349 | " c2 += 'a' - 'A';\n" |
350 | " if (c1 != 0 && c1 == c2)\n" |
351 | " continue;\n" |
352 | " return (int)c1 - (int)c2;\n" |
353 | " }\n" |
354 | "}\n" ); |
355 | #endif |
356 | printf ("#endif\n\n" ); |
357 | } |
358 | |
359 | /* Output gperf's ASCII-case insensitive strncmp replacement. */ |
360 | |
361 | static void |
362 | output_upperlower_strncmp () |
363 | { |
364 | printf ("#ifndef GPERF_CASE_STRNCMP\n" |
365 | "#define GPERF_CASE_STRNCMP 1\n" |
366 | "static int\n" |
367 | "gperf_case_strncmp " ); |
368 | printf (option[KRC] ? |
369 | "(s1, s2, n)\n" |
370 | " %schar *s1;\n" |
371 | " %schar *s2;\n" |
372 | " %ssize_t n;\n" : |
373 | option[C] ? |
374 | "(s1, s2, n)\n" |
375 | " %sconst char *s1;\n" |
376 | " %sconst char *s2;\n" |
377 | " %ssize_t n;\n" : |
378 | option[ANSIC] | option[CPLUSPLUS] ? |
379 | "(%sconst char *s1, %sconst char *s2, %ssize_t n)\n" : |
380 | "" , |
381 | register_scs, register_scs, register_scs); |
382 | #if USE_DOWNCASE_TABLE |
383 | printf ("{\n" |
384 | " for (; n > 0;)\n" |
385 | " {\n" |
386 | " unsigned char c1 = gperf_downcase[(unsigned char)*s1++];\n" |
387 | " unsigned char c2 = gperf_downcase[(unsigned char)*s2++];\n" |
388 | " if (c1 != 0 && c1 == c2)\n" |
389 | " {\n" |
390 | " n--;\n" |
391 | " continue;\n" |
392 | " }\n" |
393 | " return (int)c1 - (int)c2;\n" |
394 | " }\n" |
395 | " return 0;\n" |
396 | "}\n" ); |
397 | #else |
398 | printf ("{\n" |
399 | " for (; n > 0;)\n" |
400 | " {\n" |
401 | " unsigned char c1 = *s1++;\n" |
402 | " unsigned char c2 = *s2++;\n" |
403 | " if (c1 >= 'A' && c1 <= 'Z')\n" |
404 | " c1 += 'a' - 'A';\n" |
405 | " if (c2 >= 'A' && c2 <= 'Z')\n" |
406 | " c2 += 'a' - 'A';\n" |
407 | " if (c1 != 0 && c1 == c2)\n" |
408 | " {\n" |
409 | " n--;\n" |
410 | " continue;\n" |
411 | " }\n" |
412 | " return (int)c1 - (int)c2;\n" |
413 | " }\n" |
414 | " return 0;\n" |
415 | "}\n" ); |
416 | #endif |
417 | printf ("#endif\n\n" ); |
418 | } |
419 | |
420 | /* Output gperf's ASCII-case insensitive memcmp replacement. */ |
421 | |
422 | static void |
423 | output_upperlower_memcmp () |
424 | { |
425 | printf ("#ifndef GPERF_CASE_MEMCMP\n" |
426 | "#define GPERF_CASE_MEMCMP 1\n" |
427 | "static int\n" |
428 | "gperf_case_memcmp " ); |
429 | printf (option[KRC] ? |
430 | "(s1, s2, n)\n" |
431 | " %schar *s1;\n" |
432 | " %schar *s2;\n" |
433 | " %ssize_t n;\n" : |
434 | option[C] ? |
435 | "(s1, s2, n)\n" |
436 | " %sconst char *s1;\n" |
437 | " %sconst char *s2;\n" |
438 | " %ssize_t n;\n" : |
439 | option[ANSIC] | option[CPLUSPLUS] ? |
440 | "(%sconst char *s1, %sconst char *s2, %ssize_t n)\n" : |
441 | "" , |
442 | register_scs, register_scs, register_scs); |
443 | #if USE_DOWNCASE_TABLE |
444 | printf ("{\n" |
445 | " for (; n > 0;)\n" |
446 | " {\n" |
447 | " unsigned char c1 = gperf_downcase[(unsigned char)*s1++];\n" |
448 | " unsigned char c2 = gperf_downcase[(unsigned char)*s2++];\n" |
449 | " if (c1 == c2)\n" |
450 | " {\n" |
451 | " n--;\n" |
452 | " continue;\n" |
453 | " }\n" |
454 | " return (int)c1 - (int)c2;\n" |
455 | " }\n" |
456 | " return 0;\n" |
457 | "}\n" ); |
458 | #else |
459 | printf ("{\n" |
460 | " for (; n > 0;)\n" |
461 | " {\n" |
462 | " unsigned char c1 = *s1++;\n" |
463 | " unsigned char c2 = *s2++;\n" |
464 | " if (c1 >= 'A' && c1 <= 'Z')\n" |
465 | " c1 += 'a' - 'A';\n" |
466 | " if (c2 >= 'A' && c2 <= 'Z')\n" |
467 | " c2 += 'a' - 'A';\n" |
468 | " if (c1 == c2)\n" |
469 | " {\n" |
470 | " n--;\n" |
471 | " continue;\n" |
472 | " }\n" |
473 | " return (int)c1 - (int)c2;\n" |
474 | " }\n" |
475 | " return 0;\n" |
476 | "}\n" ); |
477 | #endif |
478 | printf ("#endif\n\n" ); |
479 | } |
480 | |
481 | /* ------------------------------------------------------------------------- */ |
482 | |
483 | /* Outputs a keyword, as a string: enclosed in double quotes, escaping |
484 | backslashes, double quote and unprintable characters. */ |
485 | |
486 | static void |
487 | output_string (const char *key, int len) |
488 | { |
489 | putchar ('"'); |
490 | for (; len > 0; len--) |
491 | { |
492 | unsigned char c = static_cast<unsigned char>(*key++); |
493 | if (isprint (c)) |
494 | { |
495 | if (c == '"' || c == '\\') |
496 | putchar ('\\'); |
497 | putchar (c); |
498 | } |
499 | else |
500 | { |
501 | /* Use octal escapes, not hexadecimal escapes, because some old |
502 | C compilers didn't understand hexadecimal escapes, and because |
503 | hexadecimal escapes are not limited to 2 digits, thus needing |
504 | special care if the following character happens to be a digit. */ |
505 | putchar ('\\'); |
506 | putchar ('0' + ((c >> 6) & 7)); |
507 | putchar ('0' + ((c >> 3) & 7)); |
508 | putchar ('0' + (c & 7)); |
509 | } |
510 | } |
511 | putchar ('"'); |
512 | } |
513 | |
514 | /* ------------------------------------------------------------------------- */ |
515 | |
516 | /* Outputs a #line directive, referring to the given line number. */ |
517 | |
518 | static void |
519 | output_line_directive (unsigned int lineno) |
520 | { |
521 | const char *file_name = option.get_input_file_name (); |
522 | if (file_name != NULL) |
523 | { |
524 | printf ("#line %u " , lineno); |
525 | output_string (file_name, strlen (file_name)); |
526 | printf ("\n" ); |
527 | } |
528 | } |
529 | |
530 | /* ------------------------------------------------------------------------- */ |
531 | |
532 | /* Outputs a type and a const specifier (i.e. "const " or ""). |
533 | The output is terminated with a space. */ |
534 | |
535 | static void |
536 | output_const_type (const char *const_string, const char *type_string) |
537 | { |
538 | if (type_string[strlen(type_string)-1] == '*') |
539 | /* For pointer types, put the 'const' after the type. */ |
540 | printf ("%s %s" , type_string, const_string); |
541 | else |
542 | /* For scalar or struct types, put the 'const' before the type. */ |
543 | printf ("%s%s " , const_string, type_string); |
544 | } |
545 | |
546 | /* ----------------------- Output_Expr and subclasses ----------------------- */ |
547 | |
548 | /* This class outputs a general expression. */ |
549 | |
550 | struct Output_Expr |
551 | { |
552 | virtual void output_expr () const = 0; |
553 | Output_Expr () {} |
554 | virtual ~Output_Expr () {} |
555 | }; |
556 | |
557 | /* This class outputs an expression formed by a single string. */ |
558 | |
559 | struct Output_Expr1 : public Output_Expr |
560 | { |
561 | virtual void output_expr () const; |
562 | Output_Expr1 (const char *piece1) : _p1 (piece1) {} |
563 | virtual ~Output_Expr1 () {} |
564 | private: |
565 | const char *_p1; |
566 | }; |
567 | |
568 | void Output_Expr1::output_expr () const |
569 | { |
570 | printf ("%s" , _p1); |
571 | } |
572 | |
573 | #if 0 /* unused */ |
574 | |
575 | /* This class outputs an expression formed by the concatenation of two |
576 | strings. */ |
577 | |
578 | struct Output_Expr2 : public Output_Expr |
579 | { |
580 | virtual void output_expr () const; |
581 | Output_Expr2 (const char *piece1, const char *piece2) |
582 | : _p1 (piece1), _p2 (piece2) {} |
583 | virtual ~Output_Expr2 () {} |
584 | private: |
585 | const char *_p1; |
586 | const char *_p2; |
587 | }; |
588 | |
589 | void Output_Expr2::output_expr () const |
590 | { |
591 | printf ("%s%s" , _p1, _p2); |
592 | } |
593 | |
594 | #endif |
595 | |
596 | /* --------------------- Output_Compare and subclasses --------------------- */ |
597 | |
598 | /* This class outputs a comparison expression. */ |
599 | |
600 | struct Output_Compare |
601 | { |
602 | /* Outputs the comparison expression. |
603 | expr1 outputs a simple expression of type 'const char *' referring to |
604 | the string being looked up. expr2 outputs a simple expression of type |
605 | 'const char *' referring to the constant string stored in the gperf |
606 | generated hash table. */ |
607 | virtual void output_comparison (const Output_Expr& expr1, |
608 | const Output_Expr& expr2) const = 0; |
609 | /* Outputs the comparison expression for the first byte. |
610 | Returns true if the this comparison is complete. */ |
611 | bool output_firstchar_comparison (const Output_Expr& expr1, |
612 | const Output_Expr& expr2) const; |
613 | Output_Compare () {} |
614 | virtual ~Output_Compare () {} |
615 | }; |
616 | |
617 | bool Output_Compare::output_firstchar_comparison (const Output_Expr& expr1, |
618 | const Output_Expr& expr2) const |
619 | { |
620 | /* First, we emit a comparison of the first byte of the two strings. |
621 | This catches most cases where the string being looked up is not in the |
622 | hash table but happens to have the same hash code as an element of the |
623 | hash table. */ |
624 | if (option[UPPERLOWER]) |
625 | { |
626 | /* Incomplete comparison, just for speedup. */ |
627 | printf ("(((unsigned char)*" ); |
628 | expr1.output_expr (); |
629 | printf (" ^ (unsigned char)*" ); |
630 | expr2.output_expr (); |
631 | printf (") & ~32) == 0" ); |
632 | return false; |
633 | } |
634 | else |
635 | { |
636 | /* Complete comparison. */ |
637 | printf ("*" ); |
638 | expr1.output_expr (); |
639 | printf (" == *" ); |
640 | expr2.output_expr (); |
641 | return true; |
642 | } |
643 | } |
644 | |
645 | /* This class outputs a comparison using strcmp. */ |
646 | |
647 | struct Output_Compare_Strcmp : public Output_Compare |
648 | { |
649 | virtual void output_comparison (const Output_Expr& expr1, |
650 | const Output_Expr& expr2) const; |
651 | Output_Compare_Strcmp () {} |
652 | virtual ~Output_Compare_Strcmp () {} |
653 | }; |
654 | |
655 | void Output_Compare_Strcmp::output_comparison (const Output_Expr& expr1, |
656 | const Output_Expr& expr2) const |
657 | { |
658 | bool firstchar_done = output_firstchar_comparison (expr1, expr2); |
659 | printf (" && !" ); |
660 | if (option[UPPERLOWER]) |
661 | printf ("gperf_case_" ); |
662 | printf ("strcmp (" ); |
663 | if (firstchar_done) |
664 | { |
665 | expr1.output_expr (); |
666 | printf (" + 1, " ); |
667 | expr2.output_expr (); |
668 | printf (" + 1" ); |
669 | } |
670 | else |
671 | { |
672 | expr1.output_expr (); |
673 | printf (", " ); |
674 | expr2.output_expr (); |
675 | } |
676 | printf (")" ); |
677 | } |
678 | |
679 | /* This class outputs a comparison using strncmp. |
680 | Note that the length of expr1 will be available through the local variable |
681 | 'len'. */ |
682 | |
683 | struct Output_Compare_Strncmp : public Output_Compare |
684 | { |
685 | virtual void output_comparison (const Output_Expr& expr1, |
686 | const Output_Expr& expr2) const; |
687 | Output_Compare_Strncmp () {} |
688 | virtual ~Output_Compare_Strncmp () {} |
689 | }; |
690 | |
691 | void Output_Compare_Strncmp::output_comparison (const Output_Expr& expr1, |
692 | const Output_Expr& expr2) const |
693 | { |
694 | bool firstchar_done = output_firstchar_comparison (expr1, expr2); |
695 | printf (" && !" ); |
696 | if (option[UPPERLOWER]) |
697 | printf ("gperf_case_" ); |
698 | printf ("strncmp (" ); |
699 | if (firstchar_done) |
700 | { |
701 | expr1.output_expr (); |
702 | printf (" + 1, " ); |
703 | expr2.output_expr (); |
704 | printf (" + 1, len - 1" ); |
705 | } |
706 | else |
707 | { |
708 | expr1.output_expr (); |
709 | printf (", " ); |
710 | expr2.output_expr (); |
711 | printf (", len" ); |
712 | } |
713 | printf (") && " ); |
714 | expr2.output_expr (); |
715 | printf ("[len] == '\\0'" ); |
716 | } |
717 | |
718 | /* This class outputs a comparison using memcmp. |
719 | Note that the length of expr1 (available through the local variable 'len') |
720 | must be verified to be equal to the length of expr2 prior to this |
721 | comparison. */ |
722 | |
723 | struct Output_Compare_Memcmp : public Output_Compare |
724 | { |
725 | virtual void output_comparison (const Output_Expr& expr1, |
726 | const Output_Expr& expr2) const; |
727 | Output_Compare_Memcmp () {} |
728 | virtual ~Output_Compare_Memcmp () {} |
729 | }; |
730 | |
731 | void Output_Compare_Memcmp::output_comparison (const Output_Expr& expr1, |
732 | const Output_Expr& expr2) const |
733 | { |
734 | bool firstchar_done = output_firstchar_comparison (expr1, expr2); |
735 | printf (" && !" ); |
736 | if (option[UPPERLOWER]) |
737 | printf ("gperf_case_" ); |
738 | printf ("memcmp (" ); |
739 | if (firstchar_done) |
740 | { |
741 | expr1.output_expr (); |
742 | printf (" + 1, " ); |
743 | expr2.output_expr (); |
744 | printf (" + 1, len - 1" ); |
745 | } |
746 | else |
747 | { |
748 | expr1.output_expr (); |
749 | printf (", " ); |
750 | expr2.output_expr (); |
751 | printf (", len" ); |
752 | } |
753 | printf (")" ); |
754 | } |
755 | |
756 | /* ------------------------------------------------------------------------- */ |
757 | |
758 | /* Generates a C expression for an asso_values[] index. */ |
759 | |
760 | void |
761 | Output::output_asso_values_index (int pos) const |
762 | { |
763 | if (pos == Positions::LASTCHAR) |
764 | printf ("str[len - 1]" ); |
765 | else |
766 | { |
767 | printf ("str[%d]" , pos); |
768 | if (_alpha_inc[pos]) |
769 | printf ("+%u" , _alpha_inc[pos]); |
770 | } |
771 | } |
772 | |
773 | /* Generates a C expression for an asso_values[] reference. */ |
774 | |
775 | void |
776 | Output::output_asso_values_ref (int pos) const |
777 | { |
778 | printf ("asso_values[" ); |
779 | /* Always cast to unsigned char. This is necessary when the alpha_inc |
780 | is nonzero, and also avoids a gcc warning "subscript has type 'char'". */ |
781 | if (option[CPLUSPLUS]) |
782 | { |
783 | /* In C++, a C style cast may lead to a 'warning: use of old-style cast'. |
784 | Therefore prefer the C++ style cast syntax. */ |
785 | printf ("static_cast<unsigned char>(" ); |
786 | output_asso_values_index (pos); |
787 | printf (")" ); |
788 | } |
789 | else |
790 | { |
791 | printf ("(unsigned char)" ); |
792 | output_asso_values_index (pos); |
793 | } |
794 | printf ("]" ); |
795 | } |
796 | |
797 | /* Generates C code for the hash function that returns the |
798 | proper encoding for each keyword. |
799 | The hash function has the signature |
800 | unsigned int <hash> (const char *str, size_t len). */ |
801 | |
802 | void |
803 | Output::output_hash_function () const |
804 | { |
805 | /* Output the function's head. */ |
806 | if (option[CPLUSPLUS]) |
807 | printf ("inline " ); |
808 | else if (option[KRC] | option[C] | option[ANSIC]) |
809 | printf ("#ifdef __GNUC__\n" |
810 | "__inline\n" |
811 | "#else\n" |
812 | "#ifdef __cplusplus\n" |
813 | "inline\n" |
814 | "#endif\n" |
815 | "#endif\n" ); |
816 | |
817 | if (/* The function does not use the 'str' argument? */ |
818 | _key_positions.get_size() == 0 |
819 | || /* The function uses 'str', but not the 'len' argument? */ |
820 | (!_hash_includes_len |
821 | && _key_positions[0] < _min_key_len |
822 | && _key_positions[_key_positions.get_size() - 1] != Positions::LASTCHAR)) |
823 | /* Pacify lint. */ |
824 | printf ("/*ARGSUSED*/\n" ); |
825 | |
826 | if (option[KRC] | option[C] | option[ANSIC]) |
827 | printf ("static " ); |
828 | printf ("unsigned int\n" ); |
829 | if (option[CPLUSPLUS]) |
830 | printf ("%s::" , option.get_class_name ()); |
831 | printf ("%s " , option.get_hash_name ()); |
832 | printf (option[KRC] ? |
833 | "(str, len)\n" |
834 | " %schar *str;\n" |
835 | " %ssize_t len;\n" : |
836 | option[C] ? |
837 | "(str, len)\n" |
838 | " %sconst char *str;\n" |
839 | " %ssize_t len;\n" : |
840 | option[ANSIC] | option[CPLUSPLUS] ? |
841 | "(%sconst char *str, %ssize_t len)\n" : |
842 | "" , |
843 | register_scs, register_scs); |
844 | |
845 | /* Note that when the hash function is called, it has already been verified |
846 | that min_key_len <= len <= max_key_len. */ |
847 | |
848 | /* Output the function's body. */ |
849 | printf ("{\n" ); |
850 | |
851 | /* First the asso_values array. */ |
852 | if (_key_positions.get_size() > 0) |
853 | { |
854 | printf (" static %s%s asso_values[] =\n" |
855 | " {" , |
856 | const_readonly_array, |
857 | smallest_integral_type (_max_hash_value + 1)); |
858 | |
859 | const int columns = 10; |
860 | |
861 | /* Calculate maximum number of digits required for MAX_HASH_VALUE. */ |
862 | int field_width = 2; |
863 | for (int trunc = _max_hash_value; (trunc /= 10) > 0;) |
864 | field_width++; |
865 | |
866 | for (unsigned int count = 0; count < _alpha_size; count++) |
867 | { |
868 | if (count > 0) |
869 | printf ("," ); |
870 | if ((count % columns) == 0) |
871 | printf ("\n " ); |
872 | printf ("%*d" , field_width, _asso_values[count]); |
873 | } |
874 | |
875 | printf ("\n" |
876 | " };\n" ); |
877 | } |
878 | |
879 | if (_key_positions.get_size() == 0) |
880 | { |
881 | /* Trivial case: No key positions at all. */ |
882 | printf (" return %s;\n" , |
883 | _hash_includes_len ? "len" : "0" ); |
884 | } |
885 | else |
886 | { |
887 | /* Iterate through the key positions. Remember that Positions::sort() |
888 | has sorted them in decreasing order, with Positions::LASTCHAR coming |
889 | last. */ |
890 | PositionIterator iter = _key_positions.iterator(_max_key_len); |
891 | int key_pos; |
892 | |
893 | /* Get the highest key position. */ |
894 | key_pos = iter.next (); |
895 | |
896 | if (key_pos == Positions::LASTCHAR || key_pos < _min_key_len) |
897 | { |
898 | /* We can perform additional optimizations here: |
899 | Write it out as a single expression. Note that the values |
900 | are added as 'int's even though the asso_values array may |
901 | contain 'unsigned char's or 'unsigned short's. */ |
902 | |
903 | printf (" return %s" , |
904 | _hash_includes_len ? "len + " : "" ); |
905 | |
906 | if (_key_positions.get_size() == 2 |
907 | && _key_positions[0] == 0 |
908 | && _key_positions[1] == Positions::LASTCHAR) |
909 | /* Optimize special case of "-k 1,$". */ |
910 | { |
911 | output_asso_values_ref (Positions::LASTCHAR); |
912 | printf (" + " ); |
913 | output_asso_values_ref (0); |
914 | } |
915 | else |
916 | { |
917 | for (; key_pos != Positions::LASTCHAR; ) |
918 | { |
919 | output_asso_values_ref (key_pos); |
920 | if ((key_pos = iter.next ()) != PositionIterator::EOS) |
921 | printf (" + " ); |
922 | else |
923 | break; |
924 | } |
925 | |
926 | if (key_pos == Positions::LASTCHAR) |
927 | output_asso_values_ref (Positions::LASTCHAR); |
928 | } |
929 | |
930 | printf (";\n" ); |
931 | } |
932 | else |
933 | { |
934 | /* We've got to use the correct, but brute force, technique. */ |
935 | /* It doesn't really matter whether hval is an 'int' or |
936 | 'unsigned int', but 'unsigned int' gives fewer warnings. */ |
937 | printf (" %sunsigned int hval = %s;\n\n" |
938 | " switch (%s)\n" |
939 | " {\n" |
940 | " default:\n" , |
941 | register_scs, _hash_includes_len ? "len" : "0" , |
942 | _hash_includes_len ? "hval" : "len" ); |
943 | |
944 | while (key_pos != Positions::LASTCHAR && key_pos >= _max_key_len) |
945 | if ((key_pos = iter.next ()) == PositionIterator::EOS) |
946 | break; |
947 | |
948 | if (key_pos != PositionIterator::EOS && key_pos != Positions::LASTCHAR) |
949 | { |
950 | int i = key_pos; |
951 | do |
952 | { |
953 | if (i > key_pos) |
954 | printf (" /*FALLTHROUGH*/\n" ); /* Pacify lint. */ |
955 | for ( ; i > key_pos; i--) |
956 | printf (" case %d:\n" , i); |
957 | |
958 | printf (" hval += " ); |
959 | output_asso_values_ref (key_pos); |
960 | printf (";\n" ); |
961 | |
962 | key_pos = iter.next (); |
963 | } |
964 | while (key_pos != PositionIterator::EOS && key_pos != Positions::LASTCHAR); |
965 | |
966 | if (i >= _min_key_len) |
967 | printf (" /*FALLTHROUGH*/\n" ); /* Pacify lint. */ |
968 | for ( ; i >= _min_key_len; i--) |
969 | printf (" case %d:\n" , i); |
970 | } |
971 | |
972 | printf (" break;\n" |
973 | " }\n" |
974 | " return hval" ); |
975 | if (key_pos == Positions::LASTCHAR) |
976 | { |
977 | printf (" + " ); |
978 | output_asso_values_ref (Positions::LASTCHAR); |
979 | } |
980 | printf (";\n" ); |
981 | } |
982 | } |
983 | printf ("}\n\n" ); |
984 | } |
985 | |
986 | /* ------------------------------------------------------------------------- */ |
987 | |
988 | /* Prints out a table of keyword lengths, for use with the |
989 | comparison code in generated function 'in_word_set'. |
990 | Only called if option[LENTABLE]. */ |
991 | |
992 | void |
993 | Output::output_keylength_table () const |
994 | { |
995 | const int columns = 14; |
996 | const char * const indent = option[GLOBAL] ? "" : " " ; |
997 | |
998 | printf ("%sstatic %s%s %s[] =\n" |
999 | "%s {" , |
1000 | indent, const_readonly_array, |
1001 | smallest_integral_type (_max_key_len), |
1002 | option.get_lengthtable_name (), |
1003 | indent); |
1004 | |
1005 | /* Generate an array of lengths, similar to output_keyword_table. */ |
1006 | int index; |
1007 | int column; |
1008 | KeywordExt_List *temp; |
1009 | |
1010 | column = 0; |
1011 | for (temp = _head, index = 0; temp; temp = temp->rest()) |
1012 | { |
1013 | KeywordExt *keyword = temp->first(); |
1014 | |
1015 | /* If generating a switch statement, and there is no user defined type, |
1016 | we generate non-duplicates directly in the code. Only duplicates go |
1017 | into the table. */ |
1018 | if (option[SWITCH] && !option[TYPE] && !keyword->_duplicate_link) |
1019 | continue; |
1020 | |
1021 | if (index < keyword->_hash_value && !option[SWITCH] && !option[DUP]) |
1022 | { |
1023 | /* Some blank entries. */ |
1024 | for ( ; index < keyword->_hash_value; index++) |
1025 | { |
1026 | if (index > 0) |
1027 | printf ("," ); |
1028 | if ((column++ % columns) == 0) |
1029 | printf ("\n%s " , indent); |
1030 | printf ("%3d" , 0); |
1031 | } |
1032 | } |
1033 | |
1034 | if (index > 0) |
1035 | printf ("," ); |
1036 | if ((column++ % columns) == 0) |
1037 | printf("\n%s " , indent); |
1038 | printf ("%3d" , keyword->_allchars_length); |
1039 | index++; |
1040 | |
1041 | /* Deal with duplicates specially. */ |
1042 | if (keyword->_duplicate_link) // implies option[DUP] |
1043 | for (KeywordExt *links = keyword->_duplicate_link; links; links = links->_duplicate_link) |
1044 | { |
1045 | printf ("," ); |
1046 | if ((column++ % columns) == 0) |
1047 | printf("\n%s " , indent); |
1048 | printf ("%3d" , links->_allchars_length); |
1049 | index++; |
1050 | } |
1051 | } |
1052 | |
1053 | printf ("\n%s };\n" , indent); |
1054 | if (option[GLOBAL]) |
1055 | printf ("\n" ); |
1056 | } |
1057 | |
1058 | /* ------------------------------------------------------------------------- */ |
1059 | |
1060 | /* Prints out the string pool, containing the strings of the keyword table. |
1061 | Only called if option[SHAREDLIB]. */ |
1062 | |
1063 | void |
1064 | Output::output_string_pool () const |
1065 | { |
1066 | const char * const indent = option[TYPE] || option[GLOBAL] ? "" : " " ; |
1067 | int index; |
1068 | KeywordExt_List *temp; |
1069 | |
1070 | printf ("%sstruct %s_t\n" |
1071 | "%s {\n" , |
1072 | indent, option.get_stringpool_name (), indent); |
1073 | for (temp = _head, index = 0; temp; temp = temp->rest()) |
1074 | { |
1075 | KeywordExt *keyword = temp->first(); |
1076 | |
1077 | /* If generating a switch statement, and there is no user defined type, |
1078 | we generate non-duplicates directly in the code. Only duplicates go |
1079 | into the table. */ |
1080 | if (option[SWITCH] && !option[TYPE] && !keyword->_duplicate_link) |
1081 | continue; |
1082 | |
1083 | if (!option[SWITCH] && !option[DUP]) |
1084 | index = keyword->_hash_value; |
1085 | |
1086 | printf ("%s char %s_str%d[sizeof(" , |
1087 | indent, option.get_stringpool_name (), index); |
1088 | output_string (keyword->_allchars, keyword->_allchars_length); |
1089 | printf (")];\n" ); |
1090 | |
1091 | /* Deal with duplicates specially. */ |
1092 | if (keyword->_duplicate_link) // implies option[DUP] |
1093 | for (KeywordExt *links = keyword->_duplicate_link; links; links = links->_duplicate_link) |
1094 | if (!(links->_allchars_length == keyword->_allchars_length |
1095 | && memcmp (links->_allchars, keyword->_allchars, |
1096 | keyword->_allchars_length) == 0)) |
1097 | { |
1098 | index++; |
1099 | printf ("%s char %s_str%d[sizeof(" , |
1100 | indent, option.get_stringpool_name (), index); |
1101 | output_string (links->_allchars, links->_allchars_length); |
1102 | printf (")];\n" ); |
1103 | } |
1104 | |
1105 | index++; |
1106 | } |
1107 | printf ("%s };\n" , |
1108 | indent); |
1109 | |
1110 | printf ("%sstatic %sstruct %s_t %s_contents =\n" |
1111 | "%s {\n" , |
1112 | indent, const_readonly_array, option.get_stringpool_name (), |
1113 | option.get_stringpool_name (), indent); |
1114 | for (temp = _head, index = 0; temp; temp = temp->rest()) |
1115 | { |
1116 | KeywordExt *keyword = temp->first(); |
1117 | |
1118 | /* If generating a switch statement, and there is no user defined type, |
1119 | we generate non-duplicates directly in the code. Only duplicates go |
1120 | into the table. */ |
1121 | if (option[SWITCH] && !option[TYPE] && !keyword->_duplicate_link) |
1122 | continue; |
1123 | |
1124 | if (index > 0) |
1125 | printf (",\n" ); |
1126 | |
1127 | if (!option[SWITCH] && !option[DUP]) |
1128 | index = keyword->_hash_value; |
1129 | |
1130 | printf ("%s " , |
1131 | indent); |
1132 | output_string (keyword->_allchars, keyword->_allchars_length); |
1133 | |
1134 | /* Deal with duplicates specially. */ |
1135 | if (keyword->_duplicate_link) // implies option[DUP] |
1136 | for (KeywordExt *links = keyword->_duplicate_link; links; links = links->_duplicate_link) |
1137 | if (!(links->_allchars_length == keyword->_allchars_length |
1138 | && memcmp (links->_allchars, keyword->_allchars, |
1139 | keyword->_allchars_length) == 0)) |
1140 | { |
1141 | index++; |
1142 | printf (",\n" ); |
1143 | printf ("%s " , |
1144 | indent); |
1145 | output_string (links->_allchars, links->_allchars_length); |
1146 | } |
1147 | |
1148 | index++; |
1149 | } |
1150 | if (index > 0) |
1151 | printf ("\n" ); |
1152 | printf ("%s };\n" , |
1153 | indent); |
1154 | printf ("%s#define %s ((%schar *) &%s_contents)\n" , |
1155 | indent, option.get_stringpool_name (), const_always, |
1156 | option.get_stringpool_name ()); |
1157 | if (option[GLOBAL]) |
1158 | printf ("\n" ); |
1159 | } |
1160 | |
1161 | /* ------------------------------------------------------------------------- */ |
1162 | |
1163 | static void |
1164 | output_keyword_entry (KeywordExt *temp, int stringpool_index, const char *indent) |
1165 | { |
1166 | if (option[TYPE]) |
1167 | output_line_directive (temp->_lineno); |
1168 | printf ("%s " , indent); |
1169 | if (option[TYPE]) |
1170 | printf ("{" ); |
1171 | if (option[SHAREDLIB]) |
1172 | /* How to determine a certain offset in stringpool at compile time? |
1173 | - The standard way would be to use the 'offsetof' macro. But it is only |
1174 | defined in <stddef.h>, and <stddef.h> is not among the prerequisite |
1175 | header files that the user must #include. |
1176 | - The next best way would be to take the address and cast to 'intptr_t' |
1177 | or 'uintptr_t'. But these types are only defined in <stdint.h>, and |
1178 | <stdint.h> is not among the prerequisite header files that the user |
1179 | must #include. |
1180 | - The next best approximation of 'uintptr_t' is 'size_t'. It is defined |
1181 | in the prerequisite header <string.h>. |
1182 | - The types 'long' and 'unsigned long' do work as well, but on 64-bit |
1183 | native Windows platforms, they don't have the same size as pointers |
1184 | and therefore generate warnings. */ |
1185 | printf ("(int)(size_t)&((struct %s_t *)0)->%s_str%d" , |
1186 | option.get_stringpool_name (), option.get_stringpool_name (), |
1187 | stringpool_index); |
1188 | else |
1189 | output_string (temp->_allchars, temp->_allchars_length); |
1190 | if (option[TYPE]) |
1191 | { |
1192 | if (strlen (temp->_rest) > 0) |
1193 | printf (",%s" , temp->_rest); |
1194 | printf ("}" ); |
1195 | } |
1196 | if (option[DEBUG]) |
1197 | printf (" /* hash value = %d, index = %d */" , |
1198 | temp->_hash_value, temp->_final_index); |
1199 | } |
1200 | |
1201 | static void |
1202 | output_keyword_blank_entries (int count, const char *indent) |
1203 | { |
1204 | int columns; |
1205 | if (option[TYPE]) |
1206 | { |
1207 | columns = 58 / (4 + (option[SHAREDLIB] ? 2 : option[NULLSTRINGS] ? 8 : 2) |
1208 | + strlen (option.get_initializer_suffix())); |
1209 | if (columns == 0) |
1210 | columns = 1; |
1211 | } |
1212 | else |
1213 | { |
1214 | columns = (option[SHAREDLIB] ? 9 : option[NULLSTRINGS] ? 4 : 9); |
1215 | } |
1216 | int column = 0; |
1217 | for (int i = 0; i < count; i++) |
1218 | { |
1219 | if ((column % columns) == 0) |
1220 | { |
1221 | if (i > 0) |
1222 | printf (",\n" ); |
1223 | printf ("%s " , indent); |
1224 | } |
1225 | else |
1226 | { |
1227 | if (i > 0) |
1228 | printf (", " ); |
1229 | } |
1230 | if (option[TYPE]) |
1231 | printf ("{" ); |
1232 | if (option[SHAREDLIB]) |
1233 | printf ("-1" ); |
1234 | else |
1235 | { |
1236 | if (option[NULLSTRINGS]) |
1237 | printf ("(char*)0" ); |
1238 | else |
1239 | printf ("\"\"" ); |
1240 | } |
1241 | if (option[TYPE]) |
1242 | printf ("%s}" , option.get_initializer_suffix()); |
1243 | column++; |
1244 | } |
1245 | } |
1246 | |
1247 | /* Prints out the array containing the keywords for the hash function. */ |
1248 | |
1249 | void |
1250 | Output::output_keyword_table () const |
1251 | { |
1252 | const char *indent = option[GLOBAL] ? "" : " " ; |
1253 | int index; |
1254 | KeywordExt_List *temp; |
1255 | |
1256 | printf ("%sstatic " , |
1257 | indent); |
1258 | output_const_type (const_readonly_array, _wordlist_eltype); |
1259 | printf ("%s[] =\n" |
1260 | "%s {\n" , |
1261 | option.get_wordlist_name (), |
1262 | indent); |
1263 | |
1264 | /* Generate an array of reserved words at appropriate locations. */ |
1265 | |
1266 | for (temp = _head, index = 0; temp; temp = temp->rest()) |
1267 | { |
1268 | KeywordExt *keyword = temp->first(); |
1269 | |
1270 | /* If generating a switch statement, and there is no user defined type, |
1271 | we generate non-duplicates directly in the code. Only duplicates go |
1272 | into the table. */ |
1273 | if (option[SWITCH] && !option[TYPE] && !keyword->_duplicate_link) |
1274 | continue; |
1275 | |
1276 | if (index > 0) |
1277 | printf (",\n" ); |
1278 | |
1279 | if (index < keyword->_hash_value && !option[SWITCH] && !option[DUP]) |
1280 | { |
1281 | /* Some blank entries. */ |
1282 | output_keyword_blank_entries (keyword->_hash_value - index, indent); |
1283 | printf (",\n" ); |
1284 | index = keyword->_hash_value; |
1285 | } |
1286 | |
1287 | keyword->_final_index = index; |
1288 | |
1289 | output_keyword_entry (keyword, index, indent); |
1290 | |
1291 | /* Deal with duplicates specially. */ |
1292 | if (keyword->_duplicate_link) // implies option[DUP] |
1293 | for (KeywordExt *links = keyword->_duplicate_link; links; links = links->_duplicate_link) |
1294 | { |
1295 | links->_final_index = ++index; |
1296 | printf (",\n" ); |
1297 | int stringpool_index = |
1298 | (links->_allchars_length == keyword->_allchars_length |
1299 | && memcmp (links->_allchars, keyword->_allchars, |
1300 | keyword->_allchars_length) == 0 |
1301 | ? keyword->_final_index |
1302 | : links->_final_index); |
1303 | output_keyword_entry (links, stringpool_index, indent); |
1304 | } |
1305 | |
1306 | index++; |
1307 | } |
1308 | if (index > 0) |
1309 | printf ("\n" ); |
1310 | |
1311 | printf ("%s };\n\n" , indent); |
1312 | } |
1313 | |
1314 | /* ------------------------------------------------------------------------- */ |
1315 | |
1316 | /* Generates the large, sparse table that maps hash values into |
1317 | the smaller, contiguous range of the keyword table. */ |
1318 | |
1319 | void |
1320 | Output::output_lookup_array () const |
1321 | { |
1322 | if (option[DUP]) |
1323 | { |
1324 | const int DEFAULT_VALUE = -1; |
1325 | |
1326 | /* Because of the way output_keyword_table works, every duplicate set is |
1327 | stored contiguously in the wordlist array. */ |
1328 | struct duplicate_entry |
1329 | { |
1330 | int hash_value; /* Hash value for this particular duplicate set. */ |
1331 | int index; /* Index into the main keyword storage array. */ |
1332 | int count; /* Number of consecutive duplicates at this index. */ |
1333 | }; |
1334 | |
1335 | duplicate_entry *duplicates = new duplicate_entry[_total_duplicates]; |
1336 | int *lookup_array = new int[_max_hash_value + 1 + 2*_total_duplicates]; |
1337 | int lookup_array_size = _max_hash_value + 1; |
1338 | duplicate_entry *dup_ptr = &duplicates[0]; |
1339 | int *lookup_ptr = &lookup_array[_max_hash_value + 1 + 2*_total_duplicates]; |
1340 | |
1341 | while (lookup_ptr > lookup_array) |
1342 | *--lookup_ptr = DEFAULT_VALUE; |
1343 | |
1344 | /* Now dup_ptr = &duplicates[0] and lookup_ptr = &lookup_array[0]. */ |
1345 | |
1346 | for (KeywordExt_List *temp = _head; temp; temp = temp->rest()) |
1347 | { |
1348 | int hash_value = temp->first()->_hash_value; |
1349 | lookup_array[hash_value] = temp->first()->_final_index; |
1350 | if (option[DEBUG]) |
1351 | fprintf (stderr, "keyword = %.*s, index = %d\n" , |
1352 | temp->first()->_allchars_length, temp->first()->_allchars, temp->first()->_final_index); |
1353 | if (temp->first()->_duplicate_link) |
1354 | { |
1355 | /* Start a duplicate entry. */ |
1356 | dup_ptr->hash_value = hash_value; |
1357 | dup_ptr->index = temp->first()->_final_index; |
1358 | dup_ptr->count = 1; |
1359 | |
1360 | for (KeywordExt *ptr = temp->first()->_duplicate_link; ptr; ptr = ptr->_duplicate_link) |
1361 | { |
1362 | dup_ptr->count++; |
1363 | if (option[DEBUG]) |
1364 | fprintf (stderr, |
1365 | "static linked keyword = %.*s, index = %d\n" , |
1366 | ptr->_allchars_length, ptr->_allchars, ptr->_final_index); |
1367 | } |
1368 | assert (dup_ptr->count >= 2); |
1369 | dup_ptr++; |
1370 | } |
1371 | } |
1372 | |
1373 | while (dup_ptr > duplicates) |
1374 | { |
1375 | dup_ptr--; |
1376 | |
1377 | if (option[DEBUG]) |
1378 | fprintf (stderr, |
1379 | "dup_ptr[%lu]: hash_value = %d, index = %d, count = %d\n" , |
1380 | static_cast<unsigned long>(dup_ptr - duplicates), |
1381 | dup_ptr->hash_value, dup_ptr->index, dup_ptr->count); |
1382 | |
1383 | int i; |
1384 | /* Start searching for available space towards the right part |
1385 | of the lookup array. */ |
1386 | for (i = dup_ptr->hash_value; i < lookup_array_size-1; i++) |
1387 | if (lookup_array[i] == DEFAULT_VALUE |
1388 | && lookup_array[i + 1] == DEFAULT_VALUE) |
1389 | goto found_i; |
1390 | /* If we didn't find it to the right look to the left instead... */ |
1391 | for (i = dup_ptr->hash_value-1; i >= 0; i--) |
1392 | if (lookup_array[i] == DEFAULT_VALUE |
1393 | && lookup_array[i + 1] == DEFAULT_VALUE) |
1394 | goto found_i; |
1395 | /* Append to the end of lookup_array. */ |
1396 | i = lookup_array_size; |
1397 | lookup_array_size += 2; |
1398 | found_i: |
1399 | /* Put in an indirection from dup_ptr->_hash_value to i. |
1400 | At i and i+1 store dup_ptr->_final_index and dup_ptr->count. */ |
1401 | assert (lookup_array[dup_ptr->hash_value] == dup_ptr->index); |
1402 | lookup_array[dup_ptr->hash_value] = - 1 - _total_keys - i; |
1403 | lookup_array[i] = - _total_keys + dup_ptr->index; |
1404 | lookup_array[i + 1] = - dup_ptr->count; |
1405 | /* All these three values are <= -2, distinct from DEFAULT_VALUE. */ |
1406 | } |
1407 | |
1408 | /* The values of the lookup array are now known. */ |
1409 | |
1410 | int min = INT_MAX; |
1411 | int max = INT_MIN; |
1412 | lookup_ptr = lookup_array + lookup_array_size; |
1413 | while (lookup_ptr > lookup_array) |
1414 | { |
1415 | int val = *--lookup_ptr; |
1416 | if (min > val) |
1417 | min = val; |
1418 | if (max < val) |
1419 | max = val; |
1420 | } |
1421 | |
1422 | const char *indent = option[GLOBAL] ? "" : " " ; |
1423 | printf ("%sstatic %s%s lookup[] =\n" |
1424 | "%s {" , |
1425 | indent, const_readonly_array, smallest_integral_type (min, max), |
1426 | indent); |
1427 | |
1428 | int field_width; |
1429 | /* Calculate maximum number of digits required for MIN..MAX. */ |
1430 | { |
1431 | field_width = 2; |
1432 | for (int trunc = max; (trunc /= 10) > 0;) |
1433 | field_width++; |
1434 | } |
1435 | if (min < 0) |
1436 | { |
1437 | int neg_field_width = 2; |
1438 | for (int trunc = -min; (trunc /= 10) > 0;) |
1439 | neg_field_width++; |
1440 | neg_field_width++; /* account for the minus sign */ |
1441 | if (field_width < neg_field_width) |
1442 | field_width = neg_field_width; |
1443 | } |
1444 | |
1445 | const int columns = 42 / field_width; |
1446 | int column; |
1447 | |
1448 | column = 0; |
1449 | for (int i = 0; i < lookup_array_size; i++) |
1450 | { |
1451 | if (i > 0) |
1452 | printf ("," ); |
1453 | if ((column++ % columns) == 0) |
1454 | printf("\n%s " , indent); |
1455 | printf ("%*d" , field_width, lookup_array[i]); |
1456 | } |
1457 | printf ("\n%s };\n\n" , indent); |
1458 | |
1459 | delete[] duplicates; |
1460 | delete[] lookup_array; |
1461 | } |
1462 | } |
1463 | |
1464 | /* ------------------------------------------------------------------------- */ |
1465 | |
1466 | /* Generate all pools needed for the lookup function. */ |
1467 | |
1468 | void |
1469 | Output::output_lookup_pools () const |
1470 | { |
1471 | if (option[SWITCH]) |
1472 | { |
1473 | if (option[TYPE] || (option[DUP] && _total_duplicates > 0)) |
1474 | output_string_pool (); |
1475 | } |
1476 | else |
1477 | { |
1478 | output_string_pool (); |
1479 | } |
1480 | } |
1481 | |
1482 | /* Generate all the tables needed for the lookup function. */ |
1483 | |
1484 | void |
1485 | Output::output_lookup_tables () const |
1486 | { |
1487 | if (option[SWITCH]) |
1488 | { |
1489 | /* Use the switch in place of lookup table. */ |
1490 | if (option[LENTABLE] && (option[DUP] && _total_duplicates > 0)) |
1491 | output_keylength_table (); |
1492 | if (option[TYPE] || (option[DUP] && _total_duplicates > 0)) |
1493 | output_keyword_table (); |
1494 | } |
1495 | else |
1496 | { |
1497 | /* Use the lookup table, in place of switch. */ |
1498 | if (option[LENTABLE]) |
1499 | output_keylength_table (); |
1500 | output_keyword_table (); |
1501 | output_lookup_array (); |
1502 | } |
1503 | } |
1504 | |
1505 | /* ------------------------------------------------------------------------- */ |
1506 | |
1507 | /* Output a single switch case (including duplicates). Advance list. */ |
1508 | |
1509 | static KeywordExt_List * |
1510 | output_switch_case (KeywordExt_List *list, int indent, int *jumps_away) |
1511 | { |
1512 | if (option[DEBUG]) |
1513 | printf ("%*s/* hash value = %4d, keyword = \"%.*s\" */\n" , |
1514 | indent, "" , list->first()->_hash_value, list->first()->_allchars_length, list->first()->_allchars); |
1515 | |
1516 | if (option[DUP] && list->first()->_duplicate_link) |
1517 | { |
1518 | if (option[LENTABLE]) |
1519 | printf ("%*slengthptr = &%s[%d];\n" , |
1520 | indent, "" , option.get_lengthtable_name (), list->first()->_final_index); |
1521 | printf ("%*swordptr = &%s[%d];\n" , |
1522 | indent, "" , option.get_wordlist_name (), list->first()->_final_index); |
1523 | |
1524 | int count = 0; |
1525 | for (KeywordExt *links = list->first(); links; links = links->_duplicate_link) |
1526 | count++; |
1527 | |
1528 | printf ("%*swordendptr = wordptr + %d;\n" |
1529 | "%*sgoto multicompare;\n" , |
1530 | indent, "" , count, |
1531 | indent, "" ); |
1532 | *jumps_away = 1; |
1533 | } |
1534 | else |
1535 | { |
1536 | if (option[LENTABLE]) |
1537 | { |
1538 | printf ("%*sif (len == %d)\n" |
1539 | "%*s {\n" , |
1540 | indent, "" , list->first()->_allchars_length, |
1541 | indent, "" ); |
1542 | indent += 4; |
1543 | } |
1544 | printf ("%*sresword = " , |
1545 | indent, "" ); |
1546 | if (option[TYPE]) |
1547 | printf ("&%s[%d]" , option.get_wordlist_name (), list->first()->_final_index); |
1548 | else |
1549 | output_string (list->first()->_allchars, list->first()->_allchars_length); |
1550 | printf (";\n" ); |
1551 | printf ("%*sgoto compare;\n" , |
1552 | indent, "" ); |
1553 | if (option[LENTABLE]) |
1554 | { |
1555 | indent -= 4; |
1556 | printf ("%*s }\n" , |
1557 | indent, "" ); |
1558 | } |
1559 | else |
1560 | *jumps_away = 1; |
1561 | } |
1562 | |
1563 | return list->rest(); |
1564 | } |
1565 | |
1566 | /* Output a total of size cases, grouped into num_switches switch statements, |
1567 | where 0 < num_switches <= size. */ |
1568 | |
1569 | static void |
1570 | output_switches (KeywordExt_List *list, int num_switches, int size, int min_hash_value, int max_hash_value, int indent) |
1571 | { |
1572 | if (option[DEBUG]) |
1573 | printf ("%*s/* know %d <= key <= %d, contains %d cases */\n" , |
1574 | indent, "" , min_hash_value, max_hash_value, size); |
1575 | |
1576 | if (num_switches > 1) |
1577 | { |
1578 | int part1 = num_switches / 2; |
1579 | int part2 = num_switches - part1; |
1580 | int size1 = static_cast<int>(static_cast<double>(size) / static_cast<double>(num_switches) * static_cast<double>(part1) + 0.5); |
1581 | int size2 = size - size1; |
1582 | |
1583 | KeywordExt_List *temp = list; |
1584 | for (int count = size1; count > 0; count--) |
1585 | temp = temp->rest(); |
1586 | |
1587 | printf ("%*sif (key < %d)\n" |
1588 | "%*s {\n" , |
1589 | indent, "" , temp->first()->_hash_value, |
1590 | indent, "" ); |
1591 | |
1592 | output_switches (list, part1, size1, min_hash_value, temp->first()->_hash_value-1, indent+4); |
1593 | |
1594 | printf ("%*s }\n" |
1595 | "%*selse\n" |
1596 | "%*s {\n" , |
1597 | indent, "" , indent, "" , indent, "" ); |
1598 | |
1599 | output_switches (temp, part2, size2, temp->first()->_hash_value, max_hash_value, indent+4); |
1600 | |
1601 | printf ("%*s }\n" , |
1602 | indent, "" ); |
1603 | } |
1604 | else |
1605 | { |
1606 | /* Output a single switch. */ |
1607 | int lowest_case_value = list->first()->_hash_value; |
1608 | if (size == 1) |
1609 | { |
1610 | int jumps_away = 0; |
1611 | assert (min_hash_value <= lowest_case_value); |
1612 | assert (lowest_case_value <= max_hash_value); |
1613 | if (min_hash_value == max_hash_value) |
1614 | output_switch_case (list, indent, &jumps_away); |
1615 | else |
1616 | { |
1617 | printf ("%*sif (key == %d)\n" |
1618 | "%*s {\n" , |
1619 | indent, "" , lowest_case_value, |
1620 | indent, "" ); |
1621 | output_switch_case (list, indent+4, &jumps_away); |
1622 | printf ("%*s }\n" , |
1623 | indent, "" ); |
1624 | } |
1625 | } |
1626 | else |
1627 | { |
1628 | if (lowest_case_value == 0) |
1629 | printf ("%*sswitch (key)\n" , indent, "" ); |
1630 | else |
1631 | printf ("%*sswitch (key - %d)\n" , indent, "" , lowest_case_value); |
1632 | printf ("%*s {\n" , |
1633 | indent, "" ); |
1634 | for (; size > 0; size--) |
1635 | { |
1636 | int jumps_away = 0; |
1637 | printf ("%*s case %d:\n" , |
1638 | indent, "" , list->first()->_hash_value - lowest_case_value); |
1639 | list = output_switch_case (list, indent+6, &jumps_away); |
1640 | if (!jumps_away) |
1641 | printf ("%*s break;\n" , |
1642 | indent, "" ); |
1643 | } |
1644 | printf ("%*s }\n" , |
1645 | indent, "" ); |
1646 | } |
1647 | } |
1648 | } |
1649 | |
1650 | /* Generates C code to perform the keyword lookup. */ |
1651 | |
1652 | void |
1653 | Output::output_lookup_function_body (const Output_Compare& comparison) const |
1654 | { |
1655 | printf (" if (len <= %sMAX_WORD_LENGTH && len >= %sMIN_WORD_LENGTH)\n" |
1656 | " {\n" |
1657 | " %sunsigned int key = %s (str, len);\n\n" , |
1658 | option.get_constants_prefix (), option.get_constants_prefix (), |
1659 | register_scs, option.get_hash_name ()); |
1660 | |
1661 | if (option[SWITCH]) |
1662 | { |
1663 | int switch_size = num_hash_values (); |
1664 | int num_switches = option.get_total_switches (); |
1665 | if (num_switches > switch_size) |
1666 | num_switches = switch_size; |
1667 | |
1668 | printf (" if (key <= %sMAX_HASH_VALUE" , |
1669 | option.get_constants_prefix ()); |
1670 | if (_min_hash_value > 0) |
1671 | printf (" && key >= %sMIN_HASH_VALUE" , |
1672 | option.get_constants_prefix ()); |
1673 | printf (")\n" |
1674 | " {\n" ); |
1675 | if (option[DUP] && _total_duplicates > 0) |
1676 | { |
1677 | if (option[LENTABLE]) |
1678 | printf (" %s%s%s *lengthptr;\n" , |
1679 | register_scs, const_always, |
1680 | smallest_integral_type (_max_key_len)); |
1681 | printf (" %s" , |
1682 | register_scs); |
1683 | output_const_type (const_readonly_array, _wordlist_eltype); |
1684 | printf ("*wordptr;\n" ); |
1685 | printf (" %s" , |
1686 | register_scs); |
1687 | output_const_type (const_readonly_array, _wordlist_eltype); |
1688 | printf ("*wordendptr;\n" ); |
1689 | } |
1690 | if (option[TYPE]) |
1691 | { |
1692 | printf (" %s" , |
1693 | register_scs); |
1694 | output_const_type (const_readonly_array, _struct_tag); |
1695 | printf ("*resword;\n\n" ); |
1696 | } |
1697 | else |
1698 | printf (" %s%sresword;\n\n" , |
1699 | register_scs, _struct_tag); |
1700 | |
1701 | output_switches (_head, num_switches, switch_size, _min_hash_value, _max_hash_value, 10); |
1702 | |
1703 | printf (" return 0;\n" ); |
1704 | if (option[DUP] && _total_duplicates > 0) |
1705 | { |
1706 | int indent = 8; |
1707 | printf ("%*smulticompare:\n" |
1708 | "%*s while (wordptr < wordendptr)\n" |
1709 | "%*s {\n" , |
1710 | indent, "" , indent, "" , indent, "" ); |
1711 | if (option[LENTABLE]) |
1712 | { |
1713 | printf ("%*s if (len == *lengthptr)\n" |
1714 | "%*s {\n" , |
1715 | indent, "" , indent, "" ); |
1716 | indent += 4; |
1717 | } |
1718 | printf ("%*s %s%schar *s = " , |
1719 | indent, "" , register_scs, const_always); |
1720 | if (option[TYPE]) |
1721 | printf ("wordptr->%s" , option.get_slot_name ()); |
1722 | else |
1723 | printf ("*wordptr" ); |
1724 | if (option[SHAREDLIB]) |
1725 | printf (" + %s" , |
1726 | option.get_stringpool_name ()); |
1727 | printf (";\n\n" |
1728 | "%*s if (" , |
1729 | indent, "" ); |
1730 | comparison.output_comparison (Output_Expr1 ("str" ), Output_Expr1 ("s" )); |
1731 | printf (")\n" |
1732 | "%*s return %s;\n" , |
1733 | indent, "" , |
1734 | option[TYPE] ? "wordptr" : "s" ); |
1735 | if (option[LENTABLE]) |
1736 | { |
1737 | indent -= 4; |
1738 | printf ("%*s }\n" , |
1739 | indent, "" ); |
1740 | } |
1741 | if (option[LENTABLE]) |
1742 | printf ("%*s lengthptr++;\n" , |
1743 | indent, "" ); |
1744 | printf ("%*s wordptr++;\n" |
1745 | "%*s }\n" |
1746 | "%*s return 0;\n" , |
1747 | indent, "" , indent, "" , indent, "" ); |
1748 | } |
1749 | printf (" compare:\n" ); |
1750 | if (option[TYPE]) |
1751 | { |
1752 | printf (" {\n" |
1753 | " %s%schar *s = resword->%s" , |
1754 | register_scs, const_always, option.get_slot_name ()); |
1755 | if (option[SHAREDLIB]) |
1756 | printf (" + %s" , |
1757 | option.get_stringpool_name ()); |
1758 | printf (";\n\n" |
1759 | " if (" ); |
1760 | comparison.output_comparison (Output_Expr1 ("str" ), Output_Expr1 ("s" )); |
1761 | printf (")\n" |
1762 | " return resword;\n" |
1763 | " }\n" ); |
1764 | } |
1765 | else |
1766 | { |
1767 | printf (" if (" ); |
1768 | comparison.output_comparison (Output_Expr1 ("str" ), Output_Expr1 ("resword" )); |
1769 | printf (")\n" |
1770 | " return resword;\n" ); |
1771 | } |
1772 | printf (" }\n" ); |
1773 | } |
1774 | else |
1775 | { |
1776 | printf (" if (key <= %sMAX_HASH_VALUE)\n" , |
1777 | option.get_constants_prefix ()); |
1778 | |
1779 | if (option[DUP]) |
1780 | { |
1781 | int indent = 8; |
1782 | printf ("%*s{\n" |
1783 | "%*s %sint index = lookup[key];\n\n" |
1784 | "%*s if (index >= 0)\n" , |
1785 | indent, "" , indent, "" , register_scs, indent, "" ); |
1786 | if (option[LENTABLE]) |
1787 | { |
1788 | printf ("%*s {\n" |
1789 | "%*s if (len == %s[index])\n" , |
1790 | indent, "" , indent, "" , option.get_lengthtable_name ()); |
1791 | indent += 4; |
1792 | } |
1793 | printf ("%*s {\n" |
1794 | "%*s %s%schar *s = %s[index]" , |
1795 | indent, "" , |
1796 | indent, "" , register_scs, const_always, |
1797 | option.get_wordlist_name ()); |
1798 | if (option[TYPE]) |
1799 | printf (".%s" , option.get_slot_name ()); |
1800 | if (option[SHAREDLIB]) |
1801 | printf (" + %s" , |
1802 | option.get_stringpool_name ()); |
1803 | printf (";\n\n" |
1804 | "%*s if (" , |
1805 | indent, "" ); |
1806 | comparison.output_comparison (Output_Expr1 ("str" ), Output_Expr1 ("s" )); |
1807 | printf (")\n" |
1808 | "%*s return " , |
1809 | indent, "" ); |
1810 | if (option[TYPE]) |
1811 | printf ("&%s[index]" , option.get_wordlist_name ()); |
1812 | else |
1813 | printf ("s" ); |
1814 | printf (";\n" |
1815 | "%*s }\n" , |
1816 | indent, "" ); |
1817 | if (option[LENTABLE]) |
1818 | { |
1819 | indent -= 4; |
1820 | printf ("%*s }\n" , indent, "" ); |
1821 | } |
1822 | if (_total_duplicates > 0) |
1823 | { |
1824 | printf ("%*s else if (index < -%sTOTAL_KEYWORDS)\n" |
1825 | "%*s {\n" |
1826 | "%*s %sint offset = - 1 - %sTOTAL_KEYWORDS - index;\n" , |
1827 | indent, "" , option.get_constants_prefix (), indent, "" , |
1828 | indent, "" , register_scs, option.get_constants_prefix ()); |
1829 | if (option[LENTABLE]) |
1830 | printf ("%*s %s%s%s *lengthptr = &%s[%sTOTAL_KEYWORDS + lookup[offset]];\n" , |
1831 | indent, "" , register_scs, const_always, smallest_integral_type (_max_key_len), |
1832 | option.get_lengthtable_name (), option.get_constants_prefix ()); |
1833 | printf ("%*s %s" , |
1834 | indent, "" , register_scs); |
1835 | output_const_type (const_readonly_array, _wordlist_eltype); |
1836 | printf ("*wordptr = &%s[%sTOTAL_KEYWORDS + lookup[offset]];\n" , |
1837 | option.get_wordlist_name (), option.get_constants_prefix ()); |
1838 | printf ("%*s %s" , |
1839 | indent, "" , register_scs); |
1840 | output_const_type (const_readonly_array, _wordlist_eltype); |
1841 | printf ("*wordendptr = wordptr + -lookup[offset + 1];\n\n" ); |
1842 | printf ("%*s while (wordptr < wordendptr)\n" |
1843 | "%*s {\n" , |
1844 | indent, "" , indent, "" ); |
1845 | if (option[LENTABLE]) |
1846 | { |
1847 | printf ("%*s if (len == *lengthptr)\n" |
1848 | "%*s {\n" , |
1849 | indent, "" , indent, "" ); |
1850 | indent += 4; |
1851 | } |
1852 | printf ("%*s %s%schar *s = " , |
1853 | indent, "" , register_scs, const_always); |
1854 | if (option[TYPE]) |
1855 | printf ("wordptr->%s" , option.get_slot_name ()); |
1856 | else |
1857 | printf ("*wordptr" ); |
1858 | if (option[SHAREDLIB]) |
1859 | printf (" + %s" , |
1860 | option.get_stringpool_name ()); |
1861 | printf (";\n\n" |
1862 | "%*s if (" , |
1863 | indent, "" ); |
1864 | comparison.output_comparison (Output_Expr1 ("str" ), Output_Expr1 ("s" )); |
1865 | printf (")\n" |
1866 | "%*s return %s;\n" , |
1867 | indent, "" , |
1868 | option[TYPE] ? "wordptr" : "s" ); |
1869 | if (option[LENTABLE]) |
1870 | { |
1871 | indent -= 4; |
1872 | printf ("%*s }\n" , |
1873 | indent, "" ); |
1874 | } |
1875 | if (option[LENTABLE]) |
1876 | printf ("%*s lengthptr++;\n" , |
1877 | indent, "" ); |
1878 | printf ("%*s wordptr++;\n" |
1879 | "%*s }\n" |
1880 | "%*s }\n" , |
1881 | indent, "" , indent, "" , indent, "" ); |
1882 | } |
1883 | printf ("%*s}\n" , |
1884 | indent, "" ); |
1885 | } |
1886 | else |
1887 | { |
1888 | int indent = 8; |
1889 | if (option[LENTABLE]) |
1890 | { |
1891 | printf ("%*sif (len == %s[key])\n" , |
1892 | indent, "" , option.get_lengthtable_name ()); |
1893 | indent += 2; |
1894 | } |
1895 | |
1896 | if (option[SHAREDLIB]) |
1897 | { |
1898 | if (!option[LENTABLE]) |
1899 | { |
1900 | printf ("%*s{\n" |
1901 | "%*s %sint o = %s[key]" , |
1902 | indent, "" , |
1903 | indent, "" , register_scs, |
1904 | option.get_wordlist_name ()); |
1905 | if (option[TYPE]) |
1906 | printf (".%s" , option.get_slot_name ()); |
1907 | printf (";\n" |
1908 | "%*s if (o >= 0)\n" |
1909 | "%*s {\n" , |
1910 | indent, "" , |
1911 | indent, "" ); |
1912 | indent += 4; |
1913 | printf ("%*s %s%schar *s = o" , |
1914 | indent, "" , register_scs, const_always); |
1915 | } |
1916 | else |
1917 | { |
1918 | /* No need for the (o >= 0) test, because the |
1919 | (len == lengthtable[key]) test already guarantees that |
1920 | key points to nonempty table entry. */ |
1921 | printf ("%*s{\n" |
1922 | "%*s %s%schar *s = %s[key]" , |
1923 | indent, "" , |
1924 | indent, "" , register_scs, const_always, |
1925 | option.get_wordlist_name ()); |
1926 | if (option[TYPE]) |
1927 | printf (".%s" , option.get_slot_name ()); |
1928 | } |
1929 | printf (" + %s" , |
1930 | option.get_stringpool_name ()); |
1931 | } |
1932 | else |
1933 | { |
1934 | printf ("%*s{\n" |
1935 | "%*s %s%schar *s = %s[key]" , |
1936 | indent, "" , |
1937 | indent, "" , register_scs, const_always, |
1938 | option.get_wordlist_name ()); |
1939 | if (option[TYPE]) |
1940 | printf (".%s" , option.get_slot_name ()); |
1941 | } |
1942 | |
1943 | printf (";\n\n" |
1944 | "%*s if (" , |
1945 | indent, "" ); |
1946 | if (!option[SHAREDLIB] && option[NULLSTRINGS]) |
1947 | printf ("s && " ); |
1948 | comparison.output_comparison (Output_Expr1 ("str" ), Output_Expr1 ("s" )); |
1949 | printf (")\n" |
1950 | "%*s return " , |
1951 | indent, "" ); |
1952 | if (option[TYPE]) |
1953 | printf ("&%s[key]" , option.get_wordlist_name ()); |
1954 | else |
1955 | printf ("s" ); |
1956 | printf (";\n" ); |
1957 | if (option[SHAREDLIB] && !option[LENTABLE]) |
1958 | { |
1959 | indent -= 4; |
1960 | printf ("%*s }\n" , |
1961 | indent, "" ); |
1962 | } |
1963 | printf ("%*s}\n" , |
1964 | indent, "" ); |
1965 | } |
1966 | } |
1967 | printf (" }\n" |
1968 | " return 0;\n" ); |
1969 | } |
1970 | |
1971 | /* Generates C code for the lookup function. */ |
1972 | |
1973 | void |
1974 | Output::output_lookup_function () const |
1975 | { |
1976 | /* Output the function's head. */ |
1977 | /* We don't declare the lookup function 'static' because we cannot make |
1978 | assumptions about the compilation units of the user. |
1979 | Since we don't make it 'static', it makes no sense to declare it 'inline', |
1980 | because non-static inline functions must not reference static functions or |
1981 | variables, see ISO C 99 section 6.7.4.(3). */ |
1982 | |
1983 | printf ("%s%s\n" , |
1984 | const_for_struct, _return_type); |
1985 | if (option[CPLUSPLUS]) |
1986 | printf ("%s::" , option.get_class_name ()); |
1987 | printf ("%s " , option.get_function_name ()); |
1988 | printf (option[KRC] ? |
1989 | "(str, len)\n" |
1990 | " %schar *str;\n" |
1991 | " %ssize_t len;\n" : |
1992 | option[C] ? |
1993 | "(str, len)\n" |
1994 | " %sconst char *str;\n" |
1995 | " %ssize_t len;\n" : |
1996 | option[ANSIC] | option[CPLUSPLUS] ? |
1997 | "(%sconst char *str, %ssize_t len)\n" : |
1998 | "" , |
1999 | register_scs, register_scs); |
2000 | |
2001 | /* Output the function's body. */ |
2002 | printf ("{\n" ); |
2003 | |
2004 | if (option[ENUM] && !option[GLOBAL]) |
2005 | { |
2006 | Output_Enum style (" " ); |
2007 | output_constants (style); |
2008 | } |
2009 | |
2010 | if (option[SHAREDLIB] && !(option[GLOBAL] || option[TYPE])) |
2011 | output_lookup_pools (); |
2012 | if (!option[GLOBAL]) |
2013 | output_lookup_tables (); |
2014 | |
2015 | if (option[LENTABLE]) |
2016 | output_lookup_function_body (Output_Compare_Memcmp ()); |
2017 | else |
2018 | { |
2019 | if (option[COMP]) |
2020 | output_lookup_function_body (Output_Compare_Strncmp ()); |
2021 | else |
2022 | output_lookup_function_body (Output_Compare_Strcmp ()); |
2023 | } |
2024 | |
2025 | printf ("}\n" ); |
2026 | } |
2027 | |
2028 | /* ------------------------------------------------------------------------- */ |
2029 | |
2030 | /* Generates the hash function and the key word recognizer function |
2031 | based upon the user's Options. */ |
2032 | |
2033 | void |
2034 | Output::output () |
2035 | { |
2036 | compute_min_max (); |
2037 | |
2038 | if (option[CPLUSPLUS]) |
2039 | /* The 'register' keyword is removed from C++17. |
2040 | See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4340 */ |
2041 | register_scs = "" ; |
2042 | else |
2043 | register_scs = "register " ; |
2044 | |
2045 | if (option[C] | option[ANSIC] | option[CPLUSPLUS]) |
2046 | { |
2047 | const_always = "const " ; |
2048 | const_readonly_array = (option[CONST] ? "const " : "" ); |
2049 | const_for_struct = ((option[CONST] && option[TYPE]) ? "const " : "" ); |
2050 | } |
2051 | else |
2052 | { |
2053 | const_always = "" ; |
2054 | const_readonly_array = "" ; |
2055 | const_for_struct = "" ; |
2056 | } |
2057 | |
2058 | if (!option[TYPE]) |
2059 | { |
2060 | _return_type = (const_always[0] ? "const char *" : "char *" ); |
2061 | _struct_tag = (const_always[0] ? "const char *" : "char *" ); |
2062 | } |
2063 | |
2064 | _wordlist_eltype = (option[SHAREDLIB] && !option[TYPE] ? "int" : _struct_tag); |
2065 | |
2066 | printf ("/* " ); |
2067 | if (option[KRC]) |
2068 | printf ("KR-C" ); |
2069 | else if (option[C]) |
2070 | printf ("C" ); |
2071 | else if (option[ANSIC]) |
2072 | printf ("ANSI-C" ); |
2073 | else if (option[CPLUSPLUS]) |
2074 | printf ("C++" ); |
2075 | printf (" code produced by gperf version %s */\n" , version_string); |
2076 | option.print_options (); |
2077 | printf ("\n" ); |
2078 | if (!option[POSITIONS]) |
2079 | { |
2080 | printf ("/* Computed positions: -k'" ); |
2081 | _key_positions.print(); |
2082 | printf ("' */\n" ); |
2083 | } |
2084 | printf ("\n" ); |
2085 | |
2086 | if (_charset_dependent |
2087 | && (_key_positions.get_size() > 0 || option[UPPERLOWER])) |
2088 | { |
2089 | /* The generated tables assume that the execution character set is |
2090 | based on ISO-646, not EBCDIC. */ |
2091 | printf ("#if !((' ' == 32) && ('!' == 33) && ('\"' == 34) && ('#' == 35) \\\n" |
2092 | " && ('%%' == 37) && ('&' == 38) && ('\\'' == 39) && ('(' == 40) \\\n" |
2093 | " && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \\\n" |
2094 | " && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \\\n" |
2095 | " && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \\\n" |
2096 | " && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \\\n" |
2097 | " && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \\\n" |
2098 | " && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \\\n" |
2099 | " && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \\\n" |
2100 | " && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \\\n" |
2101 | " && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \\\n" |
2102 | " && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \\\n" |
2103 | " && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \\\n" |
2104 | " && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \\\n" |
2105 | " && ('Z' == 90) && ('[' == 91) && ('\\\\' == 92) && (']' == 93) \\\n" |
2106 | " && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \\\n" |
2107 | " && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \\\n" |
2108 | " && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \\\n" |
2109 | " && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \\\n" |
2110 | " && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \\\n" |
2111 | " && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \\\n" |
2112 | " && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \\\n" |
2113 | " && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))\n" |
2114 | "/* The character set is not based on ISO-646. */\n" ); |
2115 | printf ("%s \"gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>.\"\n" , option[KRC] || option[C] ? "error" : "#error" ); |
2116 | printf ("#endif\n\n" ); |
2117 | } |
2118 | |
2119 | if (_verbatim_declarations < _verbatim_declarations_end) |
2120 | { |
2121 | output_line_directive (_verbatim_declarations_lineno); |
2122 | fwrite (_verbatim_declarations, 1, |
2123 | _verbatim_declarations_end - _verbatim_declarations, stdout); |
2124 | } |
2125 | |
2126 | if (option[TYPE] && !option[NOTYPE]) /* Output type declaration now, reference it later on.... */ |
2127 | { |
2128 | output_line_directive (_struct_decl_lineno); |
2129 | printf ("%s\n" , _struct_decl); |
2130 | } |
2131 | |
2132 | if (option[INCLUDE]) |
2133 | printf ("#include <string.h>\n" ); /* Declare strlen(), strcmp(), strncmp(). */ |
2134 | |
2135 | if (!option[ENUM]) |
2136 | { |
2137 | Output_Defines style; |
2138 | output_constants (style); |
2139 | } |
2140 | else if (option[GLOBAL]) |
2141 | { |
2142 | Output_Enum style ("" ); |
2143 | output_constants (style); |
2144 | } |
2145 | |
2146 | printf ("/* maximum key range = %d, duplicates = %d */\n\n" , |
2147 | _max_hash_value - _min_hash_value + 1, _total_duplicates); |
2148 | |
2149 | if (option[UPPERLOWER]) |
2150 | { |
2151 | #if USE_DOWNCASE_TABLE |
2152 | output_upperlower_table (); |
2153 | #endif |
2154 | |
2155 | if (option[LENTABLE]) |
2156 | output_upperlower_memcmp (); |
2157 | else |
2158 | { |
2159 | if (option[COMP]) |
2160 | output_upperlower_strncmp (); |
2161 | else |
2162 | output_upperlower_strcmp (); |
2163 | } |
2164 | } |
2165 | |
2166 | if (option[CPLUSPLUS]) |
2167 | printf ("class %s\n" |
2168 | "{\n" |
2169 | "private:\n" |
2170 | " static inline unsigned int %s (const char *str, size_t len);\n" |
2171 | "public:\n" |
2172 | " static %s%s%s (const char *str, size_t len);\n" |
2173 | "};\n" |
2174 | "\n" , |
2175 | option.get_class_name (), option.get_hash_name (), |
2176 | const_for_struct, _return_type, option.get_function_name ()); |
2177 | |
2178 | output_hash_function (); |
2179 | |
2180 | if (option[SHAREDLIB] && (option[GLOBAL] || option[TYPE])) |
2181 | output_lookup_pools (); |
2182 | if (option[GLOBAL]) |
2183 | output_lookup_tables (); |
2184 | |
2185 | output_lookup_function (); |
2186 | |
2187 | if (_verbatim_code < _verbatim_code_end) |
2188 | { |
2189 | output_line_directive (_verbatim_code_lineno); |
2190 | fwrite (_verbatim_code, 1, _verbatim_code_end - _verbatim_code, stdout); |
2191 | } |
2192 | |
2193 | fflush (stdout); |
2194 | } |
2195 | |