aboutsummaryrefslogtreecommitdiff
path: root/nncmpp.actions.awk
diff options
context:
space:
mode:
Diffstat (limited to 'nncmpp.actions.awk')
-rw-r--r--nncmpp.actions.awk106
1 files changed, 106 insertions, 0 deletions
diff --git a/nncmpp.actions.awk b/nncmpp.actions.awk
new file mode 100644
index 0000000..b4d7eaf
--- /dev/null
+++ b/nncmpp.actions.awk
@@ -0,0 +1,106 @@
+# nncmpp.actions.awk: produce C code for a list of user actions
+#
+# Copyright (c) 2022, Přemysl Eric Janouch <p@janouch.name>
+# SPDX-License-Identifier: 0BSD
+#
+# Usage: env LC_ALL=C A=0 B=1 awk -f nncmpp.actions.awk \
+# nncmpp.actions > nncmpp-actions.h
+
+# --- Preprocessor -------------------------------------------------------------
+
+function fatal(message) {
+ print "// " FILENAME ":" FNR ": fatal error: " message
+ print FILENAME ":" FNR ": fatal error: " message > "/dev/stderr"
+ exit 1
+}
+
+function condition(pass, passing, a, i) {
+ split(substr($0, RSTART + RLENGTH), a, /[[:space:]]+/)
+ if (!(1 in a))
+ fatal("missing condition")
+
+ passing = 0
+ for (i in a)
+ if (a[i] && !pass == !ENVIRON[a[i]])
+ passing = 1
+
+ while (getline > 0) {
+ if (match($0, /^[[:space:]]*[.]endif[[:space:]]*$/))
+ return 1
+
+ if (match($0, /^[[:space:]]*[.]else[[:space:]]*$/))
+ passing = !passing
+ else if (!directive() && passing)
+ process()
+ }
+
+ fatal("unterminated condition body")
+}
+
+# Multiple arguments mean logical OR, multiple directives mean logical AND.
+# Similar syntax is also used by Exim, BSD make, or various assemblers.
+#
+# Looking at what others have picked for their preprocessor syntax:
+# {OpenGL, FreeBASIC} reuse #ifdef, which would be confusing with C code around,
+# {Mental Ray, RapidQ and UniVerse BASIC} use $ifdef, NSIS has !ifdef,
+# and Verilog went for `ifdef. Not much more can be easily found.
+function directive() {
+ sub(/#.*/, "")
+ if (match($0, /^[[:space:]]*[.]ifdef[[:space:]]+/))
+ return condition(1)
+ if (match($0, /^[[:space:]]*[.]ifndef[[:space:]]+/))
+ return condition(0)
+ if (/^[[:space:]]*[.]/)
+ fatal("unexpected or unsupported directive")
+ return 0
+}
+
+!directive() {
+ process()
+}
+
+# --- Postprocessor ------------------------------------------------------------
+
+function strip(string) {
+ gsub(/^[[:space:]]*|[[:space:]]*$/, "", string)
+ return string
+}
+
+function process( constant, name, description) {
+ if (match($0, /,/)) {
+ constant = name = strip(substr($0, 1, RSTART - 1))
+ description = strip(substr($0, RSTART + RLENGTH))
+ gsub(/_/, "-", name)
+
+ N++
+ Constants[N] = constant
+ Names[N] = tolower(name)
+ Descriptions[N] = description
+ } else if (/[^[:space:]]/) {
+ fatal("invalid action definition syntax")
+ }
+}
+
+function tocstring(string) {
+ gsub(/\\/, "\\\\", string)
+ gsub(/"/, "\\\"", string)
+ return "\"" string "\""
+}
+
+END {
+ print "enum action {"
+ for (i in Constants)
+ print "\t" "ACTION_" Constants[i] ","
+ print "\t" "ACTION_COUNT"
+ print "};"
+ print ""
+ print "static const char *g_action_names[] = {"
+ for (i in Names)
+ print "\t" tocstring(Names[i]) ","
+ print "};"
+ print ""
+ print "static const char *g_action_descriptions[] = {"
+ for (i in Descriptions)
+ print "\t" tocstring(Descriptions[i]) ","
+ print "};"
+}