aboutsummaryrefslogtreecommitdiff
path: root/src/build/mkgamedata.c
diff options
context:
space:
mode:
authorGravatar Michael Smith <mikesmiffy128@gmail.com> 2025-03-10 02:37:19 +0000
committerGravatar Michael Smith <mikesmiffy128@gmail.com> 2025-04-06 16:41:13 +0100
commit244fea664121acf12871ab5858a5fe95a2606b52 (patch)
treee42b1990ef97adc0f0ab48b9be7e11de7fee0558 /src/build/mkgamedata.c
parentd86b7b41453c69b3854baa7cdc05a79a3cdfe092 (diff)
downloadsst-244fea664121acf12871ab5858a5fe95a2606b52.tar.gz
sst-244fea664121acf12871ab5858a5fe95a2606b52.zip
Rewrite and redesign codegen and feature system
Also switch to somewhat proper C23 flags while we're at it. This is a huge change. It took me forever, in between being really busy. Sorry about that. But the good news is I'm now free to start integrating the various patches that have accumulated since last release. Well, at least in between still being really busy. Gotta manage expectations. The main benefit of introducing GAMESPECIFIC() is that features that don't apply to a particular game no longer show up *at all*, and less time is wasted on init. It also enables a cool optimisation wherein unnecessary REQUIRE_GAMEDATA() checks can elided at compile time whenever the gamedata is known up-front to always exist in supported games. The DEF_FEAT_CVAR macro family meanwhile makes it easier to manage the lifecycle of cvars/ccmds, with less manual registering, unhiding and such. Originally I was going to try and just hack these features into the existing codegen abomination, but it just got too terrible. This rewrite should make it easier to continue tweaking codegen behaviour in future. It also has slightly better error messages.
Diffstat (limited to 'src/build/mkgamedata.c')
-rw-r--r--src/build/mkgamedata.c45
1 files changed, 38 insertions, 7 deletions
diff --git a/src/build/mkgamedata.c b/src/build/mkgamedata.c
index 1fce1cf..ed8cf97 100644
--- a/src/build/mkgamedata.c
+++ b/src/build/mkgamedata.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2024 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2025 Michael Smith <mikesmiffy128@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -29,7 +29,7 @@
#endif
static noreturn die(int status, const char *s) {
- fprintf(stderr, "mkentprops: %s\n", s);
+ fprintf(stderr, "mkentprops: fatal: %s\n", s);
exit(status);
}
@@ -156,7 +156,37 @@ static inline noreturn diewrite(void) { die(100, "couldn't write to file"); }
_( "/* This file is autogenerated by src/build/mkgamedata.c. DO NOT EDIT! */") \
_( "")
-static void decls(FILE *out) {
+static inline void knowngames(FILE *out) {
+ // kind of tricky optimisation: if a gamedata entry has no default but
+ // does have game-specific values which match a feature's GAMESPECIFIC()
+ // macro, load-time conditional checks resulting from REQUIRE_GAMEDATA() can
+ // be elided at compile-time.
+ for (int i = 0, j; i < nents - 1; i = j) {
+ while (exprs[i]) { // if there's a default value, we don't need this
+ // skip to next unindented thing, return if there isn't one with at
+ // least one indented thing under it.
+ for (++i; indents[i] != 0; ++i) if (i == nents - 1) return;
+ }
+F( "#line %d \"%" fS "\"", srclines[i], srcnames[srcfiles[i]])
+ if (fprintf(out, "#define _GAMES_WITH_%s (", sbase + tags[i]) < 0) {
+ diewrite();
+ }
+ const char *pipe = "";
+ for (j = i + 1; j < nents && indents[j] != 0; ++j) {
+ // don't attempt to optimise for nested conditionals because that's
+ // way more complicated and also basically defeats the purpose.
+ if (indents[j] != 1) continue;
+ if (fprintf(out, "%s \\\n\t _gametype_tag_%s", pipe,
+ sbase + tags[j]) < 0) {
+ diewrite();
+ }
+ pipe = " |";
+ }
+ fputs(" \\\n)\n", out);
+ }
+}
+
+static inline void decls(FILE *out) {
for (int i = 0; i < nents; ++i) {
if (indents[i] != 0) continue;
F( "#line %d \"%" fS "\"", srclines[i], srcnames[srcfiles[i]])
@@ -175,13 +205,13 @@ F( "#line %d \"%" fS "\"", srclines[i], srcnames[srcfiles[i]])
if_cold (i == nents - 1 || !indents[i + 1]) { // no tags - it's constant
F( "enum { %s = (%s) };", sbase + tags[i], sbase + exprs[i])
}
- else { // global variable intialised by gamedata_init() call
+ else { // global variable intialised by initgamedata() call
F( "extern int %s;", sbase + tags[i]);
}
}
}
-static void defs(FILE *out) {
+static inline void defs(FILE *out) {
for (int i = 0; i < nents; ++i) {
if (indents[i] != 0) continue;
if_hot (i < nents - 1 && indents[i + 1]) {
@@ -196,8 +226,8 @@ F( "int %s = -2147483648;", sbase + tags[i])
}
}
-static void init(FILE *out) {
-_( "void gamedata_init(void) {")
+static inline void init(FILE *out) {
+_( "static void initgamedata(void) {")
int varidx;
int indent = 0;
for (int i = 0; i < nents; ++i) {
@@ -261,6 +291,7 @@ int OS_MAIN(int argc, os_char *argv[]) {
FILE *out = fopen(".build/include/gamedata.gen.h", "wb");
if (!out) die(100, "couldn't open gamedata.gen.h");
H();
+ knowngames(out);
decls(out);
out = fopen(".build/include/gamedatainit.gen.h", "wb");