#!/bin/awk -f
#
-# Copyright © 2021 Nick Bowler
+# Copyright © 2021, 2023-2024 Nick Bowler
#
# Generate a function to return the C keyword corresponding to a specifier
# type as a string, for internal use by the output routines.
# There is NO WARRANTY, to the extent permitted by law.
END {
- print "/*"
+ print "/*";
if (FILENAME) {
- print " * Automatically generated by gen-specstr.awk from " FILENAME
+ print " * Automatically generated by gen-specstr.awk from " FILENAME;
} else {
- print " * Automatically generated by gen-specstr.awk"
+ print " * Automatically generated by gen-specstr.awk";
}
- print " * Do not edit."
- print " */"
+ print " * Do not edit.";
+ print " */";
}
BEGIN {
- kinds["TYPE"] = kinds["STOR"] = kinds["QUAL"] = kinds["FUNC"] = 1
- underscore["BOOL"] = underscore["COMPLEX"] = underscore["IMAGINARY"] = 1
+ kinds["TYPE"] = kinds["STOR"] = kinds["QUAL"] = kinds["FUNC"] = 1;
+ count = 0;
}
+# Locate all the relevant identifiers in cdecl.h. We assume everything
+# is in numerically increasing order within the various enums.
$1 ~ /^CDECL_/ {
- sub(/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ_].*/, "", $1)
+ sub(/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ_].*/, "", $1);
- split($1, parts, "_")
- if (parts[2] in kinds) {
- if (parts[3] == "IDENT") {
- s = ""
- } else if (parts[3] in underscore) {
- s = "_" substr(parts[3], 1, 1) tolower(substr(parts[3], 2))
- } else {
- s = tolower(parts[3])
+ split($1, parts, "_");
+ if (parts[2] == "SPEC") {
+ x = $0;
+ sub(/^.*= */, "", x);
+ sub(/,? *$/, "", x);
+
+ x = int(x / 512) % 8;
+ if (skiptab[x]) {
+ print "cannot create skip table";
+ exit 1;
}
- specs[$1] = s
+
+ skiptab[x] = parts[3];
+ }
+
+ if (parts[2] in kinds) {
+ kind_counts[parts[2]]++;
+ specs[count++] = parts[3];
}
}
END {
- print "static inline const char *spec_string(unsigned type)\n{"
- print "\tswitch (type) {"
+ # Create the token table. The first 5 entries key off of bits 9 through 11,
+ # which is sufficient to distinguish the different specifier kinds and is
+ # used to partition the rest of the token table.
+ skip_count = 0;
+ for (i in skiptab) {
+ if (skip_count < i)
+ skip_count = i;
+ }
- for (s in specs) {
- print "\tcase " s ": return \"" specs[s] "\";"
+ skip_pos = ++skip_count;
+ for (i = 0; i < skip_count; i++) {
+ offset_table = offset_table skip_pos ", ";
+ skip_pos += kind_counts[skiptab[i]];
}
+ sub(/ $/, "\n\t\t", offset_table);
+
+ for (i = 0; i < count; i++) {
+ suffix = "";
+ if (i+1 < count)
+ suffix = ",\n\t\t";
+
+ if (specs[i] == "IDENT")
+ s = "0";
+ else
+ s = "PACK_TOKEN(T_" specs[i] ")";
+ offset_table = offset_table s suffix;
+ }
+
+ print "static const char *spec_string(unsigned type)"
+ print "{"
+ print "\tstatic const unsigned char _Alignas(1) idx[] = {";
+ print "\t\t" offset_table;
+ print "\t};\n";
- print "\t}"
- print "\n\tassert(0);"
- print "}"
+ print "\tunsigned x = (type & 0xff) + idx[type >> 9];";
+ print "\tassert(x < sizeof idx);";
+ print "\tif (!(x = idx[x]))";
+ print "\t\treturn \"\";";
+ print "\treturn cdecl__token_name(UNPACK_TOKEN(x));";
+ print "}";
}