summaryrefslogtreecommitdiffstats
path: root/src/glsl/pp
diff options
context:
space:
mode:
Diffstat (limited to 'src/glsl/pp')
-rw-r--r--src/glsl/pp/Makefile27
-rw-r--r--src/glsl/pp/sl_pp_context.c182
-rw-r--r--src/glsl/pp/sl_pp_context.h92
-rw-r--r--src/glsl/pp/sl_pp_define.c238
-rw-r--r--src/glsl/pp/sl_pp_dict.c85
-rw-r--r--src/glsl/pp/sl_pp_dict.h77
-rw-r--r--src/glsl/pp/sl_pp_error.c270
-rw-r--r--src/glsl/pp/sl_pp_expression.c411
-rw-r--r--src/glsl/pp/sl_pp_expression.h40
-rw-r--r--src/glsl/pp/sl_pp_extension.c171
-rw-r--r--src/glsl/pp/sl_pp_if.c344
-rw-r--r--src/glsl/pp/sl_pp_line.c127
-rw-r--r--src/glsl/pp/sl_pp_macro.c414
-rw-r--r--src/glsl/pp/sl_pp_macro.h73
-rw-r--r--src/glsl/pp/sl_pp_pragma.c109
-rw-r--r--src/glsl/pp/sl_pp_process.c327
-rw-r--r--src/glsl/pp/sl_pp_process.h116
-rw-r--r--src/glsl/pp/sl_pp_public.h84
-rw-r--r--src/glsl/pp/sl_pp_purify.c302
-rw-r--r--src/glsl/pp/sl_pp_purify.h63
-rw-r--r--src/glsl/pp/sl_pp_token.c854
-rw-r--r--src/glsl/pp/sl_pp_token.h133
-rw-r--r--src/glsl/pp/sl_pp_token_util.c182
-rw-r--r--src/glsl/pp/sl_pp_token_util.h103
-rw-r--r--src/glsl/pp/sl_pp_version.c161
25 files changed, 4985 insertions, 0 deletions
diff --git a/src/glsl/pp/Makefile b/src/glsl/pp/Makefile
new file mode 100644
index 00000000000..fda1c4202ba
--- /dev/null
+++ b/src/glsl/pp/Makefile
@@ -0,0 +1,27 @@
+#src/glsl/pp/Makefile
+
+TOP = ../../..
+
+include $(TOP)/configs/current
+
+LIBNAME = glslpp
+
+C_SOURCES = \
+ 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_token_util.c \
+ sl_pp_version.c
+
+include ../Makefile.template
+
diff --git a/src/glsl/pp/sl_pp_context.c b/src/glsl/pp/sl_pp_context.c
new file mode 100644
index 00000000000..74a9bdddfdc
--- /dev/null
+++ b/src/glsl/pp/sl_pp_context.c
@@ -0,0 +1,182 @@
+/**************************************************************************
+ *
+ * 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 <string.h>
+#include "sl_pp_public.h"
+#include "sl_pp_context.h"
+
+
+struct sl_pp_context *
+sl_pp_context_create(const char *input,
+ const struct sl_pp_purify_options *options)
+{
+ struct sl_pp_context *context;
+
+ context = calloc(1, sizeof(struct sl_pp_context));
+ if (!context) {
+ return NULL;
+ }
+
+ if (sl_pp_dict_init(context)) {
+ sl_pp_context_destroy(context);
+ return NULL;
+ }
+
+ context->getc_buf_capacity = 64;
+ context->getc_buf = malloc(context->getc_buf_capacity * sizeof(char));
+ if (!context->getc_buf) {
+ sl_pp_context_destroy(context);
+ return NULL;
+ }
+
+ if (sl_pp_token_buffer_init(&context->tokens, context)) {
+ sl_pp_context_destroy(context);
+ return NULL;
+ }
+
+ 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->error_line = 1;
+ context->line = 1;
+ context->file = 0;
+
+ sl_pp_purify_state_init(&context->pure, input, options);
+
+ memset(&context->process_state, 0, sizeof(context->process_state));
+
+ return context;
+}
+
+void
+sl_pp_context_destroy(struct sl_pp_context *context)
+{
+ if (context) {
+ free(context->cstr_pool);
+ sl_pp_macro_free(context->macro);
+ free(context->getc_buf);
+ sl_pp_token_buffer_destroy(&context->tokens);
+ free(context->process_state.out);
+ free(context);
+ }
+}
+
+const char *
+sl_pp_context_error_message(const struct sl_pp_context *context)
+{
+ return context->error_msg;
+}
+
+void
+sl_pp_context_error_position(const struct sl_pp_context *context,
+ unsigned int *file,
+ unsigned int *line)
+{
+ if (file) {
+ *file = 0;
+ }
+ if (line) {
+ *line = context->error_line;
+ }
+}
+
+int
+sl_pp_context_add_predefined(struct sl_pp_context *context,
+ const char *name,
+ const char *value)
+{
+ struct sl_pp_predefined pre;
+
+ if (context->num_predefined == SL_PP_MAX_PREDEFINED) {
+ return -1;
+ }
+
+ pre.name = sl_pp_context_add_unique_str(context, name);
+ if (pre.name == -1) {
+ return -1;
+ }
+
+ pre.value = sl_pp_context_add_unique_str(context, value);
+ if (pre.value == -1) {
+ return -1;
+ }
+
+ context->predefined[context->num_predefined++] = pre;
+ return 0;
+}
+
+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 00000000000..3eada380cd1
--- /dev/null
+++ b/src/glsl/pp/sl_pp_context.h
@@ -0,0 +1,92 @@
+/**************************************************************************
+ *
+ * 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"
+#include "sl_pp_process.h"
+#include "sl_pp_purify.h"
+#include "sl_pp_token_util.h"
+
+
+#define SL_PP_MAX_IF_NESTING 64
+
+#define SL_PP_MAX_ERROR_MSG 1024
+
+#define SL_PP_MAX_EXTENSIONS 16
+
+#define SL_PP_MAX_PREDEFINED 16
+
+struct sl_pp_extension {
+ int name; /*< VENDOR_extension_name */
+ int name_string; /*< GL_VENDOR_extension_name */
+};
+
+struct sl_pp_predefined {
+ int name;
+ int value;
+};
+
+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;
+
+ struct sl_pp_extension extensions[SL_PP_MAX_EXTENSIONS];
+ unsigned int num_extensions;
+
+ struct sl_pp_predefined predefined[SL_PP_MAX_PREDEFINED];
+ unsigned int num_predefined;
+
+ 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 error_line;
+
+ unsigned int line;
+ unsigned int file;
+
+ struct sl_pp_purify_state pure;
+
+ char *getc_buf;
+ unsigned int getc_buf_size;
+ unsigned int getc_buf_capacity;
+
+ struct sl_pp_token_buffer tokens;
+
+ struct sl_pp_process_state process_state;
+};
+
+#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 00000000000..808a6a0d4f1
--- /dev/null
+++ b/src/glsl/pp/sl_pp_define.c
@@ -0,0 +1,238 @@
+/**************************************************************************
+ *
+ * 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 <string.h>
+#include "sl_pp_context.h"
+#include "sl_pp_process.h"
+#include "sl_pp_public.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 macro formal argument or `)'");
+ return -1;
+ }
+
+ arg = &macro->arg;
+
+ for (;;) {
+ if (*first < last && input[*first].token != SL_PP_IDENTIFIER) {
+ strcpy(context->error_msg, "expected macro formal argument");
+ 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)++;
+ skip_whitespace(input, first, last);
+ } 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 macro name");
+ return -1;
+ }
+
+ /* Check for reserved macro names */
+ {
+ const char *name = sl_pp_context_cstr(context, macro_name);
+
+ if (strstr(name, "__")) {
+ strcpy(context->error_msg, "macro names containing `__' are reserved");
+ return 1;
+ }
+ if (name[0] == 'G' && name[1] == 'L' && name[2] == '_') {
+ strcpy(context->error_msg, "macro names prefixed with `GL_' are reserved");
+ 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 = &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(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 00000000000..062139e6ac0
--- /dev/null
+++ b/src/glsl/pp/sl_pp_dict.c
@@ -0,0 +1,85 @@
+/**************************************************************************
+ *
+ * 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_public.h"
+#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(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_STR(context, ___VERSION__, "__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);
+
+ ADD_NAME_STR(context, _0, "0");
+ ADD_NAME_STR(context, _1, "1");
+
+ 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 00000000000..875217bd309
--- /dev/null
+++ b/src/glsl/pp/sl_pp_dict.h
@@ -0,0 +1,77 @@
+/**************************************************************************
+ *
+ * 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_context;
+
+struct sl_pp_dict {
+ int all;
+
+ 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 _0;
+ int _1;
+};
+
+
+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 00000000000..b628e37ce83
--- /dev/null
+++ b/src/glsl/pp/sl_pp_error.c
@@ -0,0 +1,270 @@
+/**************************************************************************
+ *
+ * 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 <string.h>
+#include "sl_pp_context.h"
+#include "sl_pp_process.h"
+#include "sl_pp_public.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_UINT:
+ s = sl_pp_context_cstr(context, input[i].data._uint);
+ break;
+
+ case SL_PP_FLOAT:
+ s = sl_pp_context_cstr(context, input[i].data._float);
+ 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 00000000000..ec904787dd7
--- /dev/null
+++ b/src/glsl/pp/sl_pp_expression.c
@@ -0,0 +1,411 @@
+/**************************************************************************
+ *
+ * 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 <string.h>
+#include "sl_pp_expression.h"
+#include "sl_pp_public.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_UINT) {
+ *result = atoi(sl_pp_context_cstr(ctx->context, ctx->input->data._uint));
+ 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 00000000000..377d5b4cbd9
--- /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 00000000000..8af5731e840
--- /dev/null
+++ b/src/glsl/pp/sl_pp_extension.c
@@ -0,0 +1,171 @@
+/**************************************************************************
+ *
+ * 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 <string.h>
+#include "sl_pp_context.h"
+#include "sl_pp_process.h"
+#include "sl_pp_public.h"
+
+
+int
+sl_pp_context_add_extension(struct sl_pp_context *context,
+ const char *name,
+ const char *name_string)
+{
+ struct sl_pp_extension ext;
+
+ if (context->num_extensions == SL_PP_MAX_EXTENSIONS) {
+ return -1;
+ }
+
+ ext.name = sl_pp_context_add_unique_str(context, name);
+ if (ext.name == -1) {
+ return -1;
+ }
+
+ ext.name_string = sl_pp_context_add_unique_str(context, name_string);
+ if (ext.name_string == -1) {
+ return -1;
+ }
+
+ context->extensions[context->num_extensions++] = ext;
+ return 0;
+}
+
+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 extension_name = -1;
+ 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. */
+ if (extension_name == context->dict.all) {
+ out.data.extension = extension_name;
+ } else {
+ unsigned int i;
+
+ out.data.extension = -1;
+ for (i = 0; i < context->num_extensions; i++) {
+ if (extension_name == context->extensions[i].name_string) {
+ 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 00000000000..f12f0f142c6
--- /dev/null
+++ b/src/glsl/pp/sl_pp_if.c
@@ -0,0 +1,344 @@
+/**************************************************************************
+ *
+ * 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 <string.h>
+#include "sl_pp_expression.h"
+#include "sl_pp_process.h"
+
+
+static int
+_parse_defined(struct sl_pp_context *context,
+ struct sl_pp_token_buffer *buffer,
+ struct sl_pp_process_state *state)
+{
+ struct sl_pp_token_info input;
+ int parens = 0;
+ int macro_name;
+ struct sl_pp_macro *macro;
+ int defined = 0;
+ struct sl_pp_token_info result;
+
+ if (sl_pp_token_buffer_skip_white(buffer, &input)) {
+ return -1;
+ }
+
+ if (input.token == SL_PP_LPAREN) {
+ if (sl_pp_token_buffer_skip_white(buffer, &input)) {
+ return -1;
+ }
+ parens = 1;
+ }
+
+ if (input.token != SL_PP_IDENTIFIER) {
+ strcpy(context->error_msg, "expected an identifier");
+ return -1;
+ }
+
+ macro_name = input.data.identifier;
+ for (macro = context->macro; macro; macro = macro->next) {
+ if (macro->name == macro_name) {
+ defined = 1;
+ break;
+ }
+ }
+
+ if (parens) {
+ if (sl_pp_token_buffer_skip_white(buffer, &input)) {
+ return -1;
+ }
+ if (input.token != SL_PP_RPAREN) {
+ strcpy(context->error_msg, "expected `)'");
+ return -1;
+ }
+ }
+
+ result.token = SL_PP_UINT;
+ result.data._uint = (defined ? context->dict._1 : context->dict._0);
+
+ 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,
+ struct sl_pp_token_buffer *buffer)
+{
+ struct sl_pp_process_state state;
+ int found_end = 0;
+ 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));
+ while (!found_end) {
+ struct sl_pp_token_info input;
+
+ sl_pp_token_buffer_get(buffer, &input);
+ switch (input.token) {
+ case SL_PP_WHITESPACE:
+ break;
+
+ case SL_PP_IDENTIFIER:
+ if (input.data.identifier == context->dict.defined) {
+ if (_parse_defined(context, buffer, &state)) {
+ free(state.out);
+ return -1;
+ }
+ } else {
+ sl_pp_token_buffer_unget(buffer, &input);
+ if (sl_pp_macro_expand(context, buffer, NULL, &state, sl_pp_macro_expand_unknown_to_0)) {
+ free(state.out);
+ return -1;
+ }
+ }
+ break;
+
+ case SL_PP_NEWLINE:
+ case SL_PP_EOF:
+ found_end = 1;
+ break;
+
+ default:
+ if (sl_pp_process_out(&state, &input)) {
+ strcpy(context->error_msg, "out of memory");
+ free(state.out);
+ return -1;
+ }
+ }
+ }
+
+ 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,
+ struct sl_pp_token_buffer *buffer)
+{
+ return _parse_if(context, buffer);
+}
+
+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,
+ struct sl_pp_token_buffer *buffer)
+{
+ if (_parse_else(context)) {
+ return -1;
+ }
+
+ if (context->if_stack[context->if_ptr] & 1) {
+ context->if_ptr++;
+ if (_parse_if(context, buffer)) {
+ 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 00000000000..6f7e9eb562c
--- /dev/null
+++ b/src/glsl/pp/sl_pp_line.c
@@ -0,0 +1,127 @@
+/**************************************************************************
+ *
+ * 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 <string.h>
+#include "sl_pp_context.h"
+#include "sl_pp_public.h"
+#include "sl_pp_process.h"
+
+
+int
+sl_pp_process_line(struct sl_pp_context *context,
+ struct sl_pp_token_buffer *buffer,
+ struct sl_pp_process_state *pstate)
+{
+ struct sl_pp_process_state state;
+ int found_end = 0;
+ int line_number = -1;
+ int file_number = -1;
+ unsigned int line;
+ unsigned int file;
+
+ memset(&state, 0, sizeof(state));
+ while (!found_end) {
+ struct sl_pp_token_info input;
+
+ sl_pp_token_buffer_get(buffer, &input);
+ switch (input.token) {
+ case SL_PP_WHITESPACE:
+ break;
+
+ case SL_PP_IDENTIFIER:
+ sl_pp_token_buffer_unget(buffer, &input);
+ if (sl_pp_macro_expand(context, buffer, NULL, &state, sl_pp_macro_expand_normal)) {
+ free(state.out);
+ return -1;
+ }
+ break;
+
+ case SL_PP_NEWLINE:
+ case SL_PP_EOF:
+ found_end = 1;
+ break;
+
+ default:
+ if (sl_pp_process_out(&state, &input)) {
+ strcpy(context->error_msg, "out of memory");
+ free(state.out);
+ return -1;
+ }
+ }
+ }
+
+ if (state.out_len > 0 && state.out[0].token == SL_PP_UINT) {
+ line_number = state.out[0].data._uint;
+ } 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_UINT) {
+ file_number = state.out[1].data._uint;
+ } 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 (file_number != -1) {
+ file = atoi(sl_pp_context_cstr(context, file_number));
+ } else {
+ file = context->file;
+ }
+
+ if (context->line != line || context->file != file) {
+ struct sl_pp_token_info ti;
+
+ ti.token = SL_PP_LINE;
+ ti.data.line.lineno = line;
+ ti.data.line.fileno = file;
+ if (sl_pp_process_out(pstate, &ti)) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+
+ context->line = line;
+ 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 00000000000..9f520b8fc53
--- /dev/null
+++ b/src/glsl/pp/sl_pp_macro.c
@@ -0,0 +1,414 @@
+/**************************************************************************
+ *
+ * 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 <string.h>
+#include "sl_pp_context.h"
+#include "sl_pp_public.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 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_UINT;
+ ti.data._uint = 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,
+ struct sl_pp_token_buffer *tokens,
+ struct sl_pp_macro *local,
+ struct sl_pp_process_state *state,
+ enum sl_pp_macro_expand_behaviour behaviour)
+{
+ int mute = (behaviour == sl_pp_macro_expand_mute);
+ struct sl_pp_token_info input;
+ int macro_name;
+ struct sl_pp_macro *macro = NULL;
+ struct sl_pp_macro *actual_arg = NULL;
+ unsigned int j;
+
+ if (sl_pp_token_buffer_get(tokens, &input)) {
+ return -1;
+ }
+
+ if (input.token != SL_PP_IDENTIFIER) {
+ strcpy(context->error_msg, "expected an identifier");
+ return -1;
+ }
+
+ macro_name = input.data.identifier;
+
+ /* First look for predefined macros.
+ */
+
+ if (macro_name == context->dict.___LINE__) {
+ if (!mute && _out_number(context, state, context->line)) {
+ return -1;
+ }
+ return 0;
+ }
+ if (macro_name == context->dict.___FILE__) {
+ if (!mute && _out_number(context, state, context->file)) {
+ return -1;
+ }
+ return 0;
+ }
+ if (macro_name == context->dict.___VERSION__) {
+ if (!mute && _out_number(context, state, 110)) {
+ return -1;
+ }
+ return 0;
+ }
+
+ for (j = 0; j < context->num_predefined; j++) {
+ if (macro_name == context->predefined[j].name) {
+ if (!mute) {
+ struct sl_pp_token_info ti;
+
+ ti.token = SL_PP_UINT;
+ ti.data._uint = context->predefined[j].value;
+ if (sl_pp_process_out(state, &ti)) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+ }
+ return 0;
+ }
+ }
+
+ /* Replace extension names with 1.
+ */
+ for (j = 0; j < context->num_extensions; j++) {
+ if (macro_name == context->extensions[j].name) {
+ if (!mute && _out_number(context, state, 1)) {
+ return -1;
+ }
+ 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 (behaviour == sl_pp_macro_expand_unknown_to_0) {
+ if (_out_number(context, state, 0)) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+ } else if (!mute) {
+ if (sl_pp_process_out(state, &input)) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ if (macro->num_args >= 0) {
+ if (sl_pp_token_buffer_skip_white(tokens, &input)) {
+ return -1;
+ }
+ if (input.token != SL_PP_LPAREN) {
+ strcpy(context->error_msg, "expected `('");
+ return -1;
+ }
+ if (sl_pp_token_buffer_skip_white(tokens, &input)) {
+ return -1;
+ }
+ sl_pp_token_buffer_unget(tokens, &input);
+ }
+
+ 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++) {
+ struct sl_pp_process_state arg_state;
+ int done = 0;
+ unsigned int paren_nesting = 0;
+ struct sl_pp_token_info eof;
+
+ memset(&arg_state, 0, sizeof(arg_state));
+
+ while (!done) {
+ if (sl_pp_token_buffer_get(tokens, &input)) {
+ goto fail_arg;
+ }
+ switch (input.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");
+ goto fail_arg;
+ }
+ } else {
+ if (sl_pp_process_out(&arg_state, &input)) {
+ strcpy(context->error_msg, "out of memory");
+ goto fail_arg;
+ }
+ }
+ break;
+
+ case SL_PP_LPAREN:
+ paren_nesting++;
+ if (sl_pp_process_out(&arg_state, &input)) {
+ goto oom_arg;
+ }
+ 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");
+ goto fail_arg;
+ }
+ } else {
+ paren_nesting--;
+ if (sl_pp_process_out(&arg_state, &input)) {
+ goto oom_arg;
+ }
+ }
+ break;
+
+ case SL_PP_IDENTIFIER:
+ sl_pp_token_buffer_unget(tokens, &input);
+ if (sl_pp_macro_expand(context, tokens, local, &arg_state, sl_pp_macro_expand_normal)) {
+ goto fail_arg;
+ }
+ break;
+
+ case SL_PP_EOF:
+ strcpy(context->error_msg, "too few actual macro arguments");
+ goto fail_arg;
+
+ default:
+ if (sl_pp_process_out(&arg_state, &input)) {
+ goto oom_arg;
+ }
+ }
+ }
+
+ eof.token = SL_PP_EOF;
+ if (sl_pp_process_out(&arg_state, &eof)) {
+ goto oom_arg;
+ }
+
+ *pmacro = sl_pp_macro_new();
+ if (!*pmacro) {
+ goto oom_arg;
+ }
+
+ (**pmacro).name = formal_arg->name;
+ (**pmacro).body = arg_state.out;
+
+ formal_arg = formal_arg->next;
+ pmacro = &(**pmacro).next;
+
+ continue;
+
+oom_arg:
+ strcpy(context->error_msg, "out of memory");
+fail_arg:
+ free(arg_state.out);
+ goto fail;
+ }
+ }
+
+ /* Right paren for non-empty argument list has already been eaten. */
+ if (macro->num_args == 0) {
+ if (sl_pp_token_buffer_skip_white(tokens, &input)) {
+ goto fail;
+ }
+ if (input.token != SL_PP_RPAREN) {
+ strcpy(context->error_msg, "expected `)'");
+ goto fail;
+ }
+ }
+
+ /* XXX: This is all wrong, we should be ungetting all tokens
+ * back to the main token buffer.
+ */
+ {
+ struct sl_pp_token_buffer buffer;
+
+ /* Seek to the end.
+ */
+ for (j = 0; macro->body[j].token != SL_PP_EOF; j++) {
+ }
+ j++;
+
+ /* Create a context-less token buffer since we are not going to underrun
+ * its internal buffer.
+ */
+ if (sl_pp_token_buffer_init(&buffer, NULL)) {
+ strcpy(context->error_msg, "out of memory");
+ goto fail;
+ }
+
+ /* Unget the tokens in reverse order so later they will be fetched correctly.
+ */
+ for (; j > 0; j--) {
+ sl_pp_token_buffer_unget(&buffer, &macro->body[j - 1]);
+ }
+
+ /* Expand.
+ */
+ for (;;) {
+ struct sl_pp_token_info input;
+
+ sl_pp_token_buffer_get(&buffer, &input);
+ switch (input.token) {
+ case SL_PP_NEWLINE:
+ if (sl_pp_process_out(state, &input)) {
+ strcpy(context->error_msg, "out of memory");
+ sl_pp_token_buffer_destroy(&buffer);
+ goto fail;
+ }
+ break;
+
+ case SL_PP_IDENTIFIER:
+ sl_pp_token_buffer_unget(&buffer, &input);
+ if (sl_pp_macro_expand(context, &buffer, actual_arg, state, behaviour)) {
+ sl_pp_token_buffer_destroy(&buffer);
+ goto fail;
+ }
+ break;
+
+ case SL_PP_EOF:
+ sl_pp_token_buffer_destroy(&buffer);
+ sl_pp_macro_free(actual_arg);
+ return 0;
+
+ default:
+ if (!mute) {
+ if (sl_pp_process_out(state, &input)) {
+ strcpy(context->error_msg, "out of memory");
+ sl_pp_token_buffer_destroy(&buffer);
+ goto fail;
+ }
+ }
+ }
+ }
+ }
+
+fail:
+ sl_pp_macro_free(actual_arg);
+ return -1;
+}
diff --git a/src/glsl/pp/sl_pp_macro.h b/src/glsl/pp/sl_pp_macro.h
new file mode 100644
index 00000000000..1d210681091
--- /dev/null
+++ b/src/glsl/pp/sl_pp_macro.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_MACRO_H
+#define SL_PP_MACRO_H
+
+#include "sl_pp_token.h"
+
+
+struct sl_pp_context;
+struct sl_pp_process_state;
+struct sl_pp_token_buffer;
+
+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);
+
+enum sl_pp_macro_expand_behaviour {
+ sl_pp_macro_expand_normal,
+ sl_pp_macro_expand_mute,
+ sl_pp_macro_expand_unknown_to_0
+};
+
+int
+sl_pp_macro_expand(struct sl_pp_context *context,
+ struct sl_pp_token_buffer *tokens,
+ struct sl_pp_macro *local,
+ struct sl_pp_process_state *state,
+ enum sl_pp_macro_expand_behaviour behaviour);
+
+#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 00000000000..caf4c63f657
--- /dev/null
+++ b/src/glsl/pp/sl_pp_pragma.c
@@ -0,0 +1,109 @@
+/**************************************************************************
+ *
+ * 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 <string.h>
+#include "sl_pp_context.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 00000000000..f89986dd8ef
--- /dev/null
+++ b/src/glsl/pp/sl_pp_process.c
@@ -0,0 +1,327 @@
+/**************************************************************************
+ *
+ * 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 <string.h>
+#include "sl_pp_context.h"
+#include "sl_pp_process.h"
+#include "sl_pp_public.h"
+
+
+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_get(struct sl_pp_context *context,
+ struct sl_pp_token_info *output)
+{
+ if (!context->process_state.out) {
+ if (context->line > 1) {
+ struct sl_pp_token_info ti;
+
+ ti.token = SL_PP_LINE;
+ ti.data.line.lineno = context->line - 1;
+ ti.data.line.fileno = context->file;
+ if (sl_pp_process_out(&context->process_state, &ti)) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+
+ ti.token = SL_PP_NEWLINE;
+ if (sl_pp_process_out(&context->process_state, &ti)) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+ }
+ }
+
+ for (;;) {
+ struct sl_pp_token_info input;
+ int found_eof = 0;
+
+ if (context->process_state.out_len) {
+ *output = context->process_state.out[0];
+
+ if (context->process_state.out_len > 1) {
+ unsigned int i;
+
+ for (i = 1; i < context->process_state.out_len; i++) {
+ context->process_state.out[i - 1] = context->process_state.out[i];
+ }
+ }
+ context->process_state.out_len--;
+
+ return 0;
+ }
+
+ if (sl_pp_token_buffer_skip_white(&context->tokens, &input)) {
+ return -1;
+ }
+ if (input.token == SL_PP_HASH) {
+ if (sl_pp_token_buffer_skip_white(&context->tokens, &input)) {
+ return -1;
+ }
+ switch (input.token) {
+ case SL_PP_IDENTIFIER:
+ {
+ int name;
+ int found_eol = 0;
+ struct sl_pp_token_info endof;
+ struct sl_pp_token_peek peek;
+ int result = 0;
+
+ /* Directive name. */
+ name = input.data.identifier;
+
+ if (sl_pp_token_buffer_skip_white(&context->tokens, &input)) {
+ return -1;
+ }
+ sl_pp_token_buffer_unget(&context->tokens, &input);
+
+ if (sl_pp_token_peek_init(&peek, &context->tokens)) {
+ return -1;
+ }
+
+ while (!found_eol) {
+ if (sl_pp_token_peek_get(&peek, &input)) {
+ sl_pp_token_peek_destroy(&peek);
+ return -1;
+ }
+ switch (input.token) {
+ case SL_PP_NEWLINE:
+ /* Preserve newline just for the sake of line numbering. */
+ endof = input;
+ found_eol = 1;
+ break;
+
+ case SL_PP_EOF:
+ endof = input;
+ found_eof = 1;
+ found_eol = 1;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (name == context->dict._if) {
+ struct sl_pp_token_buffer buffer;
+
+ result = sl_pp_token_peek_to_buffer(&peek, &buffer);
+ if (result == 0) {
+ result = sl_pp_process_if(context, &buffer);
+ sl_pp_token_buffer_destroy(&buffer);
+ }
+ } else if (name == context->dict.ifdef) {
+ result = sl_pp_process_ifdef(context, peek.tokens, 0, peek.size - 1);
+ } else if (name == context->dict.ifndef) {
+ result = sl_pp_process_ifndef(context, peek.tokens, 0, peek.size - 1);
+ } else if (name == context->dict.elif) {
+ struct sl_pp_token_buffer buffer;
+
+ result = sl_pp_token_peek_to_buffer(&peek, &buffer);
+ if (result == 0) {
+ result = sl_pp_process_elif(context, &buffer);
+ sl_pp_token_buffer_destroy(&buffer);
+ }
+ } else if (name == context->dict._else) {
+ result = sl_pp_process_else(context, peek.tokens, 0, peek.size - 1);
+ } else if (name == context->dict.endif) {
+ result = sl_pp_process_endif(context, peek.tokens, 0, peek.size - 1);
+ } else if (context->if_value) {
+ if (name == context->dict.define) {
+ result = sl_pp_process_define(context, peek.tokens, 0, peek.size - 1);
+ } else if (name == context->dict.error) {
+ sl_pp_process_error(context, peek.tokens, 0, peek.size - 1);
+ result = -1;
+ } else if (name == context->dict.extension) {
+ result = sl_pp_process_extension(context, peek.tokens, 0, peek.size - 1, &context->process_state);
+ } else if (name == context->dict.line) {
+ struct sl_pp_token_buffer buffer;
+
+ result = sl_pp_token_peek_to_buffer(&peek, &buffer);
+ if (result == 0) {
+ result = sl_pp_process_line(context, &buffer, &context->process_state);
+ sl_pp_token_buffer_destroy(&buffer);
+ }
+ } else if (name == context->dict.pragma) {
+ result = sl_pp_process_pragma(context, peek.tokens, 0, peek.size - 1, &context->process_state);
+ } else if (name == context->dict.undef) {
+ result = sl_pp_process_undef(context, peek.tokens, 0, peek.size - 1);
+ } else {
+ strcpy(context->error_msg, "unrecognised directive name");
+ result = -1;
+ }
+ }
+
+ sl_pp_token_peek_commit(&peek);
+ sl_pp_token_peek_destroy(&peek);
+
+ if (result) {
+ return result;
+ }
+
+ if (sl_pp_process_out(&context->process_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(&context->process_state, &input)) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+ context->line++;
+ break;
+
+ case SL_PP_EOF:
+ /* Empty directive. */
+ if (sl_pp_process_out(&context->process_state, &input)) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+ found_eof = 1;
+ break;
+
+ default:
+ strcpy(context->error_msg, "expected a directive name");
+ return -1;
+ }
+ } else {
+ int found_eol = 0;
+
+ sl_pp_token_buffer_unget(&context->tokens, &input);
+
+ while (!found_eol) {
+ if (sl_pp_token_buffer_get(&context->tokens, &input)) {
+ return -1;
+ }
+
+ switch (input.token) {
+ case SL_PP_WHITESPACE:
+ /* Drop whitespace all together at this point. */
+ break;
+
+ case SL_PP_NEWLINE:
+ /* Preserve newline just for the sake of line numbering. */
+ if (sl_pp_process_out(&context->process_state, &input)) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+ context->line++;
+ found_eol = 1;
+ break;
+
+ case SL_PP_EOF:
+ if (sl_pp_process_out(&context->process_state, &input)) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+ found_eof = 1;
+ found_eol = 1;
+ break;
+
+ case SL_PP_IDENTIFIER:
+ sl_pp_token_buffer_unget(&context->tokens, &input);
+ if (sl_pp_macro_expand(context, &context->tokens, NULL, &context->process_state,
+ context->if_value ? sl_pp_macro_expand_normal : sl_pp_macro_expand_mute)) {
+ return -1;
+ }
+ break;
+
+ default:
+ if (context->if_value) {
+ if (sl_pp_process_out(&context->process_state, &input)) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+ }
+ }
+ }
+ }
+
+ if (found_eof) {
+ if (context->if_ptr != SL_PP_MAX_IF_NESTING) {
+ strcpy(context->error_msg, "expected `#endif' directive");
+ return -1;
+ }
+ }
+ }
+}
+
+int
+sl_pp_process(struct sl_pp_context *context,
+ struct sl_pp_token_info **output)
+{
+ struct sl_pp_process_state state;
+
+ memset(&state, 0, sizeof(state));
+ for (;;) {
+ struct sl_pp_token_info input;
+
+ if (sl_pp_process_get(context, &input)) {
+ free(state.out);
+ return -1;
+ }
+ if (sl_pp_process_out(&state, &input)) {
+ free(state.out);
+ return -1;
+ }
+ if (input.token == SL_PP_EOF) {
+ *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 00000000000..fe6ff0d4648
--- /dev/null
+++ b/src/glsl/pp/sl_pp_process.h
@@ -0,0 +1,116 @@
+/**************************************************************************
+ *
+ * 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_macro.h"
+#include "sl_pp_token.h"
+
+
+struct sl_pp_context;
+
+struct sl_pp_process_state {
+ struct sl_pp_token_info *out;
+ unsigned int out_len;
+ unsigned int out_max;
+};
+
+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,
+ struct sl_pp_token_buffer *input);
+
+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,
+ struct sl_pp_token_buffer *buffer);
+
+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,
+ struct sl_pp_token_buffer *buffer,
+ 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_public.h b/src/glsl/pp/sl_pp_public.h
new file mode 100644
index 00000000000..12528d6f8d1
--- /dev/null
+++ b/src/glsl/pp/sl_pp_public.h
@@ -0,0 +1,84 @@
+/**************************************************************************
+ *
+ * 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_PUBLIC_H
+#define SL_PP_PUBLIC_H
+
+
+struct sl_pp_context;
+
+
+#include "sl_pp_purify.h"
+#include "sl_pp_token.h"
+
+
+struct sl_pp_context *
+sl_pp_context_create(const char *input,
+ const struct sl_pp_purify_options *options);
+
+void
+sl_pp_context_destroy(struct sl_pp_context *context);
+
+const char *
+sl_pp_context_error_message(const struct sl_pp_context *context);
+
+void
+sl_pp_context_error_position(const struct sl_pp_context *context,
+ unsigned int *file,
+ unsigned int *line);
+
+int
+sl_pp_context_add_extension(struct sl_pp_context *context,
+ const char *name,
+ const char *name_string);
+
+int
+sl_pp_context_add_predefined(struct sl_pp_context *context,
+ const char *name,
+ const char *value);
+
+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);
+
+int
+sl_pp_version(struct sl_pp_context *context,
+ unsigned int *version);
+
+int
+sl_pp_process_get(struct sl_pp_context *context,
+ struct sl_pp_token_info *output);
+
+int
+sl_pp_process(struct sl_pp_context *context,
+ struct sl_pp_token_info **output);
+
+#endif /* SL_PP_PUBLIC_H */
diff --git a/src/glsl/pp/sl_pp_purify.c b/src/glsl/pp/sl_pp_purify.c
new file mode 100644
index 00000000000..b50f8192517
--- /dev/null
+++ b/src/glsl/pp/sl_pp_purify.c
@@ -0,0 +1,302 @@
+/**************************************************************************
+ *
+ * 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 <stdarg.h>
+#include <stdio.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,
+ unsigned int *current_line)
+{
+ if (input[0] == '\n') {
+ *out = '\n';
+ (*current_line)++;
+ 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';
+ (*current_line)++;
+ 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 *current_line)
+{
+ unsigned int eaten = 0;
+
+ for (;;) {
+ if (input[0] == '\\') {
+ char next;
+ unsigned int next_eaten;
+ unsigned int next_line = *current_line;
+
+ eaten++;
+ input++;
+
+ next_eaten = _purify_newline(input, &next, &next_line);
+ 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;
+ *current_line = next_line;
+ } 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, current_line);
+ break;
+ }
+ }
+ return eaten;
+}
+
+
+static void
+_report_error(char *buf,
+ unsigned int cbbuf,
+ const char *msg,
+ ...)
+{
+ va_list args;
+
+ va_start(args, msg);
+ vsnprintf(buf, cbbuf, msg, args);
+ va_end(args);
+}
+
+
+void
+sl_pp_purify_state_init(struct sl_pp_purify_state *state,
+ const char *input,
+ const struct sl_pp_purify_options *options)
+{
+ state->options = *options;
+ state->input = input;
+ state->current_line = 1;
+ state->inside_c_comment = 0;
+}
+
+
+unsigned int
+_purify_comment(struct sl_pp_purify_state *state,
+ char *output,
+ unsigned int *current_line,
+ char *errormsg,
+ unsigned int cberrormsg)
+{
+ for (;;) {
+ unsigned int eaten;
+ char next;
+
+ eaten = _purify_backslash(state->input, &next, current_line);
+ state->input += eaten;
+ while (next == '*') {
+ eaten = _purify_backslash(state->input, &next, current_line);
+ state->input += eaten;
+ if (next == '/') {
+ *output = ' ';
+ state->inside_c_comment = 0;
+ return 1;
+ }
+ }
+ if (next == '\n') {
+ *output = '\n';
+ state->inside_c_comment = 1;
+ return 1;
+ }
+ if (next == '\0') {
+ _report_error(errormsg, cberrormsg, "expected `*/' but end of translation unit found");
+ return 0;
+ }
+ }
+}
+
+
+unsigned int
+sl_pp_purify_getc(struct sl_pp_purify_state *state,
+ char *output,
+ unsigned int *current_line,
+ char *errormsg,
+ unsigned int cberrormsg)
+{
+ unsigned int eaten;
+
+ if (state->inside_c_comment) {
+ return _purify_comment(state, output, current_line, errormsg, cberrormsg);
+ }
+
+ eaten = _purify_backslash(state->input, output, current_line);
+ state->input += eaten;
+ if (*output == '/') {
+ char next;
+ unsigned int next_line = *current_line;
+
+ eaten = _purify_backslash(state->input, &next, &next_line);
+ if (next == '/') {
+ state->input += eaten;
+ *current_line = next_line;
+
+ /* Replace a line comment with either a newline or nil. */
+ for (;;) {
+ eaten = _purify_backslash(state->input, &next, current_line);
+ state->input += eaten;
+ if (next == '\n' || next == '\0') {
+ *output = next;
+ return eaten;
+ }
+ }
+ } else if (next == '*') {
+ state->input += eaten;
+ *current_line = next_line;
+
+ return _purify_comment(state, output, current_line, errormsg, cberrormsg);
+ }
+ }
+ return eaten;
+}
+
+
+struct out_buf {
+ char *out;
+ unsigned int len;
+ unsigned int capacity;
+ unsigned int current_line;
+ char *errormsg;
+ unsigned int cberrormsg;
+};
+
+
+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) {
+ _report_error(obuf->errormsg, obuf->cberrormsg, "out of memory");
+ return -1;
+ }
+ obuf->capacity = new_max;
+ }
+
+ obuf->out[obuf->len++] = c;
+
+ return 0;
+}
+
+
+int
+sl_pp_purify(const char *input,
+ const struct sl_pp_purify_options *options,
+ char **output,
+ char *errormsg,
+ unsigned int cberrormsg,
+ unsigned int *errorline)
+{
+ struct out_buf obuf;
+ struct sl_pp_purify_state state;
+
+ obuf.out = NULL;
+ obuf.len = 0;
+ obuf.capacity = 0;
+ obuf.current_line = 1;
+ obuf.errormsg = errormsg;
+ obuf.cberrormsg = cberrormsg;
+
+ sl_pp_purify_state_init(&state, input, options);
+
+ for (;;) {
+ unsigned int eaten;
+ char c;
+
+ eaten = sl_pp_purify_getc(&state, &c, &obuf.current_line, errormsg, cberrormsg);
+ if (!eaten) {
+ *errorline = obuf.current_line;
+ return -1;
+ }
+ if (_out_buf_putc(&obuf, c)) {
+ *errorline = obuf.current_line;
+ return -1;
+ }
+
+ if (c == '\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 00000000000..c0f55cbfd89
--- /dev/null
+++ b/src/glsl/pp/sl_pp_purify.h
@@ -0,0 +1,63 @@
+/**************************************************************************
+ *
+ * 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,
+ char *errormsg,
+ unsigned int cberrormsg,
+ unsigned int *errorline);
+
+struct sl_pp_purify_state {
+ struct sl_pp_purify_options options;
+ const char *input;
+ unsigned int current_line;
+ unsigned int inside_c_comment:1;
+};
+
+void
+sl_pp_purify_state_init(struct sl_pp_purify_state *state,
+ const char *input,
+ const struct sl_pp_purify_options *options);
+
+unsigned int
+sl_pp_purify_getc(struct sl_pp_purify_state *state,
+ char *output,
+ unsigned int *current_line,
+ char *errormsg,
+ unsigned int cberrormsg);
+
+#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 00000000000..a7089787005
--- /dev/null
+++ b/src/glsl/pp/sl_pp_token.c
@@ -0,0 +1,854 @@
+/**************************************************************************
+ *
+ * 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 <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include "sl_pp_public.h"
+#include "sl_pp_context.h"
+#include "sl_pp_token.h"
+
+
+#define PURE_ERROR 256
+
+static int
+_pure_getc(struct sl_pp_context *context)
+{
+ char c;
+
+ if (context->getc_buf_size) {
+ return context->getc_buf[--context->getc_buf_size];
+ }
+
+ if (sl_pp_purify_getc(&context->pure, &c, &context->error_line, context->error_msg, sizeof(context->error_msg)) == 0) {
+ return PURE_ERROR;
+ }
+ return c;
+}
+
+
+static void
+_pure_ungetc(struct sl_pp_context *context,
+ int c)
+{
+ assert(c != PURE_ERROR);
+
+ if (context->getc_buf_size == context->getc_buf_capacity) {
+ context->getc_buf_capacity += 64;
+ context->getc_buf = realloc(context->getc_buf, context->getc_buf_capacity * sizeof(char));
+ assert(context->getc_buf);
+ }
+
+ context->getc_buf[context->getc_buf_size++] = (char)c;
+}
+
+
+struct lookahead_state {
+ char buf[256];
+ unsigned int pos;
+ struct sl_pp_context *context;
+};
+
+
+static void
+_lookahead_init(struct lookahead_state *lookahead,
+ struct sl_pp_context *context)
+{
+ lookahead->pos = 0;
+ lookahead->context = context;
+}
+
+
+static unsigned int
+_lookahead_tell(const struct lookahead_state *lookahead)
+{
+ return lookahead->pos;
+}
+
+
+static const void *
+_lookahead_buf(const struct lookahead_state *lookahead)
+{
+ return lookahead->buf;
+}
+
+
+static void
+_lookahead_revert(struct lookahead_state *lookahead,
+ unsigned int pos)
+{
+ assert(pos <= lookahead->pos);
+
+ while (lookahead->pos > pos) {
+ _pure_ungetc(lookahead->context, lookahead->buf[--lookahead->pos]);
+ }
+}
+
+
+static int
+_lookahead_getc(struct lookahead_state *lookahead)
+{
+ int c;
+
+ assert(lookahead->pos < sizeof(lookahead->buf) / sizeof(lookahead->buf[0]));
+
+ c = _pure_getc(lookahead->context);
+ if (c != PURE_ERROR) {
+ lookahead->buf[lookahead->pos++] = (char)c;
+ }
+ return c;
+}
+
+
+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,
+ struct sl_pp_token_info *out)
+{
+ int c;
+ char identifier[256]; /* XXX: Remove this artifical limit. */
+ unsigned int i = 0;
+
+ out->token = SL_PP_IDENTIFIER;
+ out->data.identifier = -1;
+
+ c = _pure_getc(context);
+ if (c == PURE_ERROR) {
+ return -1;
+ }
+ identifier[i++] = (char)c;
+ for (;;) {
+ c = _pure_getc(context);
+ if (c == PURE_ERROR) {
+ return -1;
+ }
+
+ if (_is_identifier_char((char)c)) {
+ if (i >= sizeof(identifier) / sizeof(char) - 1) {
+ strcpy(context->error_msg, "out of memory");
+ _pure_ungetc(context, c);
+ while (i) {
+ _pure_ungetc(context, identifier[--i]);
+ }
+ return -1;
+ }
+ identifier[i++] = (char)c;
+ } else {
+ _pure_ungetc(context, c);
+ break;
+ }
+ }
+ identifier[i] = '\0';
+
+ out->data.identifier = sl_pp_context_add_unique_str(context, identifier);
+ if (out->data.identifier == -1) {
+ while (i) {
+ _pure_ungetc(context, identifier[--i]);
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Return the number of consecutive decimal digits in the input stream.
+ */
+static unsigned int
+_parse_float_digits(struct lookahead_state *lookahead)
+{
+ unsigned int eaten;
+
+ for (eaten = 0;; eaten++) {
+ unsigned int pos = _lookahead_tell(lookahead);
+ char c = _lookahead_getc(lookahead);
+
+ if (c < '0' || c > '9') {
+ _lookahead_revert(lookahead, pos);
+ break;
+ }
+ }
+ 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(struct lookahead_state *lookahead)
+{
+ unsigned int pos;
+ int c;
+ unsigned int eaten;
+
+ pos = _lookahead_tell(lookahead);
+ c = _lookahead_getc(lookahead);
+ if (c == '.') {
+ eaten = _parse_float_digits(lookahead);
+ if (eaten) {
+ return eaten + 1;
+ }
+ _lookahead_revert(lookahead, pos);
+ return 0;
+ }
+
+ _lookahead_revert(lookahead, pos);
+ eaten = _parse_float_digits(lookahead);
+ if (eaten) {
+ c = _lookahead_getc(lookahead);
+ if (c == '.') {
+ return eaten + 1 + _parse_float_digits(lookahead);
+ }
+ }
+
+ _lookahead_revert(lookahead, pos);
+ 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(struct lookahead_state *lookahead)
+{
+ unsigned int pos, pos2;
+ int c;
+ unsigned int eaten, digits;
+
+ pos = _lookahead_tell(lookahead);
+ c = _lookahead_getc(lookahead);
+ if (c != 'e' && c != 'E') {
+ _lookahead_revert(lookahead, pos);
+ return 0;
+ }
+
+ pos2 = _lookahead_tell(lookahead);
+ c = _lookahead_getc(lookahead);
+ if (c == '-' || c == '+') {
+ eaten = 2;
+ } else {
+ _lookahead_revert(lookahead, pos2);
+ eaten = 1;
+ }
+
+ digits = _parse_float_digits(lookahead);
+ if (!digits) {
+ _lookahead_revert(lookahead, pos);
+ 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(struct lookahead_state *lookahead)
+{
+ unsigned int eaten;
+
+ eaten = _parse_float_frac(lookahead);
+ if (eaten) {
+ unsigned int pos;
+ int c;
+
+ eaten += _parse_float_exp(lookahead);
+
+ pos = _lookahead_tell(lookahead);
+ c = _lookahead_getc(lookahead);
+ if (c == 'f' || c == 'F') {
+ eaten++;
+ } else {
+ _lookahead_revert(lookahead, pos);
+ }
+
+ return eaten;
+ }
+
+ eaten = _parse_float_digits(lookahead);
+ if (eaten) {
+ unsigned int exponent;
+
+ exponent = _parse_float_exp(lookahead);
+ if (exponent) {
+ unsigned int pos;
+ int c;
+
+ eaten += exponent;
+
+ pos = _lookahead_tell(lookahead);
+ c = _lookahead_getc(lookahead);
+ if (c == 'f' || c == 'F') {
+ eaten++;
+ } else {
+ _lookahead_revert(lookahead, pos);
+ }
+
+ return eaten;
+ }
+ }
+
+ _lookahead_revert(lookahead, 0);
+ return 0;
+}
+
+
+static unsigned int
+_parse_hex(struct lookahead_state *lookahead)
+{
+ int c;
+ unsigned int n;
+
+ c = _lookahead_getc(lookahead);
+ if (c != '0') {
+ _lookahead_revert(lookahead, 0);
+ return 0;
+ }
+
+ c = _lookahead_getc(lookahead);
+ if (c != 'x' && c != 'X') {
+ _lookahead_revert(lookahead, 0);
+ return 0;
+ }
+
+ for (n = 2;;) {
+ unsigned int pos = _lookahead_tell(lookahead);
+
+ c = _lookahead_getc(lookahead);
+ if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
+ n++;
+ } else {
+ _lookahead_revert(lookahead, pos);
+ break;
+ }
+ }
+
+ if (n > 2) {
+ return n;
+ }
+
+ _lookahead_revert(lookahead, 0);
+ return 0;
+}
+
+
+static unsigned int
+_parse_oct(struct lookahead_state *lookahead)
+{
+ int c;
+ unsigned int n;
+
+ c = _lookahead_getc(lookahead);
+ if (c != '0') {
+ _lookahead_revert(lookahead, 0);
+ return 0;
+ }
+
+ for (n = 1;;) {
+ unsigned int pos = _lookahead_tell(lookahead);
+
+ c = _lookahead_getc(lookahead);
+ if ((c >= '0' && c <= '7')) {
+ n++;
+ } else {
+ _lookahead_revert(lookahead, pos);
+ break;
+ }
+ }
+
+ return n;
+}
+
+
+static unsigned int
+_parse_dec(struct lookahead_state *lookahead)
+{
+ unsigned int n = 0;
+
+ for (;;) {
+ unsigned int pos = _lookahead_tell(lookahead);
+ int c = _lookahead_getc(lookahead);
+
+ if ((c >= '0' && c <= '9')) {
+ n++;
+ } else {
+ _lookahead_revert(lookahead, pos);
+ break;
+ }
+ }
+
+ return n;
+}
+
+
+static int
+_tokenise_number(struct sl_pp_context *context,
+ struct sl_pp_token_info *out)
+{
+ struct lookahead_state lookahead;
+ unsigned int eaten;
+ unsigned int is_float = 0;
+ unsigned int pos;
+ int c;
+ char number[256]; /* XXX: Remove this artifical limit. */
+
+ _lookahead_init(&lookahead, context);
+
+ eaten = _parse_float(&lookahead);
+ if (!eaten) {
+ eaten = _parse_hex(&lookahead);
+ if (!eaten) {
+ eaten = _parse_oct(&lookahead);
+ if (!eaten) {
+ eaten = _parse_dec(&lookahead);
+ }
+ }
+ } else {
+ is_float = 1;
+ }
+
+ if (!eaten) {
+ strcpy(context->error_msg, "expected a number");
+ return -1;
+ }
+
+ pos = _lookahead_tell(&lookahead);
+ c = _lookahead_getc(&lookahead);
+ _lookahead_revert(&lookahead, pos);
+
+ if (_is_identifier_char(c)) {
+ strcpy(context->error_msg, "expected a number");
+ _lookahead_revert(&lookahead, 0);
+ return -1;
+ }
+
+ if (eaten > sizeof(number) - 1) {
+ strcpy(context->error_msg, "out of memory");
+ _lookahead_revert(&lookahead, 0);
+ return -1;
+ }
+
+ assert(_lookahead_tell(&lookahead) == eaten);
+
+ memcpy(number, _lookahead_buf(&lookahead), eaten);
+ number[eaten] = '\0';
+
+ if (is_float) {
+ out->token = SL_PP_FLOAT;
+ out->data._float = sl_pp_context_add_unique_str(context, number);
+ if (out->data._float == -1) {
+ _lookahead_revert(&lookahead, 0);
+ return -1;
+ }
+ } else {
+ out->token = SL_PP_UINT;
+ out->data._uint = sl_pp_context_add_unique_str(context, number);
+ if (out->data._uint == -1) {
+ _lookahead_revert(&lookahead, 0);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+int
+sl_pp_token_get(struct sl_pp_context *context,
+ struct sl_pp_token_info *out)
+{
+ int c = _pure_getc(context);
+
+ switch (c) {
+ case ' ':
+ case '\t':
+ out->token = SL_PP_WHITESPACE;
+ break;
+
+ case '\n':
+ out->token = SL_PP_NEWLINE;
+ break;
+
+ case '#':
+ out->token = SL_PP_HASH;
+ break;
+
+ case ',':
+ out->token = SL_PP_COMMA;
+ break;
+
+ case ';':
+ out->token = SL_PP_SEMICOLON;
+ break;
+
+ case '{':
+ out->token = SL_PP_LBRACE;
+ break;
+
+ case '}':
+ out->token = SL_PP_RBRACE;
+ break;
+
+ case '(':
+ out->token = SL_PP_LPAREN;
+ break;
+
+ case ')':
+ out->token = SL_PP_RPAREN;
+ break;
+
+ case '[':
+ out->token = SL_PP_LBRACKET;
+ break;
+
+ case ']':
+ out->token = SL_PP_RBRACKET;
+ break;
+
+ case '.':
+ {
+ int c2 = _pure_getc(context);
+
+ if (c2 == PURE_ERROR) {
+ return -1;
+ }
+ if (c2 >= '0' && c2 <= '9') {
+ _pure_ungetc(context, c2);
+ _pure_ungetc(context, c);
+ if (_tokenise_number(context, out)) {
+ return -1;
+ }
+ } else {
+ _pure_ungetc(context, c2);
+ out->token = SL_PP_DOT;
+ }
+ }
+ break;
+
+ case '+':
+ c = _pure_getc(context);
+ if (c == PURE_ERROR) {
+ return -1;
+ }
+ if (c == '+') {
+ out->token = SL_PP_INCREMENT;
+ } else if (c == '=') {
+ out->token = SL_PP_ADDASSIGN;
+ } else {
+ _pure_ungetc(context, c);
+ out->token = SL_PP_PLUS;
+ }
+ break;
+
+ case '-':
+ c = _pure_getc(context);
+ if (c == PURE_ERROR) {
+ return -1;
+ }
+ if (c == '-') {
+ out->token = SL_PP_DECREMENT;
+ } else if (c == '=') {
+ out->token = SL_PP_SUBASSIGN;
+ } else {
+ _pure_ungetc(context, c);
+ out->token = SL_PP_MINUS;
+ }
+ break;
+
+ case '~':
+ out->token = SL_PP_BITNOT;
+ break;
+
+ case '!':
+ c = _pure_getc(context);
+ if (c == PURE_ERROR) {
+ return -1;
+ }
+ if (c == '=') {
+ out->token = SL_PP_NOTEQUAL;
+ } else {
+ _pure_ungetc(context, c);
+ out->token = SL_PP_NOT;
+ }
+ break;
+
+ case '*':
+ c = _pure_getc(context);
+ if (c == PURE_ERROR) {
+ return -1;
+ }
+ if (c == '=') {
+ out->token = SL_PP_MULASSIGN;
+ } else {
+ _pure_ungetc(context, c);
+ out->token = SL_PP_STAR;
+ }
+ break;
+
+ case '/':
+ c = _pure_getc(context);
+ if (c == PURE_ERROR) {
+ return -1;
+ }
+ if (c == '=') {
+ out->token = SL_PP_DIVASSIGN;
+ } else {
+ _pure_ungetc(context, c);
+ out->token = SL_PP_SLASH;
+ }
+ break;
+
+ case '%':
+ c = _pure_getc(context);
+ if (c == PURE_ERROR) {
+ return -1;
+ }
+ if (c == '=') {
+ out->token = SL_PP_MODASSIGN;
+ } else {
+ _pure_ungetc(context, c);
+ out->token = SL_PP_MODULO;
+ }
+ break;
+
+ case '<':
+ c = _pure_getc(context);
+ if (c == PURE_ERROR) {
+ return -1;
+ }
+ if (c == '<') {
+ c = _pure_getc(context);
+ if (c == PURE_ERROR) {
+ return -1;
+ }
+ if (c == '=') {
+ out->token = SL_PP_LSHIFTASSIGN;
+ } else {
+ _pure_ungetc(context, c);
+ out->token = SL_PP_LSHIFT;
+ }
+ } else if (c == '=') {
+ out->token = SL_PP_LESSEQUAL;
+ } else {
+ _pure_ungetc(context, c);
+ out->token = SL_PP_LESS;
+ }
+ break;
+
+ case '>':
+ c = _pure_getc(context);
+ if (c == PURE_ERROR) {
+ return -1;
+ }
+ if (c == '>') {
+ c = _pure_getc(context);
+ if (c == PURE_ERROR) {
+ return -1;
+ }
+ if (c == '=') {
+ out->token = SL_PP_RSHIFTASSIGN;
+ } else {
+ _pure_ungetc(context, c);
+ out->token = SL_PP_RSHIFT;
+ }
+ } else if (c == '=') {
+ out->token = SL_PP_GREATEREQUAL;
+ } else {
+ _pure_ungetc(context, c);
+ out->token = SL_PP_GREATER;
+ }
+ break;
+
+ case '=':
+ c = _pure_getc(context);
+ if (c == PURE_ERROR) {
+ return -1;
+ }
+ if (c == '=') {
+ out->token = SL_PP_EQUAL;
+ } else {
+ _pure_ungetc(context, c);
+ out->token = SL_PP_ASSIGN;
+ }
+ break;
+
+ case '&':
+ c = _pure_getc(context);
+ if (c == PURE_ERROR) {
+ return -1;
+ }
+ if (c == '&') {
+ out->token = SL_PP_AND;
+ } else if (c == '=') {
+ out->token = SL_PP_BITANDASSIGN;
+ } else {
+ _pure_ungetc(context, c);
+ out->token = SL_PP_BITAND;
+ }
+ break;
+
+ case '^':
+ c = _pure_getc(context);
+ if (c == PURE_ERROR) {
+ return -1;
+ }
+ if (c == '^') {
+ out->token = SL_PP_XOR;
+ } else if (c == '=') {
+ out->token = SL_PP_BITXORASSIGN;
+ } else {
+ _pure_ungetc(context, c);
+ out->token = SL_PP_BITXOR;
+ }
+ break;
+
+ case '|':
+ c = _pure_getc(context);
+ if (c == PURE_ERROR) {
+ return -1;
+ }
+ if (c == '|') {
+ out->token = SL_PP_OR;
+ } else if (c == '=') {
+ out->token = SL_PP_BITORASSIGN;
+ } else {
+ _pure_ungetc(context, c);
+ out->token = SL_PP_BITOR;
+ }
+ break;
+
+ case '?':
+ out->token = SL_PP_QUESTION;
+ break;
+
+ case ':':
+ out->token = SL_PP_COLON;
+ break;
+
+ case '\0':
+ out->token = SL_PP_EOF;
+ break;
+
+ case PURE_ERROR:
+ return -1;
+
+ default:
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_') {
+ _pure_ungetc(context, c);
+ if (_tokenise_identifier(context, out)) {
+ return -1;
+ }
+ } else if (c >= '0' && c <= '9') {
+ _pure_ungetc(context, c);
+ if (_tokenise_number(context, out)) {
+ return -1;
+ }
+ } else {
+ out->data.other = c;
+ out->token = SL_PP_OTHER;
+ }
+ }
+
+ return 0;
+}
+
+
+int
+sl_pp_tokenise(struct sl_pp_context *context,
+ 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;
+
+ if (sl_pp_token_buffer_get(&context->tokens, &info)) {
+ free(out);
+ return -1;
+ }
+
+ 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 00000000000..a12b1934018
--- /dev/null
+++ b/src/glsl/pp/sl_pp_token.h
@@ -0,0 +1,133 @@
+/**************************************************************************
+ *
+ * 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
+
+
+struct sl_pp_context;
+
+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_UINT,
+ SL_PP_FLOAT,
+
+ 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_EOF
+};
+
+union sl_pp_token_data {
+ int identifier;
+ int _uint;
+ int _float;
+ char other;
+ int pragma;
+ int extension;
+ struct {
+ unsigned int lineno: 24;
+ unsigned int fileno: 8;
+ } line;
+};
+
+struct sl_pp_token_info {
+ enum sl_pp_token token;
+ union sl_pp_token_data data;
+};
+
+struct sl_pp_purify_options;
+
+int
+sl_pp_token_get(struct sl_pp_context *context,
+ struct sl_pp_token_info *out);
+
+int
+sl_pp_tokenise(struct sl_pp_context *context,
+ struct sl_pp_token_info **output);
+
+#endif /* SL_PP_TOKEN_H */
diff --git a/src/glsl/pp/sl_pp_token_util.c b/src/glsl/pp/sl_pp_token_util.c
new file mode 100644
index 00000000000..c85263d9a11
--- /dev/null
+++ b/src/glsl/pp/sl_pp_token_util.c
@@ -0,0 +1,182 @@
+/**************************************************************************
+ *
+ * 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 <assert.h>
+#include <stdlib.h>
+#include "sl_pp_token_util.h"
+
+
+int
+sl_pp_token_buffer_init(struct sl_pp_token_buffer *buffer,
+ struct sl_pp_context *context)
+{
+ buffer->context = context;
+ buffer->size = 0;
+ buffer->capacity = 64;
+ buffer->tokens = malloc(buffer->capacity * sizeof(struct sl_pp_token_info));
+ if (!buffer->tokens) {
+ return -1;
+ }
+ return 0;
+}
+
+void
+sl_pp_token_buffer_destroy(struct sl_pp_token_buffer *buffer)
+{
+ free(buffer->tokens);
+}
+
+int
+sl_pp_token_buffer_get(struct sl_pp_token_buffer *buffer,
+ struct sl_pp_token_info *out)
+{
+ /* Pop from stack first if not empty. */
+ if (buffer->size) {
+ *out = buffer->tokens[--buffer->size];
+ return 0;
+ }
+
+ assert(buffer->context);
+ return sl_pp_token_get(buffer->context, out);
+}
+
+void
+sl_pp_token_buffer_unget(struct sl_pp_token_buffer *buffer,
+ const struct sl_pp_token_info *in)
+{
+ /* Resize if needed. */
+ if (buffer->size == buffer->capacity) {
+ buffer->capacity += 64;
+ buffer->tokens = realloc(buffer->tokens,
+ buffer->capacity * sizeof(struct sl_pp_token_info));
+ assert(buffer->tokens);
+ }
+
+ /* Push token on stack. */
+ buffer->tokens[buffer->size++] = *in;
+}
+
+int
+sl_pp_token_buffer_skip_white(struct sl_pp_token_buffer *buffer,
+ struct sl_pp_token_info *out)
+{
+ if (sl_pp_token_buffer_get(buffer, out)) {
+ return -1;
+ }
+
+ while (out->token == SL_PP_WHITESPACE) {
+ if (sl_pp_token_buffer_get(buffer, out)) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+
+int
+sl_pp_token_peek_init(struct sl_pp_token_peek *peek,
+ struct sl_pp_token_buffer *buffer)
+{
+ peek->buffer = buffer;
+ peek->size = 0;
+ peek->capacity = 64;
+ peek->tokens = malloc(peek->capacity * sizeof(struct sl_pp_token_info));
+ if (!peek->tokens) {
+ return -1;
+ }
+ return 0;
+}
+
+void
+sl_pp_token_peek_destroy(struct sl_pp_token_peek *peek)
+{
+ /* Abort. */
+ while (peek->size) {
+ sl_pp_token_buffer_unget(peek->buffer, &peek->tokens[--peek->size]);
+ }
+ free(peek->tokens);
+}
+
+int
+sl_pp_token_peek_get(struct sl_pp_token_peek *peek,
+ struct sl_pp_token_info *out)
+{
+ /* Get token from buffer. */
+ if (sl_pp_token_buffer_get(peek->buffer, out)) {
+ return -1;
+ }
+
+ /* Save it. */
+ if (peek->size == peek->capacity) {
+ peek->capacity += 64;
+ peek->tokens = realloc(peek->tokens,
+ peek->capacity * sizeof(struct sl_pp_token_info));
+ assert(peek->tokens);
+ }
+ peek->tokens[peek->size++] = *out;
+ return 0;
+}
+
+void
+sl_pp_token_peek_commit(struct sl_pp_token_peek *peek)
+{
+ peek->size = 0;
+}
+
+int
+sl_pp_token_peek_to_buffer(const struct sl_pp_token_peek *peek,
+ struct sl_pp_token_buffer *buffer)
+{
+ unsigned int i;
+
+ if (sl_pp_token_buffer_init(buffer, NULL)) {
+ return -1;
+ }
+ for (i = peek->size; i > 0; i--) {
+ sl_pp_token_buffer_unget(buffer, &peek->tokens[i - 1]);
+ }
+ return 0;
+}
+
+int
+sl_pp_token_peek_skip_white(struct sl_pp_token_peek *peek,
+ struct sl_pp_token_info *out)
+{
+ if (sl_pp_token_peek_get(peek, out)) {
+ return -1;
+ }
+
+ while (out->token == SL_PP_WHITESPACE) {
+ if (sl_pp_token_peek_get(peek, out)) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/glsl/pp/sl_pp_token_util.h b/src/glsl/pp/sl_pp_token_util.h
new file mode 100644
index 00000000000..2a668ad0a84
--- /dev/null
+++ b/src/glsl/pp/sl_pp_token_util.h
@@ -0,0 +1,103 @@
+/**************************************************************************
+ *
+ * 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_UTIL_H
+#define SL_PP_TOKEN_UTIL_H
+
+#include <assert.h>
+#include <stdlib.h>
+#include "sl_pp_token.h"
+
+
+struct sl_pp_context;
+
+/*
+ * A token buffer allows one to get and unget a token
+ * from a preprocessor context.
+ */
+struct sl_pp_token_buffer {
+ struct sl_pp_context *context;
+ unsigned int size;
+ unsigned int capacity;
+ struct sl_pp_token_info *tokens;
+};
+
+int
+sl_pp_token_buffer_init(struct sl_pp_token_buffer *buffer,
+ struct sl_pp_context *context);
+
+void
+sl_pp_token_buffer_destroy(struct sl_pp_token_buffer *buffer);
+
+int
+sl_pp_token_buffer_get(struct sl_pp_token_buffer *buffer,
+ struct sl_pp_token_info *out);
+
+void
+sl_pp_token_buffer_unget(struct sl_pp_token_buffer *buffer,
+ const struct sl_pp_token_info *in);
+
+int
+sl_pp_token_buffer_skip_white(struct sl_pp_token_buffer *buffer,
+ struct sl_pp_token_info *out);
+
+
+/*
+ * A token peek allows one to get a number of tokens from a buffer
+ * and then either commit the operation or abort it,
+ * effectively ungetting the peeked tokens.
+ */
+struct sl_pp_token_peek {
+ struct sl_pp_token_buffer *buffer;
+ unsigned int size;
+ unsigned int capacity;
+ struct sl_pp_token_info *tokens;
+};
+
+int
+sl_pp_token_peek_init(struct sl_pp_token_peek *peek,
+ struct sl_pp_token_buffer *buffer);
+
+void
+sl_pp_token_peek_destroy(struct sl_pp_token_peek *peek);
+
+int
+sl_pp_token_peek_get(struct sl_pp_token_peek *peek,
+ struct sl_pp_token_info *out);
+
+void
+sl_pp_token_peek_commit(struct sl_pp_token_peek *peek);
+
+int
+sl_pp_token_peek_to_buffer(const struct sl_pp_token_peek *peek,
+ struct sl_pp_token_buffer *buffer);
+
+int
+sl_pp_token_peek_skip_white(struct sl_pp_token_peek *peek,
+ struct sl_pp_token_info *out);
+
+#endif /* SL_PP_TOKEN_UTIL_H */
diff --git a/src/glsl/pp/sl_pp_version.c b/src/glsl/pp/sl_pp_version.c
new file mode 100644
index 00000000000..3c995b77501
--- /dev/null
+++ b/src/glsl/pp/sl_pp_version.c
@@ -0,0 +1,161 @@
+/**************************************************************************
+ *
+ * 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 <string.h>
+#include "sl_pp_public.h"
+#include "sl_pp_context.h"
+
+
+int
+sl_pp_version(struct sl_pp_context *context,
+ unsigned int *version)
+{
+ struct sl_pp_token_peek peek;
+ unsigned int line = context->line;
+
+ /* Default values if `#version' is not present. */
+ *version = 110;
+
+ if (sl_pp_token_peek_init(&peek, &context->tokens)) {
+ return -1;
+ }
+
+ /* There can be multiple `#version' directives present.
+ * Accept the value of the last one.
+ */
+ for (;;) {
+ struct sl_pp_token_info input;
+ 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) {
+ if (sl_pp_token_peek_get(&peek, &input)) {
+ sl_pp_token_peek_destroy(&peek);
+ return -1;
+ }
+
+ switch (input.token) {
+ case SL_PP_NEWLINE:
+ line++;
+ break;
+
+ case SL_PP_WHITESPACE:
+ break;
+
+ case SL_PP_HASH:
+ found_hash = 1;
+ break;
+
+ default:
+ sl_pp_token_peek_destroy(&peek);
+ return 0;
+ }
+ }
+
+ /* Skip whitespace and seek for `version'. */
+ while (!found_version) {
+ if (sl_pp_token_peek_get(&peek, &input)) {
+ sl_pp_token_peek_destroy(&peek);
+ return -1;
+ }
+
+ switch (input.token) {
+ case SL_PP_WHITESPACE:
+ break;
+
+ case SL_PP_IDENTIFIER:
+ if (input.data.identifier != context->dict.version) {
+ sl_pp_token_peek_destroy(&peek);
+ return 0;
+ }
+ found_version = 1;
+ break;
+
+ default:
+ sl_pp_token_peek_destroy(&peek);
+ return 0;
+ }
+ }
+
+ sl_pp_token_peek_commit(&peek);
+
+ /* Skip whitespace and seek for version number. */
+ while (!found_number) {
+ if (sl_pp_token_buffer_get(&context->tokens, &input)) {
+ sl_pp_token_peek_destroy(&peek);
+ return -1;
+ }
+
+ switch (input.token) {
+ case SL_PP_WHITESPACE:
+ break;
+
+ case SL_PP_UINT:
+ *version = atoi(sl_pp_context_cstr(context, input.data._uint));
+ found_number = 1;
+ break;
+
+ default:
+ strcpy(context->error_msg, "expected version number after `#version'");
+ sl_pp_token_peek_destroy(&peek);
+ return -1;
+ }
+ }
+
+ /* Skip whitespace and seek for either newline or eof. */
+ while (!found_end) {
+ if (sl_pp_token_buffer_get(&context->tokens, &input)) {
+ sl_pp_token_peek_destroy(&peek);
+ return -1;
+ }
+
+ switch (input.token) {
+ case SL_PP_WHITESPACE:
+ break;
+
+ case SL_PP_NEWLINE:
+ line++;
+ /* pass thru */
+ case SL_PP_EOF:
+ context->line = line;
+ found_end = 1;
+ break;
+
+ default:
+ strcpy(context->error_msg, "expected end of line after version number");
+ sl_pp_token_peek_destroy(&peek);
+ return -1;
+ }
+ }
+ }
+
+ /* Should not get here. */
+}