From: Michal Krol Date: Fri, 26 Jun 2009 09:44:43 +0000 (+0200) Subject: glsl: Support if preprocessor directive and friends. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3b027bca9d54383b2fc8b2ad5a9cb6d2166c7acc;p=mesa.git glsl: Support if preprocessor directive and friends. --- 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 +#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, ¯o->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, ¯o->body[j])) { - return -1; + if (!mute) { + if (sl_pp_process_out(state, ¯o->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, @@ -47,6 +51,42 @@ sl_pp_process_define(struct sl_pp_context *context, unsigned int last, 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);