mojoshader_preprocessor.c
changeset 685 687e9def5cc6
parent 684 aadf9aad508a
child 687 bb36744480e8
equal deleted inserted replaced
684:aadf9aad508a 685:687e9def5cc6
  1275     } // for
  1275     } // for
  1276 
  1276 
  1277     return -1;
  1277     return -1;
  1278 } // find_precedence
  1278 } // find_precedence
  1279 
  1279 
       
  1280 // !!! FIXME: we're using way too much stack space here...
       
  1281 typedef struct RpnTokens
       
  1282 {
       
  1283     int isoperator;
       
  1284     int value;
       
  1285 } RpnTokens;
       
  1286 
       
  1287 static long interpret_rpn(const RpnTokens *tokens, int tokencount, int *error)
       
  1288 {
       
  1289     long stack[128];
       
  1290     int stacksize = 0;
       
  1291 
       
  1292     *error = 1;
       
  1293 
       
  1294     #define NEED_X_TOKENS(x) do { if (stacksize < x) return 0; } while (0)
       
  1295 
       
  1296     #define BINARY_OPERATION(op) do { \
       
  1297         NEED_X_TOKENS(2); \
       
  1298         stack[stacksize-2] = stack[stacksize-2] op stack[stacksize-1]; \
       
  1299         stacksize--; \
       
  1300     } while (0)
       
  1301 
       
  1302     #define UNARY_OPERATION(op) do { \
       
  1303         NEED_X_TOKENS(1); \
       
  1304         stack[stacksize-1] = op stack[stacksize-1]; \
       
  1305     } while (0)
       
  1306 
       
  1307     while (tokencount-- > 0)
       
  1308     {
       
  1309         if (!tokens->isoperator)
       
  1310         {
       
  1311             assert(stacksize < STATICARRAYLEN(stack));
       
  1312             stack[stacksize++] = (long) tokens->value;
       
  1313             tokens++;
       
  1314             continue;
       
  1315         } // if
       
  1316 
       
  1317         // operators.
       
  1318         switch (tokens->value)
       
  1319         {
       
  1320             case '!': UNARY_OPERATION(!); break;
       
  1321             case '~': UNARY_OPERATION(~); break;
       
  1322             case TOKEN_PP_UNARY_MINUS: UNARY_OPERATION(-); break;
       
  1323             case TOKEN_PP_UNARY_PLUS: UNARY_OPERATION(+); break;
       
  1324             case TOKEN_OROR: BINARY_OPERATION(||); break;
       
  1325             case TOKEN_ANDAND: BINARY_OPERATION(&&); break;
       
  1326             case '|': BINARY_OPERATION(|); break;
       
  1327             case '^': BINARY_OPERATION(^); break;
       
  1328             case '&': BINARY_OPERATION(&); break;
       
  1329             case TOKEN_NEQ: BINARY_OPERATION(!=); break;
       
  1330             case TOKEN_EQL: BINARY_OPERATION(==); break;
       
  1331             case '<': BINARY_OPERATION(<); break;
       
  1332             case '>': BINARY_OPERATION(>); break;
       
  1333             case TOKEN_LEQ: BINARY_OPERATION(<=); break;
       
  1334             case TOKEN_GEQ: BINARY_OPERATION(>=); break;
       
  1335             case TOKEN_LSHIFT: BINARY_OPERATION(<<); break;
       
  1336             case TOKEN_RSHIFT: BINARY_OPERATION(>>); break;
       
  1337             case '-': BINARY_OPERATION(-); break;
       
  1338             case '+': BINARY_OPERATION(+); break;
       
  1339             case '%': BINARY_OPERATION(%); break;
       
  1340             case '/': BINARY_OPERATION(/); break;
       
  1341             case '*': BINARY_OPERATION(*); break;
       
  1342             default: return 0;
       
  1343         } // switch
       
  1344 
       
  1345         tokens++;
       
  1346     } // while
       
  1347 
       
  1348     #undef NEED_X_TOKENS
       
  1349     #undef BINARY_OPERATION
       
  1350     #undef UNARY_OPERATION
       
  1351 
       
  1352     if (stacksize != 1)
       
  1353         return 0;
       
  1354 
       
  1355     *error = 0;
       
  1356     return stack[0];
       
  1357 } // interpret_rpn
  1280 
  1358 
  1281 // http://en.wikipedia.org/wiki/Shunting_yard_algorithm
  1359 // http://en.wikipedia.org/wiki/Shunting_yard_algorithm
  1282 //  Convert from infix to postfix, then use this for constant folding.
  1360 //  Convert from infix to postfix, then use this for constant folding.
  1283 //  Everything that parses should fold down to a constant value: any
  1361 //  Everything that parses should fold down to a constant value: any
  1284 //  identifiers that aren't resolved as macros become zero. Anything we
  1362 //  identifiers that aren't resolved as macros become zero. Anything we
  1285 //  don't explicitly expect becomes a parsing error.
  1363 //  don't explicitly expect becomes a parsing error.
  1286 // returns 1 (true), 0 (false), or -1 (error)
  1364 // returns 1 (true), 0 (false), or -1 (error)
  1287 static int reduce_pp_expression(Context *ctx)
  1365 static int reduce_pp_expression(Context *ctx)
  1288 {
  1366 {
  1289     struct { int isoperator; int value; } output[128];
  1367     RpnTokens output[128];
  1290     Token stack[64];
  1368     Token stack[64];
  1291     Token previous_token = TOKEN_UNKNOWN;
  1369     Token previous_token = TOKEN_UNKNOWN;
  1292     int outputsize = 0;
  1370     int outputsize = 0;
  1293     int previous_precedence = -1;
       
  1294     int stacksize = 0;
  1371     int stacksize = 0;
  1295     int matched = 0;
  1372     int matched = 0;
  1296     int done = 0;
  1373     int done = 0;
  1297 
  1374 
  1298     #define ADD_TO_OUTPUT(op, val) \
  1375     #define ADD_TO_OUTPUT(op, val) \
  1336             case TOKEN_IDENTIFIER:
  1413             case TOKEN_IDENTIFIER:
  1337                 if (handle_pp_identifier(ctx))
  1414                 if (handle_pp_identifier(ctx))
  1338                     continue;  // go again with new IncludeState.
  1415                     continue;  // go again with new IncludeState.
  1339 
  1416 
  1340                 // can't replace identifier with a number? It becomes zero.
  1417                 // can't replace identifier with a number? It becomes zero.
  1341                 if (previous_token == TOKEN_INT_LITERAL)  // 1 2, not 1 + 2?
       
  1342                 {
       
  1343                     pushback(state);
       
  1344                     fail(ctx, "Invalid expression");
       
  1345                     return -1;
       
  1346                 } // if
       
  1347                 token = TOKEN_INT_LITERAL;
  1418                 token = TOKEN_INT_LITERAL;
  1348                 ADD_TO_OUTPUT(0, 0);
  1419                 ADD_TO_OUTPUT(0, 0);
  1349                 break;
  1420                 break;
  1350 
  1421 
  1351             case TOKEN_INT_LITERAL:
  1422             case TOKEN_INT_LITERAL:
  1352                 if (previous_token == TOKEN_INT_LITERAL)  // 1 2, not 1 + 2?
       
  1353                 {
       
  1354                     pushback(state);
       
  1355                     fail(ctx, "Invalid expression");
       
  1356                     return -1;
       
  1357                 } // if
       
  1358                 ADD_TO_OUTPUT(0, token_to_int(state));
  1423                 ADD_TO_OUTPUT(0, token_to_int(state));
  1359                 break;
  1424                 break;
  1360 
  1425 
  1361             case ((Token) '('):
  1426             case ((Token) '('):
  1362                 PUSH_TO_STACK((Token) '(');
  1427                 PUSH_TO_STACK((Token) '(');
  1383                 break;
  1448                 break;
  1384 
  1449 
  1385             default:
  1450             default:
  1386                 precedence = find_precedence(token);
  1451                 precedence = find_precedence(token);
  1387                 // bogus token, or two operators together.
  1452                 // bogus token, or two operators together.
  1388                 if ((previous_precedence > 0) || (precedence < 0))
  1453                 if (precedence < 0)
  1389                 {
  1454                 {
  1390                     pushback(state);
  1455                     pushback(state);
  1391                     fail(ctx, "Invalid expression");
  1456                     fail(ctx, "Invalid expression");
  1392                     return -1;
  1457                     return -1;
  1393                 } // if
  1458                 } // if
  1413                     PUSH_TO_STACK(token);
  1478                     PUSH_TO_STACK(token);
  1414                 } // else
  1479                 } // else
  1415                 break;
  1480                 break;
  1416         } // switch
  1481         } // switch
  1417         previous_token = token;
  1482         previous_token = token;
  1418         previous_precedence = precedence;
       
  1419     } // while
  1483     } // while
  1420 
  1484 
  1421     while (stacksize > 0)
  1485     while (stacksize > 0)
  1422     {
  1486     {
  1423         const Token t = stack[--stacksize];
  1487         const Token t = stack[--stacksize];
  1432     #undef ADD_TO_OUTPUT
  1496     #undef ADD_TO_OUTPUT
  1433     #undef PUSH_TO_STACK
  1497     #undef PUSH_TO_STACK
  1434 
  1498 
  1435     // okay, you now have some validated data in reverse polish notation.
  1499     // okay, you now have some validated data in reverse polish notation.
  1436     #if DEBUG_PREPROCESSOR
  1500     #if DEBUG_PREPROCESSOR
  1437     printf("EXPRESSION RPN:");
  1501     printf("PREPROCESSOR EXPRESSION RPN:");
  1438     int i = 0;
  1502     int i = 0;
  1439     for (i = 0; i < outputsize; i++)
  1503     for (i = 0; i < outputsize; i++)
  1440     {
  1504     {
  1441         if (!output[i].isoperator)
  1505         if (!output[i].isoperator)
  1442             printf(" %d", output[i].value);
  1506             printf(" %d", output[i].value);
  1459         } // else
  1523         } // else
  1460     } // for
  1524     } // for
  1461     printf("\n");
  1525     printf("\n");
  1462     #endif
  1526     #endif
  1463 
  1527 
  1464     return 1;
  1528     int error = 0;
       
  1529     const long val = interpret_rpn(output, outputsize, &error);
       
  1530 
       
  1531     #if DEBUG_PREPROCESSOR
       
  1532     printf("PREPROCESSOR RPN RESULT: %ld%s\n", val, error ? " (ERROR)" : "");
       
  1533     #endif
       
  1534 
       
  1535     if (error)
       
  1536     {
       
  1537         fail(ctx, "Invalid expression");
       
  1538         return -1;
       
  1539     } // if
       
  1540 
       
  1541     return ((val) ? 1 : 0);
  1465 } // reduce_pp_expression
  1542 } // reduce_pp_expression
  1466 
  1543 
  1467 
  1544 
  1468 static Conditional *handle_pp_if(Context *ctx)
  1545 static Conditional *handle_pp_if(Context *ctx)
  1469 {
  1546 {