X-Git-Url: https://git.draconx.ca/gitweb/cdecl99.git/blobdiff_plain/8b40c60072c0549d18afb1e19fa28ee18036957c..d349b9bb3fde8fc1d1222d5b7ac8dbbaf6dee230:/src/gen-specstr.awk diff --git a/src/gen-specstr.awk b/src/gen-specstr.awk index 611b2a8..c9148f8 100755 --- a/src/gen-specstr.awk +++ b/src/gen-specstr.awk @@ -1,6 +1,6 @@ #!/bin/awk -f # -# Copyright © 2021 Nick Bowler +# Copyright © 2021, 2023 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. @@ -10,46 +10,86 @@ # 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 uint_least8_t 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 "}"; }