3 # Copyright © 2021, 2023 Nick Bowler
5 # Generate a function to return the C keyword corresponding to a specifier
6 # type as a string, for internal use by the output routines.
8 # License WTFPL2: Do What The Fuck You Want To Public License, version 2.
9 # This is free software: you are free to do what the fuck you want to.
10 # There is NO WARRANTY, to the extent permitted by law.
15 print " * Automatically generated by gen-specstr.awk from " FILENAME;
17 print " * Automatically generated by gen-specstr.awk";
19 print " * Do not edit.";
24 kinds["TYPE"] = kinds["STOR"] = kinds["QUAL"] = kinds["FUNC"] = 1;
25 underscore["BOOL"] = underscore["COMPLEX"] = underscore["IMAGINARY"] = 1;
29 # Locate all the relevant identifiers in cdecl.h. We assume everything
30 # is in numerically increasing order within the various enums.
32 sub(/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ_].*/, "", $1);
34 split($1, parts, "_");
35 if (parts[2] == "SPEC") {
42 print "cannot create skip table";
46 skiptab[x] = parts[3];
49 if (parts[2] in kinds) {
50 kind_counts[parts[2]]++;
52 if (parts[3] == "IDENT") {
54 } else if (parts[3] in underscore) {
55 s = "_" substr(parts[3], 1, 1) tolower(substr(parts[3], 2));
57 s = tolower(parts[3]);
67 # The basic approach is to first generate a suffix-compressed string
68 # table containing all the specifier strings (not a lot of overlap in
69 # C specifiers, but there is (un)signed.
70 count = bucketsort(sorted_specs, specs);
71 for (i = 0; i < count; i++) {
74 if ((n = index(string_table, s "\1")) > 0) {
75 offsets[rspecs[s]] = n - 1;
77 offsets[rspecs[s]] = length(string_table);
78 string_table = string_table s "\1";
82 # Next, we create the index table. The first 5 entries key off of bits 9
83 # through 11, which is sufficient to distinguish the different specifier
84 # kinds and is used to partition the rest of the index table.
91 skip_pos = ++skip_count;
92 for (i = 0; i < skip_count; i++) {
93 offset_table = offset_table skip_pos ", ";
94 skip_pos += kind_counts[skiptab[i]];
96 sub(/ $/, "\n\t\t", offset_table);
98 # Then, each remaining entry in the index table is an offset into the
100 for (i = 0; i < count; i++) {
101 suffix = "\t/* " (specs[i] ? specs[i] : "\"\"") " */";
103 suffix = "," suffix "\n\t\t";
104 offset_table = offset_table offsets[i] suffix;
107 sub(/\1$/, "", string_table);
108 gsub(/\1/, "\"\n\t\t\"\\0\" \"", string_table);
110 print "static const char *spec_string(unsigned type)"
112 print "\tstatic const char tab[] =";
113 print "\t\t \"" string_table "\";\n";
114 print "\tstatic const uint_least8_t idx[] = {";
115 print "\t\t" offset_table;
118 print "\tunsigned x = (type & 0xff) + idx[type >> 9];";
119 print "\tassert(x < sizeof idx);";
120 print "\treturn tab + idx[x];";
124 # bucketsort(dst, src)
127 # Sort the elements of src by descending string length,
128 # placing them into dst[0] ... dst[n].
130 # Returns the number of elements.
131 function bucketsort(dst, src, buckets, max, count, i, t)
135 if (i > max) { max = i; }
139 for (i = max; i >= 0; i--) {
148 i = length(t = src[t]);
149 dst[buckets[i]++] = t;