From 0c75182aabcc4d93a7216defede6e8cba5a46690 Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Fri, 16 Nov 2012 19:01:44 +0100 Subject: [PATCH] Some #if parsing --- ftepp.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 112 insertions(+), 18 deletions(-) diff --git a/ftepp.c b/ftepp.c index 769310b..c487058 100644 --- a/ftepp.c +++ b/ftepp.c @@ -32,6 +32,13 @@ typedef struct { typedef struct { int token; char *value; + /* a copy from the lexer */ + union { + vector v; + int i; + double f; + int t; /* type */ + } constval; } pptoken; typedef struct { @@ -42,7 +49,7 @@ typedef struct { /* yes we need an extra flag since `#define FOO x` is not the same as `#define FOO() x` */ bool has_params; - pptoken *output; + pptoken **output; } ppmacro; typedef struct { @@ -134,18 +141,17 @@ 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"); - return false; + if (ftepp->token >= TOKEN_EOF) { + ftepp_error(ftepp, "unexpected end of preprocessor directive"); + return false; + } + return true; } -static bool ftepp_ifdef(ftepp_t *ftepp, ppcondition *cond) +/** + * The huge macro parsing code... + */ +static bool ftepp_define(ftepp_t *ftepp) { ppmacro *macro; (void)ftepp_next(ftepp); @@ -154,8 +160,9 @@ static bool ftepp_ifdef(ftepp_t *ftepp, ppcondition *cond) switch (ftepp->token) { case TOKEN_IDENT: + case TOKEN_TYPENAME: case TOKEN_KEYWORD: - macro = ftepp_macro_find(ftepp, ftepp_tokval(ftepp)); + macro = ppmacro_new(ftepp_ctx(ftepp), ftepp_tokval(ftepp)); break; default: ftepp_error(ftepp, "expected macro name"); @@ -166,24 +173,110 @@ static bool ftepp_ifdef(ftepp_t *ftepp, ppcondition *cond) if (!ftepp_skipspace(ftepp)) return false; if (ftepp->token != TOKEN_EOL) { - ftepp_error(ftepp, "stray tokens after #ifdef"); + ftepp_error(ftepp, "stray tokens after macro"); return false; } - cond->on = !!macro; + vec_push(ftepp->macros, macro); return true; } -static bool ftepp_define(ftepp_t *ftepp) +/** + * #if - the FTEQCC way: + * defined(FOO) => true if FOO was #defined regardless of parameters or contents + * => True if the number is not 0 + * ! => True if the factor yields false + * => becomes the macro's FIRST token regardless of parameters + * && => True if both expressions are true + * || => True if either expression is true + * => False + * => False (remember for macros the rule applies instead) + * Unary + and - are skipped + * parenthesis in expressions are allowed + * parameter lists on macros are errors + * No mathematical calculations are executed + */ +static bool ftepp_if_expr(ftepp_t *ftepp, bool *out) { ppmacro *macro; + while (ftepp->token != TOKEN_EOL) { + switch (ftepp->token) { + case TOKEN_IDENT: + case TOKEN_TYPENAME: + case TOKEN_KEYWORD: + macro = ftepp_macro_find(ftepp, ftepp_tokval(ftepp)); + if (!macro || !vec_size(macro->output)) { + *out = false; + } else { + /* This does not expand recursively! */ + switch (macro->output[0]->token) { + case TOKEN_INTCONST: + *out = !!(macro->output[0]->constval.f); + break; + case TOKEN_FLOATCONST: + *out = !!(macro->output[0]->constval.f); + break; + default: + *out = false; + break; + } + } + break; + case TOKEN_STRINGCONST: + *out = false; + break; + case TOKEN_INTCONST: + *out = !!(ftepp->lex->tok.constval.i); + break; + case TOKEN_FLOATCONST: + *out = !!(ftepp->lex->tok.constval.f); + break; + + default: + ftepp_error(ftepp, "junk in #if"); + return false; + } + } + (void)ftepp_next(ftepp); + return true; +} + +static bool ftepp_if(ftepp_t *ftepp, ppcondition *cond) +{ + bool result = false; + + memset(cond, 0, sizeof(*cond)); + (void)ftepp_next(ftepp); + + if (!ftepp_skipspace(ftepp)) + return false; + if (ftepp->token == TOKEN_EOL) { + ftepp_error(ftepp, "expected expression for #if-directive"); + return false; + } + + if (!ftepp_if_expr(ftepp, &result)) + return false; + + cond->on = result; + return true; +} + +/** + * ifdef is rather simple + */ +static bool ftepp_ifdef(ftepp_t *ftepp, ppcondition *cond) +{ + ppmacro *macro; + memset(cond, 0, sizeof(*cond)); (void)ftepp_next(ftepp); if (!ftepp_skipspace(ftepp)) return false; switch (ftepp->token) { case TOKEN_IDENT: + case TOKEN_TYPENAME: case TOKEN_KEYWORD: - macro = ppmacro_new(ftepp_ctx(ftepp), ftepp_tokval(ftepp)); + macro = ftepp_macro_find(ftepp, ftepp_tokval(ftepp)); break; default: ftepp_error(ftepp, "expected macro name"); @@ -194,10 +287,10 @@ static bool ftepp_define(ftepp_t *ftepp) if (!ftepp_skipspace(ftepp)) return false; if (ftepp->token != TOKEN_EOL) { - ftepp_error(ftepp, "stray tokens after macro"); + ftepp_error(ftepp, "stray tokens after #ifdef"); return false; } - vec_push(ftepp->macros, macro); + cond->on = !!macro; return true; } @@ -228,6 +321,7 @@ static bool ftepp_hash(ftepp_t *ftepp) switch (ftepp->token) { case TOKEN_KEYWORD: case TOKEN_IDENT: + case TOKEN_TYPENAME: if (!strcmp(ftepp_tokval(ftepp), "define")) { return ftepp_define(ftepp); } -- 2.39.2