summaryrefslogtreecommitdiff
path: root/src/glsl/pp
diff options
context:
space:
mode:
Diffstat (limited to 'src/glsl/pp')
-rw-r--r--src/glsl/pp/SConscript26
-rw-r--r--src/glsl/pp/sl_pp_context.c98
-rw-r--r--src/glsl/pp/sl_pp_context.h70
-rw-r--r--src/glsl/pp/sl_pp_define.c213
-rw-r--r--src/glsl/pp/sl_pp_error.c263
-rw-r--r--src/glsl/pp/sl_pp_expression.c407
-rw-r--r--src/glsl/pp/sl_pp_expression.h40
-rw-r--r--src/glsl/pp/sl_pp_extension.c129
-rw-r--r--src/glsl/pp/sl_pp_if.c352
-rw-r--r--src/glsl/pp/sl_pp_line.c159
-rw-r--r--src/glsl/pp/sl_pp_macro.c337
-rw-r--r--src/glsl/pp/sl_pp_macro.h64
-rw-r--r--src/glsl/pp/sl_pp_pragma.c106
-rw-r--r--src/glsl/pp/sl_pp_process.c273
-rw-r--r--src/glsl/pp/sl_pp_process.h126
-rw-r--r--src/glsl/pp/sl_pp_purify.c239
-rw-r--r--src/glsl/pp/sl_pp_purify.h41
-rw-r--r--src/glsl/pp/sl_pp_token.c401
-rw-r--r--src/glsl/pp/sl_pp_token.h125
-rw-r--r--src/glsl/pp/sl_pp_version.c179
-rw-r--r--src/glsl/pp/sl_pp_version.h41
21 files changed, 3689 insertions, 0 deletions
diff --git a/src/glsl/pp/SConscript b/src/glsl/pp/SConscript
new file mode 100644
index 0000000000..cc930380c2
--- /dev/null
+++ b/src/glsl/pp/SConscript
@@ -0,0 +1,26 @@
+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_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..2fca3791a2
--- /dev/null
+++ b/src/glsl/pp/sl_pp_context.c
@@ -0,0 +1,98 @@
+/**************************************************************************
+ *
+ * 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"
+
+
+void
+sl_pp_context_init(struct sl_pp_context *context)
+{
+ memset(context, 0, sizeof(struct sl_pp_context));
+ 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;
+}
+
+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) {
+ 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..c7e6770f44
--- /dev/null
+++ b/src/glsl/pp/sl_pp_context.h
@@ -0,0 +1,70 @@
+/**************************************************************************
+ *
+ * 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_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_macro *macro;
+ struct sl_pp_macro **macro_tail;
+
+ unsigned int if_stack[SL_PP_MAX_IF_NESTING];
+ unsigned int if_ptr;
+ int if_value;
+
+ char error_msg[SL_PP_MAX_ERROR_MSG];
+
+ unsigned int line;
+ unsigned int file;
+};
+
+void
+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..9bc9fb5359
--- /dev/null
+++ b/src/glsl/pp/sl_pp_define.c
@@ -0,0 +1,213 @@
+/**************************************************************************
+ *
+ * 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(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 {
+ /* Expected either an identifier or `)'. */
+ return -1;
+ }
+
+ arg = &macro->arg;
+
+ for (;;) {
+ if (*first < last && input[*first].token != SL_PP_IDENTIFIER) {
+ /* Expected an identifier. */
+ return -1;
+ }
+
+ *arg = malloc(sizeof(struct sl_pp_macro_formal_arg));
+ if (!*arg) {
+ 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 {
+ /* Expected either `,' or `)'. */
+ return -1;
+ }
+ } else {
+ /* Expected either `,' or `)'. */
+ return -1;
+ }
+ }
+}
+
+
+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) {
+ 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) {
+ return -1;
+ }
+
+ *context->macro_tail = macro;
+ context->macro_tail = &macro->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(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) {
+ 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_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..a692430abb
--- /dev/null
+++ b/src/glsl/pp/sl_pp_expression.c
@@ -0,0 +1,407 @@
+/**************************************************************************
+ *
+ * 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) {
+ return -1;
+ }
+ ctx->input++;
+ if (_parse_or(ctx, result)) {
+ return -1;
+ }
+ if (ctx->input->token != SL_PP_RPAREN) {
+ 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..3d223a1a54
--- /dev/null
+++ b/src/glsl/pp/sl_pp_extension.c
@@ -0,0 +1,129 @@
+/**************************************************************************
+ *
+ * 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 all_extensions = -1;
+ const char *extension_name = NULL;
+ const char *behavior = NULL;
+ struct sl_pp_token_info out;
+
+ all_extensions = sl_pp_context_add_unique_str(context, "all");
+ if (all_extensions == -1) {
+ return -1;
+ }
+
+ if (first < last && input[first].token == SL_PP_IDENTIFIER) {
+ extension_name = sl_pp_context_cstr(context, input[first].data.identifier);
+ first++;
+ }
+ if (!extension_name) {
+ strcpy(context->error_msg, "expected identifier after `#extension'");
+ return -1;
+ }
+
+ if (!strcmp(extension_name, "all")) {
+ out.data.extension = all_extensions;
+ } else {
+ out.data.extension = -1;
+ }
+
+ 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++;
+ }
+
+ if (first < last && input[first].token == SL_PP_IDENTIFIER) {
+ behavior = sl_pp_context_cstr(context, input[first].data.identifier);
+ first++;
+ }
+ if (!behavior) {
+ strcpy(context->error_msg, "expected identifier after `:'");
+ return -1;
+ }
+
+ if (!strcmp(behavior, "require")) {
+ strcpy(context->error_msg, "unable to enable required extension");
+ return -1;
+ } else if (!strcmp(behavior, "enable")) {
+ if (out.data.extension == all_extensions) {
+ strcpy(context->error_msg, "unable to enable all extensions");
+ return -1;
+ } else {
+ return 0;
+ }
+ } else if (!strcmp(behavior, "warn")) {
+ if (out.data.extension == all_extensions) {
+ out.token = SL_PP_EXTENSION_WARN;
+ } else {
+ return 0;
+ }
+ } else if (!strcmp(behavior, "disable")) {
+ if (out.data.extension == all_extensions) {
+ out.token = SL_PP_EXTENSION_DISABLE;
+ } else {
+ return 0;
+ }
+ } else {
+ strcpy(context->error_msg, "unrecognised behavior name");
+ return -1;
+ }
+
+ 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..90b8051237
--- /dev/null
+++ b/src/glsl/pp/sl_pp_if.c
@@ -0,0 +1,352 @@
+/**************************************************************************
+ *
+ * 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) {
+ /* Identifier expected. */
+ 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) {
+ /* `)' 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;
+ }
+
+ return sl_pp_process_out(state, &result);
+}
+
+static int
+_evaluate_if_stack(struct sl_pp_context *context)
+{
+ unsigned int i;
+
+ for (i = context->if_ptr; i < SL_PP_MAX_IF_NESTING; i++) {
+ if (!(context->if_stack[i] & 1)) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int
+_parse_if(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last)
+{
+ unsigned int i;
+ struct sl_pp_process_state state;
+ struct sl_pp_token_info eof;
+ int result;
+
+ if (!context->if_ptr) {
+ /* #if nesting too deep. */
+ return -1;
+ }
+
+ memset(&state, 0, sizeof(state));
+ for (i = first; i < last;) {
+ switch (input[i].token) {
+ case SL_PP_WHITESPACE:
+ i++;
+ break;
+
+ case SL_PP_IDENTIFIER:
+ {
+ const char *id = sl_pp_context_cstr(context, input[i].data.identifier);
+
+ if (!strcmp(id, "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])) {
+ free(state.out);
+ return -1;
+ }
+ i++;
+ }
+ }
+
+ eof.token = SL_PP_EOF;
+ if (sl_pp_process_out(&state, &eof)) {
+ free(state.out);
+ return -1;
+ }
+
+ if (sl_pp_execute_expression(context, state.out, &result)) {
+ free(state.out);
+ return -1;
+ }
+
+ free(state.out);
+
+ context->if_ptr--;
+ context->if_stack[context->if_ptr] = result ? 1 : 0;
+ context->if_value = _evaluate_if_stack(context);
+
+ return 0;
+}
+
+static int
+_parse_else(struct sl_pp_context *context)
+{
+ if (context->if_ptr == SL_PP_MAX_IF_NESTING) {
+ /* No matching #if. */
+ return -1;
+ }
+
+ /* Bit b1 indicates we already went through #else. */
+ if (context->if_stack[context->if_ptr] & 2) {
+ /* No matching #if. */
+ return -1;
+ }
+
+ /* Invert current condition value and mark that we are in the #else block. */
+ context->if_stack[context->if_ptr] = (1 - (context->if_stack[context->if_ptr] & 1)) | 2;
+ context->if_value = _evaluate_if_stack(context);
+
+ return 0;
+}
+
+int
+sl_pp_process_if(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last)
+{
+ return _parse_if(context, input, first, last);
+}
+
+int
+sl_pp_process_ifdef(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last)
+{
+ unsigned int i;
+
+ if (!context->if_ptr) {
+ /* #if nesting too deep. */
+ return -1;
+ }
+
+ for (i = first; i < last; i++) {
+ switch (input[i].token) {
+ case SL_PP_IDENTIFIER:
+ {
+ struct sl_pp_macro *macro;
+ int macro_name = input[i].data.identifier;
+ int defined = 0;
+
+ for (macro = context->macro; macro; macro = macro->next) {
+ if (macro->name == macro_name) {
+ defined = 1;
+ break;
+ }
+ }
+
+ context->if_ptr--;
+ context->if_stack[context->if_ptr] = defined ? 1 : 0;
+ context->if_value = _evaluate_if_stack(context);
+ }
+ return 0;
+
+ case SL_PP_WHITESPACE:
+ break;
+
+ default:
+ /* Expected an identifier. */
+ return -1;
+ }
+ }
+
+ /* Expected an identifier. */
+ return -1;
+}
+
+int
+sl_pp_process_ifndef(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last)
+{
+ unsigned int i;
+
+ if (!context->if_ptr) {
+ /* #if nesting too deep. */
+ return -1;
+ }
+
+ for (i = first; i < last; i++) {
+ switch (input[i].token) {
+ case SL_PP_IDENTIFIER:
+ {
+ struct sl_pp_macro *macro;
+ int macro_name = input[i].data.identifier;
+ int defined = 0;
+
+ for (macro = context->macro; macro; macro = macro->next) {
+ if (macro->name == macro_name) {
+ defined = 1;
+ break;
+ }
+ }
+
+ context->if_ptr--;
+ context->if_stack[context->if_ptr] = defined ? 0 : 1;
+ context->if_value = _evaluate_if_stack(context);
+ }
+ return 0;
+
+ case SL_PP_WHITESPACE:
+ break;
+
+ default:
+ /* Expected an identifier. */
+ return -1;
+ }
+ }
+
+ /* Expected an identifier. */
+ return -1;
+}
+
+int
+sl_pp_process_elif(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last)
+{
+ if (_parse_else(context)) {
+ return -1;
+ }
+
+ if (context->if_stack[context->if_ptr] & 1) {
+ context->if_ptr++;
+ if (_parse_if(context, input, first, last)) {
+ return -1;
+ }
+ }
+
+ /* We are still in the #if block. */
+ context->if_stack[context->if_ptr] = context->if_stack[context->if_ptr] & ~2;
+
+ return 0;
+}
+
+int
+sl_pp_process_else(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last)
+{
+ return _parse_else(context);
+}
+
+int
+sl_pp_process_endif(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last)
+{
+ if (context->if_ptr == SL_PP_MAX_IF_NESTING) {
+ /* No matching #if. */
+ return -1;
+ }
+
+ context->if_ptr++;
+ context->if_value = _evaluate_if_stack(context);
+
+ return 0;
+}
diff --git a/src/glsl/pp/sl_pp_line.c b/src/glsl/pp/sl_pp_line.c
new file mode 100644
index 0000000000..a56417a861
--- /dev/null
+++ b/src/glsl/pp/sl_pp_line.c
@@ -0,0 +1,159 @@
+/**************************************************************************
+ *
+ * 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 int
+_parse_integer(const char *input,
+ unsigned int *number)
+{
+ unsigned int n = 0;
+
+ while (*input >= '0' && *input <= '9') {
+ if (n * 10 < n) {
+ /* Overflow. */
+ return -1;
+ }
+
+ n = n * 10 + (*input++ - '0');
+ }
+
+ if (*input != '\0') {
+ /* Invalid decimal number. */
+ return -1;
+ }
+
+ *number = n;
+ return 0;
+}
+
+
+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;
+ const char *str;
+ 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])) {
+ 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 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 number after line number");
+ free(state.out);
+ return -1;
+ }
+
+ if (state.out_len > 2) {
+ strcpy(context->error_msg, "expected end of line after file number");
+ free(state.out);
+ return -1;
+ }
+ }
+
+ free(state.out);
+
+ str = sl_pp_context_cstr(context, line_number);
+ if (_parse_integer(str, &line)) {
+ return -1;
+ }
+
+ 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)) {
+ return -1;
+ }
+
+ context->line = line;
+ }
+
+ if (file_number != -1) {
+ unsigned int file;
+
+ str = sl_pp_context_cstr(context, file_number);
+ if (_parse_integer(str, &file)) {
+ return -1;
+ }
+
+ 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)) {
+ 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..d14c982555
--- /dev/null
+++ b/src/glsl/pp/sl_pp_macro.c
@@ -0,0 +1,337 @@
+/**************************************************************************
+ *
+ * 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);
+ return sl_pp_process_out(state, &ti);
+}
+
+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;
+ const char *macro_str;
+ struct sl_pp_macro *macro = NULL;
+ struct sl_pp_macro *actual_arg = NULL;
+ unsigned int j;
+
+ if (input[*pi].token != SL_PP_IDENTIFIER) {
+ return -1;
+ }
+
+ macro_name = input[*pi].data.identifier;
+ macro_str = sl_pp_context_cstr(context, macro_name);
+
+ if (!strcmp(macro_str, "__LINE__")) {
+ if (!mute && _out_number(context, state, context->line)) {
+ return -1;
+ }
+ (*pi)++;
+ return 0;
+ }
+ if (!strcmp(macro_str, "__FILE__")) {
+ if (!mute && _out_number(context, state, context->file)) {
+ return -1;
+ }
+ (*pi)++;
+ return 0;
+ }
+ if (!strcmp(macro_str, "__VERSION__")) {
+ if (!mute && _out_number(context, state, 110)) {
+ return -1;
+ }
+ (*pi)++;
+ return 0;
+ }
+
+ 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])) {
+ return -1;
+ }
+ }
+ (*pi)++;
+ return 0;
+ }
+
+ (*pi)++;
+
+ if (macro->num_args >= 0) {
+ skip_whitespace(input, pi);
+ if (input[*pi].token != SL_PP_LPAREN) {
+ 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) {
+ 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 {
+ 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 {
+ return -1;
+ }
+ } else {
+ paren_nesting--;
+ body_len++;
+ }
+ break;
+
+ case SL_PP_EOF:
+ return -1;
+
+ default:
+ body_len++;
+ }
+ }
+
+ (**pmacro).body = malloc(sizeof(struct sl_pp_token_info) * body_len);
+ if (!(**pmacro).body) {
+ 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) {
+ return -1;
+ }
+ (*pi)++;
+ }
+
+ for (j = 0;;) {
+ switch (macro->body[j].token) {
+ case SL_PP_NEWLINE:
+ if (sl_pp_process_out(state, &macro->body[j])) {
+ return -1;
+ }
+ j++;
+ break;
+
+ case SL_PP_IDENTIFIER:
+ if (sl_pp_macro_expand(context, macro->body, &j, actual_arg, state, 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, &macro->body[j])) {
+ 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..059bc6f288
--- /dev/null
+++ b/src/glsl/pp/sl_pp_pragma.c
@@ -0,0 +1,106 @@
+/**************************************************************************
+ *
+ * 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)
+{
+ const char *pragma_name = NULL;
+ struct sl_pp_token_info out;
+ const char *arg_name = NULL;
+
+ if (first < last && input[first].token == SL_PP_IDENTIFIER) {
+ pragma_name = sl_pp_context_cstr(context, input[first].data.identifier);
+ first++;
+ }
+ if (!pragma_name) {
+ return 0;
+ }
+
+ if (!strcmp(pragma_name, "optimize")) {
+ out.token = SL_PP_PRAGMA_OPTIMIZE;
+ } else if (!strcmp(pragma_name, "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 = sl_pp_context_cstr(context, input[first].data.identifier);
+ first++;
+ }
+ if (!arg_name) {
+ return 0;
+ }
+
+ if (!strcmp(arg_name, "off")) {
+ out.data.pragma = 0;
+ } else if (!strcmp(arg_name, "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)) {
+ 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..c4d6efaed3
--- /dev/null
+++ b/src/glsl/pp/sl_pp_process.c
@@ -0,0 +1,273 @@
+/**************************************************************************
+ *
+ * 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)) {
+ return -1;
+ }
+
+ ti.token = SL_PP_NEWLINE;
+ if (sl_pp_process_out(&state, &ti)) {
+ 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:
+ {
+ const char *name;
+ int found_eol = 0;
+ unsigned int first;
+ unsigned int last;
+ struct sl_pp_token_info endof;
+
+ /* Directive name. */
+ name = sl_pp_context_cstr(context, 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 (!strcmp(name, "if")) {
+ if (sl_pp_process_if(context, input, first, last)) {
+ return -1;
+ }
+ } else if (!strcmp(name, "ifdef")) {
+ if (sl_pp_process_ifdef(context, input, first, last)) {
+ return -1;
+ }
+ } else if (!strcmp(name, "ifndef")) {
+ if (sl_pp_process_ifndef(context, input, first, last)) {
+ return -1;
+ }
+ } else if (!strcmp(name, "elif")) {
+ if (sl_pp_process_elif(context, input, first, last)) {
+ return -1;
+ }
+ } else if (!strcmp(name, "else")) {
+ if (sl_pp_process_else(context, input, first, last)) {
+ return -1;
+ }
+ } else if (!strcmp(name, "endif")) {
+ if (sl_pp_process_endif(context, input, first, last)) {
+ return -1;
+ }
+ } else if (context->if_value) {
+ if (!strcmp(name, "define")) {
+ if (sl_pp_process_define(context, input, first, last)) {
+ return -1;
+ }
+ } else if (!strcmp(name, "error")) {
+ sl_pp_process_error(context, input, first, last);
+ return -1;
+ } else if (!strcmp(name, "extension")) {
+ if (sl_pp_process_extension(context, input, first, last, &state)) {
+ return -1;
+ }
+ } else if (!strcmp(name, "line")) {
+ if (sl_pp_process_line(context, input, first, last, &state)) {
+ return -1;
+ }
+ } else if (!strcmp(name, "pragma")) {
+ if (sl_pp_process_pragma(context, input, first, last, &state)) {
+ return -1;
+ }
+ } else if (!strcmp(name, "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)) {
+ return -1;
+ }
+ context->line++;
+ }
+ break;
+
+ case SL_PP_NEWLINE:
+ /* Empty directive. */
+ if (sl_pp_process_out(&state, &input[i])) {
+ return -1;
+ }
+ context->line++;
+ i++;
+ break;
+
+ case SL_PP_EOF:
+ /* Empty directive. */
+ if (sl_pp_process_out(&state, &input[i])) {
+ return -1;
+ }
+ i++;
+ found_eof = 1;
+ break;
+
+ default:
+ 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])) {
+ return -1;
+ }
+ context->line++;
+ i++;
+ found_eol = 1;
+ break;
+
+ case SL_PP_EOF:
+ if (sl_pp_process_out(&state, &input[i])) {
+ 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])) {
+ return -1;
+ }
+ }
+ i++;
+ }
+ }
+ }
+ }
+
+ if (context->if_ptr != SL_PP_MAX_IF_NESTING) {
+ /* #endif expected. */
+ return -1;
+ }
+
+ *output = state.out;
+ return 0;
+}
diff --git a/src/glsl/pp/sl_pp_process.h b/src/glsl/pp/sl_pp_process.h
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..68c8fbe2ec
--- /dev/null
+++ b/src/glsl/pp/sl_pp_token.c
@@ -0,0 +1,401 @@
+/**************************************************************************
+ *
+ * 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
+_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 ((*input >= 'a' && *input <= 'z') ||
+ (*input >= 'A' && *input <= 'Z') ||
+ (*input >= '0' && *input <= '9') ||
+ (*input == '_')) {
+ if (i >= sizeof(identifier) - 1) {
+ 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;
+}
+
+
+static int
+_tokenise_number(struct sl_pp_context *context,
+ const char **pinput,
+ struct sl_pp_token_info *info)
+{
+ const char *input = *pinput;
+ char number[256]; /* XXX: Remove this artifical limit. */
+ unsigned int i = 0;
+
+ info->token = SL_PP_NUMBER;
+ info->data.number = -1;
+
+ number[i++] = *input++;
+ while ((*input >= '0' && *input <= '9') ||
+ (*input >= 'a' && *input <= 'f') ||
+ (*input >= 'A' && *input <= 'F') ||
+ (*input == 'x') ||
+ (*input == 'X') ||
+ (*input == '+') ||
+ (*input == '-') ||
+ (*input == '.')) {
+ if (i >= sizeof(number) - 1) {
+ return -1;
+ }
+ number[i++] = *input++;
+ }
+ number[i++] = '\0';
+
+ info->data.number = sl_pp_context_add_unique_str(context, number);
+ if (info->data.number == -1) {
+ return -1;
+ }
+
+ *pinput = input;
+ 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) {
+ 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..82acdd1d5a
--- /dev/null
+++ b/src/glsl/pp/sl_pp_version.c
@@ -0,0 +1,179 @@
+/**************************************************************************
+ *
+ * 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_version.h"
+
+
+static int
+_parse_integer(const char *input,
+ unsigned int *number)
+{
+ unsigned int n = 0;
+
+ while (*input >= '0' && *input <= '9') {
+ if (n * 10 < n) {
+ /* Overflow. */
+ return -1;
+ }
+
+ n = n * 10 + (*input++ - '0');
+ }
+
+ if (*input != '\0') {
+ /* Invalid decimal number. */
+ return -1;
+ }
+
+ *number = n;
+ return 0;
+}
+
+
+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:
+ {
+ const char *id = sl_pp_context_cstr(context, input[i].data.identifier);
+
+ if (!id) {
+ return -1;
+ }
+ if (strcmp(id, "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:
+ {
+ const char *num = sl_pp_context_cstr(context, input[i].data.number);
+
+ if (!num) {
+ return -1;
+ }
+ if (_parse_integer(num, version)) {
+ strcpy(context->error_msg, "expected version number after `#version'");
+ return -1;
+ }
+ 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 */