]> git.draconx.ca Git - cdecl99.git/blobdiff - src/gen-specstr.awk
libcdecl: Avoid overalignment of string tables.
[cdecl99.git] / src / gen-specstr.awk
index 611b2a851568afe53475ba895bc2e2b79cba3e76..0bc8278db172bbd7d2c782244639293c6bc8a3ed 100755 (executable)
@@ -1,6 +1,6 @@
 #!/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 "}";
 }