]> git.draconx.ca Git - cdecl99.git/blob - src/gen-specstr.awk
68401c11a6fc537d30a25c875160faaa9c47d57a
[cdecl99.git] / src / gen-specstr.awk
1 #!/bin/awk -f
2 #
3 # Copyright © 2021, 2023 Nick Bowler
4 #
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.
7 #
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.
11
12 END {
13   print "/*";
14   if (FILENAME) {
15     print " * Automatically generated by gen-specstr.awk from " FILENAME;
16   } else {
17     print " * Automatically generated by gen-specstr.awk";
18   }
19   print " * Do not edit.";
20   print " */";
21 }
22
23 BEGIN {
24   kinds["TYPE"] = kinds["STOR"] = kinds["QUAL"] = kinds["FUNC"] = 1;
25   underscore["BOOL"] = underscore["COMPLEX"] = underscore["IMAGINARY"] = 1;
26   count = 0;
27 }
28
29 # Locate all the relevant identifiers in cdecl.h.  We assume everything
30 # is in numerically increasing order within the various enums.
31 $1 ~ /^CDECL_/ {
32   sub(/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ_].*/, "", $1);
33
34   split($1, parts, "_");
35   if (parts[2] == "SPEC") {
36     x = $0;
37     sub(/^.*= */, "", x);
38     sub(/,? *$/, "", x);
39
40     x = int(x / 512) % 8;
41     if (skiptab[x]) {
42       print "cannot create skip table";
43       exit 1;
44     }
45
46     skiptab[x] = parts[3];
47   }
48
49   if (parts[2] in kinds) {
50     kind_counts[parts[2]]++;
51
52     if (parts[3] == "IDENT") {
53       s = "";
54     } else if (parts[3] in underscore) {
55       s = "_" substr(parts[3], 1, 1) tolower(substr(parts[3], 2));
56     } else {
57       s = tolower(parts[3]);
58     }
59     rspecs[s] = count;
60     specs[count++] = s;
61   }
62 }
63
64 END {
65   string_table = "";
66
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++) {
72     s = sorted_specs[i];
73
74     if ((n = index(string_table, s "\1")) > 0) {
75       offsets[rspecs[s]] = n - 1;
76     } else {
77       offsets[rspecs[s]] = length(string_table);
78       string_table = string_table s "\1";
79     }
80   }
81
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.
85   skip_count = 0;
86   for (i in skiptab) {
87     if (skip_count < i)
88       skip_count = i;
89   }
90
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]];
95   }
96   sub(/ $/, "\n\t\t", offset_table);
97
98   # Then, each remaining entry in the index table is an offset into the
99   # string table.
100   for (i = 0; i < count; i++) {
101     suffix = "\t/* " (specs[i] ? specs[i] : "\"\"") " */";
102     if (i+1 < count)
103       suffix = "," suffix "\n\t\t";
104     offset_table = offset_table offsets[i] suffix;
105   }
106
107   sub(/\1$/, "", string_table);
108   gsub(/\1/, "\"\n\t\t\"\\0\" \"", string_table);
109
110   print "static const char *spec_string(unsigned type)"
111   print "{"
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;
116   print "\t};\n";
117
118   print "\tunsigned x = (type & 0xff) + idx[type >> 9];";
119   print "\tassert(x < sizeof idx);";
120   print "\treturn tab + idx[x];";
121   print "}";
122 }
123
124 # bucketsort(dst, src)
125 #
126 #
127 # Sort the elements of src by descending string length,
128 # placing them into dst[0] ... dst[n].
129 #
130 # Returns the number of elements.
131 function bucketsort(dst, src, buckets, max, count, i, t)
132 {
133   for (t in src) {
134     i = length(src[t]);
135     if (i > max) { max = i; }
136     buckets[i]++;
137   }
138
139   for (i = max; i >= 0; i--) {
140     if (i in buckets) {
141       t = buckets[i];
142       buckets[i] = count;
143       count += t;
144     }
145   }
146
147   for (t in src) {
148     i = length(t = src[t]);
149     dst[buckets[i]++] = t;
150   }
151
152   return count;
153 }