1 #ifndef CGPERF_OUTPUT_C
2 #define CGPERF_OUTPUT_C
9 #include "keyword_list.h"
10 #include "positions.h"
11 /*------------------------------------------------------------------------------------------------*/
12 #include "namespace/globals.h"
13 #include "namespace/options.h"
14 #include "namespace/output.h"
15 #include "namespace/output.c"
16 #include "namespace/keyword.h"
17 #include "namespace/keyword_list.h"
18 #include "namespace/positions.h"
19 /*------------------------------------------------------------------------------------------------*/
20 /* We use a downcase table because when called repeatedly, the code gperf_downcase[c]
22 if (c >= 'A' && c <= 'Z')
25 #define USE_DOWNCASE_TABLE 1
26 /*------------------------------------------------------------------------------------------------*/
30 * because of the way output_keyword_table works, every duplicate set is
31 * stored contiguously in the wordlist array
33 struct Duplicate_Entry
35 s32 hash_value
; /* hash value for this particular duplicate set */
36 s32 index
; /* index into the main keyword storage array */
37 s32 count
; /* number of consecutive duplicates at this index */
41 /* the "register " storage-class specifier */
42 static u8
*register_scs
;
43 /* the "const " qualifier */
44 static u8
*const_always
;
45 /* the "const " qualifier, for read-only arrays */
46 static u8
*const_readonly_array
;
47 /* the "const " qualifier, for the array type */
48 static u8
*const_for_struct
;
49 /*}}} variables -- END */
51 /*{{{ output_string */
53 * Outputs a keyword, as a string: enclosed in double quotes, escaping backslashes, double quote and
54 * unprintable characters
56 static void output_string(u8
*key
, s32 len
)
66 if (c
== '"' || c
== '\\')
71 * Use octal escapes, not hexadecimal escapes, because some old C compilers
72 * didn't understand hexadecimal escapes, and because hexadecimal escapes
73 * are not limited to 2 digits, thus needing special care if the following
74 * character happens to be a digit.
77 putchar('0' + ((c
>> 6) & 7));
78 putchar('0' + ((c
>> 3) & 7));
79 putchar('0' + (c
& 7));
85 /*{{{ output_line_directive */
86 /* outputs a #line directive, referring to the given line number */
87 static void output_line_directive(u32 lineno
)
91 file_name
= options
->input_file_name
;
93 printf("#line %u ", lineno
);
94 output_string(file_name
, (s32
)strlen(file_name
));
98 /*{{{ output_constant_define */
99 static void output_constant_define(u8
*name
, s32 value
)
104 prefix
= options
->constants_prefix
;
105 combined_name
= calloc(strlen(prefix
) + strlen(name
) + 1, sizeof(u8
));
106 strcpy(combined_name
, prefix
);
107 strcpy(combined_name
+ strlen(prefix
), name
);
108 printf("#define %s %d\n", combined_name
, value
);
111 /*{{{ output_constant_enum */
112 static void output_constant_enum(u8
*name
, s32 value
, u8
*indentation
, bool *pending_comma
)
117 prefix
= options
->constants_prefix
;
118 combined_name
= calloc(strlen(prefix
) + strlen(name
) + 1, sizeof(u8
));
119 strcpy(combined_name
, prefix
);
120 strcpy(combined_name
+ strlen(prefix
), name
);
123 printf("%s %s = %d", indentation
, combined_name
, value
);
124 *pending_comma
= true;
127 /*{{{ ouput_upperlower_table */
128 #if USE_DOWNCASE_TABLE
129 static void output_upperlower_table(void)
134 "#ifndef GPERF_DOWNCASE\n"
135 "#define GPERF_DOWNCASE 1\n"
136 "static %sunsigned char gperf_downcase[256] =\n"
138 const_readonly_array
);
145 printf(" %3d", c
>= 'A' && c
<= 'Z' ? c
+ 'a' - 'A' : c
);
156 /*{{{ output_upperlower_memcmp */
157 /* output gperf's ASCII-case insensitive memcmp replacement */
158 static void output_upperlower_memcmp(void)
161 "#ifndef GPERF_CASE_MEMCMP\n"
162 "#define GPERF_CASE_MEMCMP 1\n"
164 "gperf_case_memcmp ");
165 printf(OPTS(KRC
) ? "(s1, s2, n)\n"
169 OPTS(C
) ? "(s1, s2, n)\n"
170 " %sconst char *s1;\n"
171 " %sconst char *s2;\n"
173 OPTS(ANSIC
) || OPTS(CPLUSPLUS
) ? "(%sconst char *s1, %sconst char *s2, %ssize_t n)\n" :
174 "", register_scs
, register_scs
, register_scs
);
175 #if USE_DOWNCASE_TABLE
180 " unsiGNED char c1 = gperf_downcase[(unsigned char)*s1++];\n"
181 " unsigned char c2 = gperf_downcase[(unsigned char)*s2++];\n"
187 " return (int)c1 - (int)c2;\n"
196 " unsigned char c1 = *s1++;\n"
197 " unsigned char c2 = *s2++;\n"
198 " if (c1 >= 'A' && c1 <= 'Z')\n"
199 " c1 += 'a' - 'A';\n"
200 " if (c2 >= 'A' && c2 <= 'Z')\n"
201 " c2 += 'a' - 'A';\n"
207 " return (int)c1 - (int)c2;\n"
215 /*{{{ output_upperlower_strncmp */
216 /* output gperf's ASCII-case insensitive strncmp replacement */
217 static void output_upperlower_strncmp(void)
220 "#ifndef GPERF_CASE_STRNCMP\n"
221 "#define GPERF_CASE_STRNCMP 1\n"
223 "gperf_case_strncmp ");
224 printf(OPTS(KRC
) ? "(s1, s2, n)\n"
228 OPTS(C
) ? "(s1, s2, n)\n"
229 " %sconst char *s1;\n"
230 " %sconst char *s2;\n"
232 OPTS(ANSIC
) || OPTS(CPLUSPLUS
) ? "(%sconst char *s1, %sconst char *s2, %ssize_t n)\n" :
233 "", register_scs
, register_scs
, register_scs
);
234 #if USE_DOWNCASE_TABLE
239 " unsigned char c1 = gperf_downcase[(unsigned char)*s1++];\n"
240 " unsigned char c2 = gperf_downcase[(unsigned char)*s2++];\n"
241 " if (c1 != 0 && c1 == c2)\n"
246 " return (int)c1 - (int)c2;\n"
255 " unsigned char c1 = *s1++;\n"
256 " unsigned char c2 = *s2++;\n"
257 " if (c1 >= 'A' && c1 <= 'Z')\n"
258 " c1 += 'a' - 'A';\n"
259 " if (c2 >= 'A' && c2 <= 'Z')\n"
260 " c2 += 'a' - 'A';\n"
261 " if (c1 != 0 && c1 == c2)\n"
266 " return (int)c1 - (int)c2;\n"
274 /*{{{ output_upperlower_strcmp */
275 /* output gperf's ASCII-case insensitive strcmp replacement */
276 static void output_upperlower_strcmp(void)
279 "#ifndef GPERF_CASE_STRCMP\n"
280 "#define GPERF_CASE_STRCMP 1\n"
282 "gperf_case_strcmp ");
283 printf(OPTS(KRC
) ? "(s1, s2)\n"
286 OPTS(C
) ? "(s1, s2)\n"
287 " %sconst char *s1;\n"
288 " %sconst char *s2;\n" :
289 OPTS(ANSIC
) || OPTS(CPLUSPLUS
) ? "(%sconst char *s1, %sconst char *s2)\n" :
290 "", register_scs
, register_scs
);
291 #if USE_DOWNCASE_TABLE
296 " unsigned char c1 = gperf_downcase[(unsigned char)*s1++];\n"
297 " unsigned char c2 = gperf_downcase[(unsigned char)*s2++];\n"
298 " if (c1 != 0 && c1 == c2)\n"
300 " return (int)c1 - (int)c2;\n"
308 " unsigned char c1 = *s1++;\n"
309 " unsigned char c2 = *s2++;\n"
310 " if (c1 >= 'A' && c1 <= 'Z')\n"
311 " c1 += 'a' - 'A';\n"
312 " if (c2 >= 'A' && c2 <= 'Z')\n"
313 " c2 += 'a' - 'A';\n"
314 " if (c1 != 0 && c1 == c2)\n"
316 " return (int)c1 - (int)c2;\n"
323 /*{{{ smallest_integral_type */
324 /* returns the smallest unsigned C type capable of holding integers up to N */
325 static u8
*smallest_integral_type(s32 n
)
327 if (n
<= UCHAR_MAX
) return "unsigned char";
328 if (n
<= USHRT_MAX
) return "unsigned short";
329 return "unsigned int";
331 /*{{{ smallest_integral_type_2 */
332 /* returns the smallest signed C type capable of holding integers from MIN to MAX */
333 static u8
*smallest_integral_type_2(s32 min
, s32 max
)
335 if (OPTS(ANSIC
) || OPTS(CPLUSPLUS
))
336 if (min
>= SCHAR_MIN
&& max
<= SCHAR_MAX
) return "signed char";
337 if (min
>= SHRT_MIN
&& max
<= SHRT_MAX
) return "short";
340 /*{{{ output_const_type */
342 * Outputs a type and a const specifier (i.e. "const " or "").
343 * The output is terminated with a space.
345 static void output_const_type(u8
*const_string
, u8
*type_string
)
347 if (type_string
[strlen(type_string
) - 1] == '*')
348 /* for pointer types, put the 'const' after the type */
350 "%s %s", type_string
, const_string
);
352 /* for scalar or struct types, put the 'const' before the type */
354 "%s%s ", const_string
, type_string
);
356 /*{{{ output_keyword_blank_entries */
357 static void output_keyword_blank_entries(s32 count
, u8
*indent
)
364 columns
= 58 / (4 + (OPTS(SHAREDLIB
) ? 2 : OPTS(NULLSTRINGS
) ? 8 : 2)
365 + strlen(options
->initializer_suffix
));
369 columns
= (OPTS(SHAREDLIB
) ? 9 : OPTS(NULLSTRINGS
) ? 4 : 9);
375 if ((column
% columns
) == 0) {
388 if (OPTS(NULLSTRINGS
))
395 "%s}", options
->initializer_suffix
);
400 /*{{{ output_keyword_entry */
401 static void output_keyword_entry(struct Keyword
*tmp
, s32 stringpool_index
, u8
*indent
,
405 output_line_directive(tmp
->lineno
);
412 * How to determine a certain offset in stringpool at compile time?
413 * - The standard way would be to use the 'offsetof' macro. But it is only
414 * defined in <stddef.h>, and <stddef.h> is not among the prerequisite
415 * header files that the user must #include.
416 * - The next best way would be to take the address and cast to 'intptr_t'
417 * or 'uintptr_t'. But these types are only defined in <stdint.h>, and
418 * <stdint.h> is not among the prerequisite header files that the user
420 * - The next best approximation of 'uintptr_t' is 'size_t'. It is defined
421 * in the prerequisite header <string.h>.
422 * - The types 'long' and 'unsigned long' do work as well, but on 64-bit
423 * native Windows platforms, they don't have the same size as pointers
424 * and therefore generate warnings.
426 printf("(int)(size_t)&((struct %s_t *)0)->%s_str%d",
427 options
->stringpool_name
, options
->stringpool_name
, stringpool_index
);
429 output_string(tmp
->allchars
, tmp
->allchars_length
);
431 if (strlen(tmp
->rest
) > 0)
432 printf(",%s", tmp
->rest
);
438 printf("hash value duplicate, ");
440 printf("hash value = %d, ", tmp
->hash_value
);
441 printf("index = %d */", tmp
->final_index
);
445 /*{{{ output_switch_case */
446 /* Output a single switch case (including duplicates). Advance list. */
447 static struct Keyword_List
*output_switch_case(struct Keyword_List
*list
, s32 indent
,
452 "%*s/* hash value = %4d, keyword = \"%.*s\" */\n", indent
, "", list
->kw
->hash_value
,
453 list
->kw
->allchars_length
, list
->kw
->allchars
);
454 if (OPTS(DUP
) && list
->kw
->duplicate_link
) {
456 struct Keyword
*links
;
460 "%*slengthptr = &%s[%d];\n", indent
, "", options
->lengthtable_name
, list
->kw
->final_index
);
462 "%*swordptr = &%s[%d];\n", indent
, "", options
->wordlist_name
, list
->kw
->final_index
);
469 links
= links
->duplicate_link
;
472 "%*swordendptr = wordptr + %d;\n"
473 "%*sgoto multicompare;\n", indent
, "", count
, indent
, "");
476 if (OPTS(LENTABLE
)) {
478 "%*sif (len == %d)\n"
479 "%*s {\n", indent
, "", list
->kw
->allchars_length
, indent
, "");
482 printf("%*sresword = ", indent
, "");
484 printf("&%s[%d]", options
->wordlist_name
, list
->kw
->final_index
);
486 output_string(list
->kw
->allchars
, list
->kw
->allchars_length
);
489 "%*sgoto compare;\n", indent
, "");
490 if (OPTS(LENTABLE
)) {
493 "%*s }\n", indent
, "");
499 /*{{{ output_switches */
501 * output a total of size cases, grouped into num_switches switch statements, where 0 <
502 * num_switches <= size
504 static void output_switches(struct Keyword_List
*list
, s32 num_switches
, s32 size
,
505 s32 min_hash_value
, s32 max_hash_value
, s32 indent
)
509 "%*s/* know %d <= key <= %d, contains %d cases */\n", indent
, "", min_hash_value
, max_hash_value
,
511 if (num_switches
> 1) {
516 struct Keyword_List
*tmp
;
519 part1
= num_switches
/ 2;
520 part2
= num_switches
- part1
;
521 size1
= (s32
)((f64
)(size
) / (f64
)(num_switches
) * (f64
)(part1
) + 0.5);
522 size2
= size
- size1
;
534 "%*s {\n", indent
, "", tmp
->kw
->hash_value
, indent
, "");
535 output_switches(list
, part1
, size1
, min_hash_value
, tmp
->kw
->hash_value
- 1,
540 "%*s {\n", indent
, "", indent
, "", indent
, "");
541 output_switches(tmp
, part2
, size2
, tmp
->kw
->hash_value
, max_hash_value
, indent
+ 4);
543 "%*s }\n", indent
, "");
545 s32 lowest_case_value
;
547 lowest_case_value
= list
->kw
->hash_value
;
552 if (min_hash_value
== max_hash_value
)
553 output_switch_case(list
, indent
, &jumps_away
);
556 "%*sif (key == %d)\n"
557 "%*s {\n", indent
, "", lowest_case_value
, indent
, "");
558 output_switch_case(list
, indent
+ 4, &jumps_away
);
560 "%*s }\n", indent
, "");
563 if (lowest_case_value
== 0)
565 "%*sswitch (key)\n", indent
, "");
568 "%*sswitch (key - %d)\n", indent
, "", lowest_case_value
);
570 "%*s {\n", indent
, "");
578 "%*s case %d:\n", indent
, "", list
->kw
->hash_value
- lowest_case_value
);
579 list
= output_switch_case(list
, indent
+ 6, &jumps_away
);
582 "%*s break;\n", indent
, "");
586 "%*s }\n", indent
, "");
590 /*{{{ output_firstchar_comparison */
592 * Outputs the comparison expression for the first byte. Returns true if the this comparison is
595 static bool output_firstchar_comparison(u8
*expr1
, u8
*expr2
)
598 * First, we emit a comparison of the first byte of the two strings. This catches most
599 * cases where the string being looked up is not in the hash table but happens to have the
600 * same hash code as an element of the hash table.
602 if (OPTS(UPPERLOWER
)) {
603 /* incomplete comparison, just for speedup */
604 printf("(((unsigned char)*");
606 printf(" ^ (unsigned char)*");
608 printf(") & ~32) == 0");
611 /* Complete comparison. */
618 /*------------------------------------------------------------------------------------------------*/
619 /*{{{ output_comparison_X */
621 * Outputs the comparison expression.
622 * expr1 outputs a simple expression of type 'const char *' referring to the string being looked up.
623 * expr2 outputs a simple expression of type 'const char *' referring to the constant string stored
624 * in the gperf generated hash table.
626 /*{{{ output_comparison_memcmp */
627 static void output_comparison_memcmp(u8
*expr1
, u8
*expr2
)
631 firstchar_done
= output_firstchar_comparison(expr1
, expr2
);
633 if (OPTS(UPPERLOWER
))
634 printf("gperf_case_");
636 if (firstchar_done
) {
640 printf(" + 1, len - 1");
649 /*{{{ output_comparison_strncmp */
650 static void output_comparison_strncmp(u8
*expr1
, u8
*expr2
)
654 firstchar_done
= output_firstchar_comparison(expr1
, expr2
);
656 if (OPTS(UPPERLOWER
))
657 printf("gperf_case_");
659 if (firstchar_done
) {
663 printf(" + 1, len - 1");
672 printf("[len] == '\\0'");
674 /*{{{ output_comparison_strcmp */
675 static void output_comparison_strcmp(u8
*expr1
, u8
*expr2
)
679 firstchar_done
= output_firstchar_comparison(expr1
, expr2
);
681 if (OPTS(UPPERLOWER
))
682 printf("gperf_case_");
684 if (firstchar_done
) {
696 /*}}} output_comparison_X -- END */
697 /*------------------------------------------------------------------------------------------------*/
699 /*}}} local -- END */
700 /*------------------------------------------------------------------------------------------------*/
703 Note about the keyword list starting at head:
704 - The list is ordered by increasing _hash_value. This has been achieved
706 - Duplicates, i.e. keywords with the same _selchars set, are chained
707 through the _duplicate_link pointer. Only one representative per
708 duplicate equivalence class remains on the linear keyword list.
709 - Accidental duplicates, i.e. keywords for which the _asso_values[] search
710 couldn't achieve different hash values, cannot occur on the linear
711 keyword list. Search::optimize would catch this mistake.
713 static struct Output
*output_new(struct Keyword_List
*head
, u8
*struct_decl
,
714 u32 struct_decl_lineno
, u8
*return_type
,
715 u8
*struct_tag
, u8
*verbatim_declarations
,
716 u8
*verbatim_declarations_end
,
717 u32 verbatim_declarations_lineno
,
718 u8
*verbatim_code
, u8
*verbatim_code_end
,
719 u32 verbatim_code_lineno
, bool charset_dependent
,
720 s32 total_keys
, s32 max_key_len
, s32 min_key_len
,
721 bool hash_includes_len
, struct Positions
*positions
,
722 u32
*alpha_inc
, s32 total_duplicates
,
723 u32 alpha_size
, s32
*asso_values
)
727 t
= calloc(1, sizeof(*t
));
729 t
->struct_decl
= struct_decl
;
730 t
->struct_decl_lineno
= struct_decl_lineno
;
731 t
->return_type
= return_type
;
732 t
->struct_tag
= struct_tag
;
733 t
->verbatim_declarations
= verbatim_declarations
;
734 t
->verbatim_declarations_end
= verbatim_declarations_end
;
735 t
->verbatim_declarations_lineno
= verbatim_declarations_lineno
;
736 t
->verbatim_code
= verbatim_code
;
737 t
->verbatim_code_end
= verbatim_code_end
;
738 t
->verbatim_code_lineno
= verbatim_code_lineno
;
739 t
->charset_dependent
= charset_dependent
;
740 t
->total_keys
= total_keys
;
741 t
->max_key_len
= max_key_len
;
742 t
->min_key_len
= min_key_len
;
743 t
->hash_includes_len
= hash_includes_len
;
744 t
->key_positions
= pos_new_cpy(positions
);
745 t
->alpha_inc
= alpha_inc
;
746 t
->total_duplicates
= total_duplicates
;
747 t
->alpha_size
= alpha_size
;
748 t
->asso_values
= asso_values
;
752 static void output_del(struct Output
*t
)
754 pos_del(t
->key_positions
);
759 /* generates the hash function and the key word recognizer function based upon the user's Options */
760 static void output_do(struct Output
*t
)
762 output_compute_min_max(t
);
763 if (OPTS(CPLUSPLUS
)) /* yeah, we know nowadays that c++ is never a good idea anyway */
765 * The 'register' keyword is removed from C++17. See
766 * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4340
770 register_scs
= "register ";
771 if (OPTS(C
) || OPTS(ANSIC
) || OPTS(CPLUSPLUS
)) {
772 const_always
= "const ";
773 const_readonly_array
= (OPTS(CONST
) ? "const " : "");
774 const_for_struct
= ((OPTS(CONST
) && OPTS(TYPE
)) ? "const " : "" );
777 const_readonly_array
= "";
778 const_for_struct
= "";
781 t
->return_type
= (const_always
[0] != 0 ? "const char *" : "char *");
782 t
->struct_tag
= (const_always
[0] != 0 ? "const char *" : "char *");
784 t
->wordlist_eltype
= (OPTS(SHAREDLIB
) && !OPTS(TYPE
) ? (u8
*)"int" : t
->struct_tag
);
790 else if (OPTS(ANSIC
))
792 else if (OPTS(CPLUSPLUS
))
794 printf(" code produced by gperf version %s */\n", cgperf_version_string
);
797 if (!OPTS(POSITIONS
)) {
798 printf ("/* Computed positions: -k'");
799 pos_print(t
->key_positions
);
803 if (t
->charset_dependent
&& (t
->key_positions
->size
> 0 || OPTS(UPPERLOWER
))) {
804 printf("#if !((' ' == 32) && ('!' == 33) && ('\"' == 34) && ('#' == 35) \\\n"
805 " && ('%%' == 37) && ('&' == 38) && ('\\'' == 39) && ('(' == 40) \\\n"
806 " && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \\\n"
807 " && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \\\n"
808 " && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \\\n"
809 " && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \\\n"
810 " && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \\\n"
811 " && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \\\n"
812 " && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \\\n"
813 " && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \\\n"
814 " && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \\\n"
815 " && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \\\n"
816 " && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \\\n"
817 " && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \\\n"
818 " && ('Z' == 90) && ('[' == 91) && ('\\\\' == 92) && (']' == 93) \\\n"
819 " && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \\\n"
820 " && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \\\n"
821 " && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \\\n"
822 " && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \\\n"
823 " && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \\\n"
824 " && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \\\n"
825 " && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \\\n"
826 " && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))\n"
827 "/* The character set is not based on ISO-646. */\n");
828 printf("%s \"gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>.\"\n", OPTS(KRC
) || OPTS(C
) ? "error" : "#error");
829 printf ("#endif\n\n");
831 if (t
->verbatim_declarations
< t
->verbatim_declarations_end
) {
832 output_line_directive(t
->verbatim_declarations_lineno
);
833 fwrite(t
->verbatim_declarations
, 1, t
->verbatim_declarations_end
-
834 t
->verbatim_declarations
, stdout
);
836 if (OPTS(TYPE
) && !OPTS(NOTYPE
)) {
837 /* output type declaration now, reference it later on.... */
838 output_line_directive(t
->struct_decl_lineno
);
839 printf("%s\n", t
->struct_decl
);
842 printf("#include <string.h>\n"); /* declare strlen(), strcmp(), strncmp() */
843 if (!OPTS(ENUM
)) /* refactored: overzealous code factorization */
844 output_constants_defines(t
);
845 else if (OPTS(GLOBAL
))
846 output_constants_enum(t
, "");
847 printf("/* maximum key range = %d, duplicates = %d */\n\n", t
->max_hash_value
- t
->min_hash_value
+ 1, t
->total_duplicates
);
848 if (OPTS(UPPERLOWER
)) {
849 #if USE_DOWNCASE_TABLE
850 output_upperlower_table();
853 output_upperlower_memcmp();
856 output_upperlower_strncmp();
858 output_upperlower_strcmp();
866 " static inline unsigned int %s (const char *str, size_t len);\n"
868 " static %s%s%s (const char *str, size_t len);\n"
870 "\n", options
->class_name
, options
->hash_name
, const_for_struct
, t
->return_type
,
871 options
->function_name
);
872 output_hash_function(t
);
873 if (OPTS(SHAREDLIB
) && (OPTS(GLOBAL
) || OPTS(TYPE
)))
874 output_lookup_pools(t
);
876 output_lookup_tables(t
);
877 output_lookup_function(t
);
878 if (t
->verbatim_code
< t
->verbatim_code_end
) {
879 output_line_directive(t
->verbatim_code_lineno
);
880 fwrite(t
->verbatim_code
, 1, t
->verbatim_code_end
- t
->verbatim_code
, stdout
);
884 /*{{{ output_compute_min_max */
885 static void output_compute_min_max(struct Output
*t
)
887 struct Keyword_List
*tmp
;
889 * since the list is already sorted by hash value all we need to do is to look at the first
890 * and the last element of the list
892 t
->min_hash_value
= t
->head
->kw
->hash_value
;
899 t
->max_hash_value
= tmp
->kw
->hash_value
;
901 /*{{{ output_constants_defines */
902 static void output_constants_defines(struct Output
*t
)
905 output_constant_define("TOTAL_KEYWORDS", t
->total_keys
);
906 output_constant_define("MIN_WORD_LENGTH", t
->min_key_len
);
907 output_constant_define("MAX_WORD_LENGTH", t
->max_key_len
);
908 output_constant_define("MIN_HASH_VALUE", t
->min_hash_value
);
909 output_constant_define("MAX_HASH_VALUE", t
->max_hash_value
);
911 /*{{{ output_constants_enum */
912 static void output_constants_enum(struct Output
*t
, u8
*indentation
)
917 "%s {\n", indentation
, indentation
);
918 pending_comma
= false;
919 output_constant_enum("TOTAL_KEYWORDS", t
->total_keys
, indentation
, &pending_comma
);
920 output_constant_enum("MIN_WORD_LENGTH", t
->min_key_len
, indentation
, &pending_comma
);
921 output_constant_enum("MAX_WORD_LENGTH", t
->max_key_len
, indentation
, &pending_comma
);
922 output_constant_enum("MIN_HASH_VALUE", t
->min_hash_value
, indentation
, &pending_comma
);
923 output_constant_enum("MAX_HASH_VALUE", t
->max_hash_value
, indentation
, &pending_comma
);
926 printf("%s };\n\n", indentation
);
928 /*{{{ output_hash_function */
929 /* Generates C code for the hash function that returns the
930 proper encoding for each keyword.
931 The hash function has the signature
932 unsigned int <hash> (const char *str, size_t len). */
933 static void output_hash_function(struct Output
*t
)
935 /* output the function's head */
938 else if (OPTS(KRC
) || OPTS(C
) || OPTS(ANSIC
))
943 "#ifdef __cplusplus\n"
947 if (/* the function does not use the 'str' argument? */
948 (t
->key_positions
->size
== 0)
949 || /* the function uses 'str', but not the 'len' argument? */
950 (!t
->hash_includes_len
951 && t
->key_positions
->positions
[0] < t
->min_key_len
)
952 && t
->key_positions
->positions
[t
->key_positions
->size
- 1] != POS_LASTCHAR
)
954 printf("/*ARGSUSED*/\n");
955 if (OPTS(KRC
) || OPTS(C
) || OPTS(ANSIC
))
957 printf("unsigned int\n");
959 printf("%s::", options
->class_name
);
960 printf("%s ", options
->hash_name
);
967 " %sconst char *str;\n"
969 OPTS(ANSIC
) || OPTS(CPLUSPLUS
) ?
970 "(%sconst char *str, %ssize_t len)\n" :
971 "", register_scs
, register_scs
);
974 * note that when the hash function is called, it has already been verified that
975 * min_key_len <= len <= max_key_len
977 /* output the function's body */
980 /* first the asso_values array */
981 if (t
->key_positions
->size
> 0) {
987 * the values in the asso_values array are all unsigned integers <= MAX_HASH_VALUE +
991 " static %s%s asso_values[] =\n"
992 " {", const_readonly_array
, smallest_integral_type(t
->max_hash_value
+ 1));
994 /* calculate maximum number of digits required for MAX_HASH_VALUE + 1 */
996 trunc
= t
->max_hash_value
+ 1;
1005 if (count
>= t
->alpha_size
)
1009 if ((count
% columns
) == 0)
1011 printf("%*d", field_width
, t
->asso_values
[count
]);
1018 if (t
->key_positions
->size
== 0) {
1019 /* trivial case: No key positions at all */
1021 " return %s;\n", t
->hash_includes_len
? "len" : "0");
1023 struct PositionIterator
*iter
;
1026 * Iterate through the key positions. Remember that Positions::sort() has sorted
1027 * them in decreasing order, with Positions::LASTCHAR coming last.
1029 iter
= pos_iterator(t
->key_positions
, t
->max_key_len
);
1030 /* get the highest key position */
1031 key_pos
= positer_next(iter
);
1032 if (key_pos
== POS_LASTCHAR
|| key_pos
< t
->min_key_len
) {
1034 * We can perform additional optimizations here: Write it out as a single
1035 * expression. Note that the values are added as 'int's even though the
1036 * asso_values array may contain 'unsigned char's or 'unsigned short's.
1039 " return %s", t
->hash_includes_len
? "len + " : "");
1040 if (t
->key_positions
->size
== 2
1041 && t
->key_positions
->positions
[0] == 0
1042 && t
->key_positions
->positions
[1] == POS_LASTCHAR
) {
1043 /* optimize special case of "-k 1,$" */
1044 output_asso_values_ref(t
, POS_LASTCHAR
);
1046 output_asso_values_ref(t
, 0);
1049 if (key_pos
== POS_LASTCHAR
)
1051 output_asso_values_ref(t
, key_pos
);
1052 key_pos
= positer_next(iter
);
1053 if (key_pos
!= POSITER_EOS
)
1058 if (key_pos
== POS_LASTCHAR
)
1059 output_asso_values_ref(t
, POS_LASTCHAR
);
1063 u8
*fallthrough_marker
;
1064 /* we've got to use the correct, but brute force, technique */
1066 * pseudo-statement or comment that avoids a compiler warning or lint
1069 fallthrough_marker
=
1070 "#if defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang_major__ && defined __clang_minor__ && __clang_major__ + (__clang_minor__ >= 9) > 3))\n"
1071 " [[fallthrough]];\n"
1072 "#elif defined __GNUC__ && __GNUC__ >= 7\n"
1073 " __attribute__ ((__fallthrough__));\n"
1075 " /*FALLTHROUGH*/\n";
1077 * it doesn't really matter whether hval is an 'int' or 'unsigned int', but
1078 * 'unsigned int' gives fewer warnings
1081 " %sunsigned int hval = %s;\n\n"
1084 " default:\n", register_scs
, t
->hash_includes_len
? "len" : "0",
1085 t
->hash_includes_len
? "hval" : "len");
1087 if (key_pos
== POS_LASTCHAR
|| key_pos
< t
->max_key_len
)
1089 key_pos
= positer_next(iter
);
1090 if (key_pos
== POSITER_EOS
)
1093 if (key_pos
!= POSITER_EOS
&& key_pos
!= POS_LASTCHAR
) {
1099 printf("%s", fallthrough_marker
);
1103 printf(" case %d:\n", i
);
1106 printf(" hval += ");
1107 output_asso_values_ref(t
, key_pos
);
1109 key_pos
= positer_next(iter
);
1110 if (key_pos
== POSITER_EOS
|| key_pos
== POS_LASTCHAR
)
1113 if (i
>= t
->min_key_len
)
1114 printf("%s", fallthrough_marker
);
1116 if (i
< t
->min_key_len
)
1118 printf(" case %d:\n", i
);
1126 if (key_pos
== POS_LASTCHAR
) {
1128 output_asso_values_ref(t
, POS_LASTCHAR
);
1136 /*{{{ output_asso_values_ref */
1137 /* Generates a C expression for an asso_values[] reference. */
1138 static void output_asso_values_ref(struct Output
*t
, s32 pos
)
1140 printf("asso_values[");
1142 * Always cast to unsigned char. This is necessary when the alpha_inc is nonzero, and also
1143 * avoids a gcc warning "subscript has type 'char'".
1145 if (OPTS(CPLUSPLUS
)) {
1147 * In C++, a C style cast may lead to a 'warning: use of old-style cast'.
1148 * Therefore prefer the C++ style cast syntax.
1150 printf("static_cast<unsigned char>(");
1151 output_asso_values_index(t
, pos
);
1154 printf("(unsigned char)");
1155 output_asso_values_index(t
, pos
);
1159 /*{{{ output_asso_values_index */
1160 /* generates a C expression for an asso_values[] index */
1161 static void output_asso_values_index(struct Output
*t
, s32 pos
)
1163 if (pos
== POS_LASTCHAR
)
1164 printf("str[len - 1]");
1166 printf("str[%d]", pos
);
1167 if (t
->alpha_inc
[pos
])
1168 printf("+%u", t
->alpha_inc
[pos
]);
1171 /*{{{ output_lookup_pools */
1172 /* generate all pools needed for the lookup function */
1173 static void output_lookup_pools(struct Output
*t
)
1176 if (OPTS(TYPE
) || (OPTS(DUP
) && t
->total_duplicates
> 0))
1177 output_string_pool(t
);
1179 output_string_pool(t
);
1181 /*{{{ output_string_pool */
1183 * Prints out the string pool, containing the strings of the keyword table.
1184 * Only called if option[SHAREDLIB]
1186 static void output_string_pool(struct Output
*t
)
1190 struct Keyword_List
*tmp
;
1192 indent
= OPTS(TYPE
) || OPTS(GLOBAL
) ? "" : " ";
1196 "%s {\n", indent
, options
->stringpool_name
, indent
);
1206 * If generating a switch statement, and there is no user defined type, we generate
1207 * non-duplicates directly in the code. Only duplicates go into the table.
1209 if (OPTS(SWITCH
) && !OPTS(TYPE
) && kw
->duplicate_link
== 0)
1211 if (!OPTS(SWITCH
) && !OPTS(DUP
))
1212 index
= kw
->hash_value
;
1213 printf("%s char %s_str%d[sizeof(", indent
, options
->stringpool_name
, index
);
1214 output_string(kw
->allchars
, kw
->allchars_length
);
1216 /* deal with duplicates specially */
1217 if (kw
->duplicate_link
) {/* implies option[DUP] */
1218 struct Keyword
*links
;
1220 links
= kw
->duplicate_link
;
1224 if (!(links
->allchars_length
== kw
->allchars_length
1225 && memcmp(links
->allchars
, kw
->allchars
,
1226 kw
->allchars_length
) == 0)) {
1228 printf("%s char %s_str%d[sizeof(", indent
,
1229 options
->stringpool_name
, index
);
1230 output_string(links
->allchars
, links
->allchars_length
);
1233 links
= links
->duplicate_link
;
1242 "%sstatic %sstruct %s_t %s_contents =\n"
1243 "%s {\n", indent
, const_readonly_array
, options
->stringpool_name
, options
->stringpool_name
,
1254 * If generating a switch statement, and there is no user defined type, we generate
1255 * non-duplicates directly in the code. Only duplicates go into the table.
1257 if (OPTS(SWITCH
) && !OPTS(TYPE
) && kw
->duplicate_link
== 0)
1262 if (!OPTS(SWITCH
) && !OPTS(DUP
))
1263 index
= kw
->hash_value
;
1266 output_string(kw
->allchars
, kw
->allchars_length
);
1267 /* deal with duplicates specially */
1268 if (kw
->duplicate_link
!= 0) {/* implies option[DUP] */
1269 struct Keyword
*links
;
1271 links
= kw
->duplicate_link
;
1275 if (!(links
->allchars_length
== kw
->allchars_length
1276 && memcmp(links
->allchars
, kw
->allchars
,
1277 kw
->allchars_length
) == 0)) {
1282 output_string(links
->allchars
, links
->allchars_length
);
1284 links
= links
->duplicate_link
;
1295 "%s#define %s ((%schar *) &%s_contents)\n", indent
, options
->stringpool_name
, const_always
,
1296 options
->stringpool_name
);
1301 /*{{{ output_lookup_tables */
1302 /* generate all the tables needed for the lookup function */
1303 static void output_lookup_tables(struct Output
*t
)
1306 /* use the switch in place of lookup table */
1307 if (OPTS(LENTABLE
) && (OPTS(DUP
) && t
->total_duplicates
> 0))
1308 output_keylength_table(t
);
1309 if (OPTS(TYPE
) || (OPTS(DUP
) && t
->total_duplicates
> 0))
1310 output_keyword_table(t
);
1312 /* use the lookup table, in place of switch */
1314 output_keylength_table(t
);
1315 output_keyword_table(t
);
1316 output_lookup_array(t
);
1319 /*{{{ output_keylength_table */
1321 * Prints out a table of keyword lengths, for use with the comparison code in generated function
1322 * 'in_word_set'. Only called if option[LENTABLE].
1324 static void output_keylength_table(struct Output
*t
)
1330 struct Keyword_List
*tmp
;
1333 indent
= OPTS(GLOBAL
) ? "" : " ";
1336 "%sstatic %s%s %s[] =\n"
1337 "%s {", indent
, const_readonly_array
, smallest_integral_type(t
->max_key_len
),
1338 options
->lengthtable_name
, indent
);
1349 * If generating a switch statement, and there is no user defined type, we generate
1350 * non-duplicates directly in the code. Only duplicates go into the table.
1352 if (OPTS(SWITCH
) && !OPTS(TYPE
) && kw
->duplicate_link
== 0)
1354 if (index
< kw
->hash_value
&& !OPTS(SWITCH
) && !OPTS(DUP
)) {
1355 /* some blank entries */
1357 if (index
>= kw
->hash_value
)
1361 if ((column
% columns
) == 0)
1371 if ((column
% columns
) == 0)
1375 printf("%3d", kw
->allchars_length
);
1377 /* deal with duplicates specially */
1378 if (kw
->duplicate_link
!= 0) {
1379 struct Keyword
*links
;
1381 links
= kw
->duplicate_link
;
1386 if ((column
% columns
) == 0)
1390 printf("%3d", links
->allchars_length
);
1392 links
= links
->duplicate_link
;
1398 "\n%s };\n", indent
);
1403 /*{{{ output_keyword_table */
1404 /* prints out the array containing the keywords for the hash function */
1405 static void output_keyword_table(struct Output
*t
)
1409 struct Keyword_List
*tmp
;
1411 indent
= OPTS(GLOBAL
) ? "" : " ";
1413 "%sstatic ", indent
);
1414 output_const_type(const_readonly_array
, t
->wordlist_eltype
);
1416 "%s {\n", options
->wordlist_name
, indent
);
1417 /* generate an array of reserved words at appropriate locations */
1427 * If generating a switch statement, and there is no user defined type, we generate
1428 * non-duplicates directly in the code. Only duplicates go into the table.
1430 if (OPTS(SWITCH
) && !OPTS(TYPE
) && kw
->duplicate_link
== 0)
1434 if (index
< kw
->hash_value
&& !OPTS(SWITCH
) && !OPTS(DUP
)) {
1435 /* some blank entries */
1436 output_keyword_blank_entries(kw
->hash_value
- index
, indent
);
1438 index
= kw
->hash_value
;
1440 kw
->final_index
= index
;
1441 output_keyword_entry(kw
, index
, indent
, false);
1442 /* deal with duplicates specially */
1443 if (kw
->duplicate_link
!= 0) { /* implies option[DUP] */
1444 struct Keyword
*links
;
1446 links
= kw
->duplicate_link
;
1448 s32 stringpool_index
;
1453 links
->final_index
= index
;
1456 (links
->allchars_length
== kw
->allchars_length
1457 && memcmp(links
->allchars
, kw
->allchars
,
1458 kw
->allchars_length
) == 0
1459 ? kw
->final_index
: links
->final_index
);
1460 output_keyword_entry(links
, stringpool_index
, indent
, true);
1461 links
= links
->duplicate_link
;
1470 "%s };\n\n", indent
);
1472 /*{{{ output_lookup_array */
1474 * generates the large, sparse table that maps hash values into the smaller, contiguous range of the
1477 static void output_lookup_array(struct Output
*t
)
1480 struct Duplicate_Entry
*duplicates
;
1482 s32 lookup_array_size
;
1483 struct Duplicate_Entry
*dup_ptr
;
1485 struct Keyword_List
*tmp
;
1498 duplicates
= calloc(t
->total_duplicates
, sizeof(*duplicates
));
1499 lookup_array
= calloc(t
->max_hash_value
+ 1 + 2 * t
->total_duplicates
,
1500 sizeof(*lookup_array
));
1501 lookup_array_size
= t
->max_hash_value
+ 1;
1502 dup_ptr
= &duplicates
[0];
1503 lookup_ptr
= &lookup_array
[t
->max_hash_value
+ 1 + 2 * t
->total_duplicates
];
1506 if (lookup_ptr
<= lookup_array
)
1508 *--lookup_ptr
= DEFAULT_VALUE
;
1510 /* now dup_ptr = &duplicates[0] and lookup_ptr = &lookup_array[0] */
1517 hash_value
= tmp
->kw
->hash_value
;
1518 lookup_array
[hash_value
] = tmp
->kw
->final_index
;
1520 fprintf(stderr
, "keyword = %.*s, index = %d\n", tmp
->kw
->allchars_length
, tmp
->kw
->allchars
, tmp
->kw
->final_index
);
1521 if (tmp
->kw
->duplicate_link
!= 0) {
1522 struct Keyword
*ptr
;
1524 /* start a duplicate entry */
1525 dup_ptr
->hash_value
= hash_value
;
1526 dup_ptr
->index
= tmp
->kw
->final_index
;
1529 ptr
= tmp
->kw
->duplicate_link
;
1535 fprintf(stderr
, "static linked keyword = %.*s, index = %d\n", ptr
->allchars_length
, ptr
->allchars
, ptr
->final_index
);
1536 ptr
= ptr
->duplicate_link
;
1545 if (dup_ptr
<= duplicates
)
1549 fprintf(stderr
, "dup_ptr[%lu]: hash_value = %d, index = %d, count = %d\n", (unsigned long)(dup_ptr
- duplicates
), dup_ptr
->hash_value
, dup_ptr
->index
, dup_ptr
->count
);
1551 * start searching for available space towards the right part of the lookup
1554 i
= dup_ptr
->hash_value
;
1556 if (i
>= lookup_array_size
- 1)
1558 if (lookup_array
[i
] == DEFAULT_VALUE
&& lookup_array
[i
+ 1]
1563 /* if we didn't find it to the right look to the left instead... */
1564 i
= dup_ptr
->hash_value
- 1;
1568 if (lookup_array
[i
] == DEFAULT_VALUE
&& lookup_array
[i
+ 1]
1573 /* append to the end of lookup_array */
1574 i
= lookup_array_size
;
1575 lookup_array_size
+= 2;
1578 * Put in an indirection from dup_ptr->_hash_value to i.
1579 * At i and i+1 store dup_ptr->_final_index and dup_ptr->count.
1581 lookup_array
[dup_ptr
->hash_value
] = - 1 - t
->total_keys
- i
;
1582 lookup_array
[i
] = - t
->total_keys
+ dup_ptr
->index
;
1583 lookup_array
[i
+ 1] = - dup_ptr
->count
;
1584 /* All these three values are <= -2, distinct from DEFAULT_VALUE */
1586 /* the values of the lookup array are now known */
1589 lookup_ptr
= lookup_array
+ lookup_array_size
;
1593 if (lookup_ptr
<= lookup_array
)
1595 val
= *--lookup_ptr
;
1601 indent
= OPTS(GLOBAL
) ? "" : " ";
1603 "%sstatic %s%s lookup[] =\n"
1604 "%s {", indent
, const_readonly_array
, smallest_integral_type_2(min
, max
), indent
);
1605 /* calculate maximum number of digits required for MIN..MAX */
1619 s32 neg_field_width
;
1622 neg_field_width
= 2;
1630 ++neg_field_width
; /* account for the minus sign */
1631 if (field_width
< neg_field_width
)
1632 field_width
= neg_field_width
;
1634 columns
= 42 / field_width
;
1638 if (i
>= lookup_array_size
)
1642 if ((column
% columns
) == 0)
1643 printf("\n%s ", indent
);
1645 printf("%*d", field_width
, lookup_array
[i
]);
1649 "\n%s };\n\n", indent
);
1653 /*{{{ output_lookup_function */
1654 /* generates C code for the lookup function */
1655 static void output_lookup_function(struct Output
*t
)
1657 /* output the function's head */
1659 * We don't declare the lookup function 'static' because we cannot make assumptions about
1660 * the compilation units of the user.
1661 * Since we don't make it 'static', it makes no sense to declare it 'inline', because
1662 * non-static inline functions must not reference static functions or variables, see ISO C
1663 * 99 section 6.7.4.(3).
1666 "%s%s\n", const_for_struct
, t
->return_type
);
1667 if (OPTS(CPLUSPLUS
))
1669 "%s::", options
->class_name
);
1670 printf("%s ", options
->function_name
);
1672 OPTS(KRC
) ? "(str, len)\n"
1674 " %ssize_t len;\n" :
1675 OPTS(C
) ? "(str, len)\n"
1676 " %sconst char *str;\n"
1677 " %ssize_t len;\n" :
1678 OPTS(ANSIC
) || OPTS(CPLUSPLUS
) ? "(%sconst char *str, %ssize_t len)\n" :
1679 "", register_scs
, register_scs
);
1681 /* output the function's body */
1684 if (OPTS(ENUM
) && !OPTS(GLOBAL
))
1685 output_constants_enum(t
, " ");
1686 if (OPTS(SHAREDLIB
) && !(OPTS(GLOBAL
) || OPTS(TYPE
)))
1687 output_lookup_pools(t
);
1689 output_lookup_tables(t
);
1691 output_lookup_function_body(t
, output_comparison_memcmp
);
1694 output_lookup_function_body(t
, output_comparison_strncmp
);
1696 output_lookup_function_body(t
, output_comparison_strcmp
);
1701 /*{{{ output_lookup_function_body */
1702 static void output_lookup_function_body(struct Output
*t
,
1703 void (*output_comparison
)(u8
*expr1
, u8
*expr2
))
1706 " if (len <= %sMAX_WORD_LENGTH && len >= %sMIN_WORD_LENGTH)\n"
1708 " %sunsigned int key = %s (str, len);\n\n", options
->constants_prefix
,
1709 options
->constants_prefix
, register_scs
, options
->hash_name
);
1714 switch_size
= output_num_hash_values(t
);
1715 num_switches
= options
->total_switches
;
1716 if (num_switches
> switch_size
)
1717 num_switches
= switch_size
;
1719 " if (key <= %sMAX_HASH_VALUE", options
->constants_prefix
);
1720 if (t
->min_hash_value
> 0)
1722 " && key >= %sMIN_HASH_VALUE", options
->constants_prefix
);
1726 if (OPTS(DUP
) && t
->total_duplicates
> 0) {
1729 " %s%s%s *lengthptr;\n", register_scs
, const_always
, smallest_integral_type(
1732 " %s", register_scs
);
1733 output_const_type(const_readonly_array
, t
->wordlist_eltype
);
1734 printf("*wordptr;\n");
1736 " %s", register_scs
);
1737 output_const_type(const_readonly_array
, t
->wordlist_eltype
);
1738 printf("*wordendptr;\n");
1742 " %s", register_scs
);
1743 output_const_type(const_readonly_array
, t
->struct_tag
);
1744 printf("*resword;\n\n");
1747 " %s%sresword;\n\n", register_scs
, t
->struct_tag
);
1748 output_switches(t
->head
, num_switches
, switch_size
, t
->min_hash_value
,
1749 t
->max_hash_value
, 10);
1752 if (OPTS(DUP
) && t
->total_duplicates
> 0) {
1757 "%*smulticompare:\n"
1758 "%*s while (wordptr < wordendptr)\n"
1759 "%*s {\n", indent
, "", indent
, "", indent
, "");
1760 if (OPTS(LENTABLE
)) {
1762 "%*s if (len == *lengthptr)\n"
1763 "%*s {\n", indent
, "", indent
, "");
1767 "%*s %s%schar *s = ", indent
, "", register_scs
, const_always
);
1769 printf("wordptr->%s", options
->slot_name
);
1772 if (OPTS(SHAREDLIB
))
1773 printf(" + %s", options
->stringpool_name
);
1775 "%*s if (", indent
, "");
1776 output_comparison("str", "s");
1778 "%*s return %s;\n", indent
, "", OPTS(TYPE
) ? "wordptr" : "s");
1779 if (OPTS(LENTABLE
)) {
1782 "%*s }\n", indent
, "");
1786 "%*s lengthptr++;\n", indent
, "");
1790 "%*s return 0;\n", indent
, "", indent
, "", indent
, "");
1797 " %s%schar *s = resword->%s", register_scs
, const_always
, options
->slot_name
);
1798 if (OPTS(SHAREDLIB
))
1799 printf(" + %s", options
->stringpool_name
);
1802 output_comparison("str", "s");
1805 " return resword;\n"
1808 output_comparison("str", "resword");
1811 " return resword;\n");
1817 " if (key <= %sMAX_HASH_VALUE)\n", options
->constants_prefix
);
1824 "%*s %sint index = lookup[key];\n\n"
1825 "%*s if (index >= 0)\n", indent
, "", indent
, "", register_scs
, indent
, "");
1826 if (OPTS(LENTABLE
)) {
1829 "%*s if (len == %s[index])\n", indent
, "", indent
, "", options
->lengthtable_name
);
1834 "%*s %s%schar *s = %s[index]", indent
, "", indent
, "", register_scs
, const_always
,
1835 options
->wordlist_name
);
1837 printf(".%s", options
->slot_name
);
1838 if (OPTS(SHAREDLIB
))
1839 printf (" + %s", options
->stringpool_name
);
1841 "%*s if (", indent
, "");
1842 output_comparison("str", "s");
1844 "%*s return ", indent
, "");
1846 printf("&%s[index]", options
->wordlist_name
);
1850 "%*s }\n", indent
, "");
1851 if (OPTS(LENTABLE
)) {
1854 "%*s }\n", indent
, "");
1856 if (t
->total_duplicates
> 0) {
1858 "%*s else if (index < -%sTOTAL_KEYWORDS)\n"
1860 "%*s %sint offset = - 1 - %sTOTAL_KEYWORDS - index;\n", indent
, "", options
->constants_prefix
,
1861 indent
, "", indent
, "", register_scs
,
1862 options
->constants_prefix
);
1865 "%*s %s%s%s *lengthptr = &%s[%sTOTAL_KEYWORDS + lookup[offset]];\n", indent
, "",
1866 register_scs
, const_always
,
1867 smallest_integral_type(t
->max_key_len
),
1868 options
->lengthtable_name
,
1869 options
->constants_prefix
);
1871 "%*s %s", indent
, "", register_scs
);
1872 output_const_type(const_readonly_array
, t
->wordlist_eltype
);
1873 printf("*wordptr = &%s[%sTOTAL_KEYWORDS + lookup[offset]];\n",
1874 options
->wordlist_name
, options
->constants_prefix
);
1876 "%*s %s", indent
, "", register_scs
);
1877 output_const_type(const_readonly_array
, t
->wordlist_eltype
);
1878 printf("*wordendptr = wordptr + -lookup[offset + 1];\n\n");
1880 "%*s while (wordptr < wordendptr)\n"
1881 "%*s {\n", indent
, "", indent
, "");
1882 if (OPTS(LENTABLE
)) {
1884 "%*s if (len == *lengthptr)\n"
1885 "%*s {\n", indent
, "", indent
, "");
1889 "%*s %s%schar *s = ", indent
, "", register_scs
, const_always
);
1891 printf("wordptr->%s", options
->slot_name
);
1894 if (OPTS(SHAREDLIB
))
1895 printf(" + %s", options
->stringpool_name
);
1897 "%*s if (", indent
, "");
1898 output_comparison("str", "s");
1900 "%*s return %s;\n", indent
, "", OPTS(TYPE
) ? "wordptr" : "s");
1901 if (OPTS(LENTABLE
)) {
1904 "%*s }\n", indent
, "");
1908 "%*s lengthptr++;\n", indent
, "");
1912 "%*s }\n", indent
, "", indent
, "", indent
, "");
1915 "%*s}\n", indent
, "");
1920 if (OPTS(LENTABLE
)) {
1922 "%*sif (len == %s[key])\n", indent
, "", options
->lengthtable_name
);
1925 if (OPTS(SHAREDLIB
)) {
1926 if (!OPTS(LENTABLE
)) {
1929 "%*s %sint o = %s[key]", indent
, "", indent
, "", register_scs
,
1930 options
->wordlist_name
);
1932 printf(".%s", options
->slot_name
);
1935 "%*s {\n", indent
, "", indent
, "");
1938 "%*s %s%schar *s = o", indent
, "", register_scs
, const_always
);
1941 * no need for the (o >= 0) test, because the
1942 * (len == lengthtable[key]) test already guarantees that
1943 * key points to nonempty table entry
1947 "%*s %s%schar *s = %s[key]", indent
, "", indent
, "", register_scs
, const_always
,
1948 options
->wordlist_name
);
1950 printf(".%s", options
->slot_name
);
1952 printf (" + %s", options
->stringpool_name
);
1956 "%*s %s%schar *s = %s[key]", indent
, "", indent
, "", register_scs
, const_always
,
1957 options
->wordlist_name
);
1959 printf(".%s", options
->slot_name
);
1962 "%*s if (", indent
, "");
1963 if (!OPTS(SHAREDLIB
) && OPTS(NULLSTRINGS
))
1965 output_comparison("str", "s");
1967 "%*s return ", indent
, "");
1969 printf("&%s[key]", options
->wordlist_name
);
1973 if (OPTS(SHAREDLIB
) && !OPTS(LENTABLE
)) {
1976 "%*s }\n", indent
, "");
1979 "%*s}\n", indent
, "");
1986 /*{{{ output_num_hash_values */
1987 /* Returns the number of different hash values. */
1988 static s32
output_num_hash_values(struct Output
*t
)
1991 struct Keyword_List
*tmp
;
1993 * since the list is already sorted by hash value and doesn't contain duplicates, we can
1994 * simply count the number of keywords on the list
2006 /*------------------------------------------------------------------------------------------------*/
2007 #undef USE_DOWNCASE_TABLE
2008 /*------------------------------------------------------------------------------------------------*/
2010 #include "namespace/globals.h"
2011 #include "namespace/options.h"
2012 #include "namespace/output.h"
2013 #include "namespace/output.c"
2014 #include "namespace/keyword.h"
2015 #include "namespace/keyword_list.h"
2016 #include "namespace/positions.h"
2018 /*------------------------------------------------------------------------------------------------*/