summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Krol <[email protected]>2009-06-26 11:44:43 +0200
committerMichal Krol <[email protected]>2009-09-07 10:11:50 +0200
commit3b027bca9d54383b2fc8b2ad5a9cb6d2166c7acc (patch)
treeb7a9904765a0ff67e1c50705bae0fc7975c46b6e
parent3bb446ba6e890bc3f60a34318a5a0fe860e53cbb (diff)
glsl: Support if preprocessor directive and friends.
-rw-r--r--src/glsl/pp/SConscript1
-rw-r--r--src/glsl/pp/sl_pp_context.c2
-rw-r--r--src/glsl/pp/sl_pp_context.h6
-rw-r--r--src/glsl/pp/sl_pp_if.c276
-rw-r--r--src/glsl/pp/sl_pp_macro.c24
-rw-r--r--src/glsl/pp/sl_pp_macro.h3
-rw-r--r--src/glsl/pp/sl_pp_process.c59
-rw-r--r--src/glsl/pp/sl_pp_process.h42
8 files changed, 388 insertions, 25 deletions
diff --git a/src/glsl/pp/SConscript b/src/glsl/pp/SConscript
index 623d2362ce0..c7718d1d8fd 100644
--- a/src/glsl/pp/SConscript
+++ b/src/glsl/pp/SConscript
@@ -11,6 +11,7 @@ glsl = env.StaticLibrary(
'sl_pp_context.c',
'sl_pp_define.c',
'sl_pp_expression.c',
+ 'sl_pp_if.c',
'sl_pp_macro.c',
'sl_pp_process.c',
'sl_pp_purify.c',
diff --git a/src/glsl/pp/sl_pp_context.c b/src/glsl/pp/sl_pp_context.c
index 6d3076b8697..1afe9a5d5e0 100644
--- a/src/glsl/pp/sl_pp_context.c
+++ b/src/glsl/pp/sl_pp_context.c
@@ -33,6 +33,8 @@ void
sl_pp_context_init(struct sl_pp_context *context)
{
memset(context, 0, sizeof(struct sl_pp_context));
+ context->if_ptr = SL_PP_MAX_IF_NESTING;
+ context->if_value = 1;
}
void
diff --git a/src/glsl/pp/sl_pp_context.h b/src/glsl/pp/sl_pp_context.h
index 56f70777507..e8200d55d7f 100644
--- a/src/glsl/pp/sl_pp_context.h
+++ b/src/glsl/pp/sl_pp_context.h
@@ -31,12 +31,18 @@
#include "sl_pp_macro.h"
+#define SL_PP_MAX_IF_NESTING 64
+
struct sl_pp_context {
char *cstr_pool;
unsigned int cstr_pool_max;
unsigned int cstr_pool_len;
struct sl_pp_macro *macro;
+
+ unsigned int if_stack[SL_PP_MAX_IF_NESTING];
+ unsigned int if_ptr;
+ int if_value;
};
void
diff --git a/src/glsl/pp/sl_pp_if.c b/src/glsl/pp/sl_pp_if.c
new file mode 100644
index 00000000000..e331acc4cd5
--- /dev/null
+++ b/src/glsl/pp/sl_pp_if.c
@@ -0,0 +1,276 @@
+/**************************************************************************
+ *
+ * Copyright 2009 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include <stdlib.h>
+#include "sl_pp_expression.h"
+#include "sl_pp_process.h"
+
+
+static int
+_evaluate_if_stack(struct sl_pp_context *context)
+{
+ unsigned int i;
+
+ for (i = context->if_ptr; i < SL_PP_MAX_IF_NESTING; i++) {
+ if (!(context->if_stack[i] & 1)) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int
+_parse_if(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last)
+{
+ unsigned int i;
+ struct sl_pp_process_state state;
+ struct sl_pp_token_info eof;
+ int result;
+
+ if (!context->if_ptr) {
+ /* #if nesting too deep. */
+ return -1;
+ }
+
+ memset(&state, 0, sizeof(state));
+ for (i = first; i < last;) {
+ switch (input[i].token) {
+ case SL_PP_WHITESPACE:
+ i++;
+ break;
+
+ case SL_PP_IDENTIFIER:
+ if (sl_pp_macro_expand(context, input, &i, NULL, &state, 0)) {
+ free(state.out);
+ return -1;
+ }
+ break;
+
+ default:
+ if (sl_pp_process_out(&state, &input[i])) {
+ free(state.out);
+ return -1;
+ }
+ i++;
+ }
+ }
+
+ eof.token = SL_PP_EOF;
+ if (sl_pp_process_out(&state, &eof)) {
+ free(state.out);
+ return -1;
+ }
+
+ if (sl_pp_execute_expression(context, state.out, &result)) {
+ free(state.out);
+ return -1;
+ }
+
+ free(state.out);
+
+ context->if_ptr--;
+ context->if_stack[context->if_ptr] = result ? 1 : 0;
+ context->if_value = _evaluate_if_stack(context);
+
+ return 0;
+}
+
+static int
+_parse_else(struct sl_pp_context *context)
+{
+ if (context->if_ptr == SL_PP_MAX_IF_NESTING) {
+ /* No matching #if. */
+ return -1;
+ }
+
+ /* Bit b1 indicates we already went through #else. */
+ if (context->if_stack[context->if_ptr] & 2) {
+ /* No matching #if. */
+ return -1;
+ }
+
+ /* Invert current condition value and mark that we are in the #else block. */
+ context->if_stack[context->if_ptr] = (1 - (context->if_stack[context->if_ptr] & 1)) | 2;
+ context->if_value = _evaluate_if_stack(context);
+
+ return 0;
+}
+
+int
+sl_pp_process_if(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last)
+{
+ return _parse_if(context, input, first, last);
+}
+
+int
+sl_pp_process_ifdef(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last)
+{
+ unsigned int i;
+
+ if (!context->if_ptr) {
+ /* #if nesting too deep. */
+ return -1;
+ }
+
+ for (i = first; i < last; i++) {
+ switch (input[i].token) {
+ case SL_PP_IDENTIFIER:
+ {
+ struct sl_pp_macro *macro;
+ int macro_name = input[i].data.identifier;
+ int defined = 0;
+
+ for (macro = context->macro; macro; macro = macro->next) {
+ if (macro->name == macro_name) {
+ defined = 1;
+ break;
+ }
+ }
+
+ context->if_ptr--;
+ context->if_stack[context->if_ptr] = defined ? 1 : 0;
+ context->if_value = _evaluate_if_stack(context);
+ }
+ return 0;
+
+ case SL_PP_WHITESPACE:
+ break;
+
+ default:
+ /* Expected an identifier. */
+ return -1;
+ }
+ }
+
+ /* Expected an identifier. */
+ return -1;
+}
+
+int
+sl_pp_process_ifndef(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last)
+{
+ unsigned int i;
+
+ if (!context->if_ptr) {
+ /* #if nesting too deep. */
+ return -1;
+ }
+
+ for (i = first; i < last; i++) {
+ switch (input[i].token) {
+ case SL_PP_IDENTIFIER:
+ {
+ struct sl_pp_macro *macro;
+ int macro_name = input[i].data.identifier;
+ int defined = 0;
+
+ for (macro = context->macro; macro; macro = macro->next) {
+ if (macro->name == macro_name) {
+ defined = 1;
+ break;
+ }
+ }
+
+ context->if_ptr--;
+ context->if_stack[context->if_ptr] = defined ? 0 : 1;
+ context->if_value = _evaluate_if_stack(context);
+ }
+ return 0;
+
+ case SL_PP_WHITESPACE:
+ break;
+
+ default:
+ /* Expected an identifier. */
+ return -1;
+ }
+ }
+
+ /* Expected an identifier. */
+ return -1;
+}
+
+int
+sl_pp_process_elif(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last)
+{
+ if (_parse_else(context)) {
+ return -1;
+ }
+
+ if (context->if_stack[context->if_ptr] & 1) {
+ context->if_ptr++;
+ if (_parse_if(context, input, first, last)) {
+ return -1;
+ }
+ }
+
+ /* We are still in the #if block. */
+ context->if_stack[context->if_ptr] = context->if_stack[context->if_ptr] & ~2;
+
+ return 0;
+}
+
+int
+sl_pp_process_else(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last)
+{
+ return _parse_else(context);
+}
+
+int
+sl_pp_process_endif(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last)
+{
+ if (context->if_ptr == SL_PP_MAX_IF_NESTING) {
+ /* No matching #if. */
+ return -1;
+ }
+
+ context->if_ptr++;
+ context->if_value = _evaluate_if_stack(context);
+
+ return 0;
+}
diff --git a/src/glsl/pp/sl_pp_macro.c b/src/glsl/pp/sl_pp_macro.c
index 0138270c67b..a8412f0651c 100644
--- a/src/glsl/pp/sl_pp_macro.c
+++ b/src/glsl/pp/sl_pp_macro.c
@@ -78,7 +78,8 @@ sl_pp_macro_expand(struct sl_pp_context *context,
const struct sl_pp_token_info *input,
unsigned int *pi,
struct sl_pp_macro *local,
- struct sl_pp_process_state *state)
+ struct sl_pp_process_state *state,
+ int mute)
{
int macro_name;
struct sl_pp_macro *macro = NULL;
@@ -108,8 +109,10 @@ sl_pp_macro_expand(struct sl_pp_context *context,
}
if (!macro) {
- if (sl_pp_process_out(state, &input[*pi])) {
- return -1;
+ if (!mute) {
+ if (sl_pp_process_out(state, &input[*pi])) {
+ return -1;
+ }
}
(*pi)++;
return 0;
@@ -244,8 +247,15 @@ sl_pp_macro_expand(struct sl_pp_context *context,
for (j = 0;;) {
switch (macro->body[j].token) {
+ case SL_PP_NEWLINE:
+ if (sl_pp_process_out(state, &macro->body[j])) {
+ return -1;
+ }
+ j++;
+ break;
+
case SL_PP_IDENTIFIER:
- if (sl_pp_macro_expand(context, macro->body, &j, actual_arg, state)) {
+ if (sl_pp_macro_expand(context, macro->body, &j, actual_arg, state, mute)) {
return -1;
}
break;
@@ -255,8 +265,10 @@ sl_pp_macro_expand(struct sl_pp_context *context,
return 0;
default:
- if (sl_pp_process_out(state, &macro->body[j])) {
- return -1;
+ if (!mute) {
+ if (sl_pp_process_out(state, &macro->body[j])) {
+ return -1;
+ }
}
j++;
}
diff --git a/src/glsl/pp/sl_pp_macro.h b/src/glsl/pp/sl_pp_macro.h
index 63edd21aa24..476991d581d 100644
--- a/src/glsl/pp/sl_pp_macro.h
+++ b/src/glsl/pp/sl_pp_macro.h
@@ -55,6 +55,7 @@ sl_pp_macro_expand(struct sl_pp_context *context,
const struct sl_pp_token_info *input,
unsigned int *pi,
struct sl_pp_macro *local,
- struct sl_pp_process_state *state);
+ struct sl_pp_process_state *state,
+ int mute);
#endif /* SL_PP_MACRO_H */
diff --git a/src/glsl/pp/sl_pp_process.c b/src/glsl/pp/sl_pp_process.c
index baffaf2cd95..441de9439c5 100644
--- a/src/glsl/pp/sl_pp_process.c
+++ b/src/glsl/pp/sl_pp_process.c
@@ -38,14 +38,6 @@ skip_whitespace(const struct sl_pp_token_info *input,
}
}
-
-struct sl_pp_process_state {
- struct sl_pp_token_info *out;
- unsigned int out_len;
- unsigned int out_max;
-};
-
-
int
sl_pp_process_out(struct sl_pp_process_state *state,
const struct sl_pp_token_info *token)
@@ -133,16 +125,42 @@ sl_pp_process(struct sl_pp_context *context,
last = i - 1;
if (!strcmp(name, "define")) {
- *macro = sl_pp_macro_new();
- if (!*macro) {
+ if (context->if_value) {
+ *macro = sl_pp_macro_new();
+ if (!*macro) {
+ return -1;
+ }
+
+ if (sl_pp_process_define(context, input, first, last, *macro)) {
+ return -1;
+ }
+
+ macro = &(**macro).next;
+ }
+ } else if (!strcmp(name, "if")) {
+ if (sl_pp_process_if(context, input, first, last)) {
return -1;
}
-
- if (sl_pp_process_define(context, input, first, last, *macro)) {
+ } else if (!strcmp(name, "ifdef")) {
+ if (sl_pp_process_ifdef(context, input, first, last)) {
+ return -1;
+ }
+ } else if (!strcmp(name, "ifndef")) {
+ if (sl_pp_process_ifndef(context, input, first, last)) {
+ return -1;
+ }
+ } else if (!strcmp(name, "elif")) {
+ if (sl_pp_process_elif(context, input, first, last)) {
+ return -1;
+ }
+ } else if (!strcmp(name, "else")) {
+ if (sl_pp_process_else(context, input, first, last)) {
+ return -1;
+ }
+ } else if (!strcmp(name, "endif")) {
+ if (sl_pp_process_endif(context, input, first, last)) {
return -1;
}
-
- macro = &(**macro).next;
} else {
/* XXX: Ignore. */
}
@@ -198,14 +216,16 @@ sl_pp_process(struct sl_pp_context *context,
break;
case SL_PP_IDENTIFIER:
- if (sl_pp_macro_expand(context, input, &i, NULL, &state)) {
+ if (sl_pp_macro_expand(context, input, &i, NULL, &state, !context->if_value)) {
return -1;
}
break;
default:
- if (sl_pp_process_out(&state, &input[i])) {
- return -1;
+ if (context->if_value) {
+ if (sl_pp_process_out(&state, &input[i])) {
+ return -1;
+ }
}
i++;
}
@@ -213,6 +233,11 @@ sl_pp_process(struct sl_pp_context *context,
}
}
+ if (context->if_ptr != SL_PP_MAX_IF_NESTING) {
+ /* #endif expected. */
+ return -1;
+ }
+
*output = state.out;
return 0;
}
diff --git a/src/glsl/pp/sl_pp_process.h b/src/glsl/pp/sl_pp_process.h
index 37cdc4c9a78..cc934bd89c5 100644
--- a/src/glsl/pp/sl_pp_process.h
+++ b/src/glsl/pp/sl_pp_process.h
@@ -33,7 +33,11 @@
#include "sl_pp_token.h"
-struct sl_pp_process_state;
+struct sl_pp_process_state {
+ struct sl_pp_token_info *out;
+ unsigned int out_len;
+ unsigned int out_max;
+};
int
sl_pp_process(struct sl_pp_context *context,
@@ -48,6 +52,42 @@ sl_pp_process_define(struct sl_pp_context *context,
struct sl_pp_macro *macro);
int
+sl_pp_process_if(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last);
+
+int
+sl_pp_process_ifdef(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last);
+
+int
+sl_pp_process_ifndef(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last);
+
+int
+sl_pp_process_elif(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last);
+
+int
+sl_pp_process_else(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last);
+
+int
+sl_pp_process_endif(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last);
+
+int
sl_pp_process_out(struct sl_pp_process_state *state,
const struct sl_pp_token_info *token);