From: Wolfgang (Blub) Bumiller Date: Fri, 16 Nov 2012 17:27:32 +0000 (+0100) Subject: macro structure, parsing ifdefs and non-macro defines X-Git-Tag: 0.1.9~404^2~56 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=cc1c197fc6c80721ae7c12e316cd06bcbc1a57a6;p=xonotic%2Fgmqcc.git macro structure, parsing ifdefs and non-macro defines --- diff --git a/ftepp.c b/ftepp.c index 877fee3..7b31a60 100644 --- a/ftepp.c +++ b/ftepp.c @@ -29,6 +29,22 @@ typedef struct { bool had_else; } ppcondition; +typedef struct { + int token; + char *value; +} pptoken; + +typedef struct { + lex_ctx ctx; + + char *name; + char **params; + /* yes we need an extra flag since `#define FOO x` is not the same as `#define FOO() x` */ + bool has_params; + + pptoken *output; +} ppmacro; + typedef struct { lex_file *lex; int token; @@ -36,6 +52,7 @@ typedef struct { unsigned int errors; ppcondition *conditions; + ppmacro **macros; } ftepp_t; #define ftepp_tokval(f) ((f)->lex->tok.value) @@ -63,6 +80,22 @@ static void ftepp_error(ftepp_t *ftepp, const char *fmt, ...) va_end(ap); } +ppmacro *ppmacro_new(lex_ctx ctx, const char *name) +{ + ppmacro *macro = (ppmacro*)mem_a(sizeof(ppmacro)); + memset(macro, 0, sizeof(*macro)); + macro->name = util_strdup(name); + return macro; +} + +void ppmacro_delete(ppmacro *self) +{ + vec_free(self->params); + vec_free(self->output); + mem_d(self->name); + mem_d(self); +} + ftepp_t* ftepp_init() { ftepp_t *ftepp; @@ -73,6 +106,23 @@ ftepp_t* ftepp_init() return ftepp; } +void ftepp_delete(ftepp_t *self) +{ + vec_free(self->macros); + vec_free(self->conditions); + mem_d(self); +} + +ppmacro* ftepp_macro_find(ftepp_t *ftepp, const char *name) +{ + size_t i; + for (i = 0; i < vec_size(ftepp->macros); ++i) { + if (!strcmp(name, ftepp->macros[i]->name)) + return ftepp->macros[i]; + } + return NULL; +} + static inline int ftepp_next(ftepp_t *ftepp) { return (ftepp->token = lex_do(ftepp->lex)); @@ -81,10 +131,14 @@ static inline int ftepp_next(ftepp_t *ftepp) /* Important: this does not skip newlines! */ static bool ftepp_skipspace(ftepp_t *ftepp) { + if (ftepp->token != TOKEN_WHITE) + return true; while (ftepp_next(ftepp) == TOKEN_WHITE) {} return (ftepp->token < TOKEN_EOF); } +/* if/ifdef/define handlers */ + static bool ftepp_if(ftepp_t *ftepp, ppcondition *cond) { ftepp_error(ftepp, "TODO: #if"); @@ -93,16 +147,61 @@ static bool ftepp_if(ftepp_t *ftepp, ppcondition *cond) static bool ftepp_ifdef(ftepp_t *ftepp, ppcondition *cond) { - ftepp_error(ftepp, "TODO: #ifdef"); - return false; + ppmacro *macro; + (void)ftepp_next(ftepp); + if (!ftepp_skipspace(ftepp)) + return false; + + switch (ftepp->token) { + case TOKEN_IDENT: + case TOKEN_KEYWORD: + macro = ftepp_macro_find(ftepp, ftepp_tokval(ftepp)); + break; + default: + ftepp_error(ftepp, "expected macro name"); + return false; + } + + (void)ftepp_next(ftepp); + if (!ftepp_skipspace(ftepp)) + return false; + if (ftepp->token != TOKEN_EOL) { + ftepp_error(ftepp, "stray tokens after #ifdef"); + return false; + } + cond->on = !!macro; + return true; } static bool ftepp_define(ftepp_t *ftepp) { - ftepp_error(ftepp, "TODO: #define"); - return false; + ppmacro *macro; + (void)ftepp_next(ftepp); + if (!ftepp_skipspace(ftepp)) + return false; + + switch (ftepp->token) { + case TOKEN_IDENT: + case TOKEN_KEYWORD: + macro = ppmacro_new(ftepp_ctx(ftepp), ftepp_tokval(ftepp)); + break; + default: + ftepp_error(ftepp, "expected macro name"); + return false; + } + + (void)ftepp_next(ftepp); + if (!ftepp_skipspace(ftepp)) + return false; + if (ftepp->token != TOKEN_EOL) { + ftepp_error(ftepp, "stray tokens after macro"); + return false; + } + vec_push(ftepp->macros, macro); + return true; } +/* Basic structure handlers */ static bool ftepp_else_allowed(ftepp_t *ftepp) { if (!vec_size(ftepp->conditions)) { @@ -127,6 +226,7 @@ static bool ftepp_hash(ftepp_t *ftepp) return false; switch (ftepp->token) { + case TOKEN_KEYWORD: case TOKEN_IDENT: if (!strcmp(ftepp_tokval(ftepp), "define")) { return ftepp_define(ftepp); @@ -202,14 +302,6 @@ static bool ftepp_hash(ftepp_t *ftepp) return false; } break; - case TOKEN_KEYWORD: - if (!strcmp(ftepp_tokval(ftepp), "if")) { - if (!ftepp_if(ftepp, &cond)) - return false; - vec_push(ftepp->conditions, cond); - return true; - } - /* fall through */ default: ftepp_error(ftepp, "unexpected preprocessor token: `%s`", ftepp_tokval(ftepp)); return false; @@ -229,10 +321,9 @@ static bool ftepp_preprocess(ftepp_t *ftepp) ftepp->lex->flags.preprocessing = true; + ftepp_next(ftepp); do { - ftepp_next(ftepp); - if (ftepp->token >= TOKEN_EOF) break; @@ -243,21 +334,30 @@ static bool ftepp_preprocess(ftepp_t *ftepp) case '#': if (!ftepp->newline) { printf("%s", ftepp_tokval(ftepp)); + ftepp_next(ftepp); + break; + } + if (ftepp_next(ftepp) >= TOKEN_EOF) { + ftepp_error(ftepp, "error in preprocessor directive"); + ftepp->token = TOKEN_ERROR; break; } if (!ftepp_hash(ftepp)) - return false; + ftepp->token = TOKEN_ERROR; break; case TOKEN_EOL: newline = true; printf("\n"); + ftepp_next(ftepp); break; default: printf("%s", ftepp_tokval(ftepp)); + ftepp_next(ftepp); break; } } while (!ftepp->errors && ftepp->token < TOKEN_EOF); + ftepp_delete(ftepp); return (ftepp->token == TOKEN_EOF); }