Support for "#if defined" in preprocessor.
authorRyan C. Gordon <icculus@icculus.org>
Tue, 24 Feb 2009 03:00:21 -0500
changeset 699 c2f50b391d96
parent 698 a6cd16b3e270
child 700 2213a232d2fb
Support for "#if defined" in preprocessor.
mojoshader_preprocessor.c
--- a/mojoshader_preprocessor.c	Tue Feb 24 02:57:47 2009 -0500
+++ b/mojoshader_preprocessor.c	Tue Feb 24 03:00:21 2009 -0500
@@ -460,6 +460,17 @@
 } // find_define
 
 
+static const Define *find_define_by_token(Context *ctx)
+{
+    IncludeState *state = ctx->include_stack;
+    assert(state->tokenval == TOKEN_IDENTIFIER);
+    char *sym = (char *) alloca(state->tokenlen+1);
+    memcpy(sym, state->token, state->tokenlen);
+    sym[state->tokenlen] = '\0';
+    return find_define(ctx, sym);
+} // find_define_by_token
+
+
 static void put_all_defines(Context *ctx)
 {
     int i;
@@ -928,6 +939,13 @@
     memcpy(sym, state->token, state->tokenlen);
     sym[state->tokenlen] = '\0';
 
+    if (strcmp(sym, "defined") == 0)
+    {
+        Free(ctx, sym);
+        fail(ctx, "'defined' cannot be used as a macro name");
+        return;
+    } // if
+
     // #define a(b) is different than #define a (b)    :(
     state->report_whitespace = 1;
     lexer(state);
@@ -1429,6 +1447,33 @@
                 if (handle_pp_identifier(ctx))
                     continue;  // go again with new IncludeState.
 
+                if ( (state->tokenlen == 7) &&
+                     (memcmp(state->token, "defined", 7) == 0) )
+                {
+                    token = lexer(state);
+                    const int paren = (token == ((Token) '('));
+                    if (paren)  // gcc doesn't let us nest parens here, either.
+                        token = lexer(state);
+                    if (token != TOKEN_IDENTIFIER)
+                    {
+                        fail(ctx, "operator 'defined' requires an identifier");
+                        return -1;
+                    } // if
+                    const int found = (find_define_by_token(ctx) != NULL);
+
+                    if (paren)
+                    {
+                        if (lexer(state) != ((Token) ')'))
+                        {
+                            fail(ctx, "Unmatched ')'");
+                            return -1;
+                        } // if
+                    } // if
+
+                    ADD_TO_OUTPUT(0, found);
+                    continue;
+                } // if
+
                 // can't replace identifier with a number? It becomes zero.
                 token = TOKEN_INT_LITERAL;
                 ADD_TO_OUTPUT(0, 0);