summaryrefslogtreecommitdiffhomepage
path: root/src/build/cmeta.c
diff options
context:
space:
mode:
authorMichael Smith <mikesmiffy128@gmail.com>2022-09-13 21:46:21 +0100
committerMichael Smith <mikesmiffy128@gmail.com>2022-09-13 22:50:30 +0100
commit792463cb133f65645feb48743bbc03ef8eb96bdd (patch)
tree3879cd6895fe5c8f597f445af2410a41bcf00f73 /src/build/cmeta.c
parent378892d089b6742a95b8d573af58535597f19d25 (diff)
Move towards C23, improve events and vcall macros
Another big one. Here's a list of things: - Since the upcoming C23 standardises typeof(), use it as an extension for the time being in order to allow passing arbitrary types as macro/codegen parameters. It wouldn't have been a big leap to do this even without standardisation since it's apparently an easy extension to implement - and also, to be honest, this project is essentially glued to Clang anyway so who cares. - Likewise, bool, true and false are becoming pre-defined, so pre-pre-define them now in order to get the benefit of not having to remember one header everywhere. - Really ungodly/amazing vcall macro stuff now allows us to call C++ virtual functions like regular C functions. It's pretty cool! - Events can now take arbitrary parameters and come in two types: regular events and predicates. All this makes the base code even uglier but makes the feature implementation nicer. In other words, it places more of the cognitive burden on myself and less on other people who might want to contribute. This is a good tradeoff, because I'm a genius.
Diffstat (limited to 'src/build/cmeta.c')
-rw-r--r--src/build/cmeta.c87
1 files changed, 67 insertions, 20 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;