From: Wolfgang (Blub) Bumiller Date: Fri, 16 Nov 2012 16:46:16 +0000 (+0100) Subject: Basic structure of ftepp X-Git-Tag: 0.1.9~404^2~57 X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=commitdiff_plain;h=4bee1bdb6e2b7f25ac7fdd9e55cdb9d052c430a4 Basic structure of ftepp --- diff --git a/ftepp.c b/ftepp.c index b32c7aa..877fee3 100644 --- a/ftepp.c +++ b/ftepp.c @@ -24,10 +24,44 @@ #include "lexer.h" typedef struct { - lex_file *lex; + bool on; + bool was_on; + bool had_else; +} ppcondition; + +typedef struct { + lex_file *lex; + int token; + bool newline; + unsigned int errors; + + ppcondition *conditions; } ftepp_t; #define ftepp_tokval(f) ((f)->lex->tok.value) +#define ftepp_ctx(f) ((f)->lex->tok.ctx) + +static void ftepp_errorat(ftepp_t *ftepp, lex_ctx ctx, const char *fmt, ...) +{ + va_list ap; + + ftepp->errors++; + + va_start(ap, fmt); + con_vprintmsg(LVL_ERROR, ctx.file, ctx.line, "error", fmt, ap); + va_end(ap); +} + +static void ftepp_error(ftepp_t *ftepp, const char *fmt, ...) +{ + va_list ap; + + ftepp->errors++; + + va_start(ap, fmt); + con_vprintmsg(LVL_ERROR, ftepp->lex->tok.ctx.file, ftepp->lex->tok.ctx.line, "error", fmt, ap); + va_end(ap); +} ftepp_t* ftepp_init() { @@ -39,23 +73,192 @@ ftepp_t* ftepp_init() return ftepp; } +static inline int ftepp_next(ftepp_t *ftepp) +{ + return (ftepp->token = lex_do(ftepp->lex)); +} + +/* Important: this does not skip newlines! */ +static bool ftepp_skipspace(ftepp_t *ftepp) +{ + while (ftepp_next(ftepp) == TOKEN_WHITE) {} + return (ftepp->token < TOKEN_EOF); +} + +static bool ftepp_if(ftepp_t *ftepp, ppcondition *cond) +{ + ftepp_error(ftepp, "TODO: #if"); + return false; +} + +static bool ftepp_ifdef(ftepp_t *ftepp, ppcondition *cond) +{ + ftepp_error(ftepp, "TODO: #ifdef"); + return false; +} + +static bool ftepp_define(ftepp_t *ftepp) +{ + ftepp_error(ftepp, "TODO: #define"); + return false; +} + +static bool ftepp_else_allowed(ftepp_t *ftepp) +{ + if (!vec_size(ftepp->conditions)) { + ftepp_error(ftepp, "#else without #if"); + return false; + } + if (vec_last(ftepp->conditions).had_else) { + ftepp_error(ftepp, "multiple #else for a single #if"); + return false; + } + return true; +} + +static bool ftepp_hash(ftepp_t *ftepp) +{ + ppcondition cond; + ppcondition *pc; + + lex_ctx ctx = ftepp_ctx(ftepp); + + if (!ftepp_skipspace(ftepp)) + return false; + + switch (ftepp->token) { + case TOKEN_IDENT: + if (!strcmp(ftepp_tokval(ftepp), "define")) { + return ftepp_define(ftepp); + } + else if (!strcmp(ftepp_tokval(ftepp), "ifdef")) { + if (!ftepp_ifdef(ftepp, &cond)) + return false; + vec_push(ftepp->conditions, cond); + return true; + } + else if (!strcmp(ftepp_tokval(ftepp), "ifndef")) { + if (!ftepp_ifdef(ftepp, &cond)) + return false; + cond.on = !cond.on; + vec_push(ftepp->conditions, cond); + return true; + } + else if (!strcmp(ftepp_tokval(ftepp), "elifdef")) { + if (!ftepp_else_allowed(ftepp)) + return false; + if (!ftepp_ifdef(ftepp, &cond)) + return false; + pc = &vec_last(ftepp->conditions); + pc->on = !pc->was_on && cond.on; + pc->was_on = pc->was_on || pc->on; + return true; + } + else if (!strcmp(ftepp_tokval(ftepp), "elifndef")) { + if (!ftepp_else_allowed(ftepp)) + return false; + if (!ftepp_ifdef(ftepp, &cond)) + return false; + cond.on = !cond.on; + pc = &vec_last(ftepp->conditions); + pc->on = !pc->was_on && cond.on; + pc->was_on = pc->was_on || pc->on; + return true; + } + else if (!strcmp(ftepp_tokval(ftepp), "elif")) { + if (!ftepp_else_allowed(ftepp)) + return false; + if (!ftepp_if(ftepp, &cond)) + return false; + pc = &vec_last(ftepp->conditions); + pc->on = !pc->was_on && cond.on; + pc->was_on = pc->was_on || pc->on; + return true; + } + else if (!strcmp(ftepp_tokval(ftepp), "if")) { + if (!ftepp_if(ftepp, &cond)) + return false; + vec_push(ftepp->conditions, cond); + return true; + } + else if (!strcmp(ftepp_tokval(ftepp), "else")) { + if (!ftepp_else_allowed(ftepp)) + return false; + pc = &vec_last(ftepp->conditions); + pc->on = !pc->was_on; + pc->had_else = true; + return true; + } + else if (!strcmp(ftepp_tokval(ftepp), "endif")) { + if (!vec_size(ftepp->conditions)) { + ftepp_error(ftepp, "#endif without #if"); + return false; + } + vec_pop(ftepp->conditions); + break; + } + else { + ftepp_error(ftepp, "unrecognized preprocessor directive: `%s`", ftepp_tokval(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; + case TOKEN_EOL: + ftepp_errorat(ftepp, ctx, "empty preprocessor directive"); + return false; + case TOKEN_EOF: + ftepp_error(ftepp, "missing newline at end of file", ftepp_tokval(ftepp)); + return false; + } + return true; +} + static bool ftepp_preprocess(ftepp_t *ftepp) { - int token; + bool newline = true; ftepp->lex->flags.preprocessing = true; - for (token = lex_do(ftepp->lex); token < TOKEN_EOF; token = lex_do(ftepp->lex)) + do { - switch (token) { - case TOKEN_EOL: printf("\n"); break; + ftepp_next(ftepp); + + if (ftepp->token >= TOKEN_EOF) + break; + + ftepp->newline = newline; + newline = false; + + switch (ftepp->token) { + case '#': + if (!ftepp->newline) { + printf("%s", ftepp_tokval(ftepp)); + break; + } + if (!ftepp_hash(ftepp)) + return false; + break; + case TOKEN_EOL: + newline = true; + printf("\n"); + break; default: printf("%s", ftepp_tokval(ftepp)); break; } - } + } while (!ftepp->errors && ftepp->token < TOKEN_EOF); - return (token == TOKEN_EOF); + return (ftepp->token == TOKEN_EOF); } bool ftepp_preprocess_file(const char *filename)