mojoshader_preprocessor.c
changeset 685 687e9def5cc6
parent 684 aadf9aad508a
child 687 bb36744480e8
--- a/mojoshader_preprocessor.c	Mon Feb 23 17:21:48 2009 -0500
+++ b/mojoshader_preprocessor.c	Mon Feb 23 17:39:30 2009 -0500
@@ -1277,6 +1277,84 @@
     return -1;
 } // find_precedence
 
+// !!! FIXME: we're using way too much stack space here...
+typedef struct RpnTokens
+{
+    int isoperator;
+    int value;
+} RpnTokens;
+
+static long interpret_rpn(const RpnTokens *tokens, int tokencount, int *error)
+{
+    long stack[128];
+    int stacksize = 0;
+
+    *error = 1;
+
+    #define NEED_X_TOKENS(x) do { if (stacksize < x) return 0; } while (0)
+
+    #define BINARY_OPERATION(op) do { \
+        NEED_X_TOKENS(2); \
+        stack[stacksize-2] = stack[stacksize-2] op stack[stacksize-1]; \
+        stacksize--; \
+    } while (0)
+
+    #define UNARY_OPERATION(op) do { \
+        NEED_X_TOKENS(1); \
+        stack[stacksize-1] = op stack[stacksize-1]; \
+    } while (0)
+
+    while (tokencount-- > 0)
+    {
+        if (!tokens->isoperator)
+        {
+            assert(stacksize < STATICARRAYLEN(stack));
+            stack[stacksize++] = (long) tokens->value;
+            tokens++;
+            continue;
+        } // if
+
+        // operators.
+        switch (tokens->value)
+        {
+            case '!': UNARY_OPERATION(!); break;
+            case '~': UNARY_OPERATION(~); break;
+            case TOKEN_PP_UNARY_MINUS: UNARY_OPERATION(-); break;
+            case TOKEN_PP_UNARY_PLUS: UNARY_OPERATION(+); break;
+            case TOKEN_OROR: BINARY_OPERATION(||); break;
+            case TOKEN_ANDAND: BINARY_OPERATION(&&); break;
+            case '|': BINARY_OPERATION(|); break;
+            case '^': BINARY_OPERATION(^); break;
+            case '&': BINARY_OPERATION(&); break;
+            case TOKEN_NEQ: BINARY_OPERATION(!=); break;
+            case TOKEN_EQL: BINARY_OPERATION(==); break;
+            case '<': BINARY_OPERATION(<); break;
+            case '>': BINARY_OPERATION(>); break;
+            case TOKEN_LEQ: BINARY_OPERATION(<=); break;
+            case TOKEN_GEQ: BINARY_OPERATION(>=); break;
+            case TOKEN_LSHIFT: BINARY_OPERATION(<<); break;
+            case TOKEN_RSHIFT: BINARY_OPERATION(>>); break;
+            case '-': BINARY_OPERATION(-); break;
+            case '+': BINARY_OPERATION(+); break;
+            case '%': BINARY_OPERATION(%); break;
+            case '/': BINARY_OPERATION(/); break;
+            case '*': BINARY_OPERATION(*); break;
+            default: return 0;
+        } // switch
+
+        tokens++;
+    } // while
+
+    #undef NEED_X_TOKENS
+    #undef BINARY_OPERATION
+    #undef UNARY_OPERATION
+
+    if (stacksize != 1)
+        return 0;
+
+    *error = 0;
+    return stack[0];
+} // interpret_rpn
 
 // http://en.wikipedia.org/wiki/Shunting_yard_algorithm
 //  Convert from infix to postfix, then use this for constant folding.
@@ -1286,11 +1364,10 @@
 // returns 1 (true), 0 (false), or -1 (error)
 static int reduce_pp_expression(Context *ctx)
 {
-    struct { int isoperator; int value; } output[128];
+    RpnTokens output[128];
     Token stack[64];
     Token previous_token = TOKEN_UNKNOWN;
     int outputsize = 0;
-    int previous_precedence = -1;
     int stacksize = 0;
     int matched = 0;
     int done = 0;
@@ -1338,23 +1415,11 @@
                     continue;  // go again with new IncludeState.
 
                 // can't replace identifier with a number? It becomes zero.
-                if (previous_token == TOKEN_INT_LITERAL)  // 1 2, not 1 + 2?
-                {
-                    pushback(state);
-                    fail(ctx, "Invalid expression");
-                    return -1;
-                } // if
                 token = TOKEN_INT_LITERAL;
                 ADD_TO_OUTPUT(0, 0);
                 break;
 
             case TOKEN_INT_LITERAL:
-                if (previous_token == TOKEN_INT_LITERAL)  // 1 2, not 1 + 2?
-                {
-                    pushback(state);
-                    fail(ctx, "Invalid expression");
-                    return -1;
-                } // if
                 ADD_TO_OUTPUT(0, token_to_int(state));
                 break;
 
@@ -1385,7 +1450,7 @@
             default:
                 precedence = find_precedence(token);
                 // bogus token, or two operators together.
-                if ((previous_precedence > 0) || (precedence < 0))
+                if (precedence < 0)
                 {
                     pushback(state);
                     fail(ctx, "Invalid expression");
@@ -1415,7 +1480,6 @@
                 break;
         } // switch
         previous_token = token;
-        previous_precedence = precedence;
     } // while
 
     while (stacksize > 0)
@@ -1434,7 +1498,7 @@
 
     // okay, you now have some validated data in reverse polish notation.
     #if DEBUG_PREPROCESSOR
-    printf("EXPRESSION RPN:");
+    printf("PREPROCESSOR EXPRESSION RPN:");
     int i = 0;
     for (i = 0; i < outputsize; i++)
     {
@@ -1461,7 +1525,20 @@
     printf("\n");
     #endif
 
-    return 1;
+    int error = 0;
+    const long val = interpret_rpn(output, outputsize, &error);
+
+    #if DEBUG_PREPROCESSOR
+    printf("PREPROCESSOR RPN RESULT: %ld%s\n", val, error ? " (ERROR)" : "");
+    #endif
+
+    if (error)
+    {
+        fail(ctx, "Invalid expression");
+        return -1;
+    } // if
+
+    return ((val) ? 1 : 0);
 } // reduce_pp_expression