diff options
Diffstat (limited to 'src/build')
| -rw-r--r-- | src/build/cmeta.c | 464 | ||||
| -rw-r--r-- | src/build/cmeta.h | 49 | ||||
| -rw-r--r-- | src/build/gluegen.c | 40 |
3 files changed, 317 insertions, 236 deletions
diff --git a/src/build/cmeta.c b/src/build/cmeta.c index 434be76..88ac327 100644 --- a/src/build/cmeta.c +++ b/src/build/cmeta.c @@ -17,56 +17,12 @@ #include <stdio.h> #include <stdlib.h> +#include "../chunklets/clex.h" #include "../intdefs.h" #include "../langext.h" #include "../os.h" #include "cmeta.h" -// lazy inlined 3rd party stuff {{{ -// too lazy to write a C tokenizer at the moment, or indeed probably ever, so -// let's just yoink some code from a hacked-up copy of chibicc, a nice minimal C -// compiler with code that's pretty easy to work with. it does leak memory by -// design, but build stuff is all one-shot so that's fine. -#include "../3p/chibicc/chibicc.h" -#include "../3p/chibicc/unicode.c" -// type sentinels from type.c (don't bring in the rest of type.c because it -// circularly depends on other stuff and we really only want tokenize here) -Type *ty_void = &(Type){TY_VOID, 1, 1}; -Type *ty_bool = &(Type){TY_BOOL, 1, 1}; -Type *ty_char = &(Type){TY_CHAR, 1, 1}; -Type *ty_short = &(Type){TY_SHORT, 2, 2}; -Type *ty_int = &(Type){TY_INT, 4, 4}; -Type *ty_long = &(Type){TY_LONG, 8, 8}; -Type *ty_uchar = &(Type){TY_CHAR, 1, 1, true}; -Type *ty_ushort = &(Type){TY_SHORT, 2, 2, true}; -Type *ty_uint = &(Type){TY_INT, 4, 4, true}; -Type *ty_ulong = &(Type){TY_LONG, 8, 8, true}; -Type *ty_float = &(Type){TY_FLOAT, 4, 4}; -Type *ty_double = &(Type){TY_DOUBLE, 8, 8}; -Type *ty_ldouble = &(Type){TY_LDOUBLE, 16, 16}; -// inline just a couple more things, super lazy, but whatever -static Type *new_type(TypeKind kind, int size, int align) { - Type *ty = calloc(1, sizeof(Type)); - ty->kind = kind; - ty->size = size; - ty->align = align; - return ty; -} -Type *array_of(Type *base, int len) { - Type *ty = new_type(TY_ARRAY, base->size * len, base->align); - ty->base = base; - ty->array_len = len; - return ty; -} -#include "../3p/chibicc/hashmap.c" -#include "../3p/chibicc/strings.c" -#include "../3p/chibicc/tokenize.c" -// }}} - -#ifdef _WIN32 -#include "../3p/openbsd/asprintf.c" // missing from libc; plonked here for now -#endif - static cold noreturn die(int status, const char *s) { fprintf(stderr, "cmeta: fatal: %s\n", s); exit(status); @@ -76,188 +32,314 @@ struct cmeta cmeta_loadfile(const os_char *path) { int f = os_open_read(path); if_cold (f == -1) die(100, "couldn't open file"); vlong len = os_fsize(f); - if_cold (len > 1u << 30 - 1) die(2, "input file is far too large"); + if_cold (len == 0) die(2, "empty source file"); + // limit this a little lower so that clex_memreq doesn't overflow if (for + // some reason!?) the host compiler target is 32-bit. no point worrying as + // we should never have a 256MiB source file anyway! + if_cold (len > 1u << 28 - 1) die(2, "input file is far too large"); struct cmeta ret; - ret.sbase = malloc(len + 1); - ret.sbase[len] = '\0'; // chibicc needs a null terminator - if_cold (!ret.sbase) die(100, "couldn't allocate memory"); - if_cold (os_read(f, ret.sbase, len) != len) die(100, "couldn't read file"); - int maxitems = len / 4; // shortest word is "END" + usize lexmemreq = clex_memreq(len, os_strlen(path)); + // smallest possible item is END{} (5 chars), but it's nice to be able to go + // >> 2, so pretend it's 4 chars. for each item we store 1 32-bit ints and + // an 8-bit int, so the memory requirement ends up being clex_memreq() + + // len + len >> 2. in total, including the file buffer, that should be 7.25x + // the file size. which is pretty reasonable for normal files. + usize memreq = lexmemreq + (len << 1) + (len >> 2); + void *mem = malloc(memreq); ret.nitems = 0; - // eventual overall memory requirement: file size * 6. seems fine to me. - // current memory requirement: file size * 10, + all the chibicc linked list - // crap. not as good but we'll continue tolerating it... probably for years! - //ret.itemoffs = malloc(maxitems * sizeof(*ret.itemoffs)); - //if (!ret.itemoffs) die(100, "couldn't allocate memory"); - ret.itemtoks = malloc(maxitems * sizeof(*ret.itemtoks)); - if_cold (!ret.itemtoks) die(100, "couldn't allocate memory"); - ret.itemtypes = malloc(maxitems * sizeof(*ret.itemtypes)); - if_cold (!ret.itemtypes) die(100, "couldn't allocate memory"); + ret.itemtoks = mem; + // put the string and item bytes at the end so the cmeta stuff is aligned. + ret.sbase = (char *)mem + memreq - len; + ret.items = (struct cmeta_item *)mem + memreq - (len << 1); + if_cold (!mem) die(100, "couldn't allocate memory"); + if_cold (os_read(f, ret.sbase, len) != len) die(100, "couldn't read file"); os_close(f); #ifdef _WIN32 - char *realname = malloc(wcslen(path) + 1); - if_cold (!realname) die(100, "couldn't allocate memory"); + char *asciiname = malloc(wcslen(path) + 1); + if_cold (!asciiname) die(100, "couldn't allocate memory"); // XXX: being lazy about Unicode right now; a general purpose tool should // implement WTF8 or something. SST itself doesn't have any unicode paths // though, so we don't really care as much. this code still sucks though. - *realname = *path; - for (const ushort *p = path + 1; p[-1]; ++p) realname[p - path] = *p; + *asciiname = *path; + for (const ushort *p = path + 1; p[-1]; ++p) asciiname[p - path] = *p; #else - const char *realname = f; + const char *asciiname = f; #endif - struct Token *t = tokenize_buf(realname, ret.sbase); - // everything is THING() or THING {} so we need at least 3 tokens ahead - if - // we have fewer tokens left in the file we can bail - if (t && t->next) while (t->next->next) { - if (!t->at_bol) { - t = t->next; - continue; + ret.lexer = clex(ret.sbase, len, (u32 *)mem + (len >> 2), asciiname); + if (ret.lexer.err) die(2, ret.lexer.err); + // everything is THING() or THING {}, and file also ends in an EOL, so once + // there's less than 4 tokens left in the file, we can bail. + for (u32 i = 0, end = ret.lexer.ntoks - 4; i < end; ++i) { + if_hot (ret.lexer.toks[i] != CLEX_TOK_IDENT) continue; + // technically we don't have to validate *every* token, but doing so + // gives less confusing syntax errors. + struct clex_ident_validate_ret val = clex_ident_validate( + &ret.lexer, ret.sbase, i); + if (val.err) { + char buf[CLEX_IDENT_ERRSTR_MEMREQ(PATH_MAX)]; + clex_ident_errstr(buf, ret.sbase, val.err, val.err_off, asciiname); + die(2, buf); } + // everything we match has to be followed by either ( or { + if (ret.lexer.toks[i + 1] != CLEX_TOK_OP1) { ++i; continue; } + if (val.len > 24) continue; // longer than the longest string below + char name[24]; + clex_ident(&ret.lexer, ret.sbase, i, name); int type; - if ((equal(t, "DEF_CVAR") || equal(t, "DEF_CVAR_MIN") || - equal(t, "DEF_CVAR_MAX") || equal(t, "DEF_CVAR_MINMAX") || - equal(t, "DEF_CVAR_UNREG") || equal(t, "DEF_CVAR_MIN_UNREG") || - equal(t, "DEF_CVAR_MAX_UNREG") || - equal(t, "DEF_CVAR_MINMAX_UNREG") || - equal(t, "DEF_FEAT_CVAR") || equal(t, "DEF_FEAT_CVAR_MIN") || - equal(t, "DEF_FEAT_CVAR_MAX") || - equal(t, "DEF_FEAT_CVAR_MINMAX")) && equal(t->next, "(")) { - type = CMETA_ITEM_DEF_CVAR; - } - else if ((equal(t, "DEF_CCMD") || equal(t, "DEF_CCMD_HERE") || - equal(t, "DEF_CCMD_UNREG") || equal(t, "DEF_CCMD_HERE_UNREG") || - equal(t, "DEF_CCMD_PLUSMINUS") || - equal(t, "DEF_CCMD_PLUSMINUS_UNREG") || - equal(t, "DEF_FEAT_CCMD") || equal(t, "DEF_FEAT_CCMD_HERE") || - equal(t, "DEF_FEAT_CCMD_PLUSMINUS")) && equal(t->next, "(")) { - type = CMETA_ITEM_DEF_CCMD; - } - else if ((equal(t, "DEF_EVENT") || equal(t, "DEF_PREDICATE")) && - equal(t->next, "(")) { - type = CMETA_ITEM_DEF_EVENT; - } - else if (equal(t, "HANDLE_EVENT") && equal(t->next, "(")) { - type = CMETA_ITEM_HANDLE_EVENT; - } - else if (equal(t, "FEATURE") && equal(t->next, "(")) { - type = CMETA_ITEM_FEATURE; - } - else if ((equal(t, "REQUIRE") || equal(t, "REQUIRE_GAMEDATA") || - equal(t, "REQUIRE_GLOBAL") || equal(t, "REQUEST")) && - equal(t->next, "(")) { - type = CMETA_ITEM_REQUIRE; - } - else if (equal(t, "GAMESPECIFIC") && equal(t->next, "(")) { - type = CMETA_ITEM_GAMESPECIFIC; - } - else if (equal(t, "PREINIT") && equal(t->next, "{")) { - type = CMETA_ITEM_PREINIT; + int flags = 0; + char nextop = '('; + // this is kind of dumb code. oh well, good enough probably. + switch (val.len) { + case 3: + if (!memcmp(name, "END", 3)) { + type = CMETA_ITEM_END; + nextop = '{'; + break; + } + continue; + case 4: + if (!memcmp(name, "INIT", 4)) { + type = CMETA_ITEM_INIT; + nextop = '{'; + break; + } + continue; + case 7: + if (!memcmp(name, "FEATURE", 7)) { + type = CMETA_ITEM_FEATURE; + break; + } + if (!memcmp(name, "PREINIT", 7)) { + type = CMETA_ITEM_PREINIT; + nextop = '{'; + break; + } + if (!memcmp(name, "REQUIRE", 7)) { + type = CMETA_ITEM_REQUIRE; + break; + } + if (!memcmp(name, "REQUEST", 7)) { + type = CMETA_ITEM_REQUIRE; + flags = CMETA_REQUIRE_OPTIONAL; + break; + } + continue; + case 8: + if (!memcmp(name, "DEF_CCMD", 8)) { + type = CMETA_ITEM_DEF_CCMD; + break; + } + if (!memcmp(name, "DEF_CVAR", 8)) { + type = CMETA_ITEM_DEF_CVAR; + break; + } + continue; + case 9: + if (!memcmp(name, "DEF_EVENT", 9)) { + type = CMETA_ITEM_DEF_EVENT; + break; + } + continue; + case 12: + if (!memcmp(name, "DEF_CVAR_MAX", 12) || + !memcmp(name, "DEF_CVAR_MIN", 12)) { + type = CMETA_ITEM_DEF_CVAR; + break; + } + if (!memcmp(name, "GAMESPECIFIC", 12)) { + type = CMETA_ITEM_GAMESPECIFIC; + break; + } + if (!memcmp(name, "HANDLE_EVENT", 12)) { + type = CMETA_ITEM_HANDLE_EVENT; + break; + } + continue; + case 13: + if (!memcmp(name, "DEF_CCMD_HERE", 13)) { + type = CMETA_ITEM_DEF_CCMD; + break; + } + if (!memcmp(name, "DEF_FEAT_CCMD", 13)) { + type = CMETA_ITEM_DEF_CCMD; + flags = CMETA_CVAR_FEAT; + break; + } + if (!memcmp(name, "DEF_FEAT_CVAR", 13)) { + type = CMETA_ITEM_DEF_CVAR; + flags = CMETA_CVAR_FEAT; + break; + } + if (!memcmp(name, "DEF_PREDICATE", 13)) { + type = CMETA_ITEM_DEF_EVENT; + flags = CMETA_EVENT_ISPREDICATE; + break; + } + continue; + case 14: + if (!memcmp(name, "DEF_CCMD_UNREG", 14)) { + type = CMETA_ITEM_DEF_CCMD; + flags = CMETA_CCMD_UNREG; + break; + } + if (!memcmp(name, "DEF_CVAR_UNREG", 14)) { + type = CMETA_ITEM_DEF_CVAR; + flags = CMETA_CVAR_UNREG; + break; + } + if (!memcmp(name, "REQUIRE_GLOBAL", 14)) { + type = CMETA_ITEM_REQUIRE; + flags = CMETA_REQUIRE_GLOBAL; + break; + } + continue; + case 15: + if (!memcmp(name, "DEF_CVAR_MINMAX", 15)) { + type = CMETA_ITEM_DEF_CVAR; + break; + } + continue; + case 16: + if (!memcmp(name, "REQUIRE_GAMEDATA", 16)) { + type = CMETA_ITEM_REQUIRE; + flags = CMETA_REQUIRE_GAMEDATA; + break; + } + continue; + case 17: + if (!memcmp(name, "DEF_FEAT_CVAR_MAX", 17) || + !memcmp(name, "DEF_FEAT_CVAR_MIN", 17)) { + type = CMETA_ITEM_DEF_CVAR; + flags = CMETA_CVAR_FEAT; + break; + } + continue; + case 18: + if (!memcmp(name, "DEF_CCMD_PLUSMINUS", 18)) { + type = CMETA_ITEM_DEF_CCMD; + flags = CMETA_CCMD_PLUSMINUS; + break; + } + if (!memcmp(name, "DEF_CVAR_MAX_UNREG", 18) || + !memcmp(name, "DEF_CVAR_MIN_UNREG", 18)) { + type = CMETA_ITEM_DEF_CVAR; + flags = CMETA_CVAR_UNREG; + break; + } + if (!memcmp(name, "DEF_FEAT_CCMD_HERE", 18)) { + type = CMETA_ITEM_DEF_CCMD; + flags = CMETA_CCMD_FEAT; + break; + } + continue; + case 19: + if (!memcmp(name, "DEF_CCMD_HERE_UNREG", 19)) { + type = CMETA_ITEM_DEF_CCMD; + flags = CMETA_CCMD_UNREG; + break; + } + continue; + case 20: + if (!memcmp(name, "DEF_FEAT_CVAR_MINMAX", 20)) { + type = CMETA_ITEM_DEF_CVAR; + flags = CMETA_CVAR_FEAT; + break; + } + continue; + case 21: + if (!memcmp(name, "DEF_CVAR_MINMAX_UNREG", 21)) { + type = CMETA_ITEM_DEF_CVAR; + flags = CMETA_CVAR_UNREG; + break; + } + continue; + case 23: + if (!memcmp(name, "DEF_FEAT_CCMD_PLUSMINUS", 23)) { + type = CMETA_ITEM_DEF_CCMD; + flags = CMETA_CCMD_FEAT | CMETA_CCMD_PLUSMINUS; + break; + } + continue; + case 24: + if (!memcmp(name, "DEF_CCMD_PLUSMINUS_UNREG", 24)) { + type = CMETA_ITEM_DEF_CCMD; + flags = CMETA_CCMD_UNREG | CMETA_CCMD_PLUSMINUS; + break; + } + default: + continue; } - else if (equal(t, "INIT") && equal(t->next, "{")) { - type = CMETA_ITEM_INIT; - } - else if (equal(t, "END") && equal(t->next, "{")) { - type = CMETA_ITEM_END; - } - else { - t = t->next; + if (ret.sbase[ret.lexer.tokoffs[i + 1]] != nextop) { + // bump i a little further as we've already looked at at least 2 + // tokens. this is technically kind of inefficient; in most cases we + // can skip more stuff, but we're always scanning for something + // specific, so who cares actually, this is good enough. + ++i; continue; } - ret.itemtoks[ret.nitems] = t; - ret.itemtypes[ret.nitems] = type; + ret.itemtoks[ret.nitems] = i; + ret.items[ret.nitems] = (struct cmeta_item){type, flags}; ++ret.nitems; - // this is kind of inefficient; in most cases we can skip more stuff, - // but then also, we're always scanning for something specific, so who - // cares actually, this will do for now. - t = t->next->next; + ++i; } return ret; } -int cmeta_flags_cvar(const struct cmeta *cm, u32 i) { - struct Token *t = cm->itemtoks[i]; - switch_exhaust (t->len) { - // It JUST so happens all of the possible tokens here have a unique - // length. I swear this wasn't planned. But it IS convenient! - case 8: case 12: case 15: return 0; - case 14: case 18: case 21: return CMETA_CVAR_UNREG; - case 13: case 17: case 20: return CMETA_CVAR_FEAT; - } -} - -int cmeta_flags_ccmd(const struct cmeta *cm, u32 i) { - struct Token *t = cm->itemtoks[i]; - switch_exhaust (t->len) { - case 13: if (t->loc[4] == 'F') return CMETA_CCMD_FEAT; - case 8: return 0; - case 18: if (t->loc[4] == 'F') return CMETA_CCMD_FEAT; - return CMETA_CCMD_PLUSMINUS; - case 14: case 19: return CMETA_CCMD_UNREG; - case 23: return CMETA_CCMD_FEAT | CMETA_CCMD_PLUSMINUS; - case 24: return CMETA_CCMD_UNREG | CMETA_CCMD_PLUSMINUS; - } -} - -int cmeta_flags_event(const struct cmeta *cm, u32 i) { - // assuming CMETA_EVENT_ISPREDICATE remains 1, the ternary should - // optimise out - return cm->itemtoks[i]->len == 13 ? CMETA_EVENT_ISPREDICATE : 0; -} - -int cmeta_flags_require(const struct cmeta *cm, u32 i) { - struct Token *t = cm->itemtoks[i]; - // NOTE: this is somewhat more flexible to enable REQUEST_GAMEDATA or - // something in future, although that's kind of useless currently - int optflag = t->loc[4] == 'E'; // REQU[E]ST - switch_exhaust (t->len) { - case 7: return optflag; - case 16: return optflag | CMETA_REQUIRE_GAMEDATA; - case 14: return optflag | CMETA_REQUIRE_GLOBAL; - }; -} - -int cmeta_nparams(const struct cmeta *cm, u32 i) { +int cmeta_nparams(const struct cmeta *cm, u32 item) { int argc = 1, nest = 0; - struct Token *t = cm->itemtoks[i]->next->next; - if (equal(t, ")")) return 0; // XXX: stupid special case, surely improvable? - for (; t; t = t->next) { - if (equal(t, "(")) { ++nest; continue; } - if (!nest && equal(t, ",")) ++argc; - else if (equal(t, ")") && !nest--) break; + int i = cm->itemtoks[item] + 2; // get past the first ( + // handle immediate ) - XXX: stupid special case, surely improvable? + if (clex_isrparen(&cm->lexer, cm->sbase, i)) return 0; + for (; i < cm->lexer.ntoks; ++i) { + if (clex_islparen(&cm->lexer, cm->sbase, i)) { ++nest; continue; } + if (!nest && clex_iscomma(&cm->lexer, cm->sbase, i)) ++argc; + else if (clex_isrparen(&cm->lexer, cm->sbase, i) && !nest--) break; } if (nest != -1) return 0; // XXX: any need to do anything better here? return argc; } struct cmeta_param_iter cmeta_param_iter_init(const struct cmeta *cm, u32 i) { - return (struct cmeta_param_iter){cm->itemtoks[i]->next->next}; + return (struct cmeta_param_iter){cm->itemtoks[i] + 2}; } -struct cmeta_slice cmeta_param_iter(struct cmeta_param_iter *it) { +struct cmeta_slice cmeta_param_iter(const struct cmeta *cm, + struct cmeta_param_iter *it) { int nest = 0; - const char *start = it->cur->loc; - for (struct Token *last = 0; it->cur; - last = it->cur, it->cur = it->cur->next) { - if (equal(it->cur, "(")) { ++nest; continue; } - if (!nest && equal(it->cur, ",")) { - if (!last) { // , immediately after (, for some reason. treat as "" - return (struct cmeta_slice){start, 0}; - } - it->cur = it->cur->next; + const char *start = cm->sbase + cm->lexer.tokoffs[it->i]; + for (; it->i < cm->lexer.ntoks; ++it->i) { + if (clex_islparen(&cm->lexer, cm->sbase, it->i)) { + ++nest; + continue; } - else if (equal(it->cur, ")") && !nest--) { - if (!last) break; + if (!nest && clex_iscomma(&cm->lexer, cm->sbase, it->i)) { + const char *end = cm->sbase + cm->lexer.tokoffs[it->i]; + // XXX: to avoid picking up random whitespace we should get the + // previous token and ask clex for its extent, but I've not yet + // implemented full parsing of all variable-length tokens (i.e. + // numbers and string/char literals). not worrying about it too much + // at the moment since it's not really a problem anyway in practice + ++it->i; // skip past comma for next time + return (struct cmeta_slice){start, end - start}; } - else { - continue; + else if (clex_isrparen(&cm->lexer, cm->sbase, it->i) && !nest--) { + // annoying case: 0 args is different from ", )" (empty arg) + if (clex_islparen(&cm->lexer, cm->sbase, it->i - 1)) break; + const char *end = cm->sbase + cm->lexer.tokoffs[it->i]; + it->i = -1u; // force next call to return {0, 0} + return (struct cmeta_slice){start, end - start}; } - return (struct cmeta_slice){start, last->loc - start + last->len}; } return (struct cmeta_slice){0, 0}; } -u32 cmeta_line(const struct cmeta *cm, u32 i) { - return cm->itemtoks[i]->line_no; +cold u32 cmeta_line(const struct cmeta *cm, u32 i) { + u32 line = 1; + for (u32 off = 0, end = cm->lexer.tokoffs[cm->itemtoks[i]]; + off != end; ++off) { + line += cm->sbase[off] == '\n'; + } + return line; } // vi: sw=4 ts=4 noet tw=80 cc=80 fdm=marker diff --git a/src/build/cmeta.h b/src/build/cmeta.h index e7c275d..c18adbb 100644 --- a/src/build/cmeta.h +++ b/src/build/cmeta.h @@ -17,33 +17,23 @@ #ifndef INC_CMETA_H #define INC_CMETA_H +#include "../chunklets/clex.h" /* XXX: only need this for struct, kinda leaky */ #include "../intdefs.h" #include "../os.h" -// XXX: leaking chibicc internals. won't matter after we do away with that -typedef struct Token Token; - -enum cmeta_item { - CMETA_ITEM_DEF_CVAR, // includes all min/max/unreg variants - CMETA_ITEM_DEF_CCMD, // includes plusminus/unreg variants - CMETA_ITEM_DEF_EVENT, // includes predicates +enum cmeta_itemtype { + CMETA_ITEM_DEF_CVAR, /* includes all min/max/unreg variants */ + CMETA_ITEM_DEF_CCMD, /* includes plusminus/unreg variants */ + CMETA_ITEM_DEF_EVENT, /* includes predicates */ CMETA_ITEM_HANDLE_EVENT, CMETA_ITEM_FEATURE, - CMETA_ITEM_REQUIRE, // includes all REQUIRE_*/REQUEST variants + CMETA_ITEM_REQUIRE, /* includes all REQUIRE_* and REQUEST variants */ CMETA_ITEM_GAMESPECIFIC, CMETA_ITEM_PREINIT, CMETA_ITEM_INIT, CMETA_ITEM_END }; -struct cmeta { - char *sbase; - u32 nitems; // number of interesting macros - //u32 *itemoffs; // file offsets of interesting macros (ONE DAY!) - Token **itemtoks; // crappy linked token structures, for the time being - u8 *itemtypes; // CMETA_ITEM_* enum values -}; - enum cmeta_flag_cvar { CMETA_CVAR_UNREG = 1, CMETA_CVAR_FEAT = 2, @@ -57,28 +47,37 @@ enum cmeta_flag_event { CMETA_EVENT_ISPREDICATE = 1 }; enum cmeta_flag_require { - CMETA_REQUIRE_OPTIONAL = 1, // i.e. REQUEST() macro, could be extended + CMETA_REQUIRE_OPTIONAL = 1, /* i.e. REQUEST() macro, could be extended */ CMETA_REQUIRE_GAMEDATA = 2, CMETA_REQUIRE_GLOBAL = 4 }; +struct cmeta { + char *sbase; + u32 nitems; /* number of interesting macros */ + //char pad[4]; + struct cmeta_item { + u8 type : 4; /* CMETA_ITEM_* enum value */ + u8 flags : 4; /* relevant flags (see above) */ + } *items; + u32 *itemtoks; /* internal */ + struct clex lexer; /* internal */ +}; + struct cmeta_slice { const char *s; int len; }; struct cmeta cmeta_loadfile(const os_char *path); -int cmeta_flags_cvar(const struct cmeta *cm, u32 i); -int cmeta_flags_ccmd(const struct cmeta *cm, u32 i); -int cmeta_flags_event(const struct cmeta *cm, u32 i); -int cmeta_flags_require(const struct cmeta *cm, u32 i); int cmeta_nparams(const struct cmeta *cm, u32 i); -struct cmeta_param_iter { Token *cur; }; +struct cmeta_param_iter { u32 i; }; struct cmeta_param_iter cmeta_param_iter_init(const struct cmeta *cm, u32 i); -struct cmeta_slice cmeta_param_iter(struct cmeta_param_iter *it); +struct cmeta_slice cmeta_param_iter(const struct cmeta *cm, + struct cmeta_param_iter *it); -#define cmeta_param_foreach(varname, cm, u32) \ +#define cmeta_param_foreach(varname, cm, i) \ switch (0) for (struct cmeta_slice varname; 0;) default: \ for (struct cmeta_param_iter _it = cmeta_param_iter_init(cm, i); \ - varname = cmeta_param_iter(&_it), varname.s;) \ + varname = cmeta_param_iter(cm, &_it), varname.s;) \ /* {...} */ u32 cmeta_line(const struct cmeta *cm, u32 i); diff --git a/src/build/gluegen.c b/src/build/gluegen.c index a055241..33ba600 100644 --- a/src/build/gluegen.c +++ b/src/build/gluegen.c @@ -324,21 +324,23 @@ static inline void handle(s16 mod, s16 mods, s16 *featdescs, s16 *events, struct list_chunkhdr *tail_gamedata = &mod_gamedata[mod].hdr; struct list_chunkhdr *tail_globals = &mod_globals[mod].hdr; for (u32 i = 0; i != cm->nitems; ++i) { - switch_exhaust_enum(cmeta_item, cm->itemtypes[i]) { + struct cmeta_item item = cm->items[i]; + switch_exhaust_enum(cmeta_itemtype, item.type) { case CMETA_ITEM_DEF_CVAR: if_cold (!cmeta_nparams(cm, i)) { diefile(2, file, cmeta_line(cm, i), "cvar macro missing required parameter"); } - int flags = cmeta_flags_cvar(cm, i); s16 idx = cvar_new(); - cvar_flags[idx] = flags; + cvar_flags[idx] = item.flags; // NOTE: always hooking cvar/ccmd up to a feat entry for // GAMESPECIFIC checks, even if it's not a DEF_FEAT_*. // If a module doesn't declare FEATURE, its cvars/ccmds will // end up getting initialised/registered unconditionally. cvar_feats[idx] = mod; - if (flags & CMETA_CVAR_FEAT) needfeat = "feature cvar defined"; + if (item.flags & CMETA_CVAR_FEAT) { + needfeat = "feature cvar defined"; + } cmeta_param_foreach (name, cm, i) { cvar_names[idx] = name; break; // ignore subsequent args @@ -349,15 +351,14 @@ static inline void handle(s16 mod, s16 mods, s16 *featdescs, s16 *events, diefile(2, file, cmeta_line(cm, i), "ccmd macro missing required parameter"); } - flags = cmeta_flags_ccmd(cm, i); - if (flags & CMETA_CCMD_FEAT) { + if (item.flags & CMETA_CCMD_FEAT) { needfeat = "feature ccmd defined"; } - if (flags & CMETA_CCMD_PLUSMINUS) { + if (item.flags & CMETA_CCMD_PLUSMINUS) { // split PLUSMINUS entries in two; makes stuff easier later. - flags &= ~CMETA_CCMD_PLUSMINUS; + item.flags &= ~CMETA_CCMD_PLUSMINUS; idx = ccmd_new(); - ccmd_flags[idx] = flags; + ccmd_flags[idx] = item.flags; ccmd_feats[idx] = mod; cmeta_param_foreach (name, cm, i) { char *s = arena + arena_new(5 + name.len); @@ -367,7 +368,7 @@ static inline void handle(s16 mod, s16 mods, s16 *featdescs, s16 *events, break; } idx = ccmd_new(); - ccmd_flags[idx] = flags; + ccmd_flags[idx] = item.flags; ccmd_feats[idx] = mod; cmeta_param_foreach (name, cm, i) { char *s = arena + arena_new(6 + name.len); @@ -379,7 +380,7 @@ static inline void handle(s16 mod, s16 mods, s16 *featdescs, s16 *events, } else { idx = ccmd_new(); - ccmd_flags[idx] = flags; + ccmd_flags[idx] = item.flags; ccmd_feats[idx] = mod; cmeta_param_foreach (name, cm, i) { ccmd_names[idx] = name; @@ -392,9 +393,8 @@ static inline void handle(s16 mod, s16 mods, s16 *featdescs, s16 *events, diefile(2, file, cmeta_line(cm, i), "event macro missing required parameter"); } - flags = cmeta_flags_event(cm, i); struct cmeta_param_iter it = cmeta_param_iter_init(cm, i); - struct cmeta_slice evname = cmeta_param_iter(&it); + struct cmeta_slice evname = cmeta_param_iter(cm, &it); struct radix_insert_ret r = radix_insert(events, event_names, evname.s, evname.len, false); int e; @@ -412,10 +412,11 @@ static inline void handle(s16 mod, s16 mods, s16 *featdescs, s16 *events, } } event_owners[e] = mod; - event_predicateflags[e] = !!(flags & CMETA_EVENT_ISPREDICATE); + event_predicateflags[e] = !!( + item.flags & CMETA_EVENT_ISPREDICATE); struct list_chunkhdr *tail = &event_params[e].hdr; - for (struct cmeta_slice param; param = cmeta_param_iter(&it), - param.s;) { + for (struct cmeta_slice param; + param = cmeta_param_iter(cm, &it), param.s;) { list_append(&tail, param); } break; @@ -426,7 +427,7 @@ static inline void handle(s16 mod, s16 mods, s16 *featdescs, s16 *events, "event handler macro missing required parameter"); } it = cmeta_param_iter_init(cm, i); - evname = cmeta_param_iter(&it); + evname = cmeta_param_iter(cm, &it); r = radix_insert(events, event_names, evname.s, evname.len, false); if (r.isnew) { @@ -459,9 +460,8 @@ static inline void handle(s16 mod, s16 mods, s16 *featdescs, s16 *events, diefile(2, file, cmeta_line(cm, i), "dependency macro missing required parameter"); } - flags = cmeta_flags_require(cm, i); struct list_chunkhdr **tailp; - switch_exhaust(flags) { + switch_exhaust(item.flags) { case 0: tailp = &tail_needs; break; case CMETA_REQUIRE_OPTIONAL: tailp = &tail_wants; break; case CMETA_REQUIRE_GAMEDATA: tailp = &tail_gamedata; break; @@ -469,7 +469,7 @@ static inline void handle(s16 mod, s16 mods, s16 *featdescs, s16 *events, } cmeta_param_foreach(param, cm, i) { int modflags = 0; - switch_exhaust(flags) { + switch_exhaust(item.flags) { case CMETA_REQUIRE_OPTIONAL: modflags = HAS_OPTDEPS; case 0: |
