diff options
Diffstat (limited to 'src/build')
-rw-r--r-- | src/build/cmeta.c | 87 | ||||
-rw-r--r-- | src/build/cmeta.h | 6 | ||||
-rw-r--r-- | src/build/codegen.c | 84 | ||||
-rw-r--r-- | src/build/mkentprops.c | 1 | ||||
-rw-r--r-- | src/build/mkgamedata.c | 1 | ||||
-rw-r--r-- | src/build/vec.h | 1 |
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" |