From 20cffa9b3bb055cdfc52e1f4785b0b3e88d8e86f Mon Sep 17 00:00:00 2001
From: Anonymous Maarten <[EMAIL REDACTED]>
Date: Fri, 22 Sep 2023 19:26:19 +0200
Subject: [PATCH] Short circuit && and || in preprocessor conditionals
---
SDL_shader_preprocessor.c | 75 ++++++++++++++++---
unit_tests/preprocessor/errors/division-zero | 2 +
.../preprocessor/errors/division-zero.correct | 1 +
.../errors/failing-short-circuit-and | 3 +
.../errors/failing-short-circuit-and.correct | 1 +
.../errors/failing-short-circuit-or | 3 +
.../errors/failing-short-circuit-or.correct | 1 +
unit_tests/preprocessor/errors/modulo-zero | 2 +
.../preprocessor/errors/modulo-zero.correct | 1 +
.../preprocessor/output/short-circuit-and | 5 ++
.../output/short-circuit-and.correct | 1 +
.../preprocessor/output/short-circuit-or | 5 ++
.../output/short-circuit-or.correct | 1 +
13 files changed, 90 insertions(+), 11 deletions(-)
create mode 100644 unit_tests/preprocessor/errors/division-zero
create mode 100644 unit_tests/preprocessor/errors/division-zero.correct
create mode 100644 unit_tests/preprocessor/errors/failing-short-circuit-and
create mode 100644 unit_tests/preprocessor/errors/failing-short-circuit-and.correct
create mode 100644 unit_tests/preprocessor/errors/failing-short-circuit-or
create mode 100644 unit_tests/preprocessor/errors/failing-short-circuit-or.correct
create mode 100644 unit_tests/preprocessor/errors/modulo-zero
create mode 100644 unit_tests/preprocessor/errors/modulo-zero.correct
create mode 100644 unit_tests/preprocessor/output/short-circuit-and
create mode 100644 unit_tests/preprocessor/output/short-circuit-and.correct
create mode 100644 unit_tests/preprocessor/output/short-circuit-or
create mode 100644 unit_tests/preprocessor/output/short-circuit-or.correct
diff --git a/SDL_shader_preprocessor.c b/SDL_shader_preprocessor.c
index 7f90aa8..7be0f0a 100644
--- a/SDL_shader_preprocessor.c
+++ b/SDL_shader_preprocessor.c
@@ -1616,25 +1616,35 @@ typedef struct RpnTokens
static long interpret_rpn(Context *ctx, const RpnTokens *tokens, int tokencount, SDL_bool *_error)
{
DECLARE_RPN_ARRAY(stack, long, 16);
+ DECLARE_RPN_ARRAY(error_stack, const char *, 16);
long retval = 0;
*_error = SDL_TRUE; /* by default */
#define NEED_X_TOKENS(x) do { if (stack_size < x) goto interpret_rpn_failed; } while (SDL_FALSE)
- #define BINARY_OPERATION(op) do { \
- NEED_X_TOKENS(2); \
- stack[stack_size-2] = stack[stack_size-2] op stack[stack_size-1]; \
- stack_size--; \
+ #define BINARY_OPERATION(op) do { \
+ NEED_X_TOKENS(2); \
+ if (error_stack[stack_size-2]) { \
+ /* FIXME: error_stack[stack_size-1] gets dropped */ \
+ } else if (error_stack[stack_size-1]) { \
+ error_stack[stack_size-2] = error_stack[stack_size-1]; \
+ } else { \
+ stack[stack_size-2] = stack[stack_size-2] op stack[stack_size-1]; \
+ } \
+ stack_size--; \
} while (SDL_FALSE)
- #define UNARY_OPERATION(op) do { \
- NEED_X_TOKENS(1); \
- stack[stack_size-1] = op stack[stack_size-1]; \
+ #define UNARY_OPERATION(op) do { \
+ NEED_X_TOKENS(1); \
+ if (!error_stack[stack_size-1]) { \
+ stack[stack_size-1] = op stack[stack_size-1]; \
+ } \
} while (SDL_FALSE)
while (tokencount-- > 0) {
if (!tokens->isoperator) {
VERIFY_RPN_ARRAY_ALLOCATION(stack, long, 128, { goto interpret_rpn_failed; });
+ error_stack[stack_size] = NULL;
stack[stack_size++] = (long) tokens->value;
tokens++;
continue;
@@ -1646,8 +1656,6 @@ static long interpret_rpn(Context *ctx, const RpnTokens *tokens, int tokencount,
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;
@@ -1663,10 +1671,50 @@ static long interpret_rpn(Context *ctx, const RpnTokens *tokens, int tokencount,
case '+': BINARY_OPERATION(+); break;
case '*': BINARY_OPERATION(*); break;
+ case TOKEN_OROR:
+ NEED_X_TOKENS(2);
+ if (error_stack[stack_size-2]) {
+ stack_size--;
+ break;
+ }
+ if (stack[stack_size-2]) {
+ stack_size--;
+ break;
+ }
+ if (error_stack[stack_size-1]) {
+ error_stack[stack_size-2] = error_stack[stack_size-1];
+ stack_size--;
+ break;
+ }
+ stack[stack_size-2] = stack[stack_size-1];
+ stack_size--;
+ break;
+
+ case TOKEN_ANDAND:
+ NEED_X_TOKENS(2);
+ if (error_stack[stack_size-2]) {
+ stack_size--;
+ break;
+ }
+ if (!stack[stack_size-2]) {
+ stack_size--;
+ break;
+ }
+ if (error_stack[stack_size-1]) {
+ error_stack[stack_size-2] = error_stack[stack_size-1];
+ stack_size--;
+ break;
+ }
+ stack[stack_size-2] = stack[stack_size-1];
+ stack_size--;
+ break;
+
case '/':
NEED_X_TOKENS(2);
if (stack[stack_size-1] == 0) {
- goto interpret_rpn_failed; // division by zero. !!! FIXME: report this error.
+ error_stack[stack_size-2] = "division by zero";
+ stack_size--;
+ break;
}
BINARY_OPERATION(/);
break;
@@ -1674,7 +1722,9 @@ static long interpret_rpn(Context *ctx, const RpnTokens *tokens, int tokencount,
case '%':
NEED_X_TOKENS(2);
if (stack[stack_size-1] == 0) {
- goto interpret_rpn_failed; // division by zero. !!! FIXME: report this error.
+ error_stack[stack_size-2] = "division by zero";
+ stack_size--;
+ break;
}
BINARY_OPERATION(%);
break;
@@ -1691,6 +1741,9 @@ static long interpret_rpn(Context *ctx, const RpnTokens *tokens, int tokencount,
if (stack_size == 1) {
retval = stack[0];
+ if (error_stack[0]) {
+ fail(ctx, error_stack[0]);
+ }
*_error = SDL_FALSE;
}
diff --git a/unit_tests/preprocessor/errors/division-zero b/unit_tests/preprocessor/errors/division-zero
new file mode 100644
index 0000000..42b670b
--- /dev/null
+++ b/unit_tests/preprocessor/errors/division-zero
@@ -0,0 +1,2 @@
+#if 4 / 0
+#endif
diff --git a/unit_tests/preprocessor/errors/division-zero.correct b/unit_tests/preprocessor/errors/division-zero.correct
new file mode 100644
index 0000000..3a5a3c9
--- /dev/null
+++ b/unit_tests/preprocessor/errors/division-zero.correct
@@ -0,0 +1 @@
+preprocessor/errors/division-zero:1: error: division by zero
diff --git a/unit_tests/preprocessor/errors/failing-short-circuit-and b/unit_tests/preprocessor/errors/failing-short-circuit-and
new file mode 100644
index 0000000..6a43464
--- /dev/null
+++ b/unit_tests/preprocessor/errors/failing-short-circuit-and
@@ -0,0 +1,3 @@
+#if 1 && 1 / 0
+#else
+#endif
diff --git a/unit_tests/preprocessor/errors/failing-short-circuit-and.correct b/unit_tests/preprocessor/errors/failing-short-circuit-and.correct
new file mode 100644
index 0000000..e752705
--- /dev/null
+++ b/unit_tests/preprocessor/errors/failing-short-circuit-and.correct
@@ -0,0 +1 @@
+preprocessor/errors/failing-short-circuit-and:1: error: division by zero
diff --git a/unit_tests/preprocessor/errors/failing-short-circuit-or b/unit_tests/preprocessor/errors/failing-short-circuit-or
new file mode 100644
index 0000000..76eb7a9
--- /dev/null
+++ b/unit_tests/preprocessor/errors/failing-short-circuit-or
@@ -0,0 +1,3 @@
+#if 0 || 1 / 0
+#else
+#endif
diff --git a/unit_tests/preprocessor/errors/failing-short-circuit-or.correct b/unit_tests/preprocessor/errors/failing-short-circuit-or.correct
new file mode 100644
index 0000000..f024729
--- /dev/null
+++ b/unit_tests/preprocessor/errors/failing-short-circuit-or.correct
@@ -0,0 +1 @@
+preprocessor/errors/failing-short-circuit-or:1: error: division by zero
diff --git a/unit_tests/preprocessor/errors/modulo-zero b/unit_tests/preprocessor/errors/modulo-zero
new file mode 100644
index 0000000..09146d4
--- /dev/null
+++ b/unit_tests/preprocessor/errors/modulo-zero
@@ -0,0 +1,2 @@
+#if 4 % 0
+#endif
diff --git a/unit_tests/preprocessor/errors/modulo-zero.correct b/unit_tests/preprocessor/errors/modulo-zero.correct
new file mode 100644
index 0000000..ed5712a
--- /dev/null
+++ b/unit_tests/preprocessor/errors/modulo-zero.correct
@@ -0,0 +1 @@
+preprocessor/errors/modulo-zero:1: error: division by zero
diff --git a/unit_tests/preprocessor/output/short-circuit-and b/unit_tests/preprocessor/output/short-circuit-and
new file mode 100644
index 0000000..2f78d50
--- /dev/null
+++ b/unit_tests/preprocessor/output/short-circuit-and
@@ -0,0 +1,5 @@
+#if 0 && 1 / 0
+bad
+#else
+good
+#endif
diff --git a/unit_tests/preprocessor/output/short-circuit-and.correct b/unit_tests/preprocessor/output/short-circuit-and.correct
new file mode 100644
index 0000000..12799cc
--- /dev/null
+++ b/unit_tests/preprocessor/output/short-circuit-and.correct
@@ -0,0 +1 @@
+good
diff --git a/unit_tests/preprocessor/output/short-circuit-or b/unit_tests/preprocessor/output/short-circuit-or
new file mode 100644
index 0000000..ed682b3
--- /dev/null
+++ b/unit_tests/preprocessor/output/short-circuit-or
@@ -0,0 +1,5 @@
+#if 1 || 1 / 0
+good
+#else
+bad
+#endif
diff --git a/unit_tests/preprocessor/output/short-circuit-or.correct b/unit_tests/preprocessor/output/short-circuit-or.correct
new file mode 100644
index 0000000..12799cc
--- /dev/null
+++ b/unit_tests/preprocessor/output/short-circuit-or.correct
@@ -0,0 +1 @@
+good