summaryrefslogtreecommitdiffhomepage
path: root/src/build
diff options
context:
space:
mode:
Diffstat (limited to 'src/build')
-rw-r--r--src/build/cmeta.c87
-rw-r--r--src/build/cmeta.h6
-rw-r--r--src/build/codegen.c84
-rw-r--r--src/build/mkentprops.c1
-rw-r--r--src/build/mkgamedata.c1
-rw-r--r--src/build/vec.h1
6 files changed, 139 insertions, 41 deletions
diff --git a/src/build/cmeta.c b/src/build/cmeta.c
index 260d33f..7f314c7 100644
--- a/src/build/cmeta.c
+++ b/src/build/cmeta.c
@@ -14,13 +14,13 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "../intdefs.h"
#include "../os.h"
#include "cmeta.h"
+#include "vec.h"
/*
* This file does C metadata parsing/scraping for the build system. This
@@ -73,16 +73,16 @@ Type *array_of(Type *base, int len) {
#include "../3p/chibicc/tokenize.c"
// one more copypaste from preprocess.c for #include <filename> and then I'm
// done I promise
-static char *join_tokens(Token *tok, Token *end) {
+static char *join_tokens(const Token *tok, const Token *end) {
int len = 1;
- for (Token *t = tok; t != end && t->kind != TK_EOF; t = t->next) {
+ for (const Token *t = tok; t != end && t->kind != TK_EOF; t = t->next) {
if (t != tok && t->has_space)
len++;
len += t->len;
}
char *buf = calloc(1, len);
int pos = 0;
- for (Token *t = tok; t != end && t->kind != TK_EOF; t = t->next) {
+ for (const Token *t = tok; t != end && t->kind != TK_EOF; t = t->next) {
if (t != tok && t->has_space)
buf[pos++] = ' ';
strncpy(buf + pos, t->loc, t->len);
@@ -166,7 +166,7 @@ const struct cmeta *cmeta_loadfile(const os_char *f) {
// picks it anyway, and gives far better diagnostics.
void cmeta_includes(const struct cmeta *cm,
void (*cb)(const char *f, bool issys, void *ctxt), void *ctxt) {
- Token *tp = (Token *)cm;
+ const Token *tp = (const Token *)cm;
if (!tp || !tp->next || !tp->next->next) return; // #, include, "string"
while (tp) {
if (!tp->at_bol || !equal(tp, "#")) { tp = tp->next; continue; }
@@ -187,7 +187,7 @@ void cmeta_includes(const struct cmeta *cm,
else if (equal(tp, "<")) {
tp = tp->next;
if (!tp) break;
- Token *end = tp;
+ const Token *end = tp;
while (!equal(end, ">")) {
end = end->next;
if (!end) return; // shouldn't happen in valid source obviously
@@ -210,7 +210,7 @@ void cmeta_includes(const struct cmeta *cm,
// we're not writing something weird. Don't write something weird!
void cmeta_conmacros(const struct cmeta *cm,
void (*cb)(const char *, bool, bool)) {
- Token *tp = (Token *)cm;
+ const Token *tp = (const Token *)cm;
if (!tp || !tp->next || !tp->next->next) return; // DEF_xyz, (, name
while (tp) {
bool isplusminus = false, isvar = false;
@@ -271,7 +271,7 @@ void cmeta_conmacros(const struct cmeta *cm,
}
const char *cmeta_findfeatmacro(const struct cmeta *cm) {
- Token *tp = (Token *)cm;
+ const Token *tp = (const Token *)cm;
if (!tp || !tp->next) return 0; // FEATURE, (
while (tp) {
if (equal(tp, "FEATURE") && equal(tp->next, "(")) {
@@ -288,7 +288,7 @@ const char *cmeta_findfeatmacro(const struct cmeta *cm) {
void cmeta_featinfomacros(const struct cmeta *cm, void (*cb)(
enum cmeta_featmacro type, const char *param, void *ctxt), void *ctxt) {
- Token *tp = (Token *)cm;
+ const Token *tp = (const Token *)cm;
if (!tp || !tp->next) return;
while (tp) {
int type = -1;
@@ -336,26 +336,73 @@ void cmeta_featinfomacros(const struct cmeta *cm, void (*cb)(
}
}
-void cmeta_evdefmacros(const struct cmeta *cm,
- void (*cb_def)(const char *name)) {
- Token *tp = (Token *)cm;
+struct vec_str VEC(const char *);
+
+static void pushmacroarg(const Token *last, const char *start,
+ struct vec_str *list) {
+ int len = last->loc - start + last->len;
+ char *dup = malloc(len + 1);
+ if (!dup) die1("couldn't allocate memory");
+ memcpy(dup, start, len);
+ dup[len] = '\0';
+ if (!vec_push(list, dup)) die1("couldn't append to array");
+}
+
+// XXX: maybe this should be used for the other functions too. it'd be less ugly
+// and handle closing parentheses better, but alloc for tokens we don't care
+// about. probably a worthy tradeoff?
+static const Token *macroargs(const Token *t, struct vec_str *list) {
+ int paren = 1;
+ const Token *last; // avoids copying extra ws/comments in
+ for (const char *start = t->loc; t; last = t, t = t->next) {
+ if (equal(t, "(")) {
+ ++paren;
+ }
+ else if (equal(t, ")")) {
+ if (!--paren) {
+ pushmacroarg(last, start, list);
+ return t->next;
+ }
+ }
+ else if (paren == 1 && equal(t, ",")) {
+ pushmacroarg(last, start, list);
+ t = t->next;
+ if (t) start = t->loc; // slightly annoying...
+ }
+ }
+ // I guess we handle this here.
+ fprintf(stderr, "cmeta: fatal: unexpected EOF in %s\n", t->filename);
+ exit(2);
+}
+
+void cmeta_evdefmacros(const struct cmeta *cm, void (*cb)(const char *name,
+ const char *const *params, int nparams, bool predicate)) {
+ const Token *tp = (const Token *)cm;
if (!tp || !tp->next || !tp->next->next) return; // DEF_EVENT, (, name
while (tp) {
+ bool predicate = true;
if (equal(tp, "DEF_EVENT") && equal(tp->next, "(")) {
- tp = tp->next->next;
- char *name = malloc(tp->len + 1);
- if (!name) die1("couldn't allocate memory");
- memcpy(name, tp->loc, tp->len);
- name[tp->len] = '\0';
- cb_def(name);
+ predicate = false;
}
- tp = tp->next;
+ else if (!equal(tp, "DEF_PREDICATE") || !equal(tp->next, "(")) {
+ tp = tp->next;
+ continue;
+ }
+ tp = tp->next->next;
+ struct vec_str args = {0};
+ tp = macroargs(tp, &args);
+ if (args.sz == 0) {
+ fprintf(stderr, "cmeta: fatal: missing event parameters in %s\n",
+ tp->filename);
+ exit(2);
+ }
+ cb(args.data[0], args.data + 1, args.sz - 1, predicate);
}
}
void cmeta_evhandlermacros(const struct cmeta *cm, const char *modname,
void (*cb_handler)(const char *evname, const char *modname)) {
- Token *tp = (Token *)cm;
+ const Token *tp = (const Token *)cm;
while (tp) {
if (equal(tp, "HANDLE_EVENT") && equal(tp->next, "(")) {
tp = tp->next->next;
diff --git a/src/build/cmeta.h b/src/build/cmeta.h
index 40c4ac5..48a2d6d 100644
--- a/src/build/cmeta.h
+++ b/src/build/cmeta.h
@@ -17,8 +17,6 @@
#ifndef INC_CMETA_H
#define INC_CMETA_H
-#include <stdbool.h>
-
#include "../os.h"
struct cmeta;
@@ -76,8 +74,8 @@ void cmeta_featinfomacros(const struct cmeta *cm, void (*cb)(
* Iterates through all event-related macros and takes note of which events are
* defined, giving a callback for each.
*/
-void cmeta_evdefmacros(const struct cmeta *cm, void (*cb)(const char *name));
-
+void cmeta_evdefmacros(const struct cmeta *cm, void (*cb)(const char *name,
+ const char *const *params, int nparams, bool predicate));
/*
* Iterates through all event-related macros and gives a callback for each event
* that is handled by the given module.
diff --git a/src/build/codegen.c b/src/build/codegen.c
index 04a9058..f5231c0 100644
--- a/src/build/codegen.c
+++ b/src/build/codegen.c
@@ -14,7 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -139,12 +138,15 @@ push: if (!vec_push(vecp, param)) die("couldn't allocate memory");
DECL_SKIPLIST(static, event, struct event, const char *, 4)
struct event {
- const char *name;
+ usize name; // string, but tagged pointer - see below
+ const char *const *params;
+ int nparams;
+ //char pad[4];
struct vec_usize handlers; // strings, but with tagged pointers - see below
struct skiplist_hdr_event hdr;
};
static inline int cmp_event(struct event *e, const char *s) {
- return strcmp(e->name, s);
+ return strcmp((const char *)(e->name & ~1ull), s);
}
static inline struct skiplist_hdr_event *hdr_event(struct event *e) {
return &e->hdr;
@@ -152,12 +154,15 @@ static inline struct skiplist_hdr_event *hdr_event(struct event *e) {
DEF_SKIPLIST(static, event, cmp_event, hdr_event)
static struct skiplist_hdr_event events = {0};
-static void onevdef(const char *name) {
+static void onevdef(const char *name, const char *const *params, int nparams,
+ bool predicate) {
struct event *e = skiplist_get_event(&events, name);
if (!e) {
struct event *e = malloc(sizeof(*e));
if (!e) die("couldn't allocate memory");
- e->name = name;
+ // hack: using unused pointer bit to distinguish the two types of event
+ e->name = (usize)name | predicate;
+ e->params = params; e->nparams = nparams;
e->handlers = (struct vec_usize){0};
e->hdr = (struct skiplist_hdr_event){0};
skiplist_insert_event(&events, name, e);
@@ -445,19 +450,70 @@ _( "")
H_()
for (const struct event *e = events.x[0]; e; e = e->hdr.x[0]) {
_( "")
-F( "void _evemit_%s(void) {", e->name)
- for (usize *pp = e->handlers.data;
- pp - e->handlers.data < e->handlers.sz; ++pp) {
- const char *modname = (const char *)(*pp & ~1ull);
-F( " void _evhandler_%s_%s(void);", modname, e->name) // blegh.
- if (*pp & 1ull) {
- // note: has_* variables are already included by this point (above)
-F( " if (has_%s) _evhandler_%s_%s();", modname, modname, e->name)
+ // gotta break from the string emit macros for a sec in order to do the
+ // somewhat more complicated task sometimes referred to as a "for loop"
+ fprintf(out, "%s_%s(", e->name & 1 ? "bool CHECK" : "void EMIT",
+ (const char *)(e->name & ~1ull));
+ for (int n = 0; n < (int)e->nparams - 1; ++n) {
+ fprintf(out, "typeof(%s) a%d, ", e->params[n], n + 1);
+ }
+ if (e->nparams && strcmp(e->params[0], "void")) {
+ fprintf(out, "typeof(%s) a%d", e->params[e->nparams - 1],
+ e->nparams);
}
else {
-F( " _evhandler_%s_%s();", modname, e->name)
+ // just unilaterally doing void for now. when we're fully on C23
+ // eventually we can unilaterally do nothing instead
+ fputs("void", out);
}
+_( ") {")
+ for (usize *pp = e->handlers.data;
+ pp - e->handlers.data < e->handlers.sz; ++pp) {
+ const char *modname = (const char *)(*pp & ~1ull);
+ fprintf(out, "\t%s _evhandler_%s_%s(", e->name & 1 ? "bool" : "void",
+ modname, (const char *)(e->name & ~1ull));
+ for (int n = 0; n < (int)e->nparams - 1; ++n) {
+ fprintf(out, "typeof(%s) a%d, ", e->params[n], n + 1);
+ }
+ if (e->nparams && strcmp(e->params[0], "void")) {
+ fprintf(out, "typeof(%s) a%d", e->params[e->nparams - 1],
+ e->nparams);
+ }
+ else {
+ fputs("void", out);
+ }
+ fputs(");\n\t", out);
+ // conditional and non-conditional cases - in theory could be
+ // unified a bit but this is easier to make output relatively pretty
+ // note: has_* variables are already included by this point (above)
+ if (e->name & 1) {
+ if (*pp & 1) fprintf(out, "if (has_%s && !", modname);
+ else fprintf(out, "if (!");
+ fprintf(out, "_evhandler_%s_%s(", modname,
+ (const char *)(e->name & ~1ull));
+ // XXX: much repetitive drivel here
+ for (int n = 0; n < (int)e->nparams - 1; ++n) {
+ fprintf(out, "a%d,", n + 1);
+ }
+ if (e->nparams && strcmp(e->params[0], "void")) {
+ fprintf(out, "a%d", e->nparams);
+ }
+ fputs(")) return false;\n", out);
+ }
+ else {
+ if (*pp & 1) fprintf(out, "if (has_%s) ", modname);
+ fprintf(out, "_evhandler_%s_%s(", modname,
+ (const char *)(e->name & ~1ull));
+ for (int n = 0; n < (int)e->nparams - 1; ++n) {
+ fprintf(out, "a%d,", n + 1);
+ }
+ if (e->nparams && strcmp(e->params[0], "void")) {
+ fprintf(out, "a%d", e->nparams);
+ }
+ fputs(");\n", out);
+ }
}
+ if (e->name & 1) fputs("\treturn true;\n", out);
_( "}")
}
if (fclose(out) == EOF) die("couldn't fully write evglue.gen.h");
diff --git a/src/build/mkentprops.c b/src/build/mkentprops.c
index 300dafa..fdb6982 100644
--- a/src/build/mkentprops.c
+++ b/src/build/mkentprops.c
@@ -14,7 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/src/build/mkgamedata.c b/src/build/mkgamedata.c
index 7d7a425..fdb2aef 100644
--- a/src/build/mkgamedata.c
+++ b/src/build/mkgamedata.c
@@ -14,7 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/src/build/vec.h b/src/build/vec.h
index 50b0a3b..6b4dffb 100644
--- a/src/build/vec.h
+++ b/src/build/vec.h
@@ -4,7 +4,6 @@
#define INC_VEC_H
#include <errno.h>
-#include <stdbool.h>
#include <stdlib.h>
#include "../intdefs.h"