diff options
Diffstat (limited to 'src/glsl/pp')
-rw-r--r-- | src/glsl/pp/SConscript | 27 | ||||
-rw-r--r-- | src/glsl/pp/sl_pp_context.c | 107 | ||||
-rw-r--r-- | src/glsl/pp/sl_pp_context.h | 72 | ||||
-rw-r--r-- | src/glsl/pp/sl_pp_define.c | 220 | ||||
-rw-r--r-- | src/glsl/pp/sl_pp_dict.c | 83 | ||||
-rw-r--r-- | src/glsl/pp/sl_pp_dict.h | 73 | ||||
-rw-r--r-- | src/glsl/pp/sl_pp_error.c | 263 | ||||
-rw-r--r-- | src/glsl/pp/sl_pp_expression.c | 409 | ||||
-rw-r--r-- | src/glsl/pp/sl_pp_expression.h | 40 | ||||
-rw-r--r-- | src/glsl/pp/sl_pp_extension.c | 144 | ||||
-rw-r--r-- | src/glsl/pp/sl_pp_if.c | 355 | ||||
-rw-r--r-- | src/glsl/pp/sl_pp_line.c | 130 | ||||
-rw-r--r-- | src/glsl/pp/sl_pp_macro.c | 356 | ||||
-rw-r--r-- | src/glsl/pp/sl_pp_macro.h | 64 | ||||
-rw-r--r-- | src/glsl/pp/sl_pp_pragma.c | 107 | ||||
-rw-r--r-- | src/glsl/pp/sl_pp_process.c | 282 | ||||
-rw-r--r-- | src/glsl/pp/sl_pp_process.h | 126 | ||||
-rw-r--r-- | src/glsl/pp/sl_pp_purify.c | 239 | ||||
-rw-r--r-- | src/glsl/pp/sl_pp_purify.h | 41 | ||||
-rw-r--r-- | src/glsl/pp/sl_pp_token.c | 608 | ||||
-rw-r--r-- | src/glsl/pp/sl_pp_token.h | 125 | ||||
-rw-r--r-- | src/glsl/pp/sl_pp_version.c | 138 | ||||
-rw-r--r-- | src/glsl/pp/sl_pp_version.h | 41 |
23 files changed, 4050 insertions, 0 deletions
diff --git a/src/glsl/pp/SConscript b/src/glsl/pp/SConscript new file mode 100644 index 0000000000..621db1e765 --- /dev/null +++ b/src/glsl/pp/SConscript @@ -0,0 +1,27 @@ +Import('*') + +if env['platform'] not in ['windows']: + Return() + +env = env.Clone() + +glsl = env.StaticLibrary( + target = 'glsl', + source = [ + 'sl_pp_context.c', + 'sl_pp_define.c', + 'sl_pp_dict.c', + 'sl_pp_error.c', + 'sl_pp_expression.c', + 'sl_pp_extension.c', + 'sl_pp_if.c', + 'sl_pp_line.c', + 'sl_pp_macro.c', + 'sl_pp_pragma.c', + 'sl_pp_process.c', + 'sl_pp_purify.c', + 'sl_pp_token.c', + 'sl_pp_version.c', + ], +) +Export('glsl') diff --git a/src/glsl/pp/sl_pp_context.c b/src/glsl/pp/sl_pp_context.c new file mode 100644 index 0000000000..b196d8102a --- /dev/null +++ b/src/glsl/pp/sl_pp_context.c @@ -0,0 +1,107 @@ +/************************************************************************** + * + * 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_context.h" + + +int +sl_pp_context_init(struct sl_pp_context *context) +{ + memset(context, 0, sizeof(struct sl_pp_context)); + + if (sl_pp_dict_init(context)) { + sl_pp_context_destroy(context); + return -1; + } + + context->macro_tail = &context->macro; + context->if_ptr = SL_PP_MAX_IF_NESTING; + context->if_value = 1; + memset(context->error_msg, 0, sizeof(context->error_msg)); + context->line = 1; + context->file = 0; + + return 0; +} + +void +sl_pp_context_destroy(struct sl_pp_context *context) +{ + free(context->cstr_pool); + sl_pp_macro_free(context->macro); +} + +int +sl_pp_context_add_unique_str(struct sl_pp_context *context, + const char *str) +{ + unsigned int size; + unsigned int offset = 0; + + size = strlen(str) + 1; + + /* Find out if this is a unique string. */ + while (offset < context->cstr_pool_len) { + const char *str2; + unsigned int size2; + + str2 = &context->cstr_pool[offset]; + size2 = strlen(str2) + 1; + if (size == size2 && !memcmp(str, str2, size - 1)) { + return offset; + } + + offset += size2; + } + + if (context->cstr_pool_len + size > context->cstr_pool_max) { + context->cstr_pool_max = (context->cstr_pool_len + size + 0xffff) & ~0xffff; + context->cstr_pool = realloc(context->cstr_pool, context->cstr_pool_max); + } + + if (!context->cstr_pool) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + + offset = context->cstr_pool_len; + memcpy(&context->cstr_pool[offset], str, size); + context->cstr_pool_len += size; + + return offset; +} + +const char * +sl_pp_context_cstr(const struct sl_pp_context *context, + int offset) +{ + if (offset == -1) { + return NULL; + } + return &context->cstr_pool[offset]; +} diff --git a/src/glsl/pp/sl_pp_context.h b/src/glsl/pp/sl_pp_context.h new file mode 100644 index 0000000000..8bed142045 --- /dev/null +++ b/src/glsl/pp/sl_pp_context.h @@ -0,0 +1,72 @@ +/************************************************************************** + * + * 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. + * + **************************************************************************/ + +#ifndef SL_PP_CONTEXT_H +#define SL_PP_CONTEXT_H + +#include "sl_pp_dict.h" +#include "sl_pp_macro.h" + + +#define SL_PP_MAX_IF_NESTING 64 + +#define SL_PP_MAX_ERROR_MSG 1024 + +struct sl_pp_context { + char *cstr_pool; + unsigned int cstr_pool_max; + unsigned int cstr_pool_len; + struct sl_pp_dict dict; + + struct sl_pp_macro *macro; + struct sl_pp_macro **macro_tail; + + unsigned int if_stack[SL_PP_MAX_IF_NESTING]; + unsigned int if_ptr; + unsigned int if_value; + + char error_msg[SL_PP_MAX_ERROR_MSG]; + + unsigned int line; + unsigned int file; +}; + +int +sl_pp_context_init(struct sl_pp_context *context); + +void +sl_pp_context_destroy(struct sl_pp_context *context); + +int +sl_pp_context_add_unique_str(struct sl_pp_context *context, + const char *str); + +const char * +sl_pp_context_cstr(const struct sl_pp_context *context, + int offset); + +#endif /* SL_PP_CONTEXT_H */ diff --git a/src/glsl/pp/sl_pp_define.c b/src/glsl/pp/sl_pp_define.c new file mode 100644 index 0000000000..391178aa69 --- /dev/null +++ b/src/glsl/pp/sl_pp_define.c @@ -0,0 +1,220 @@ +/************************************************************************** + * + * 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_process.h" + + +static void +skip_whitespace(const struct sl_pp_token_info *input, + unsigned int *first, + unsigned int last) +{ + while (*first < last && input[*first].token == SL_PP_WHITESPACE) { + (*first)++; + } +} + + +static int +_parse_formal_args(struct sl_pp_context *context, + const struct sl_pp_token_info *input, + unsigned int *first, + unsigned int last, + struct sl_pp_macro *macro) +{ + struct sl_pp_macro_formal_arg **arg; + + macro->num_args = 0; + + skip_whitespace(input, first, last); + if (*first < last) { + if (input[*first].token == SL_PP_RPAREN) { + (*first)++; + return 0; + } + } else { + strcpy(context->error_msg, "expected either an identifier or `)'"); + return -1; + } + + arg = ¯o->arg; + + for (;;) { + if (*first < last && input[*first].token != SL_PP_IDENTIFIER) { + strcpy(context->error_msg, "expected an identifier"); + return -1; + } + + *arg = malloc(sizeof(struct sl_pp_macro_formal_arg)); + if (!*arg) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + + (**arg).name = input[*first].data.identifier; + (*first)++; + + (**arg).next = NULL; + arg = &(**arg).next; + + macro->num_args++; + + skip_whitespace(input, first, last); + if (*first < last) { + if (input[*first].token == SL_PP_COMMA) { + (*first)++; + } else if (input[*first].token == SL_PP_RPAREN) { + (*first)++; + return 0; + } else { + strcpy(context->error_msg, "expected either `,' or `)'"); + return -1; + } + } else { + strcpy(context->error_msg, "expected either `,' or `)'"); + return -1; + } + } + + /* Should not gete here. */ +} + + +int +sl_pp_process_define(struct sl_pp_context *context, + const struct sl_pp_token_info *input, + unsigned int first, + unsigned int last) +{ + int macro_name = -1; + struct sl_pp_macro *macro; + unsigned int i; + unsigned int body_len; + unsigned int j; + + if (first < last && input[first].token == SL_PP_IDENTIFIER) { + macro_name = input[first].data.identifier; + first++; + } + if (macro_name == -1) { + strcpy(context->error_msg, "expected an identifier"); + return -1; + } + + for (macro = context->macro; macro; macro = macro->next) { + if (macro->name == macro_name) { + break; + } + } + + if (!macro) { + macro = sl_pp_macro_new(); + if (!macro) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + + *context->macro_tail = macro; + context->macro_tail = ¯o->next; + } else { + sl_pp_macro_reset(macro); + } + + macro->name = macro_name; + + /* + * If there is no whitespace between macro name and left paren, a macro + * formal argument list follows. This is the only place where the presence + * of a whitespace matters and it's the only reason why we are dealing + * with whitespace at this level. + */ + if (first < last && input[first].token == SL_PP_LPAREN) { + first++; + if (_parse_formal_args(context, input, &first, last, macro)) { + return -1; + } + } + + /* Calculate body size, trim out whitespace, make room for EOF. */ + body_len = 1; + for (i = first; i < last; i++) { + if (input[i].token != SL_PP_WHITESPACE) { + body_len++; + } + } + + macro->body = malloc(sizeof(struct sl_pp_token_info) * body_len); + if (!macro->body) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + + for (j = 0, i = first; i < last; i++) { + if (input[i].token != SL_PP_WHITESPACE) { + macro->body[j++] = input[i]; + } + } + macro->body[j++].token = SL_PP_EOF; + + return 0; +} + + +int +sl_pp_process_undef(struct sl_pp_context *context, + const struct sl_pp_token_info *input, + unsigned int first, + unsigned int last) +{ + int macro_name = -1; + struct sl_pp_macro **pmacro; + struct sl_pp_macro *macro; + + if (first < last && input[first].token == SL_PP_IDENTIFIER) { + macro_name = input[first].data.identifier; + } + if (macro_name == -1) { + return 0; + } + + for (pmacro = &context->macro; *pmacro; pmacro = &(**pmacro).next) { + if ((**pmacro).name == macro_name) { + break; + } + } + if (!*pmacro) { + return 0; + } + + macro = *pmacro; + *pmacro = macro->next; + macro->next = NULL; + sl_pp_macro_free(macro); + + return 0; +} diff --git a/src/glsl/pp/sl_pp_dict.c b/src/glsl/pp/sl_pp_dict.c new file mode 100644 index 0000000000..f2885c763d --- /dev/null +++ b/src/glsl/pp/sl_pp_dict.c @@ -0,0 +1,83 @@ +/************************************************************************** + * + * 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 "sl_pp_context.h" +#include "sl_pp_dict.h" + + +#define ADD_NAME_STR(CTX, NAME, STR)\ + do {\ + (CTX)->dict.NAME = sl_pp_context_add_unique_str((CTX), (STR));\ + if ((CTX)->dict.NAME == -1) {\ + return -1;\ + }\ + } while (0) + +#define ADD_NAME(CTX, NAME) ADD_NAME_STR(CTX, NAME, #NAME) + + +int +sl_pp_dict_init(struct sl_pp_context *context) +{ + ADD_NAME(context, all); + ADD_NAME_STR(context, _GL_ARB_draw_buffers, "GL_ARB_draw_buffers"); + ADD_NAME_STR(context, _GL_ARB_texture_rectangle, "GL_ARB_texture_rectangle"); + + ADD_NAME(context, require); + ADD_NAME(context, enable); + ADD_NAME(context, warn); + ADD_NAME(context, disable); + + ADD_NAME(context, defined); + + ADD_NAME_STR(context, ___LINE__, "__LINE__"); + ADD_NAME_STR(context, ___FILE__, "__FILE__"); + ADD_NAME(context, __VERSION__); + + ADD_NAME(context, optimize); + ADD_NAME(context, debug); + + ADD_NAME(context, off); + ADD_NAME(context, on); + + ADD_NAME(context, define); + ADD_NAME(context, elif); + ADD_NAME_STR(context, _else, "else"); + ADD_NAME(context, endif); + ADD_NAME(context, error); + ADD_NAME(context, extension); + ADD_NAME_STR(context, _if, "if"); + ADD_NAME(context, ifdef); + ADD_NAME(context, ifndef); + ADD_NAME(context, line); + ADD_NAME(context, pragma); + ADD_NAME(context, undef); + + ADD_NAME(context, version); + + return 0; +} diff --git a/src/glsl/pp/sl_pp_dict.h b/src/glsl/pp/sl_pp_dict.h new file mode 100644 index 0000000000..ba82b389b2 --- /dev/null +++ b/src/glsl/pp/sl_pp_dict.h @@ -0,0 +1,73 @@ +/************************************************************************** + * + * 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. + * + **************************************************************************/ + +#ifndef SL_PP_DICT_H +#define SL_PP_DICT_H + +struct sl_pp_dict { + int all; + int _GL_ARB_draw_buffers; + int _GL_ARB_texture_rectangle; + + int require; + int enable; + int warn; + int disable; + + int defined; + + int ___LINE__; + int ___FILE__; + int __VERSION__; + + int optimize; + int debug; + + int off; + int on; + + int define; + int elif; + int _else; + int endif; + int error; + int extension; + int _if; + int ifdef; + int ifndef; + int line; + int pragma; + int undef; + + int version; +}; + + +int +sl_pp_dict_init(struct sl_pp_context *context); + +#endif /* SL_PP_DICT_H */ diff --git a/src/glsl/pp/sl_pp_error.c b/src/glsl/pp/sl_pp_error.c new file mode 100644 index 0000000000..d42568d23d --- /dev/null +++ b/src/glsl/pp/sl_pp_error.c @@ -0,0 +1,263 @@ +/************************************************************************** + * + * 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_process.h" + + +void +sl_pp_process_error(struct sl_pp_context *context, + const struct sl_pp_token_info *input, + unsigned int first, + unsigned int last) +{ + unsigned int out_len = 0; + unsigned int i; + + for (i = first; i < last; i++) { + const char *s = NULL; + char buf[2]; + + switch (input[i].token) { + case SL_PP_WHITESPACE: + s = " "; + break; + + case SL_PP_NEWLINE: + s = "\n"; + break; + + case SL_PP_HASH: + s = "#"; + break; + + case SL_PP_COMMA: + s = ","; + break; + + case SL_PP_SEMICOLON: + s = ";"; + break; + + case SL_PP_LBRACE: + s = "{"; + break; + + case SL_PP_RBRACE: + s = "}"; + break; + + case SL_PP_LPAREN: + s = "("; + break; + + case SL_PP_RPAREN: + s = ")"; + break; + + case SL_PP_LBRACKET: + s = "["; + break; + + case SL_PP_RBRACKET: + s = "]"; + break; + + case SL_PP_DOT: + s = "."; + break; + + case SL_PP_INCREMENT: + s = "++"; + break; + + case SL_PP_ADDASSIGN: + s = "+="; + break; + + case SL_PP_PLUS: + s = "+"; + break; + + case SL_PP_DECREMENT: + s = "--"; + break; + + case SL_PP_SUBASSIGN: + s = "-="; + break; + + case SL_PP_MINUS: + s = "-"; + break; + + case SL_PP_BITNOT: + s = "~"; + break; + + case SL_PP_NOTEQUAL: + s = "!="; + break; + + case SL_PP_NOT: + s = "!"; + break; + + case SL_PP_MULASSIGN: + s = "*="; + break; + + case SL_PP_STAR: + s = "*"; + break; + + case SL_PP_DIVASSIGN: + s = "/="; + break; + + case SL_PP_SLASH: + s = "/"; + break; + + case SL_PP_MODASSIGN: + s = "%="; + break; + + case SL_PP_MODULO: + s = "%"; + break; + + case SL_PP_LSHIFTASSIGN: + s = "<<="; + break; + + case SL_PP_LSHIFT: + s = "<<"; + break; + + case SL_PP_LESSEQUAL: + s = "<="; + break; + + case SL_PP_LESS: + s = "<"; + break; + + case SL_PP_RSHIFTASSIGN: + s = ">>="; + break; + + case SL_PP_RSHIFT: + s = ">>"; + break; + + case SL_PP_GREATEREQUAL: + s = ">="; + break; + + case SL_PP_GREATER: + s = ">"; + break; + + case SL_PP_EQUAL: + s = "=="; + break; + + case SL_PP_ASSIGN: + s = "="; + break; + + case SL_PP_AND: + s = "&&"; + break; + + case SL_PP_BITANDASSIGN: + s = "&="; + break; + + case SL_PP_BITAND: + s = "&"; + break; + + case SL_PP_XOR: + s = "^^"; + break; + + case SL_PP_BITXORASSIGN: + s = "^="; + break; + + case SL_PP_BITXOR: + s = "^"; + break; + + case SL_PP_OR: + s = "||"; + break; + + case SL_PP_BITORASSIGN: + s = "|="; + break; + + case SL_PP_BITOR: + s = "|"; + break; + + case SL_PP_QUESTION: + s = "?"; + break; + + case SL_PP_COLON: + s = ":"; + break; + + case SL_PP_IDENTIFIER: + s = sl_pp_context_cstr(context, input[i].data.identifier); + break; + + case SL_PP_NUMBER: + s = sl_pp_context_cstr(context, input[i].data.number); + break; + + case SL_PP_OTHER: + buf[0] = input[i].data.other; + buf[1] = '\0'; + s = buf; + break; + + default: + strcpy(context->error_msg, "internal error"); + return; + } + + while (*s != '\0' && out_len < sizeof(context->error_msg) - 1) { + context->error_msg[out_len++] = *s++; + } + } + + context->error_msg[out_len] = '\0'; +} diff --git a/src/glsl/pp/sl_pp_expression.c b/src/glsl/pp/sl_pp_expression.c new file mode 100644 index 0000000000..6b2329ed1a --- /dev/null +++ b/src/glsl/pp/sl_pp_expression.c @@ -0,0 +1,409 @@ +/************************************************************************** + * + * 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" + + +struct parse_context { + struct sl_pp_context *context; + const struct sl_pp_token_info *input; +}; + +static int +_parse_or(struct parse_context *ctx, + int *result); + +static int +_parse_primary(struct parse_context *ctx, + int *result) +{ + if (ctx->input->token == SL_PP_NUMBER) { + *result = atoi(sl_pp_context_cstr(ctx->context, ctx->input->data.number)); + ctx->input++; + } else { + if (ctx->input->token != SL_PP_LPAREN) { + strcpy(ctx->context->error_msg, "expected `('"); + return -1; + } + ctx->input++; + if (_parse_or(ctx, result)) { + return -1; + } + if (ctx->input->token != SL_PP_RPAREN) { + strcpy(ctx->context->error_msg, "expected `)'"); + return -1; + } + ctx->input++; + } + return 0; +} + +static int +_parse_unary(struct parse_context *ctx, + int *result) +{ + if (!_parse_primary(ctx, result)) { + return 0; + } + + switch (ctx->input->token) { + case SL_PP_PLUS: + ctx->input++; + if (_parse_unary(ctx, result)) { + return -1; + } + *result = +*result; + break; + + case SL_PP_MINUS: + ctx->input++; + if (_parse_unary(ctx, result)) { + return -1; + } + *result = -*result; + break; + + case SL_PP_NOT: + ctx->input++; + if (_parse_unary(ctx, result)) { + return -1; + } + *result = !*result; + break; + + case SL_PP_BITNOT: + ctx->input++; + if (_parse_unary(ctx, result)) { + return -1; + } + *result = ~*result; + break; + + default: + return -1; + } + + return 0; +} + +static int +_parse_multiplicative(struct parse_context *ctx, + int *result) +{ + if (_parse_unary(ctx, result)) { + return -1; + } + for (;;) { + int right; + + switch (ctx->input->token) { + case SL_PP_STAR: + ctx->input++; + if (_parse_unary(ctx, &right)) { + return -1; + } + *result = *result * right; + break; + + case SL_PP_SLASH: + ctx->input++; + if (_parse_unary(ctx, &right)) { + return -1; + } + *result = *result / right; + break; + + case SL_PP_MODULO: + ctx->input++; + if (_parse_unary(ctx, &right)) { + return -1; + } + *result = *result % right; + break; + + default: + return 0; + } + } +} + +static int +_parse_additive(struct parse_context *ctx, + int *result) +{ + if (_parse_multiplicative(ctx, result)) { + return -1; + } + for (;;) { + int right; + + switch (ctx->input->token) { + case SL_PP_PLUS: + ctx->input++; + if (_parse_multiplicative(ctx, &right)) { + return -1; + } + *result = *result + right; + break; + + case SL_PP_MINUS: + ctx->input++; + if (_parse_multiplicative(ctx, &right)) { + return -1; + } + *result = *result - right; + break; + + default: + return 0; + } + } +} + +static int +_parse_shift(struct parse_context *ctx, + int *result) +{ + if (_parse_additive(ctx, result)) { + return -1; + } + for (;;) { + int right; + + switch (ctx->input->token) { + case SL_PP_LSHIFT: + ctx->input++; + if (_parse_additive(ctx, &right)) { + return -1; + } + *result = *result << right; + break; + + case SL_PP_RSHIFT: + ctx->input++; + if (_parse_additive(ctx, &right)) { + return -1; + } + *result = *result >> right; + break; + + default: + return 0; + } + } +} + +static int +_parse_relational(struct parse_context *ctx, + int *result) +{ + if (_parse_shift(ctx, result)) { + return -1; + } + for (;;) { + int right; + + switch (ctx->input->token) { + case SL_PP_LESSEQUAL: + ctx->input++; + if (_parse_shift(ctx, &right)) { + return -1; + } + *result = *result <= right; + break; + + case SL_PP_GREATEREQUAL: + ctx->input++; + if (_parse_shift(ctx, &right)) { + return -1; + } + *result = *result >= right; + break; + + case SL_PP_LESS: + ctx->input++; + if (_parse_shift(ctx, &right)) { + return -1; + } + *result = *result < right; + break; + + case SL_PP_GREATER: + ctx->input++; + if (_parse_shift(ctx, &right)) { + return -1; + } + *result = *result > right; + break; + + default: + return 0; + } + } +} + +static int +_parse_equality(struct parse_context *ctx, + int *result) +{ + if (_parse_relational(ctx, result)) { + return -1; + } + for (;;) { + int right; + + switch (ctx->input->token) { + case SL_PP_EQUAL: + ctx->input++; + if (_parse_relational(ctx, &right)) { + return -1; + } + *result = *result == right; + break; + + case SL_PP_NOTEQUAL: + ctx->input++; + if (_parse_relational(ctx, &right)) { + return -1; + } + *result = *result != right; + break; + + default: + return 0; + } + } +} + +static int +_parse_bitand(struct parse_context *ctx, + int *result) +{ + if (_parse_equality(ctx, result)) { + return -1; + } + while (ctx->input->token == SL_PP_BITAND) { + int right; + + ctx->input++; + if (_parse_equality(ctx, &right)) { + return -1; + } + *result = *result & right; + } + return 0; +} + +static int +_parse_xor(struct parse_context *ctx, + int *result) +{ + if (_parse_bitand(ctx, result)) { + return -1; + } + while (ctx->input->token == SL_PP_XOR) { + int right; + + ctx->input++; + if (_parse_bitand(ctx, &right)) { + return -1; + } + *result = *result ^ right; + } + return 0; +} + +static int +_parse_bitor(struct parse_context *ctx, + int *result) +{ + if (_parse_xor(ctx, result)) { + return -1; + } + while (ctx->input->token == SL_PP_BITOR) { + int right; + + ctx->input++; + if (_parse_xor(ctx, &right)) { + return -1; + } + *result = *result | right; + } + return 0; +} + +static int +_parse_and(struct parse_context *ctx, + int *result) +{ + if (_parse_bitor(ctx, result)) { + return -1; + } + while (ctx->input->token == SL_PP_AND) { + int right; + + ctx->input++; + if (_parse_bitor(ctx, &right)) { + return -1; + } + *result = *result && right; + } + return 0; +} + +static int +_parse_or(struct parse_context *ctx, + int *result) +{ + if (_parse_and(ctx, result)) { + return -1; + } + while (ctx->input->token == SL_PP_OR) { + int right; + + ctx->input++; + if (_parse_and(ctx, &right)) { + return -1; + } + *result = *result || right; + } + return 0; +} + +int +sl_pp_execute_expression(struct sl_pp_context *context, + const struct sl_pp_token_info *input, + int *result) +{ + struct parse_context ctx; + + ctx.context = context; + ctx.input = input; + + return _parse_or(&ctx, result); +} diff --git a/src/glsl/pp/sl_pp_expression.h b/src/glsl/pp/sl_pp_expression.h new file mode 100644 index 0000000000..377d5b4cbd --- /dev/null +++ b/src/glsl/pp/sl_pp_expression.h @@ -0,0 +1,40 @@ +/************************************************************************** + * + * 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. + * + **************************************************************************/ + +#ifndef SL_PP_EXPRESSION_H +#define SL_PP_EXPRESSION_H + +#include "sl_pp_context.h" +#include "sl_pp_token.h" + + +int +sl_pp_execute_expression(struct sl_pp_context *context, + const struct sl_pp_token_info *input, + int *result); + +#endif /* SL_PP_EXPRESSION_H */ diff --git a/src/glsl/pp/sl_pp_extension.c b/src/glsl/pp/sl_pp_extension.c new file mode 100644 index 0000000000..33193d03a8 --- /dev/null +++ b/src/glsl/pp/sl_pp_extension.c @@ -0,0 +1,144 @@ +/************************************************************************** + * + * 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_process.h" + + +int +sl_pp_process_extension(struct sl_pp_context *context, + const struct sl_pp_token_info *input, + unsigned int first, + unsigned int last, + struct sl_pp_process_state *state) +{ + int extensions[] = { + context->dict.all, + context->dict._GL_ARB_draw_buffers, + context->dict._GL_ARB_texture_rectangle, + -1 + }; + int extension_name = -1; + int *ext; + int behavior = -1; + struct sl_pp_token_info out; + + /* Grab the extension name. */ + if (first < last && input[first].token == SL_PP_IDENTIFIER) { + extension_name = input[first].data.identifier; + first++; + } + if (extension_name == -1) { + strcpy(context->error_msg, "expected identifier after `#extension'"); + return -1; + } + + /* Make sure the extension is supported. */ + out.data.extension = -1; + for (ext = extensions; *ext != -1; ext++) { + if (extension_name == *ext) { + out.data.extension = extension_name; + break; + } + } + + /* Grab the colon separating the extension name and behavior. */ + while (first < last && input[first].token == SL_PP_WHITESPACE) { + first++; + } + if (first < last && input[first].token == SL_PP_COLON) { + first++; + } else { + strcpy(context->error_msg, "expected `:' after extension name"); + return -1; + } + while (first < last && input[first].token == SL_PP_WHITESPACE) { + first++; + } + + /* Grab the behavior name. */ + if (first < last && input[first].token == SL_PP_IDENTIFIER) { + behavior = input[first].data.identifier; + first++; + } + if (behavior == -1) { + strcpy(context->error_msg, "expected identifier after `:'"); + return -1; + } + + if (behavior == context->dict.require) { + if (out.data.extension == -1) { + strcpy(context->error_msg, "the required extension is not supported"); + return -1; + } + if (out.data.extension == context->dict.all) { + strcpy(context->error_msg, "invalid behavior for `all' extension: `require'"); + return -1; + } + out.token = SL_PP_EXTENSION_REQUIRE; + } else if (behavior == context->dict.enable) { + if (out.data.extension == -1) { + /* Warning: the extension cannot be enabled. */ + return 0; + } + if (out.data.extension == context->dict.all) { + strcpy(context->error_msg, "invalid behavior for `all' extension: `enable'"); + return -1; + } + out.token = SL_PP_EXTENSION_ENABLE; + } else if (behavior == context->dict.warn) { + if (out.data.extension == -1) { + /* Warning: the extension is not supported. */ + return 0; + } + out.token = SL_PP_EXTENSION_WARN; + } else if (behavior == context->dict.disable) { + if (out.data.extension == -1) { + /* Warning: the extension is not supported. */ + return 0; + } + out.token = SL_PP_EXTENSION_DISABLE; + } else { + strcpy(context->error_msg, "unrecognised behavior name"); + return -1; + } + + /* Grab the end of line. */ + while (first < last && input[first].token == SL_PP_WHITESPACE) { + first++; + } + if (first < last) { + strcpy(context->error_msg, "expected end of line after behavior name"); + return -1; + } + + if (sl_pp_process_out(state, &out)) { + return -1; + } + + return 0; +} diff --git a/src/glsl/pp/sl_pp_if.c b/src/glsl/pp/sl_pp_if.c new file mode 100644 index 0000000000..cf1c746d5f --- /dev/null +++ b/src/glsl/pp/sl_pp_if.c @@ -0,0 +1,355 @@ +/************************************************************************** + * + * 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 void +skip_whitespace(const struct sl_pp_token_info *input, + unsigned int *pi) +{ + while (input[*pi].token == SL_PP_WHITESPACE) { + (*pi)++; + } +} + +static int +_parse_defined(struct sl_pp_context *context, + const struct sl_pp_token_info *input, + unsigned int *pi, + struct sl_pp_process_state *state) +{ + int parens = 0; + int macro_name; + struct sl_pp_macro *macro; + int defined = 0; + struct sl_pp_token_info result; + + skip_whitespace(input, pi); + if (input[*pi].token == SL_PP_LPAREN) { + (*pi)++; + skip_whitespace(input, pi); + parens = 1; + } + + if (input[*pi].token != SL_PP_IDENTIFIER) { + strcpy(context->error_msg, "expected an identifier"); + return -1; + } + + macro_name = input[*pi].data.identifier; + for (macro = context->macro; macro; macro = macro->next) { + if (macro->name == macro_name) { + defined = 1; + break; + } + } + (*pi)++; + + if (parens) { + skip_whitespace(input, pi); + if (input[*pi].token != SL_PP_RPAREN) { + strcpy(context->error_msg, "expected `)'"); + return -1; + } + (*pi)++; + } + + result.token = SL_PP_NUMBER; + if (defined) { + result.data.number = sl_pp_context_add_unique_str(context, "1"); + } else { + result.data.number = sl_pp_context_add_unique_str(context, "0"); + } + if (result.data.number == -1) { + return -1; + } + + if (sl_pp_process_out(state, &result)) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + + return 0; +} + +static unsigned 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) { + strcpy(context->error_msg, "`#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 (input[i].data.identifier == context->dict.defined) { + i++; + if (_parse_defined(context, input, &i, &state)) { + free(state.out); + return -1; + } + } else { + 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])) { + strcpy(context->error_msg, "out of memory"); + free(state.out); + return -1; + } + i++; + } + } + + eof.token = SL_PP_EOF; + if (sl_pp_process_out(&state, &eof)) { + strcpy(context->error_msg, "out of memory"); + 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) { + strcpy(context->error_msg, "no matching `#if'"); + return -1; + } + + /* Bit b1 indicates we already went through #else. */ + if (context->if_stack[context->if_ptr] & 2) { + strcpy(context->error_msg, "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) { + strcpy(context->error_msg, "`#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: + strcpy(context->error_msg, "expected an identifier"); + return -1; + } + } + + strcpy(context->error_msg, "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) { + strcpy(context->error_msg, "`#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: + strcpy(context->error_msg, "expected an identifier"); + return -1; + } + } + + strcpy(context->error_msg, "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) { + strcpy(context->error_msg, "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_line.c b/src/glsl/pp/sl_pp_line.c new file mode 100644 index 0000000000..504c20ebcd --- /dev/null +++ b/src/glsl/pp/sl_pp_line.c @@ -0,0 +1,130 @@ +/************************************************************************** + * + * 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_process.h" + + +int +sl_pp_process_line(struct sl_pp_context *context, + const struct sl_pp_token_info *input, + unsigned int first, + unsigned int last, + struct sl_pp_process_state *pstate) +{ + unsigned int i; + struct sl_pp_process_state state; + int line_number = -1; + int file_number = -1; + unsigned int line; + + 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])) { + strcpy(context->error_msg, "out of memory"); + free(state.out); + return -1; + } + i++; + } + } + + if (state.out_len > 0 && state.out[0].token == SL_PP_NUMBER) { + line_number = state.out[0].data.number; + } else { + strcpy(context->error_msg, "expected a number after `#line'"); + free(state.out); + return -1; + } + + if (state.out_len > 1) { + if (state.out[1].token == SL_PP_NUMBER) { + file_number = state.out[1].data.number; + } else { + strcpy(context->error_msg, "expected a number after line number"); + free(state.out); + return -1; + } + + if (state.out_len > 2) { + strcpy(context->error_msg, "expected an end of line after file number"); + free(state.out); + return -1; + } + } + + free(state.out); + + line = atoi(sl_pp_context_cstr(context, line_number)); + + if (context->line != line) { + struct sl_pp_token_info ti; + + ti.token = SL_PP_LINE; + ti.data.line = line; + if (sl_pp_process_out(pstate, &ti)) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + + context->line = line; + } + + if (file_number != -1) { + unsigned int file; + + file = atoi(sl_pp_context_cstr(context, file_number)); + + if (context->file != file) { + struct sl_pp_token_info ti; + + ti.token = SL_PP_FILE; + ti.data.file = file; + if (sl_pp_process_out(pstate, &ti)) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + + context->file = file; + } + } + + return 0; +} diff --git a/src/glsl/pp/sl_pp_macro.c b/src/glsl/pp/sl_pp_macro.c new file mode 100644 index 0000000000..878b22ed9c --- /dev/null +++ b/src/glsl/pp/sl_pp_macro.c @@ -0,0 +1,356 @@ +/************************************************************************** + * + * 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 <stdio.h> +#include "sl_pp_macro.h" +#include "sl_pp_process.h" + + +static void +_macro_init(struct sl_pp_macro *macro) +{ + macro->name = -1; + macro->num_args = -1; + macro->arg = NULL; + macro->body = NULL; +} + +struct sl_pp_macro * +sl_pp_macro_new(void) +{ + struct sl_pp_macro *macro; + + macro = calloc(1, sizeof(struct sl_pp_macro)); + if (macro) { + _macro_init(macro); + } + return macro; +} + +static void +_macro_destroy(struct sl_pp_macro *macro) +{ + struct sl_pp_macro_formal_arg *arg = macro->arg; + + while (arg) { + struct sl_pp_macro_formal_arg *next_arg = arg->next; + + free(arg); + arg = next_arg; + } + + free(macro->body); +} + +void +sl_pp_macro_free(struct sl_pp_macro *macro) +{ + while (macro) { + struct sl_pp_macro *next_macro = macro->next; + + _macro_destroy(macro); + free(macro); + macro = next_macro; + } +} + +void +sl_pp_macro_reset(struct sl_pp_macro *macro) +{ + _macro_destroy(macro); + _macro_init(macro); +} + +static void +skip_whitespace(const struct sl_pp_token_info *input, + unsigned int *pi) +{ + while (input[*pi].token == SL_PP_WHITESPACE) { + (*pi)++; + } +} + +static int +_out_number(struct sl_pp_context *context, + struct sl_pp_process_state *state, + unsigned int number) +{ + char buf[32]; + struct sl_pp_token_info ti; + + sprintf(buf, "%u", number); + + ti.token = SL_PP_NUMBER; + ti.data.number = sl_pp_context_add_unique_str(context, buf); + if (sl_pp_process_out(state, &ti)) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + + return 0; +} + +int +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, + int mute) +{ + int macro_name; + struct sl_pp_macro *macro = NULL; + struct sl_pp_macro *actual_arg = NULL; + unsigned int j; + + if (input[*pi].token != SL_PP_IDENTIFIER) { + strcpy(context->error_msg, "expected an identifier"); + return -1; + } + + macro_name = input[*pi].data.identifier; + + if (macro_name == context->dict.___LINE__) { + if (!mute && _out_number(context, state, context->line)) { + return -1; + } + (*pi)++; + return 0; + } + if (macro_name == context->dict.___FILE__) { + if (!mute && _out_number(context, state, context->file)) { + return -1; + } + (*pi)++; + return 0; + } + if (macro_name == context->dict.__VERSION__) { + if (!mute && _out_number(context, state, 110)) { + return -1; + } + (*pi)++; + return 0; + } + + /* TODO: For FEATURE_es2_glsl, expand to 1 the following symbols. + * GL_ES + * GL_FRAGMENT_PRECISION_HIGH + */ + + if (local) { + for (macro = local; macro; macro = macro->next) { + if (macro->name == macro_name) { + break; + } + } + } + + if (!macro) { + for (macro = context->macro; macro; macro = macro->next) { + if (macro->name == macro_name) { + break; + } + } + } + + if (!macro) { + if (!mute) { + if (sl_pp_process_out(state, &input[*pi])) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + } + (*pi)++; + return 0; + } + + (*pi)++; + + if (macro->num_args >= 0) { + skip_whitespace(input, pi); + if (input[*pi].token != SL_PP_LPAREN) { + strcpy(context->error_msg, "expected `('"); + return -1; + } + (*pi)++; + skip_whitespace(input, pi); + } + + if (macro->num_args > 0) { + struct sl_pp_macro_formal_arg *formal_arg = macro->arg; + struct sl_pp_macro **pmacro = &actual_arg; + + for (j = 0; j < (unsigned int)macro->num_args; j++) { + unsigned int body_len; + unsigned int i; + int done = 0; + unsigned int paren_nesting = 0; + unsigned int k; + + *pmacro = sl_pp_macro_new(); + if (!*pmacro) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + + (**pmacro).name = formal_arg->name; + + body_len = 1; + for (i = *pi; !done; i++) { + switch (input[i].token) { + case SL_PP_WHITESPACE: + break; + + case SL_PP_COMMA: + if (!paren_nesting) { + if (j < (unsigned int)macro->num_args - 1) { + done = 1; + } else { + strcpy(context->error_msg, "too many actual macro arguments"); + return -1; + } + } else { + body_len++; + } + break; + + case SL_PP_LPAREN: + paren_nesting++; + body_len++; + break; + + case SL_PP_RPAREN: + if (!paren_nesting) { + if (j == (unsigned int)macro->num_args - 1) { + done = 1; + } else { + strcpy(context->error_msg, "too few actual macro arguments"); + return -1; + } + } else { + paren_nesting--; + body_len++; + } + break; + + case SL_PP_EOF: + strcpy(context->error_msg, "too few actual macro arguments"); + return -1; + + default: + body_len++; + } + } + + (**pmacro).body = malloc(sizeof(struct sl_pp_token_info) * body_len); + if (!(**pmacro).body) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + + for (done = 0, k = 0, i = *pi; !done; i++) { + switch (input[i].token) { + case SL_PP_WHITESPACE: + break; + + case SL_PP_COMMA: + if (!paren_nesting && j < (unsigned int)macro->num_args - 1) { + done = 1; + } else { + (**pmacro).body[k++] = input[i]; + } + break; + + case SL_PP_LPAREN: + paren_nesting++; + (**pmacro).body[k++] = input[i]; + break; + + case SL_PP_RPAREN: + if (!paren_nesting && j == (unsigned int)macro->num_args - 1) { + done = 1; + } else { + paren_nesting--; + (**pmacro).body[k++] = input[i]; + } + break; + + default: + (**pmacro).body[k++] = input[i]; + } + } + + (**pmacro).body[k++].token = SL_PP_EOF; + (*pi) = i; + + formal_arg = formal_arg->next; + pmacro = &(**pmacro).next; + } + } + + /* Right paren for non-empty argument list has already been eaten. */ + if (macro->num_args == 0) { + skip_whitespace(input, pi); + if (input[*pi].token != SL_PP_RPAREN) { + strcpy(context->error_msg, "expected `)'"); + return -1; + } + (*pi)++; + } + + for (j = 0;;) { + switch (macro->body[j].token) { + case SL_PP_NEWLINE: + if (sl_pp_process_out(state, ¯o->body[j])) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + j++; + break; + + case SL_PP_IDENTIFIER: + if (sl_pp_macro_expand(context, macro->body, &j, actual_arg, state, mute)) { + return -1; + } + break; + + case SL_PP_EOF: + sl_pp_macro_free(actual_arg); + return 0; + + default: + if (!mute) { + if (sl_pp_process_out(state, ¯o->body[j])) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + } + j++; + } + } +} diff --git a/src/glsl/pp/sl_pp_macro.h b/src/glsl/pp/sl_pp_macro.h new file mode 100644 index 0000000000..7af11c5ece --- /dev/null +++ b/src/glsl/pp/sl_pp_macro.h @@ -0,0 +1,64 @@ +/************************************************************************** + * + * 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. + * + **************************************************************************/ + +#ifndef SL_PP_MACRO_H +#define SL_PP_MACRO_H + +#include "sl_pp_token.h" + + +struct sl_pp_macro_formal_arg { + int name; + struct sl_pp_macro_formal_arg *next; +}; + +struct sl_pp_macro { + int name; + int num_args; /* -1 means no args, 0 means `()' */ + struct sl_pp_macro_formal_arg *arg; + struct sl_pp_token_info *body; + struct sl_pp_macro *next; +}; + +struct sl_pp_macro * +sl_pp_macro_new(void); + +void +sl_pp_macro_free(struct sl_pp_macro *macro); + +void +sl_pp_macro_reset(struct sl_pp_macro *macro); + +int +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, + int mute); + +#endif /* SL_PP_MACRO_H */ diff --git a/src/glsl/pp/sl_pp_pragma.c b/src/glsl/pp/sl_pp_pragma.c new file mode 100644 index 0000000000..03269b63db --- /dev/null +++ b/src/glsl/pp/sl_pp_pragma.c @@ -0,0 +1,107 @@ +/************************************************************************** + * + * 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_process.h" + + +int +sl_pp_process_pragma(struct sl_pp_context *context, + const struct sl_pp_token_info *input, + unsigned int first, + unsigned int last, + struct sl_pp_process_state *state) +{ + int pragma_name = -1; + struct sl_pp_token_info out; + int arg_name = -1; + + if (first < last && input[first].token == SL_PP_IDENTIFIER) { + pragma_name = input[first].data.identifier; + first++; + } + if (pragma_name == -1) { + return 0; + } + + if (pragma_name == context->dict.optimize) { + out.token = SL_PP_PRAGMA_OPTIMIZE; + } else if (pragma_name == context->dict.debug) { + out.token = SL_PP_PRAGMA_DEBUG; + } else { + return 0; + } + + while (first < last && input[first].token == SL_PP_WHITESPACE) { + first++; + } + + if (first < last && input[first].token == SL_PP_LPAREN) { + first++; + } else { + return 0; + } + + while (first < last && input[first].token == SL_PP_WHITESPACE) { + first++; + } + + if (first < last && input[first].token == SL_PP_IDENTIFIER) { + arg_name = input[first].data.identifier; + first++; + } + if (arg_name == -1) { + return 0; + } + + if (arg_name == context->dict.off) { + out.data.pragma = 0; + } else if (arg_name == context->dict.on) { + out.data.pragma = 1; + } else { + return 0; + } + + while (first < last && input[first].token == SL_PP_WHITESPACE) { + first++; + } + + if (first < last && input[first].token == SL_PP_RPAREN) { + first++; + } else { + return 0; + } + + /* Ignore the tokens that follow. */ + + if (sl_pp_process_out(state, &out)) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + + return 0; +} diff --git a/src/glsl/pp/sl_pp_process.c b/src/glsl/pp/sl_pp_process.c new file mode 100644 index 0000000000..ab2f2d8eb4 --- /dev/null +++ b/src/glsl/pp/sl_pp_process.c @@ -0,0 +1,282 @@ +/************************************************************************** + * + * 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_process.h" + + +static void +skip_whitespace(const struct sl_pp_token_info *input, + unsigned int *pi) +{ + while (input[*pi].token == SL_PP_WHITESPACE) { + (*pi)++; + } +} + +int +sl_pp_process_out(struct sl_pp_process_state *state, + const struct sl_pp_token_info *token) +{ + if (state->out_len >= state->out_max) { + unsigned int new_max = state->out_max; + + if (new_max < 0x100) { + new_max = 0x100; + } else if (new_max < 0x10000) { + new_max *= 2; + } else { + new_max += 0x10000; + } + + state->out = realloc(state->out, new_max * sizeof(struct sl_pp_token_info)); + if (!state->out) { + return -1; + } + state->out_max = new_max; + } + + state->out[state->out_len++] = *token; + return 0; +} + +int +sl_pp_process(struct sl_pp_context *context, + const struct sl_pp_token_info *input, + struct sl_pp_token_info **output) +{ + unsigned int i = 0; + int found_eof = 0; + struct sl_pp_process_state state; + + memset(&state, 0, sizeof(state)); + + if (context->line > 1) { + struct sl_pp_token_info ti; + + ti.token = SL_PP_LINE; + ti.data.line = context->line - 1; + if (sl_pp_process_out(&state, &ti)) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + + ti.token = SL_PP_NEWLINE; + if (sl_pp_process_out(&state, &ti)) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + } + + while (!found_eof) { + skip_whitespace(input, &i); + if (input[i].token == SL_PP_HASH) { + i++; + skip_whitespace(input, &i); + switch (input[i].token) { + case SL_PP_IDENTIFIER: + { + int name; + int found_eol = 0; + unsigned int first; + unsigned int last; + struct sl_pp_token_info endof; + + /* Directive name. */ + name = input[i].data.identifier; + i++; + skip_whitespace(input, &i); + + first = i; + + while (!found_eol) { + switch (input[i].token) { + case SL_PP_NEWLINE: + /* Preserve newline just for the sake of line numbering. */ + endof = input[i]; + i++; + found_eol = 1; + break; + + case SL_PP_EOF: + endof = input[i]; + i++; + found_eof = 1; + found_eol = 1; + break; + + default: + i++; + } + } + + last = i - 1; + + if (name == context->dict._if) { + if (sl_pp_process_if(context, input, first, last)) { + return -1; + } + } else if (name == context->dict.ifdef) { + if (sl_pp_process_ifdef(context, input, first, last)) { + return -1; + } + } else if (name == context->dict.ifndef) { + if (sl_pp_process_ifndef(context, input, first, last)) { + return -1; + } + } else if (name == context->dict.elif) { + if (sl_pp_process_elif(context, input, first, last)) { + return -1; + } + } else if (name == context->dict._else) { + if (sl_pp_process_else(context, input, first, last)) { + return -1; + } + } else if (name == context->dict.endif) { + if (sl_pp_process_endif(context, input, first, last)) { + return -1; + } + } else if (context->if_value) { + if (name == context->dict.define) { + if (sl_pp_process_define(context, input, first, last)) { + return -1; + } + } else if (name == context->dict.error) { + sl_pp_process_error(context, input, first, last); + return -1; + } else if (name == context->dict.extension) { + if (sl_pp_process_extension(context, input, first, last, &state)) { + return -1; + } + } else if (name == context->dict.line) { + if (sl_pp_process_line(context, input, first, last, &state)) { + return -1; + } + } else if (name == context->dict.pragma) { + if (sl_pp_process_pragma(context, input, first, last, &state)) { + return -1; + } + } else if (name == context->dict.undef) { + if (sl_pp_process_undef(context, input, first, last)) { + return -1; + } + } else { + strcpy(context->error_msg, "unrecognised directive name"); + return -1; + } + } + + if (sl_pp_process_out(&state, &endof)) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + context->line++; + } + break; + + case SL_PP_NEWLINE: + /* Empty directive. */ + if (sl_pp_process_out(&state, &input[i])) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + context->line++; + i++; + break; + + case SL_PP_EOF: + /* Empty directive. */ + if (sl_pp_process_out(&state, &input[i])) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + i++; + found_eof = 1; + break; + + default: + strcpy(context->error_msg, "expected a directive name"); + return -1; + } + } else { + int found_eol = 0; + + while (!found_eol) { + switch (input[i].token) { + case SL_PP_WHITESPACE: + /* Drop whitespace all together at this point. */ + i++; + break; + + case SL_PP_NEWLINE: + /* Preserve newline just for the sake of line numbering. */ + if (sl_pp_process_out(&state, &input[i])) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + context->line++; + i++; + found_eol = 1; + break; + + case SL_PP_EOF: + if (sl_pp_process_out(&state, &input[i])) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + i++; + found_eof = 1; + found_eol = 1; + break; + + case SL_PP_IDENTIFIER: + if (sl_pp_macro_expand(context, input, &i, NULL, &state, !context->if_value)) { + return -1; + } + break; + + default: + if (context->if_value) { + if (sl_pp_process_out(&state, &input[i])) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + } + i++; + } + } + } + } + + if (context->if_ptr != SL_PP_MAX_IF_NESTING) { + strcpy(context->error_msg, "expected `#endif' directive"); + 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 new file mode 100644 index 0000000000..adc08c18ae --- /dev/null +++ b/src/glsl/pp/sl_pp_process.h @@ -0,0 +1,126 @@ +/************************************************************************** + * + * 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. + * + **************************************************************************/ + +#ifndef SL_PP_PROCESS_H +#define SL_PP_PROCESS_H + +#include "sl_pp_context.h" +#include "sl_pp_macro.h" +#include "sl_pp_token.h" + + +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, + const struct sl_pp_token_info *input, + struct sl_pp_token_info **output); + +int +sl_pp_process_define(struct sl_pp_context *context, + const struct sl_pp_token_info *input, + unsigned int first, + unsigned int last); + +int +sl_pp_process_undef(struct sl_pp_context *context, + const struct sl_pp_token_info *input, + unsigned int first, + unsigned int last); + +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); + +void +sl_pp_process_error(struct sl_pp_context *context, + const struct sl_pp_token_info *input, + unsigned int first, + unsigned int last); + +int +sl_pp_process_pragma(struct sl_pp_context *context, + const struct sl_pp_token_info *input, + unsigned int first, + unsigned int last, + struct sl_pp_process_state *state); + +int +sl_pp_process_extension(struct sl_pp_context *context, + const struct sl_pp_token_info *input, + unsigned int first, + unsigned int last, + struct sl_pp_process_state *state); + +int +sl_pp_process_line(struct sl_pp_context *context, + const struct sl_pp_token_info *input, + unsigned int first, + unsigned int last, + struct sl_pp_process_state *state); + +int +sl_pp_process_out(struct sl_pp_process_state *state, + const struct sl_pp_token_info *token); + +#endif /* SL_PP_PROCESS_H */ diff --git a/src/glsl/pp/sl_pp_purify.c b/src/glsl/pp/sl_pp_purify.c new file mode 100644 index 0000000000..3fb91430f3 --- /dev/null +++ b/src/glsl/pp/sl_pp_purify.c @@ -0,0 +1,239 @@ +/************************************************************************** + * + * 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_purify.h" + + +/* + * Preprocessor purifier performs the following tasks. + * - Convert all variants of newlines into a Unix newline. + * - Merge continued lines into a single long line. + * - Remove line comments and replace block comments with whitespace. + */ + + +static unsigned int +_purify_newline(const char *input, + char *out) +{ + if (input[0] == '\n') { + *out = '\n'; + if (input[1] == '\r') { + /* + * The GLSL spec is not explicit about whether this + * combination is a valid newline or not. + * Let's assume it is acceptable. + */ + return 2; + } + return 1; + } + if (input[0] == '\r') { + *out = '\n'; + if (input[1] == '\n') { + return 2; + } + return 1; + } + *out = input[0]; + return 1; +} + + +static unsigned int +_purify_backslash(const char *input, + char *out) +{ + unsigned int eaten = 0; + + for (;;) { + if (input[0] == '\\') { + char next; + unsigned int next_eaten; + + eaten++; + input++; + + next_eaten = _purify_newline(input, &next); + if (next == '\n') { + /* + * If this is really a line continuation sequence, eat + * it and do not exit the loop. + */ + eaten += next_eaten; + input += next_eaten; + } else { + /* + * It is an error to put anything between a backslash + * and a newline and still expect it to behave like a line + * continuation sequence. + * Even if it is an innocent whitespace. + */ + *out = '\\'; + break; + } + } else { + eaten += _purify_newline(input, out); + break; + } + } + return eaten; +} + + +struct out_buf { + char *out; + unsigned int len; + unsigned int capacity; +}; + + +static int +_out_buf_putc(struct out_buf *obuf, + char c) +{ + if (obuf->len >= obuf->capacity) { + unsigned int new_max = obuf->capacity; + + if (new_max < 0x100) { + new_max = 0x100; + } else if (new_max < 0x10000) { + new_max *= 2; + } else { + new_max += 0x10000; + } + + obuf->out = realloc(obuf->out, new_max); + if (!obuf->out) { + return -1; + } + obuf->capacity = new_max; + } + + obuf->out[obuf->len++] = c; + + return 0; +} + + +static unsigned int +_purify_comment(const char *input, + struct out_buf *obuf) +{ + unsigned int eaten; + char curr; + + eaten = _purify_backslash(input, &curr); + input += eaten; + if (curr == '/') { + char next; + unsigned int next_eaten; + + next_eaten = _purify_backslash(input, &next); + if (next == '/') { + eaten += next_eaten; + input += next_eaten; + + /* Replace a line comment with either a newline or nil. */ + for (;;) { + next_eaten = _purify_backslash(input, &next); + eaten += next_eaten; + input += next_eaten; + if (next == '\n' || next == '\0') { + if (_out_buf_putc(obuf, next)) { + return 0; + } + return eaten; + } + } + } else if (next == '*') { + eaten += next_eaten; + input += next_eaten; + + /* Replace a block comment with a whitespace. */ + for (;;) { + next_eaten = _purify_backslash(input, &next); + eaten += next_eaten; + input += next_eaten; + while (next == '*') { + next_eaten = _purify_backslash(input, &next); + eaten += next_eaten; + input += next_eaten; + if (next == '/') { + if (_out_buf_putc(obuf, ' ')) { + return 0; + } + return eaten; + } + } + if (next == '\n') { + if (_out_buf_putc(obuf, '\n')) { + return 0; + } + } + if (next == '\0') { + return 0; + } + } + } + } + if (_out_buf_putc(obuf, curr)) { + return 0; + } + return eaten; +} + + +int +sl_pp_purify(const char *input, + const struct sl_pp_purify_options *options, + char **output) +{ + struct out_buf obuf; + + obuf.out = NULL; + obuf.len = 0; + obuf.capacity = 0; + + for (;;) { + unsigned int eaten; + + eaten = _purify_comment(input, &obuf); + if (!eaten) { + return -1; + } + input += eaten; + + if (obuf.out[obuf.len - 1] == '\0') { + break; + } + } + + *output = obuf.out; + return 0; +} diff --git a/src/glsl/pp/sl_pp_purify.h b/src/glsl/pp/sl_pp_purify.h new file mode 100644 index 0000000000..011b117937 --- /dev/null +++ b/src/glsl/pp/sl_pp_purify.h @@ -0,0 +1,41 @@ +/************************************************************************** + * + * 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. + * + **************************************************************************/ + +#ifndef SL_PP_PURIFY_H +#define SL_PP_PURIFY_H + +struct sl_pp_purify_options { + unsigned int preserve_columns:1; + unsigned int tab_width:4; +}; + +int +sl_pp_purify(const char *input, + const struct sl_pp_purify_options *options, + char **output); + +#endif /* SL_PP_PURIFY_H */ diff --git a/src/glsl/pp/sl_pp_token.c b/src/glsl/pp/sl_pp_token.c new file mode 100644 index 0000000000..a6a2bb2748 --- /dev/null +++ b/src/glsl/pp/sl_pp_token.c @@ -0,0 +1,608 @@ +/************************************************************************** + * + * 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_token.h" + + +static int +_is_identifier_char(char c) +{ + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; +} + + +static int +_tokenise_identifier(struct sl_pp_context *context, + const char **pinput, + struct sl_pp_token_info *info) +{ + const char *input = *pinput; + char identifier[256]; /* XXX: Remove this artifical limit. */ + unsigned int i = 0; + + info->token = SL_PP_IDENTIFIER; + info->data.identifier = -1; + + identifier[i++] = *input++; + while (_is_identifier_char(*input)) { + if (i >= sizeof(identifier) - 1) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + identifier[i++] = *input++; + } + identifier[i++] = '\0'; + + info->data.identifier = sl_pp_context_add_unique_str(context, identifier); + if (info->data.identifier == -1) { + return -1; + } + + *pinput = input; + return 0; +} + + +/* + * Return the number of consecutive decimal digits in the input stream. + */ +static unsigned int +_parse_float_digits(const char *input) +{ + unsigned int eaten = 0; + + while (input[eaten] >= '0' && input[eaten] <= '9') { + eaten++; + } + return eaten; +} + + +/* + * Try to match one of the following patterns for the fractional part + * of a floating point number. + * + * digits . [digits] + * . digits + * + * Return 0 if the pattern could not be matched, otherwise the number + * of eaten characters from the input stream. + */ +static unsigned int +_parse_float_frac(const char *input) +{ + unsigned int eaten; + + if (input[0] == '.') { + eaten = _parse_float_digits(&input[1]); + if (eaten) { + return eaten + 1; + } + return 0; + } + + eaten = _parse_float_digits(input); + if (eaten && input[eaten] == '.') { + unsigned int trailing; + + trailing = _parse_float_digits(&input[eaten + 1]); + if (trailing) { + return eaten + trailing + 1; + } + return eaten + 1; + } + + return 0; +} + + +/* + * Try to match the following pattern for the exponential part + * of a floating point number. + * + * (e|E) [(+|-)] digits + * + * Return 0 if the pattern could not be matched, otherwise the number + * of eaten characters from the input stream. + */ +static unsigned int +_parse_float_exp(const char *input) +{ + unsigned int eaten, digits; + + if (input[0] != 'e' && input[0] != 'E') { + return 0; + } + + if (input[1] == '-' || input[1] == '+') { + eaten = 2; + } else { + eaten = 1; + } + + digits = _parse_float_digits(&input[eaten]); + if (!digits) { + return 0; + } + + return eaten + digits; +} + + +/* + * Try to match one of the following patterns for a floating point number. + * + * fract [exp] [(f|F)] + * digits exp [(f|F)] + * + * Return 0 if the pattern could not be matched, otherwise the number + * of eaten characters from the input stream. + */ +static unsigned int +_parse_float(const char *input) +{ + unsigned int eaten; + + eaten = _parse_float_frac(input); + if (eaten) { + unsigned int exponent; + + exponent = _parse_float_exp(&input[eaten]); + if (exponent) { + eaten += exponent; + } + + if (input[eaten] == 'f' || input[eaten] == 'F') { + eaten++; + } + + return eaten; + } + + eaten = _parse_float_digits(input); + if (eaten) { + unsigned int exponent; + + exponent = _parse_float_exp(&input[eaten]); + if (exponent) { + eaten += exponent; + + if (input[eaten] == 'f' || input[eaten] == 'F') { + eaten++; + } + + return eaten; + } + } + + return 0; +} + + +static unsigned int +_parse_hex(const char *input) +{ + unsigned int n; + + if (input[0] != '0') { + return 0; + } + + if (input[1] != 'x' && input[1] != 'X') { + return 0; + } + + n = 2; + while ((input[n] >= '0' && input[n] <= '9') || + (input[n] >= 'a' && input[n] <= 'f') || + (input[n] >= 'A' && input[n] <= 'F')) { + n++; + } + + if (n > 2) { + return n; + } + + return 0; +} + + +static unsigned int +_parse_oct(const char *input) +{ + unsigned int n; + + if (input[0] != '0') { + return 0; + } + + n = 1; + while ((input[n] >= '0' && input[n] <= '7')) { + n++; + } + + return n; +} + + +static unsigned int +_parse_dec(const char *input) +{ + unsigned int n = 0; + + while ((input[n] >= '0' && input[n] <= '9')) { + n++; + } + + return n; +} + + +static int +_tokenise_number(struct sl_pp_context *context, + const char **pinput, + struct sl_pp_token_info *info) +{ + const char *input = *pinput; + unsigned int eaten; + char number[256]; /* XXX: Remove this artifical limit. */ + + eaten = _parse_float(input); + if (!eaten) { + eaten = _parse_hex(input); + if (!eaten) { + eaten = _parse_oct(input); + if (!eaten) { + eaten = _parse_dec(input); + } + } + } + + if (!eaten || _is_identifier_char(input[eaten])) { + strcpy(context->error_msg, "expected a number"); + return -1; + } + + if (eaten > sizeof(number) - 1) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + + memcpy(number, input, eaten); + number[eaten] = '\0'; + + info->token = SL_PP_NUMBER; + info->data.number = sl_pp_context_add_unique_str(context, number); + if (info->data.number == -1) { + return -1; + } + + *pinput = input + eaten; + return 0; +} + + +int +sl_pp_tokenise(struct sl_pp_context *context, + const char *input, + struct sl_pp_token_info **output) +{ + struct sl_pp_token_info *out = NULL; + unsigned int out_len = 0; + unsigned int out_max = 0; + + for (;;) { + struct sl_pp_token_info info; + + switch (*input) { + case ' ': + case '\t': + input++; + info.token = SL_PP_WHITESPACE; + break; + + case '\n': + input++; + info.token = SL_PP_NEWLINE; + break; + + case '#': + input++; + info.token = SL_PP_HASH; + break; + + case ',': + input++; + info.token = SL_PP_COMMA; + break; + + case ';': + input++; + info.token = SL_PP_SEMICOLON; + break; + + case '{': + input++; + info.token = SL_PP_LBRACE; + break; + + case '}': + input++; + info.token = SL_PP_RBRACE; + break; + + case '(': + input++; + info.token = SL_PP_LPAREN; + break; + + case ')': + input++; + info.token = SL_PP_RPAREN; + break; + + case '[': + input++; + info.token = SL_PP_LBRACKET; + break; + + case ']': + input++; + info.token = SL_PP_RBRACKET; + break; + + case '.': + if (input[1] >= '0' && input[1] <= '9') { + if (_tokenise_number(context, &input, &info)) { + free(out); + return -1; + } + } else { + input++; + info.token = SL_PP_DOT; + } + break; + + case '+': + input++; + if (*input == '+') { + input++; + info.token = SL_PP_INCREMENT; + } else if (*input == '=') { + input++; + info.token = SL_PP_ADDASSIGN; + } else { + info.token = SL_PP_PLUS; + } + break; + + case '-': + input++; + if (*input == '-') { + input++; + info.token = SL_PP_DECREMENT; + } else if (*input == '=') { + input++; + info.token = SL_PP_SUBASSIGN; + } else { + info.token = SL_PP_MINUS; + } + break; + + case '~': + input++; + info.token = SL_PP_BITNOT; + break; + + case '!': + input++; + if (*input == '=') { + input++; + info.token = SL_PP_NOTEQUAL; + } else { + info.token = SL_PP_NOT; + } + break; + + case '*': + input++; + if (*input == '=') { + input++; + info.token = SL_PP_MULASSIGN; + } else { + info.token = SL_PP_STAR; + } + break; + + case '/': + input++; + if (*input == '=') { + input++; + info.token = SL_PP_DIVASSIGN; + } else { + info.token = SL_PP_SLASH; + } + break; + + case '%': + input++; + if (*input == '=') { + input++; + info.token = SL_PP_MODASSIGN; + } else { + info.token = SL_PP_MODULO; + } + break; + + case '<': + input++; + if (*input == '<') { + input++; + if (*input == '=') { + input++; + info.token = SL_PP_LSHIFTASSIGN; + } else { + info.token = SL_PP_LSHIFT; + } + } else if (*input == '=') { + input++; + info.token = SL_PP_LESSEQUAL; + } else { + info.token = SL_PP_LESS; + } + break; + + case '>': + input++; + if (*input == '>') { + input++; + if (*input == '=') { + input++; + info.token = SL_PP_RSHIFTASSIGN; + } else { + info.token = SL_PP_RSHIFT; + } + } else if (*input == '=') { + input++; + info.token = SL_PP_GREATEREQUAL; + } else { + info.token = SL_PP_GREATER; + } + break; + + case '=': + input++; + if (*input == '=') { + input++; + info.token = SL_PP_EQUAL; + } else { + info.token = SL_PP_ASSIGN; + } + break; + + case '&': + input++; + if (*input == '&') { + input++; + info.token = SL_PP_AND; + } else if (*input == '=') { + input++; + info.token = SL_PP_BITANDASSIGN; + } else { + info.token = SL_PP_BITAND; + } + break; + + case '^': + input++; + if (*input == '^') { + input++; + info.token = SL_PP_XOR; + } else if (*input == '=') { + input++; + info.token = SL_PP_BITXORASSIGN; + } else { + info.token = SL_PP_BITXOR; + } + break; + + case '|': + input++; + if (*input == '|') { + input++; + info.token = SL_PP_OR; + } else if (*input == '=') { + input++; + info.token = SL_PP_BITORASSIGN; + } else { + info.token = SL_PP_BITOR; + } + break; + + case '?': + input++; + info.token = SL_PP_QUESTION; + break; + + case ':': + input++; + info.token = SL_PP_COLON; + break; + + case '\0': + info.token = SL_PP_EOF; + break; + + default: + if ((*input >= 'a' && *input <= 'z') || + (*input >= 'A' && *input <= 'Z') || + (*input == '_')) { + if (_tokenise_identifier(context, &input, &info)) { + free(out); + return -1; + } + } else if (*input >= '0' && *input <= '9') { + if (_tokenise_number(context, &input, &info)) { + free(out); + return -1; + } + } else { + info.data.other = *input++; + info.token = SL_PP_OTHER; + } + } + + if (out_len >= out_max) { + unsigned int new_max = out_max; + + if (new_max < 0x100) { + new_max = 0x100; + } else if (new_max < 0x10000) { + new_max *= 2; + } else { + new_max += 0x10000; + } + + out = realloc(out, new_max * sizeof(struct sl_pp_token_info)); + if (!out) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + out_max = new_max; + } + + out[out_len++] = info; + + if (info.token == SL_PP_EOF) { + break; + } + } + + *output = out; + return 0; +} diff --git a/src/glsl/pp/sl_pp_token.h b/src/glsl/pp/sl_pp_token.h new file mode 100644 index 0000000000..5901959383 --- /dev/null +++ b/src/glsl/pp/sl_pp_token.h @@ -0,0 +1,125 @@ +/************************************************************************** + * + * 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. + * + **************************************************************************/ + +#ifndef SL_PP_TOKEN_H +#define SL_PP_TOKEN_H + +#include "sl_pp_context.h" + + +enum sl_pp_token { + SL_PP_WHITESPACE, + SL_PP_NEWLINE, + SL_PP_HASH, /* # */ + + SL_PP_COMMA, /* , */ + SL_PP_SEMICOLON, /* ; */ + SL_PP_LBRACE, /* { */ + SL_PP_RBRACE, /* } */ + SL_PP_LPAREN, /* ( */ + SL_PP_RPAREN, /* ) */ + SL_PP_LBRACKET, /* [ */ + SL_PP_RBRACKET, /* ] */ + SL_PP_DOT, /* . */ + SL_PP_INCREMENT, /* ++ */ + SL_PP_ADDASSIGN, /* += */ + SL_PP_PLUS, /* + */ + SL_PP_DECREMENT, /* -- */ + SL_PP_SUBASSIGN, /* -= */ + SL_PP_MINUS, /* - */ + SL_PP_BITNOT, /* ~ */ + SL_PP_NOTEQUAL, /* != */ + SL_PP_NOT, /* ! */ + SL_PP_MULASSIGN, /* *= */ + SL_PP_STAR, /* * */ + SL_PP_DIVASSIGN, /* /= */ + SL_PP_SLASH, /* / */ + SL_PP_MODASSIGN, /* %= */ + SL_PP_MODULO, /* % */ + SL_PP_LSHIFTASSIGN, /* <<= */ + SL_PP_LSHIFT, /* << */ + SL_PP_LESSEQUAL, /* <= */ + SL_PP_LESS, /* < */ + SL_PP_RSHIFTASSIGN, /* >>= */ + SL_PP_RSHIFT, /* >> */ + SL_PP_GREATEREQUAL, /* >= */ + SL_PP_GREATER, /* > */ + SL_PP_EQUAL, /* == */ + SL_PP_ASSIGN, /* = */ + SL_PP_AND, /* && */ + SL_PP_BITANDASSIGN, /* &= */ + SL_PP_BITAND, /* & */ + SL_PP_XOR, /* ^^ */ + SL_PP_BITXORASSIGN, /* ^= */ + SL_PP_BITXOR, /* ^ */ + SL_PP_OR, /* || */ + SL_PP_BITORASSIGN, /* |= */ + SL_PP_BITOR, /* | */ + SL_PP_QUESTION, /* ? */ + SL_PP_COLON, /* : */ + + SL_PP_IDENTIFIER, + + SL_PP_NUMBER, + + SL_PP_OTHER, + + SL_PP_PRAGMA_OPTIMIZE, + SL_PP_PRAGMA_DEBUG, + + SL_PP_EXTENSION_REQUIRE, + SL_PP_EXTENSION_ENABLE, + SL_PP_EXTENSION_WARN, + SL_PP_EXTENSION_DISABLE, + + SL_PP_LINE, + SL_PP_FILE, + + SL_PP_EOF +}; + +union sl_pp_token_data { + int identifier; + int number; + char other; + int pragma; + int extension; + unsigned int line; + unsigned int file; +}; + +struct sl_pp_token_info { + enum sl_pp_token token; + union sl_pp_token_data data; +}; + +int +sl_pp_tokenise(struct sl_pp_context *context, + const char *input, + struct sl_pp_token_info **output); + +#endif /* SL_PP_TOKEN_H */ diff --git a/src/glsl/pp/sl_pp_version.c b/src/glsl/pp/sl_pp_version.c new file mode 100644 index 0000000000..814da46a67 --- /dev/null +++ b/src/glsl/pp/sl_pp_version.c @@ -0,0 +1,138 @@ +/************************************************************************** + * + * 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_version.h" + + +int +sl_pp_version(struct sl_pp_context *context, + const struct sl_pp_token_info *input, + unsigned int *version, + unsigned int *tokens_eaten) +{ + unsigned int i = 0; + unsigned int line = context->line; + + /* Default values if `#version' is not present. */ + *version = 110; + *tokens_eaten = 0; + + /* There can be multiple `#version' directives present. + * Accept the value of the last one. + */ + for (;;) { + int found_hash = 0; + int found_version = 0; + int found_number = 0; + int found_end = 0; + + /* Skip whitespace and newlines and seek for hash. */ + while (!found_hash) { + switch (input[i].token) { + case SL_PP_NEWLINE: + line++; + /* pass thru */ + case SL_PP_WHITESPACE: + i++; + break; + + case SL_PP_HASH: + i++; + found_hash = 1; + break; + + default: + return 0; + } + } + + /* Skip whitespace and seek for `version'. */ + while (!found_version) { + switch (input[i].token) { + case SL_PP_WHITESPACE: + i++; + break; + + case SL_PP_IDENTIFIER: + if (input[i].data.identifier != context->dict.version) { + return 0; + } + i++; + found_version = 1; + break; + + default: + return 0; + } + } + + /* Skip whitespace and seek for version number. */ + while (!found_number) { + switch (input[i].token) { + case SL_PP_WHITESPACE: + i++; + break; + + case SL_PP_NUMBER: + *version = atoi(sl_pp_context_cstr(context, input[i].data.number)); + i++; + found_number = 1; + break; + + default: + strcpy(context->error_msg, "expected version number after `#version'"); + return -1; + } + } + + /* Skip whitespace and seek for either newline or eof. */ + while (!found_end) { + switch (input[i].token) { + case SL_PP_WHITESPACE: + i++; + break; + + case SL_PP_NEWLINE: + line++; + /* pass thru */ + case SL_PP_EOF: + i++; + *tokens_eaten = i; + context->line = line; + found_end = 1; + break; + + default: + strcpy(context->error_msg, "expected end of line after version number"); + return -1; + } + } + } + + /* Should not get here. */ +} diff --git a/src/glsl/pp/sl_pp_version.h b/src/glsl/pp/sl_pp_version.h new file mode 100644 index 0000000000..cee9f55bc6 --- /dev/null +++ b/src/glsl/pp/sl_pp_version.h @@ -0,0 +1,41 @@ +/************************************************************************** + * + * 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. + * + **************************************************************************/ + +#ifndef SL_PP_VERSION_H +#define SL_PP_VERSION_H + +#include "sl_pp_context.h" +#include "sl_pp_token.h" + + +int +sl_pp_version(struct sl_pp_context *context, + const struct sl_pp_token_info *input, + unsigned int *version, + unsigned int *tokens_eaten); + +#endif /* SL_PP_VERSION_H */ |