summaryrefslogtreecommitdiff
path: root/src/glsl
diff options
context:
space:
mode:
Diffstat (limited to 'src/glsl')
-rw-r--r--src/glsl/Makefile15
-rw-r--r--src/glsl/Makefile.template50
-rw-r--r--src/glsl/SConscript68
-rw-r--r--src/glsl/apps/Makefile42
-rw-r--r--src/glsl/apps/compile.c234
-rw-r--r--src/glsl/apps/process.c394
-rw-r--r--src/glsl/apps/purify.c105
-rw-r--r--src/glsl/apps/tokenise.c333
-rw-r--r--src/glsl/apps/version.c131
-rw-r--r--src/glsl/cl/Makefile13
-rw-r--r--src/glsl/cl/sl_cl_parse.c2714
-rw-r--r--src/glsl/cl/sl_cl_parse.h41
-rw-r--r--src/glsl/pp/Makefile26
-rw-r--r--src/glsl/pp/sl_pp_context.c155
-rw-r--r--src/glsl/pp/sl_pp_context.h85
-rw-r--r--src/glsl/pp/sl_pp_define.c237
-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.c269
-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.c170
-rw-r--r--src/glsl/pp/sl_pp_if.c349
-rw-r--r--src/glsl/pp/sl_pp_line.c121
-rw-r--r--src/glsl/pp/sl_pp_macro.c397
-rw-r--r--src/glsl/pp/sl_pp_macro.h73
-rw-r--r--src/glsl/pp/sl_pp_pragma.c108
-rw-r--r--src/glsl/pp/sl_pp_process.c286
-rw-r--r--src/glsl/pp/sl_pp_process.h121
-rw-r--r--src/glsl/pp/sl_pp_public.h77
-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.c859
-rw-r--r--src/glsl/pp/sl_pp_token.h131
-rw-r--r--src/glsl/pp/sl_pp_version.c140
35 files changed, 8722 insertions, 0 deletions
diff --git a/src/glsl/Makefile b/src/glsl/Makefile
new file mode 100644
index 0000000000..ca7f2d2ac7
--- /dev/null
+++ b/src/glsl/Makefile
@@ -0,0 +1,15 @@
+# src/glsl/Makefile
+
+TOP = ../..
+
+include $(TOP)/configs/current
+
+SUBDIRS = pp cl apps
+
+default install clean:
+ @for dir in $(SUBDIRS) ; do \
+ if [ -d $$dir ] ; then \
+ (cd $$dir && $(MAKE) $@) || exit 1; \
+ fi \
+ done
+
diff --git a/src/glsl/Makefile.template b/src/glsl/Makefile.template
new file mode 100644
index 0000000000..974987a0a0
--- /dev/null
+++ b/src/glsl/Makefile.template
@@ -0,0 +1,50 @@
+# src/glsl/Makefile.template
+
+# Template makefile for glsl libraries.
+#
+# Usage:
+# The minimum that the including makefile needs to define
+# is TOP, LIBNAME and one of of the *_SOURCES.
+#
+# Optional defines:
+# LIBRARY_INCLUDES are appended to the list of includes directories.
+# LIBRARY_DEFINES is not used for makedepend, but for compilation.
+
+
+### Basic defines ###
+
+OBJECTS = $(C_SOURCES:.c=.o)
+
+INCLUDES = \
+ -I. \
+ $(LIBRARY_INCLUDES)
+
+
+##### TARGETS #####
+
+default: depend lib$(LIBNAME).a
+
+lib$(LIBNAME).a: $(OBJECTS) Makefile $(TOP)/src/glsl/Makefile.template
+ $(MKLIB) -o $(LIBNAME) -static $(OBJECTS)
+
+depend: $(C_SOURCES)
+ rm -f depend
+ touch depend
+ $(MKDEP) $(MKDEP_OPTIONS) $(INCLUDES) $(C_SOURCES) 2> /dev/null
+
+# Remove .o and backup files
+clean:
+ rm -f $(OBJECTS) lib$(LIBNAME).a depend depend.bak
+
+# Dummy target
+install:
+ @echo -n ""
+
+
+##### RULES #####
+
+.c.o:
+ $(CC) -c $(INCLUDES) $(CFLAGS) $(LIBRARY_DEFINES) $< -o $@
+
+-include depend
+
diff --git a/src/glsl/SConscript b/src/glsl/SConscript
new file mode 100644
index 0000000000..6f1f81b199
--- /dev/null
+++ b/src/glsl/SConscript
@@ -0,0 +1,68 @@
+import common
+
+Import('*')
+
+env = env.Clone()
+
+sources = [
+ 'pp/sl_pp_context.c',
+ 'pp/sl_pp_define.c',
+ 'pp/sl_pp_dict.c',
+ 'pp/sl_pp_error.c',
+ 'pp/sl_pp_expression.c',
+ 'pp/sl_pp_extension.c',
+ 'pp/sl_pp_if.c',
+ 'pp/sl_pp_line.c',
+ 'pp/sl_pp_macro.c',
+ 'pp/sl_pp_pragma.c',
+ 'pp/sl_pp_process.c',
+ 'pp/sl_pp_purify.c',
+ 'pp/sl_pp_token.c',
+ 'pp/sl_pp_version.c',
+ 'cl/sl_cl_parse.c',
+]
+
+glsl = env.StaticLibrary(
+ target = 'glsl',
+ source = sources,
+)
+
+Export('glsl')
+
+env = env.Clone()
+
+if env['platform'] == 'windows':
+ env.PrependUnique(LIBS = [
+ 'user32',
+ ])
+
+env.Prepend(LIBS = [glsl])
+
+env.Program(
+ target = 'purify',
+ source = ['apps/purify.c'],
+)
+
+env.Program(
+ target = 'tokenise',
+ source = ['apps/tokenise.c'],
+)
+
+env.Program(
+ target = 'version',
+ source = ['apps/version.c'],
+)
+
+env.Program(
+ target = 'process',
+ source = ['apps/process.c'],
+)
+
+glsl_compile = env.Program(
+ target = 'compile',
+ source = ['apps/compile.c'],
+)
+
+if env['platform'] == common.default_platform:
+ # Only export the GLSL compiler when building for the host platform
+ Export('glsl_compile')
diff --git a/src/glsl/apps/Makefile b/src/glsl/apps/Makefile
new file mode 100644
index 0000000000..c80fcb9d97
--- /dev/null
+++ b/src/glsl/apps/Makefile
@@ -0,0 +1,42 @@
+# src/glsl/apps/Makefile
+
+TOP = ../../..
+
+include $(TOP)/configs/current
+
+LIBS = \
+ $(TOP)/src/glsl/pp/libglslpp.a \
+ $(TOP)/src/glsl/cl/libglslcl.a
+
+SOURCES = \
+ compile.c \
+ process.c \
+ purify.c \
+ tokenise.c \
+ version.c
+
+APPS = $(SOURCES:%.c=%)
+
+INCLUDES = -I.
+
+
+##### RULES #####
+
+.SUFFIXES:
+.SUFFIXES: .c
+
+.c:
+ $(APP_CC) $(INCLUDES) $(CFLAGS) $(LDFLAGS) $< $(LIBS) -o $@
+
+.c.o:
+ $(APP_CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@
+
+
+##### TARGETS #####
+
+default: $(APPS)
+
+clean:
+ -rm -f $(APPS)
+ -rm -f *.o
+
diff --git a/src/glsl/apps/compile.c b/src/glsl/apps/compile.c
new file mode 100644
index 0000000000..b1165420fb
--- /dev/null
+++ b/src/glsl/apps/compile.c
@@ -0,0 +1,234 @@
+/**************************************************************************
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "../pp/sl_pp_public.h"
+#include "../cl/sl_cl_parse.h"
+
+
+static void
+usage(void)
+{
+ printf("Usage:\n");
+ printf(" compile fragment|vertex <source> <output>\n");
+}
+
+int
+main(int argc,
+ char *argv[])
+{
+ FILE *in;
+ long size;
+ char *inbuf;
+ struct sl_pp_purify_options options;
+ char errmsg[100] = "";
+ struct sl_pp_context *context;
+ struct sl_pp_token_info *tokens;
+ unsigned int version;
+ unsigned int tokens_eaten;
+ struct sl_pp_token_info *outtokens;
+ FILE *out;
+ unsigned int i, j;
+ unsigned char *outbytes;
+ unsigned int cboutbytes;
+ unsigned int shader_type;
+
+ if (argc != 4) {
+ usage();
+ return 1;
+ }
+
+ if (!strcmp(argv[1], "fragment")) {
+ shader_type = 1;
+ } else if (!strcmp(argv[1], "vertex")) {
+ shader_type = 2;
+ } else {
+ usage();
+ return 1;
+ }
+
+ in = fopen(argv[2], "rb");
+ if (!in) {
+ printf("Could not open `%s' for read.\n", argv[2]);
+ usage();
+ return 1;
+ }
+
+ fseek(in, 0, SEEK_END);
+ size = ftell(in);
+ fseek(in, 0, SEEK_SET);
+
+ out = fopen(argv[3], "w");
+ if (!out) {
+ fclose(in);
+ printf("Could not open `%s' for write.\n", argv[3]);
+ usage();
+ return 1;
+ }
+
+ inbuf = malloc(size + 1);
+ if (!inbuf) {
+ fprintf(out, "$OOMERROR\n");
+
+ fclose(out);
+ fclose(in);
+ printf("Out of memory.\n");
+ return 0;
+ }
+
+ if (fread(inbuf, 1, size, in) != size) {
+ fprintf(out, "$READERROR\n");
+
+ free(inbuf);
+ fclose(out);
+ fclose(in);
+ printf("Could not read from `%s'.\n", argv[2]);
+ return 0;
+ }
+ inbuf[size] = '\0';
+
+ fclose(in);
+
+ memset(&options, 0, sizeof(options));
+
+ context = sl_pp_context_create();
+ if (!context) {
+ fprintf(out, "$CONTEXERROR\n");
+
+ free(inbuf);
+ fclose(out);
+ printf("Could not create parse context.\n");
+ return 0;
+ }
+
+ if (sl_pp_tokenise(context, inbuf, &options, &tokens)) {
+ fprintf(out, "$ERROR: `%s'\n", sl_pp_context_error_message(context));
+
+ printf("Error: %s.\n", sl_pp_context_error_message(context));
+ sl_pp_context_destroy(context);
+ free(inbuf);
+ fclose(out);
+ return 0;
+ }
+
+ free(inbuf);
+
+ if (sl_pp_version(context, tokens, &version, &tokens_eaten)) {
+ fprintf(out, "$ERROR: `%s'\n", sl_pp_context_error_message(context));
+
+ printf("Error: %s\n", sl_pp_context_error_message(context));
+ sl_pp_context_destroy(context);
+ free(tokens);
+ fclose(out);
+ return 0;
+ }
+
+ if (sl_pp_context_add_extension(context, "ARB_draw_buffers", "GL_ARB_draw_buffers") ||
+ sl_pp_context_add_extension(context, "ARB_texture_rectangle", "GL_ARB_texture_rectangle")) {
+ fprintf(out, "$ERROR: `%s'\n", sl_pp_context_error_message(context));
+
+ printf("Error: %s\n", sl_pp_context_error_message(context));
+ sl_pp_context_destroy(context);
+ free(tokens);
+ fclose(out);
+ return 0;
+ }
+
+ if (sl_pp_process(context, &tokens[tokens_eaten], &outtokens)) {
+ fprintf(out, "$ERROR: `%s'\n", sl_pp_context_error_message(context));
+
+ printf("Error: %s\n", sl_pp_context_error_message(context));
+ sl_pp_context_destroy(context);
+ free(tokens);
+ fclose(out);
+ return 0;
+ }
+
+ free(tokens);
+
+ for (i = j = 0; outtokens[i].token != SL_PP_EOF; i++) {
+ switch (outtokens[i].token) {
+ case SL_PP_NEWLINE:
+ case SL_PP_EXTENSION_REQUIRE:
+ case SL_PP_EXTENSION_ENABLE:
+ case SL_PP_EXTENSION_WARN:
+ case SL_PP_EXTENSION_DISABLE:
+ case SL_PP_LINE:
+ break;
+ default:
+ outtokens[j++] = outtokens[i];
+ }
+ }
+ outtokens[j] = outtokens[i];
+
+ if (sl_cl_compile(context, outtokens, shader_type, 1, &outbytes, &cboutbytes, errmsg, sizeof(errmsg)) == 0) {
+ unsigned int i;
+ unsigned int line = 0;
+
+ fprintf(out, "\n/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE FOLLOWING FILE: */");
+ fprintf(out, "\n/* %s */", argv[2]);
+ fprintf(out, "\n\n");
+
+ for (i = 0; i < cboutbytes; i++) {
+ unsigned int a;
+
+ if (outbytes[i] < 10) {
+ a = 1;
+ } else if (outbytes[i] < 100) {
+ a = 2;
+ } else {
+ a = 3;
+ }
+ if (i < cboutbytes - 1) {
+ a++;
+ }
+ if (line + a >= 100) {
+ fprintf (out, "\n");
+ line = 0;
+ }
+ line += a;
+ fprintf (out, "%u", outbytes[i]);
+ if (i < cboutbytes - 1) {
+ fprintf (out, ",");
+ }
+ }
+ fprintf (out, "\n");
+ free(outbytes);
+ } else {
+ fprintf(out, "$SYNTAXERROR: `%s'\n", errmsg);
+
+ printf("Error: %s\n", errmsg);
+ }
+
+ sl_pp_context_destroy(context);
+ free(outtokens);
+ fclose(out);
+ return 0;
+}
diff --git a/src/glsl/apps/process.c b/src/glsl/apps/process.c
new file mode 100644
index 0000000000..d7bc16577e
--- /dev/null
+++ b/src/glsl/apps/process.c
@@ -0,0 +1,394 @@
+/**************************************************************************
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "../pp/sl_pp_public.h"
+
+
+int
+main(int argc,
+ char *argv[])
+{
+ FILE *in;
+ long size;
+ char *inbuf;
+ struct sl_pp_purify_options options;
+ struct sl_pp_context *context;
+ struct sl_pp_token_info *tokens;
+ unsigned int version;
+ unsigned int tokens_eaten;
+ struct sl_pp_token_info *outtokens;
+ FILE *out;
+ unsigned int i;
+
+ if (argc != 3) {
+ return 1;
+ }
+
+ in = fopen(argv[1], "rb");
+ if (!in) {
+ return 1;
+ }
+
+ fseek(in, 0, SEEK_END);
+ size = ftell(in);
+ fseek(in, 0, SEEK_SET);
+
+ out = fopen(argv[2], "wb");
+ if (!out) {
+ fclose(in);
+ return 1;
+ }
+
+ inbuf = malloc(size + 1);
+ if (!inbuf) {
+ fprintf(out, "$OOMERROR\n");
+
+ fclose(out);
+ fclose(in);
+ return 1;
+ }
+
+ if (fread(inbuf, 1, size, in) != size) {
+ fprintf(out, "$READERROR\n");
+
+ free(inbuf);
+ fclose(out);
+ fclose(in);
+ return 1;
+ }
+ inbuf[size] = '\0';
+
+ fclose(in);
+
+ memset(&options, 0, sizeof(options));
+
+ context = sl_pp_context_create();
+ if (!context) {
+ fprintf(out, "$CONTEXERROR\n");
+
+ free(inbuf);
+ fclose(out);
+ return 1;
+ }
+
+ if (sl_pp_tokenise(context, inbuf, &options, &tokens)) {
+ fprintf(out, "$ERROR: `%s'\n", sl_pp_context_error_message(context));
+
+ sl_pp_context_destroy(context);
+ free(inbuf);
+ fclose(out);
+ return 1;
+ }
+
+ free(inbuf);
+
+ if (sl_pp_version(context, tokens, &version, &tokens_eaten)) {
+ fprintf(out, "$ERROR: `%s'\n", sl_pp_context_error_message(context));
+
+ sl_pp_context_destroy(context);
+ free(tokens);
+ fclose(out);
+ return -1;
+ }
+
+ if (sl_pp_context_add_extension(context, "ARB_draw_buffers", "GL_ARB_draw_buffers") ||
+ sl_pp_context_add_extension(context, "ARB_texture_rectangle", "GL_ARB_texture_rectangle")) {
+ fprintf(out, "$ERROR: `%s'\n", sl_pp_context_error_message(context));
+
+ printf("Error: %s\n", sl_pp_context_error_message(context));
+ sl_pp_context_destroy(context);
+ free(tokens);
+ fclose(out);
+ return 0;
+ }
+
+ if (sl_pp_context_add_predefined(context, "__GLSL_PP_PREDEFINED_MACRO_TEST", "1")) {
+ fprintf(out, "$ERROR: `%s'\n", sl_pp_context_error_message(context));
+
+ printf("Error: %s\n", sl_pp_context_error_message(context));
+ sl_pp_context_destroy(context);
+ free(tokens);
+ fclose(out);
+ return 0;
+ }
+
+ if (sl_pp_process(context, &tokens[tokens_eaten], &outtokens)) {
+ fprintf(out, "$ERROR: `%s'\n", sl_pp_context_error_message(context));
+
+ sl_pp_context_destroy(context);
+ free(tokens);
+ fclose(out);
+ return -1;
+ }
+
+ free(tokens);
+
+ for (i = 0; outtokens[i].token != SL_PP_EOF; i++) {
+ switch (outtokens[i].token) {
+ case SL_PP_NEWLINE:
+ fprintf(out, "\n");
+ break;
+
+ case SL_PP_COMMA:
+ fprintf(out, ", ");
+ break;
+
+ case SL_PP_SEMICOLON:
+ fprintf(out, "; ");
+ break;
+
+ case SL_PP_LBRACE:
+ fprintf(out, "{ ");
+ break;
+
+ case SL_PP_RBRACE:
+ fprintf(out, "} ");
+ break;
+
+ case SL_PP_LPAREN:
+ fprintf(out, "( ");
+ break;
+
+ case SL_PP_RPAREN:
+ fprintf(out, ") ");
+ break;
+
+ case SL_PP_LBRACKET:
+ fprintf(out, "[ ");
+ break;
+
+ case SL_PP_RBRACKET:
+ fprintf(out, "] ");
+ break;
+
+ case SL_PP_DOT:
+ fprintf(out, ". ");
+ break;
+
+ case SL_PP_INCREMENT:
+ fprintf(out, "++ ");
+ break;
+
+ case SL_PP_ADDASSIGN:
+ fprintf(out, "+= ");
+ break;
+
+ case SL_PP_PLUS:
+ fprintf(out, "+ ");
+ break;
+
+ case SL_PP_DECREMENT:
+ fprintf(out, "-- ");
+ break;
+
+ case SL_PP_SUBASSIGN:
+ fprintf(out, "-= ");
+ break;
+
+ case SL_PP_MINUS:
+ fprintf(out, "- ");
+ break;
+
+ case SL_PP_BITNOT:
+ fprintf(out, "~ ");
+ break;
+
+ case SL_PP_NOTEQUAL:
+ fprintf(out, "!= ");
+ break;
+
+ case SL_PP_NOT:
+ fprintf(out, "! ");
+ break;
+
+ case SL_PP_MULASSIGN:
+ fprintf(out, "*= ");
+ break;
+
+ case SL_PP_STAR:
+ fprintf(out, "* ");
+ break;
+
+ case SL_PP_DIVASSIGN:
+ fprintf(out, "/= ");
+ break;
+
+ case SL_PP_SLASH:
+ fprintf(out, "/ ");
+ break;
+
+ case SL_PP_MODASSIGN:
+ fprintf(out, "%%= ");
+ break;
+
+ case SL_PP_MODULO:
+ fprintf(out, "%% ");
+ break;
+
+ case SL_PP_LSHIFTASSIGN:
+ fprintf(out, "<<= ");
+ break;
+
+ case SL_PP_LSHIFT:
+ fprintf(out, "<< ");
+ break;
+
+ case SL_PP_LESSEQUAL:
+ fprintf(out, "<= ");
+ break;
+
+ case SL_PP_LESS:
+ fprintf(out, "< ");
+ break;
+
+ case SL_PP_RSHIFTASSIGN:
+ fprintf(out, ">>= ");
+ break;
+
+ case SL_PP_RSHIFT:
+ fprintf(out, ">> ");
+ break;
+
+ case SL_PP_GREATEREQUAL:
+ fprintf(out, ">= ");
+ break;
+
+ case SL_PP_GREATER:
+ fprintf(out, "> ");
+ break;
+
+ case SL_PP_EQUAL:
+ fprintf(out, "== ");
+ break;
+
+ case SL_PP_ASSIGN:
+ fprintf(out, "= ");
+ break;
+
+ case SL_PP_AND:
+ fprintf(out, "&& ");
+ break;
+
+ case SL_PP_BITANDASSIGN:
+ fprintf(out, "&= ");
+ break;
+
+ case SL_PP_BITAND:
+ fprintf(out, "& ");
+ break;
+
+ case SL_PP_XOR:
+ fprintf(out, "^^ ");
+ break;
+
+ case SL_PP_BITXORASSIGN:
+ fprintf(out, "^= ");
+ break;
+
+ case SL_PP_BITXOR:
+ fprintf(out, "^ ");
+ break;
+
+ case SL_PP_OR:
+ fprintf(out, "|| ");
+ break;
+
+ case SL_PP_BITORASSIGN:
+ fprintf(out, "|= ");
+ break;
+
+ case SL_PP_BITOR:
+ fprintf(out, "| ");
+ break;
+
+ case SL_PP_QUESTION:
+ fprintf(out, "? ");
+ break;
+
+ case SL_PP_COLON:
+ fprintf(out, ": ");
+ break;
+
+ case SL_PP_IDENTIFIER:
+ fprintf(out, "%s ", sl_pp_context_cstr(context, outtokens[i].data.identifier));
+ break;
+
+ case SL_PP_UINT:
+ fprintf(out, "%s ", sl_pp_context_cstr(context, outtokens[i].data._uint));
+ break;
+
+ case SL_PP_FLOAT:
+ fprintf(out, "%s ", sl_pp_context_cstr(context, outtokens[i].data._float));
+ break;
+
+ case SL_PP_OTHER:
+ fprintf(out, "%c", outtokens[i].data.other);
+ break;
+
+ case SL_PP_PRAGMA_OPTIMIZE:
+ fprintf(out, "#pragma optimize(%s)", outtokens[i].data.pragma ? "on" : "off");
+ break;
+
+ case SL_PP_PRAGMA_DEBUG:
+ fprintf(out, "#pragma debug(%s)", outtokens[i].data.pragma ? "on" : "off");
+ break;
+
+ case SL_PP_EXTENSION_REQUIRE:
+ fprintf(out, "#extension %s : require", sl_pp_context_cstr(context, outtokens[i].data.extension));
+ break;
+
+ case SL_PP_EXTENSION_ENABLE:
+ fprintf(out, "#extension %s : enable", sl_pp_context_cstr(context, outtokens[i].data.extension));
+ break;
+
+ case SL_PP_EXTENSION_WARN:
+ fprintf(out, "#extension %s : warn", sl_pp_context_cstr(context, outtokens[i].data.extension));
+ break;
+
+ case SL_PP_EXTENSION_DISABLE:
+ fprintf(out, "#extension %s : disable", sl_pp_context_cstr(context, outtokens[i].data.extension));
+ break;
+
+ case SL_PP_LINE:
+ fprintf(out, "#line %u %u", outtokens[i].data.line.lineno, outtokens[i].data.line.fileno);
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+
+ sl_pp_context_destroy(context);
+ free(outtokens);
+ fclose(out);
+
+ return 0;
+}
diff --git a/src/glsl/apps/purify.c b/src/glsl/apps/purify.c
new file mode 100644
index 0000000000..8c01f4fc6a
--- /dev/null
+++ b/src/glsl/apps/purify.c
@@ -0,0 +1,105 @@
+/**************************************************************************
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "../pp/sl_pp_public.h"
+
+
+int
+main(int argc,
+ char *argv[])
+{
+ FILE *in;
+ long size;
+ char *inbuf;
+ struct sl_pp_purify_options options;
+ char *outbuf;
+ char errmsg[100] = "";
+ unsigned int errline = 0;
+ FILE *out;
+
+ if (argc != 3) {
+ return 1;
+ }
+
+ in = fopen(argv[1], "rb");
+ if (!in) {
+ return 1;
+ }
+
+ fseek(in, 0, SEEK_END);
+ size = ftell(in);
+ fseek(in, 0, SEEK_SET);
+
+ out = fopen(argv[2], "wb");
+ if (!out) {
+ fclose(in);
+ return 1;
+ }
+
+ inbuf = malloc(size + 1);
+ if (!inbuf) {
+ fprintf(out, "$OOMERROR\n");
+
+ fclose(out);
+ fclose(in);
+ return 1;
+ }
+
+ if (fread(inbuf, 1, size, in) != size) {
+ fprintf(out, "$READERROR\n");
+
+ free(inbuf);
+ fclose(out);
+ fclose(in);
+ return 1;
+ }
+ inbuf[size] = '\0';
+
+ fclose(in);
+
+ memset(&options, 0, sizeof(options));
+
+ if (sl_pp_purify(inbuf, &options, &outbuf, errmsg, sizeof(errmsg), &errline)) {
+ fprintf(out, "$PURIFYERROR %u: %s\n", errline, errmsg);
+
+ free(inbuf);
+ fclose(out);
+ return 1;
+ }
+
+ free(inbuf);
+
+ fwrite(outbuf, 1, strlen(outbuf), out);
+
+ free(outbuf);
+ fclose(out);
+
+ return 0;
+}
diff --git a/src/glsl/apps/tokenise.c b/src/glsl/apps/tokenise.c
new file mode 100644
index 0000000000..91368c32a4
--- /dev/null
+++ b/src/glsl/apps/tokenise.c
@@ -0,0 +1,333 @@
+/**************************************************************************
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "../pp/sl_pp_public.h"
+
+
+int
+main(int argc,
+ char *argv[])
+{
+ FILE *in;
+ long size;
+ char *inbuf;
+ struct sl_pp_purify_options options;
+ struct sl_pp_context *context;
+ struct sl_pp_token_info *tokens;
+ FILE *out;
+ unsigned int i;
+
+ if (argc != 3) {
+ return 1;
+ }
+
+ in = fopen(argv[1], "rb");
+ if (!in) {
+ return 1;
+ }
+
+ fseek(in, 0, SEEK_END);
+ size = ftell(in);
+ fseek(in, 0, SEEK_SET);
+
+ out = fopen(argv[2], "wb");
+ if (!out) {
+ fclose(in);
+ return 1;
+ }
+
+ inbuf = malloc(size + 1);
+ if (!inbuf) {
+ fprintf(out, "$OOMERROR\n");
+
+ fclose(out);
+ fclose(in);
+ return 1;
+ }
+
+ if (fread(inbuf, 1, size, in) != size) {
+ fprintf(out, "$READERROR\n");
+
+ free(inbuf);
+ fclose(out);
+ fclose(in);
+ return 1;
+ }
+ inbuf[size] = '\0';
+
+ fclose(in);
+
+ memset(&options, 0, sizeof(options));
+
+ context = sl_pp_context_create();
+ if (!context) {
+ fprintf(out, "$CONTEXERROR\n");
+
+ free(inbuf);
+ fclose(out);
+ return 1;
+ }
+
+ if (sl_pp_tokenise(context, inbuf, &options, &tokens)) {
+ fprintf(out, "$ERROR: `%s'\n", sl_pp_context_error_message(context));
+
+ sl_pp_context_destroy(context);
+ free(inbuf);
+ fclose(out);
+ return 1;
+ }
+
+ free(inbuf);
+
+ for (i = 0; tokens[i].token != SL_PP_EOF; i++) {
+ switch (tokens[i].token) {
+ case SL_PP_WHITESPACE:
+ break;
+
+ case SL_PP_NEWLINE:
+ fprintf(out, "\n");
+ break;
+
+ case SL_PP_HASH:
+ fprintf(out, "# ");
+ break;
+
+ case SL_PP_COMMA:
+ fprintf(out, ", ");
+ break;
+
+ case SL_PP_SEMICOLON:
+ fprintf(out, "; ");
+ break;
+
+ case SL_PP_LBRACE:
+ fprintf(out, "{ ");
+ break;
+
+ case SL_PP_RBRACE:
+ fprintf(out, "} ");
+ break;
+
+ case SL_PP_LPAREN:
+ fprintf(out, "( ");
+ break;
+
+ case SL_PP_RPAREN:
+ fprintf(out, ") ");
+ break;
+
+ case SL_PP_LBRACKET:
+ fprintf(out, "[ ");
+ break;
+
+ case SL_PP_RBRACKET:
+ fprintf(out, "] ");
+ break;
+
+ case SL_PP_DOT:
+ fprintf(out, ". ");
+ break;
+
+ case SL_PP_INCREMENT:
+ fprintf(out, "++ ");
+ break;
+
+ case SL_PP_ADDASSIGN:
+ fprintf(out, "+= ");
+ break;
+
+ case SL_PP_PLUS:
+ fprintf(out, "+ ");
+ break;
+
+ case SL_PP_DECREMENT:
+ fprintf(out, "-- ");
+ break;
+
+ case SL_PP_SUBASSIGN:
+ fprintf(out, "-= ");
+ break;
+
+ case SL_PP_MINUS:
+ fprintf(out, "- ");
+ break;
+
+ case SL_PP_BITNOT:
+ fprintf(out, "~ ");
+ break;
+
+ case SL_PP_NOTEQUAL:
+ fprintf(out, "!= ");
+ break;
+
+ case SL_PP_NOT:
+ fprintf(out, "! ");
+ break;
+
+ case SL_PP_MULASSIGN:
+ fprintf(out, "*= ");
+ break;
+
+ case SL_PP_STAR:
+ fprintf(out, "* ");
+ break;
+
+ case SL_PP_DIVASSIGN:
+ fprintf(out, "/= ");
+ break;
+
+ case SL_PP_SLASH:
+ fprintf(out, "/ ");
+ break;
+
+ case SL_PP_MODASSIGN:
+ fprintf(out, "%%= ");
+ break;
+
+ case SL_PP_MODULO:
+ fprintf(out, "%% ");
+ break;
+
+ case SL_PP_LSHIFTASSIGN:
+ fprintf(out, "<<= ");
+ break;
+
+ case SL_PP_LSHIFT:
+ fprintf(out, "<< ");
+ break;
+
+ case SL_PP_LESSEQUAL:
+ fprintf(out, "<= ");
+ break;
+
+ case SL_PP_LESS:
+ fprintf(out, "< ");
+ break;
+
+ case SL_PP_RSHIFTASSIGN:
+ fprintf(out, ">>= ");
+ break;
+
+ case SL_PP_RSHIFT:
+ fprintf(out, ">> ");
+ break;
+
+ case SL_PP_GREATEREQUAL:
+ fprintf(out, ">= ");
+ break;
+
+ case SL_PP_GREATER:
+ fprintf(out, "> ");
+ break;
+
+ case SL_PP_EQUAL:
+ fprintf(out, "== ");
+ break;
+
+ case SL_PP_ASSIGN:
+ fprintf(out, "= ");
+ break;
+
+ case SL_PP_AND:
+ fprintf(out, "&& ");
+ break;
+
+ case SL_PP_BITANDASSIGN:
+ fprintf(out, "&= ");
+ break;
+
+ case SL_PP_BITAND:
+ fprintf(out, "& ");
+ break;
+
+ case SL_PP_XOR:
+ fprintf(out, "^^ ");
+ break;
+
+ case SL_PP_BITXORASSIGN:
+ fprintf(out, "^= ");
+ break;
+
+ case SL_PP_BITXOR:
+ fprintf(out, "^ ");
+ break;
+
+ case SL_PP_OR:
+ fprintf(out, "|| ");
+ break;
+
+ case SL_PP_BITORASSIGN:
+ fprintf(out, "|= ");
+ break;
+
+ case SL_PP_BITOR:
+ fprintf(out, "| ");
+ break;
+
+ case SL_PP_QUESTION:
+ fprintf(out, "? ");
+ break;
+
+ case SL_PP_COLON:
+ fprintf(out, ": ");
+ break;
+
+ case SL_PP_IDENTIFIER:
+ fprintf(out, "%s ", sl_pp_context_cstr(context, tokens[i].data.identifier));
+ break;
+
+ case SL_PP_UINT:
+ fprintf(out, "(%s) ", sl_pp_context_cstr(context, tokens[i].data._uint));
+ break;
+
+ case SL_PP_FLOAT:
+ fprintf(out, "(%s) ", sl_pp_context_cstr(context, tokens[i].data._float));
+ break;
+
+ case SL_PP_OTHER:
+ if (tokens[i].data.other == '\'') {
+ fprintf(out, "'\\'' ");
+ } else {
+ fprintf(out, "'%c' ", tokens[i].data.other);
+ }
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+
+ sl_pp_context_destroy(context);
+ free(tokens);
+ fclose(out);
+
+ return 0;
+}
diff --git a/src/glsl/apps/version.c b/src/glsl/apps/version.c
new file mode 100644
index 0000000000..6f77f230ca
--- /dev/null
+++ b/src/glsl/apps/version.c
@@ -0,0 +1,131 @@
+/**************************************************************************
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "../pp/sl_pp_public.h"
+
+
+int
+main(int argc,
+ char *argv[])
+{
+ FILE *in;
+ long size;
+ char *inbuf;
+ struct sl_pp_purify_options options;
+ struct sl_pp_context *context;
+ struct sl_pp_token_info *tokens;
+ unsigned int version;
+ unsigned int tokens_eaten;
+ FILE *out;
+
+ if (argc != 3) {
+ return 1;
+ }
+
+ in = fopen(argv[1], "rb");
+ if (!in) {
+ return 1;
+ }
+
+ fseek(in, 0, SEEK_END);
+ size = ftell(in);
+ fseek(in, 0, SEEK_SET);
+
+ out = fopen(argv[2], "wb");
+ if (!out) {
+ fclose(in);
+ return 1;
+ }
+
+ inbuf = malloc(size + 1);
+ if (!inbuf) {
+ fprintf(out, "$OOMERROR\n");
+
+ fclose(out);
+ fclose(in);
+ return 1;
+ }
+
+ if (fread(inbuf, 1, size, in) != size) {
+ fprintf(out, "$READERROR\n");
+
+ free(inbuf);
+ fclose(out);
+ fclose(in);
+ return 1;
+ }
+ inbuf[size] = '\0';
+
+ fclose(in);
+
+ memset(&options, 0, sizeof(options));
+
+ context = sl_pp_context_create();
+ if (!context) {
+ fprintf(out, "$CONTEXERROR\n");
+
+ free(inbuf);
+ fclose(out);
+ return 1;
+ }
+
+ if (sl_pp_tokenise(context, inbuf, &options, &tokens)) {
+ fprintf(out, "$ERROR: `%s'\n", sl_pp_context_error_message(context));
+
+ sl_pp_context_destroy(context);
+ free(inbuf);
+ fclose(out);
+ return 1;
+ }
+
+ free(inbuf);
+
+ if (sl_pp_version(context, tokens, &version, &tokens_eaten)) {
+ fprintf(out, "$ERROR: `%s'\n", sl_pp_context_error_message(context));
+
+ sl_pp_context_destroy(context);
+ free(tokens);
+ fclose(out);
+ return -1;
+ }
+
+ sl_pp_context_destroy(context);
+ free(tokens);
+
+ fprintf(out,
+ "%u\n%u\n",
+ version,
+ tokens_eaten);
+
+ fclose(out);
+
+ return 0;
+}
diff --git a/src/glsl/cl/Makefile b/src/glsl/cl/Makefile
new file mode 100644
index 0000000000..04a52df8c3
--- /dev/null
+++ b/src/glsl/cl/Makefile
@@ -0,0 +1,13 @@
+#src/glsl/cl/Makefile
+
+TOP = ../../..
+
+include $(TOP)/configs/current
+
+LIBNAME = glslcl
+
+C_SOURCES = \
+ sl_cl_parse.c
+
+include ../Makefile.template
+
diff --git a/src/glsl/cl/sl_cl_parse.c b/src/glsl/cl/sl_cl_parse.c
new file mode 100644
index 0000000000..a9db65c7ad
--- /dev/null
+++ b/src/glsl/cl/sl_cl_parse.c
@@ -0,0 +1,2714 @@
+/**************************************************************************
+ *
+ * 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 "../pp/sl_pp_public.h"
+#include "sl_cl_parse.h"
+
+
+/* revision number - increment after each change affecting emitted output */
+#define REVISION 5
+
+/* external declaration (or precision or invariant stmt) */
+#define EXTERNAL_NULL 0
+#define EXTERNAL_FUNCTION_DEFINITION 1
+#define EXTERNAL_DECLARATION 2
+#define DEFAULT_PRECISION 3
+#define INVARIANT_STMT 4
+
+/* precision */
+#define PRECISION_DEFAULT 0
+#define PRECISION_LOW 1
+#define PRECISION_MEDIUM 2
+#define PRECISION_HIGH 3
+
+/* declaration */
+#define DECLARATION_FUNCTION_PROTOTYPE 1
+#define DECLARATION_INIT_DECLARATOR_LIST 2
+
+/* function type */
+#define FUNCTION_ORDINARY 0
+#define FUNCTION_CONSTRUCTOR 1
+#define FUNCTION_OPERATOR 2
+
+/* function call type */
+#define FUNCTION_CALL_NONARRAY 0
+#define FUNCTION_CALL_ARRAY 1
+
+/* operator type */
+#define OPERATOR_ADDASSIGN 1
+#define OPERATOR_SUBASSIGN 2
+#define OPERATOR_MULASSIGN 3
+#define OPERATOR_DIVASSIGN 4
+/*#define OPERATOR_MODASSIGN 5*/
+/*#define OPERATOR_LSHASSIGN 6*/
+/*#define OPERATOR_RSHASSIGN 7*/
+/*#define OPERATOR_ORASSIGN 8*/
+/*#define OPERATOR_XORASSIGN 9*/
+/*#define OPERATOR_ANDASSIGN 10*/
+#define OPERATOR_LOGICALXOR 11
+/*#define OPERATOR_BITOR 12*/
+/*#define OPERATOR_BITXOR 13*/
+/*#define OPERATOR_BITAND 14*/
+#define OPERATOR_LESS 15
+#define OPERATOR_GREATER 16
+#define OPERATOR_LESSEQUAL 17
+#define OPERATOR_GREATEREQUAL 18
+/*#define OPERATOR_LSHIFT 19*/
+/*#define OPERATOR_RSHIFT 20*/
+#define OPERATOR_MULTIPLY 21
+#define OPERATOR_DIVIDE 22
+/*#define OPERATOR_MODULUS 23*/
+#define OPERATOR_INCREMENT 24
+#define OPERATOR_DECREMENT 25
+#define OPERATOR_PLUS 26
+#define OPERATOR_MINUS 27
+/*#define OPERATOR_COMPLEMENT 28*/
+#define OPERATOR_NOT 29
+
+/* init declarator list */
+#define DECLARATOR_NONE 0
+#define DECLARATOR_NEXT 1
+
+/* variable declaration */
+#define VARIABLE_NONE 0
+#define VARIABLE_IDENTIFIER 1
+#define VARIABLE_INITIALIZER 2
+#define VARIABLE_ARRAY_EXPLICIT 3
+#define VARIABLE_ARRAY_UNKNOWN 4
+
+/* type qualifier */
+#define TYPE_QUALIFIER_NONE 0
+#define TYPE_QUALIFIER_CONST 1
+#define TYPE_QUALIFIER_ATTRIBUTE 2
+#define TYPE_QUALIFIER_VARYING 3
+#define TYPE_QUALIFIER_UNIFORM 4
+#define TYPE_QUALIFIER_FIXEDOUTPUT 5
+#define TYPE_QUALIFIER_FIXEDINPUT 6
+
+/* invariant qualifier */
+#define TYPE_VARIANT 90
+#define TYPE_INVARIANT 91
+
+/* centroid qualifier */
+#define TYPE_CENTER 95
+#define TYPE_CENTROID 96
+
+/* type specifier */
+#define TYPE_SPECIFIER_VOID 0
+#define TYPE_SPECIFIER_BOOL 1
+#define TYPE_SPECIFIER_BVEC2 2
+#define TYPE_SPECIFIER_BVEC3 3
+#define TYPE_SPECIFIER_BVEC4 4
+#define TYPE_SPECIFIER_INT 5
+#define TYPE_SPECIFIER_IVEC2 6
+#define TYPE_SPECIFIER_IVEC3 7
+#define TYPE_SPECIFIER_IVEC4 8
+#define TYPE_SPECIFIER_FLOAT 9
+#define TYPE_SPECIFIER_VEC2 10
+#define TYPE_SPECIFIER_VEC3 11
+#define TYPE_SPECIFIER_VEC4 12
+#define TYPE_SPECIFIER_MAT2 13
+#define TYPE_SPECIFIER_MAT3 14
+#define TYPE_SPECIFIER_MAT4 15
+#define TYPE_SPECIFIER_SAMPLER1D 16
+#define TYPE_SPECIFIER_SAMPLER2D 17
+#define TYPE_SPECIFIER_SAMPLER3D 18
+#define TYPE_SPECIFIER_SAMPLERCUBE 19
+#define TYPE_SPECIFIER_SAMPLER1DSHADOW 20
+#define TYPE_SPECIFIER_SAMPLER2DSHADOW 21
+#define TYPE_SPECIFIER_SAMPLER2DRECT 22
+#define TYPE_SPECIFIER_SAMPLER2DRECTSHADOW 23
+#define TYPE_SPECIFIER_STRUCT 24
+#define TYPE_SPECIFIER_TYPENAME 25
+
+/* OpenGL 2.1 */
+#define TYPE_SPECIFIER_MAT23 26
+#define TYPE_SPECIFIER_MAT32 27
+#define TYPE_SPECIFIER_MAT24 28
+#define TYPE_SPECIFIER_MAT42 29
+#define TYPE_SPECIFIER_MAT34 30
+#define TYPE_SPECIFIER_MAT43 31
+
+/* type specifier array */
+#define TYPE_SPECIFIER_NONARRAY 0
+#define TYPE_SPECIFIER_ARRAY 1
+
+/* structure field */
+#define FIELD_NONE 0
+#define FIELD_NEXT 1
+#define FIELD_ARRAY 2
+
+/* operation */
+#define OP_END 0
+#define OP_BLOCK_BEGIN_NO_NEW_SCOPE 1
+#define OP_BLOCK_BEGIN_NEW_SCOPE 2
+#define OP_DECLARE 3
+#define OP_ASM 4
+#define OP_BREAK 5
+#define OP_CONTINUE 6
+#define OP_DISCARD 7
+#define OP_RETURN 8
+#define OP_EXPRESSION 9
+#define OP_IF 10
+#define OP_WHILE 11
+#define OP_DO 12
+#define OP_FOR 13
+#define OP_PUSH_VOID 14
+#define OP_PUSH_BOOL 15
+#define OP_PUSH_INT 16
+#define OP_PUSH_FLOAT 17
+#define OP_PUSH_IDENTIFIER 18
+#define OP_SEQUENCE 19
+#define OP_ASSIGN 20
+#define OP_ADDASSIGN 21
+#define OP_SUBASSIGN 22
+#define OP_MULASSIGN 23
+#define OP_DIVASSIGN 24
+/*#define OP_MODASSIGN 25*/
+/*#define OP_LSHASSIGN 26*/
+/*#define OP_RSHASSIGN 27*/
+/*#define OP_ORASSIGN 28*/
+/*#define OP_XORASSIGN 29*/
+/*#define OP_ANDASSIGN 30*/
+#define OP_SELECT 31
+#define OP_LOGICALOR 32
+#define OP_LOGICALXOR 33
+#define OP_LOGICALAND 34
+/*#define OP_BITOR 35*/
+/*#define OP_BITXOR 36*/
+/*#define OP_BITAND 37*/
+#define OP_EQUAL 38
+#define OP_NOTEQUAL 39
+#define OP_LESS 40
+#define OP_GREATER 41
+#define OP_LESSEQUAL 42
+#define OP_GREATEREQUAL 43
+/*#define OP_LSHIFT 44*/
+/*#define OP_RSHIFT 45*/
+#define OP_ADD 46
+#define OP_SUBTRACT 47
+#define OP_MULTIPLY 48
+#define OP_DIVIDE 49
+/*#define OP_MODULUS 50*/
+#define OP_PREINCREMENT 51
+#define OP_PREDECREMENT 52
+#define OP_PLUS 53
+#define OP_MINUS 54
+/*#define OP_COMPLEMENT 55*/
+#define OP_NOT 56
+#define OP_SUBSCRIPT 57
+#define OP_CALL 58
+#define OP_FIELD 59
+#define OP_POSTINCREMENT 60
+#define OP_POSTDECREMENT 61
+#define OP_PRECISION 62
+#define OP_METHOD 63
+
+/* parameter qualifier */
+#define PARAM_QUALIFIER_IN 0
+#define PARAM_QUALIFIER_OUT 1
+#define PARAM_QUALIFIER_INOUT 2
+
+/* function parameter */
+#define PARAMETER_NONE 0
+#define PARAMETER_NEXT 1
+
+/* function parameter array presence */
+#define PARAMETER_ARRAY_NOT_PRESENT 0
+#define PARAMETER_ARRAY_PRESENT 1
+
+
+struct parse_dict {
+ int _void;
+ int _float;
+ int _int;
+ int _bool;
+ int vec2;
+ int vec3;
+ int vec4;
+ int bvec2;
+ int bvec3;
+ int bvec4;
+ int ivec2;
+ int ivec3;
+ int ivec4;
+ int mat2;
+ int mat3;
+ int mat4;
+ int mat2x3;
+ int mat3x2;
+ int mat2x4;
+ int mat4x2;
+ int mat3x4;
+ int mat4x3;
+ int sampler1D;
+ int sampler2D;
+ int sampler3D;
+ int samplerCube;
+ int sampler1DShadow;
+ int sampler2DShadow;
+ int sampler2DRect;
+ int sampler2DRectShadow;
+
+ int invariant;
+
+ int centroid;
+
+ int precision;
+ int lowp;
+ int mediump;
+ int highp;
+
+ int _const;
+ int attribute;
+ int varying;
+ int uniform;
+ int __fixed_output;
+ int __fixed_input;
+
+ int in;
+ int out;
+ int inout;
+
+ int _struct;
+
+ int __constructor;
+ int __operator;
+ int ___asm;
+
+ int _if;
+ int _else;
+ int _for;
+ int _while;
+ int _do;
+
+ int _continue;
+ int _break;
+ int _return;
+ int discard;
+
+ int _false;
+ int _true;
+};
+
+
+struct parse_context {
+ struct sl_pp_context *context;
+ const struct sl_pp_token_info *input;
+
+ struct parse_dict dict;
+
+ unsigned char *out_buf;
+ unsigned int out_cap;
+
+ unsigned int shader_type;
+ unsigned int parsing_builtin;
+
+ char error[256];
+};
+
+
+struct parse_state {
+ unsigned int in;
+ unsigned int out;
+};
+
+
+static __inline unsigned int
+_emit(struct parse_context *ctx,
+ unsigned int *out,
+ unsigned char b)
+{
+ if (*out == ctx->out_cap) {
+ ctx->out_cap += 4096;
+ ctx->out_buf = (unsigned char *)realloc(ctx->out_buf, ctx->out_cap * sizeof(unsigned char));
+ }
+ ctx->out_buf[*out] = b;
+ return (*out)++;
+}
+
+
+static void
+_update(struct parse_context *ctx,
+ unsigned int out,
+ unsigned char b)
+{
+ ctx->out_buf[out] = b;
+}
+
+
+static void
+_error(struct parse_context *ctx,
+ char *msg)
+{
+ if (ctx->error[0] == '\0') {
+ strcpy(ctx->error, msg);
+ }
+}
+
+
+static int
+_parse_token(struct parse_context *ctx,
+ enum sl_pp_token token,
+ struct parse_state *ps)
+{
+ if (ctx->input[ps->in].token == token) {
+ ps->in++;
+ return 0;
+ }
+ return -1;
+}
+
+
+static int
+_parse_id(struct parse_context *ctx,
+ int id,
+ struct parse_state *ps)
+{
+ if (ctx->input[ps->in].token == SL_PP_IDENTIFIER &&
+ ctx->input[ps->in].data.identifier == id) {
+ ps->in++;
+ return 0;
+ }
+ return -1;
+}
+
+
+static int
+_parse_identifier(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ if (ctx->input[ps->in].token == SL_PP_IDENTIFIER) {
+ const char *cstr = sl_pp_context_cstr(ctx->context, ctx->input[ps->in].data.identifier);
+
+ do {
+ _emit(ctx, &ps->out, *cstr);
+ } while (*cstr++);
+ ps->in++;
+ return 0;
+ }
+ return -1;
+}
+
+
+static int
+_parse_float(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ if (ctx->input[ps->in].token == SL_PP_FLOAT) {
+ const char *cstr = sl_pp_context_cstr(ctx->context, ctx->input[ps->in].data._float);
+
+ _emit(ctx, &ps->out, 1);
+ do {
+ _emit(ctx, &ps->out, *cstr);
+ } while (*cstr++);
+ ps->in++;
+ return 0;
+ }
+ return -1;
+}
+
+
+static int
+_parse_uint(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ if (ctx->input[ps->in].token == SL_PP_UINT) {
+ const char *cstr = sl_pp_context_cstr(ctx->context, ctx->input[ps->in].data._uint);
+
+ _emit(ctx, &ps->out, 1);
+ do {
+ _emit(ctx, &ps->out, *cstr);
+ } while (*cstr++);
+ ps->in++;
+ return 0;
+ }
+ return -1;
+}
+
+
+/**************************************/
+
+
+static int
+_parse_unary_expression(struct parse_context *ctx,
+ struct parse_state *ps);
+
+static int
+_parse_conditional_expression(struct parse_context *ctx,
+ struct parse_state *ps);
+
+
+static int
+_parse_constant_expression(struct parse_context *ctx,
+ struct parse_state *ps);
+
+
+static int
+_parse_primary_expression(struct parse_context *ctx,
+ struct parse_state *ps);
+
+
+static int
+_parse_statement(struct parse_context *ctx,
+ struct parse_state *ps);
+
+
+static int
+_parse_type_specifier(struct parse_context *ctx,
+ struct parse_state *ps);
+
+
+static int
+_parse_declaration(struct parse_context *ctx,
+ struct parse_state *ps);
+
+
+static int
+_parse_statement_list(struct parse_context *ctx,
+ struct parse_state *ps);
+
+
+static int
+_parse_assignment_expression(struct parse_context *ctx,
+ struct parse_state *ps);
+
+
+static int
+_parse_precision(struct parse_context *ctx,
+ struct parse_state *ps);
+
+
+static int
+_parse_overriden_operator(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ unsigned int op;
+
+ if (_parse_token(ctx, SL_PP_INCREMENT, ps) == 0) {
+ op = OPERATOR_INCREMENT;
+ } else if (_parse_token(ctx, SL_PP_ADDASSIGN, ps) == 0) {
+ op = OPERATOR_ADDASSIGN;
+ } else if (_parse_token(ctx, SL_PP_PLUS, ps) == 0) {
+ op = OPERATOR_PLUS;
+ } else if (_parse_token(ctx, SL_PP_DECREMENT, ps) == 0) {
+ op = OPERATOR_DECREMENT;
+ } else if (_parse_token(ctx, SL_PP_SUBASSIGN, ps) == 0) {
+ op = OPERATOR_SUBASSIGN;
+ } else if (_parse_token(ctx, SL_PP_MINUS, ps) == 0) {
+ op = OPERATOR_MINUS;
+ } else if (_parse_token(ctx, SL_PP_NOT, ps) == 0) {
+ op = OPERATOR_NOT;
+ } else if (_parse_token(ctx, SL_PP_MULASSIGN, ps) == 0) {
+ op = OPERATOR_MULASSIGN;
+ } else if (_parse_token(ctx, SL_PP_STAR, ps) == 0) {
+ op = OPERATOR_MULTIPLY;
+ } else if (_parse_token(ctx, SL_PP_DIVASSIGN, ps) == 0) {
+ op = OPERATOR_DIVASSIGN;
+ } else if (_parse_token(ctx, SL_PP_SLASH, ps) == 0) {
+ op = OPERATOR_DIVIDE;
+ } else if (_parse_token(ctx, SL_PP_LESSEQUAL, ps) == 0) {
+ op = OPERATOR_LESSEQUAL;
+ } else if (_parse_token(ctx, SL_PP_LESS, ps) == 0) {
+ op = OPERATOR_LESS;
+ } else if (_parse_token(ctx, SL_PP_GREATEREQUAL, ps) == 0) {
+ op = OPERATOR_GREATEREQUAL;
+ } else if (_parse_token(ctx, SL_PP_GREATER, ps) == 0) {
+ op = OPERATOR_GREATER;
+ } else if (_parse_token(ctx, SL_PP_XOR, ps) == 0) {
+ op = OPERATOR_LOGICALXOR;
+ } else {
+ return -1;
+ }
+
+ _emit(ctx, &ps->out, op);
+ return 0;
+}
+
+
+static int
+_parse_function_decl_identifier(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+ unsigned int e = _emit(ctx, &p.out, 0);
+
+ if (ctx->parsing_builtin && _parse_id(ctx, ctx->dict.__constructor, &p) == 0) {
+ _update(ctx, e, FUNCTION_CONSTRUCTOR);
+ *ps = p;
+ return 0;
+ }
+
+ if (ctx->parsing_builtin && _parse_id(ctx, ctx->dict.__operator, &p) == 0) {
+ _update(ctx, e, FUNCTION_OPERATOR);
+ if (_parse_overriden_operator(ctx, &p) == 0) {
+ *ps = p;
+ return 0;
+ }
+ return -1;
+ }
+
+ if (_parse_identifier(ctx, &p) == 0) {
+ _update(ctx, e, FUNCTION_ORDINARY);
+ *ps = p;
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int
+_parse_invariant_qualifier(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ if (_parse_id(ctx, ctx->dict.invariant, ps)) {
+ return -1;
+ }
+ _emit(ctx, &ps->out, TYPE_INVARIANT);
+ return 0;
+}
+
+
+static int
+_parse_centroid_qualifier(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ if (_parse_id(ctx, ctx->dict.centroid, ps)) {
+ return -1;
+ }
+ _emit(ctx, &ps->out, TYPE_CENTROID);
+ return 0;
+}
+
+
+static int
+_parse_type_qualifier(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+ unsigned int e = _emit(ctx, &p.out, 0);
+ int id;
+
+ if (ctx->input[p.in].token != SL_PP_IDENTIFIER) {
+ return -1;
+ }
+ id = ctx->input[p.in].data.identifier;
+
+ if (id == ctx->dict._const) {
+ _update(ctx, e, TYPE_QUALIFIER_CONST);
+ } else if (ctx->shader_type == 2 && id == ctx->dict.attribute) {
+ _update(ctx, e, TYPE_QUALIFIER_ATTRIBUTE);
+ } else if (id == ctx->dict.varying) {
+ _update(ctx, e, TYPE_QUALIFIER_VARYING);
+ } else if (id == ctx->dict.uniform) {
+ _update(ctx, e, TYPE_QUALIFIER_UNIFORM);
+ } else if (ctx->parsing_builtin && id == ctx->dict.__fixed_output) {
+ _update(ctx, e, TYPE_QUALIFIER_FIXEDOUTPUT);
+ } else if (ctx->parsing_builtin && id == ctx->dict.__fixed_input) {
+ _update(ctx, e, TYPE_QUALIFIER_FIXEDINPUT);
+ } else {
+ return -1;
+ }
+ _parse_token(ctx, SL_PP_IDENTIFIER, &p);
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_struct_declarator(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+ unsigned int e;
+
+ if (_parse_identifier(ctx, &p)) {
+ return -1;
+ }
+ e = _emit(ctx, &p.out, FIELD_NONE);
+ *ps = p;
+
+ if (_parse_token(ctx, SL_PP_LBRACKET, &p)) {
+ return 0;
+ }
+ if (_parse_constant_expression(ctx, &p)) {
+ _error(ctx, "expected constant integral expression");
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_RBRACKET, &p)) {
+ _error(ctx, "expected `]'");
+ return -1;
+ }
+ _update(ctx, e, FIELD_ARRAY);
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_struct_declarator_list(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_struct_declarator(ctx, &p)) {
+ return -1;
+ }
+
+ for (;;) {
+ *ps = p;
+ _emit(ctx, &p.out, FIELD_NEXT);
+ if (_parse_token(ctx, SL_PP_COMMA, &p)) {
+ return 0;
+ }
+ if (_parse_struct_declarator(ctx, &p)) {
+ return 0;
+ }
+ }
+}
+
+
+static int
+_parse_struct_declaration(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_type_specifier(ctx, &p)) {
+ return -1;
+ }
+ if (_parse_struct_declarator_list(ctx, &p)) {
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_SEMICOLON, &p)) {
+ return -1;
+ }
+ _emit(ctx, &p.out, FIELD_NONE);
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_struct_declaration_list(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_struct_declaration(ctx, &p)) {
+ return -1;
+ }
+
+ for (;;) {
+ *ps = p;
+ _emit(ctx, &p.out, FIELD_NEXT);
+ if (_parse_struct_declaration(ctx, &p)) {
+ return 0;
+ }
+ }
+}
+
+
+static int
+_parse_struct_specifier(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_id(ctx, ctx->dict._struct, &p)) {
+ return -1;
+ }
+ if (_parse_identifier(ctx, &p)) {
+ _emit(ctx, &p.out, '\0');
+ }
+ if (_parse_token(ctx, SL_PP_LBRACE, &p)) {
+ _error(ctx, "expected `{'");
+ return -1;
+ }
+ if (_parse_struct_declaration_list(ctx, &p)) {
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_RBRACE, &p)) {
+ return -1;
+ }
+ _emit(ctx, &p.out, FIELD_NONE);
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_type_specifier_nonarray(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+ unsigned int e = _emit(ctx, &p.out, 0);
+ int id;
+
+ if (_parse_struct_specifier(ctx, &p) == 0) {
+ _update(ctx, e, TYPE_SPECIFIER_STRUCT);
+ *ps = p;
+ return 0;
+ }
+
+ if (ctx->input[p.in].token != SL_PP_IDENTIFIER) {
+ return -1;
+ }
+ id = ctx->input[p.in].data.identifier;
+
+ if (id == ctx->dict._void) {
+ _update(ctx, e, TYPE_SPECIFIER_VOID);
+ } else if (id == ctx->dict._float) {
+ _update(ctx, e, TYPE_SPECIFIER_FLOAT);
+ } else if (id == ctx->dict._int) {
+ _update(ctx, e, TYPE_SPECIFIER_INT);
+ } else if (id == ctx->dict._bool) {
+ _update(ctx, e, TYPE_SPECIFIER_BOOL);
+ } else if (id == ctx->dict.vec2) {
+ _update(ctx, e, TYPE_SPECIFIER_VEC2);
+ } else if (id == ctx->dict.vec3) {
+ _update(ctx, e, TYPE_SPECIFIER_VEC3);
+ } else if (id == ctx->dict.vec4) {
+ _update(ctx, e, TYPE_SPECIFIER_VEC4);
+ } else if (id == ctx->dict.bvec2) {
+ _update(ctx, e, TYPE_SPECIFIER_BVEC2);
+ } else if (id == ctx->dict.bvec3) {
+ _update(ctx, e, TYPE_SPECIFIER_BVEC3);
+ } else if (id == ctx->dict.bvec4) {
+ _update(ctx, e, TYPE_SPECIFIER_BVEC4);
+ } else if (id == ctx->dict.ivec2) {
+ _update(ctx, e, TYPE_SPECIFIER_IVEC2);
+ } else if (id == ctx->dict.ivec3) {
+ _update(ctx, e, TYPE_SPECIFIER_IVEC3);
+ } else if (id == ctx->dict.ivec4) {
+ _update(ctx, e, TYPE_SPECIFIER_IVEC4);
+ } else if (id == ctx->dict.mat2) {
+ _update(ctx, e, TYPE_SPECIFIER_MAT2);
+ } else if (id == ctx->dict.mat3) {
+ _update(ctx, e, TYPE_SPECIFIER_MAT3);
+ } else if (id == ctx->dict.mat4) {
+ _update(ctx, e, TYPE_SPECIFIER_MAT4);
+ } else if (id == ctx->dict.mat2x3) {
+ _update(ctx, e, TYPE_SPECIFIER_MAT23);
+ } else if (id == ctx->dict.mat3x2) {
+ _update(ctx, e, TYPE_SPECIFIER_MAT32);
+ } else if (id == ctx->dict.mat2x4) {
+ _update(ctx, e, TYPE_SPECIFIER_MAT24);
+ } else if (id == ctx->dict.mat4x2) {
+ _update(ctx, e, TYPE_SPECIFIER_MAT42);
+ } else if (id == ctx->dict.mat3x4) {
+ _update(ctx, e, TYPE_SPECIFIER_MAT34);
+ } else if (id == ctx->dict.mat4x3) {
+ _update(ctx, e, TYPE_SPECIFIER_MAT43);
+ } else if (id == ctx->dict.sampler1D) {
+ _update(ctx, e, TYPE_SPECIFIER_SAMPLER1D);
+ } else if (id == ctx->dict.sampler2D) {
+ _update(ctx, e, TYPE_SPECIFIER_SAMPLER2D);
+ } else if (id == ctx->dict.sampler3D) {
+ _update(ctx, e, TYPE_SPECIFIER_SAMPLER3D);
+ } else if (id == ctx->dict.samplerCube) {
+ _update(ctx, e, TYPE_SPECIFIER_SAMPLERCUBE);
+ } else if (id == ctx->dict.sampler1DShadow) {
+ _update(ctx, e, TYPE_SPECIFIER_SAMPLER1DSHADOW);
+ } else if (id == ctx->dict.sampler2DShadow) {
+ _update(ctx, e, TYPE_SPECIFIER_SAMPLER2DSHADOW);
+ } else if (id == ctx->dict.sampler2DRect) {
+ _update(ctx, e, TYPE_SPECIFIER_SAMPLER2DRECT);
+ } else if (id == ctx->dict.sampler2DRectShadow) {
+ _update(ctx, e, TYPE_SPECIFIER_SAMPLER2DRECTSHADOW);
+ } else if (_parse_identifier(ctx, &p) == 0) {
+ _update(ctx, e, TYPE_SPECIFIER_TYPENAME);
+ *ps = p;
+ return 0;
+ } else {
+ return -1;
+ }
+
+ _parse_token(ctx, SL_PP_IDENTIFIER, &p);
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_type_specifier_array(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_token(ctx, SL_PP_LBRACKET, &p)) {
+ return -1;
+ }
+ if (_parse_constant_expression(ctx, &p)) {
+ _error(ctx, "expected constant integral expression");
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_RBRACKET, &p)) {
+ _error(ctx, "expected `]'");
+ return -1;
+ }
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_type_specifier(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+ unsigned int e;
+
+ if (_parse_type_specifier_nonarray(ctx, &p)) {
+ return -1;
+ }
+
+ e = _emit(ctx, &p.out, TYPE_SPECIFIER_ARRAY);
+ if (_parse_type_specifier_array(ctx, &p)) {
+ _update(ctx, e, TYPE_SPECIFIER_NONARRAY);
+ }
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_fully_specified_type(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_invariant_qualifier(ctx, &p)) {
+ _emit(ctx, &p.out, TYPE_VARIANT);
+ }
+ if (_parse_centroid_qualifier(ctx, &p)) {
+ _emit(ctx, &p.out, TYPE_CENTER);
+ }
+ if (_parse_type_qualifier(ctx, &p)) {
+ _emit(ctx, &p.out, TYPE_QUALIFIER_NONE);
+ }
+ if (_parse_precision(ctx, &p)) {
+ _emit(ctx, &p.out, PRECISION_DEFAULT);
+ }
+ if (_parse_type_specifier(ctx, &p)) {
+ return -1;
+ }
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_function_header(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_fully_specified_type(ctx, &p)) {
+ return -1;
+ }
+ if (_parse_function_decl_identifier(ctx, &p)) {
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_LPAREN, &p)) {
+ return -1;
+ }
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_parameter_qualifier(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ unsigned int e = _emit(ctx, &ps->out, PARAM_QUALIFIER_IN);
+
+ if (_parse_id(ctx, ctx->dict.out, ps) == 0) {
+ _update(ctx, e, PARAM_QUALIFIER_OUT);
+ } else if (_parse_id(ctx, ctx->dict.inout, ps) == 0) {
+ _update(ctx, e, PARAM_QUALIFIER_INOUT);
+ } else {
+ _parse_id(ctx, ctx->dict.in, ps);
+ }
+ return 0;
+}
+
+
+static int
+_parse_function_identifier(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p;
+ unsigned int e;
+
+ if (_parse_identifier(ctx, ps)) {
+ return -1;
+ }
+ e = _emit(ctx, &ps->out, FUNCTION_CALL_NONARRAY);
+
+ p = *ps;
+ if (_parse_token(ctx, SL_PP_LBRACKET, &p)) {
+ return 0;
+ }
+ if (_parse_constant_expression(ctx, &p)) {
+ _error(ctx, "expected constant integral expression");
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_RBRACKET, &p)) {
+ _error(ctx, "expected `]'");
+ return -1;
+ }
+ _update(ctx, e, FUNCTION_CALL_ARRAY);
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_function_call_header(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_function_identifier(ctx, &p)) {
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_LPAREN, &p)) {
+ return -1;
+ }
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_assign_expression(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+ unsigned int op;
+
+ if (_parse_unary_expression(ctx, &p)) {
+ return -1;
+ }
+
+ if (_parse_token(ctx, SL_PP_ASSIGN, &p) == 0) {
+ op = OP_ASSIGN;
+ } else if (_parse_token(ctx, SL_PP_MULASSIGN, &p) == 0) {
+ op = OP_MULASSIGN;
+ } else if (_parse_token(ctx, SL_PP_DIVASSIGN, &p) == 0) {
+ op = OP_DIVASSIGN;
+ } else if (_parse_token(ctx, SL_PP_ADDASSIGN, &p) == 0) {
+ op = OP_ADDASSIGN;
+ } else if (_parse_token(ctx, SL_PP_SUBASSIGN, &p) == 0) {
+ op = OP_SUBASSIGN;
+ } else {
+ return -1;
+ }
+
+ if (_parse_assignment_expression(ctx, &p)) {
+ return -1;
+ }
+ _emit(ctx, &p.out, op);
+
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_assignment_expression(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ if (_parse_assign_expression(ctx, ps) == 0) {
+ return 0;
+ }
+
+ if (_parse_conditional_expression(ctx, ps) == 0) {
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int
+_parse_function_call_header_with_parameters(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_function_call_header(ctx, &p)) {
+ return -1;
+ }
+ if (_parse_assignment_expression(ctx, &p)) {
+ return -1;
+ }
+ _emit(ctx, &p.out, OP_END);
+ for (;;) {
+ *ps = p;
+ if (_parse_token(ctx, SL_PP_COMMA, &p)) {
+ return 0;
+ }
+ if (_parse_assignment_expression(ctx, &p)) {
+ return 0;
+ }
+ _emit(ctx, &p.out, OP_END);
+ }
+}
+
+
+static int
+_parse_function_call_header_no_parameters(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ if (_parse_function_call_header(ctx, ps)) {
+ return -1;
+ }
+ _parse_id(ctx, ctx->dict._void, ps);
+ return 0;
+}
+
+
+static int
+_parse_function_call_generic(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_function_call_header_with_parameters(ctx, &p) == 0) {
+ if (_parse_token(ctx, SL_PP_RPAREN, &p) == 0) {
+ *ps = p;
+ return 0;
+ }
+ _error(ctx, "expected `)'");
+ return -1;
+ }
+
+ p = *ps;
+ if (_parse_function_call_header_no_parameters(ctx, &p) == 0) {
+ if (_parse_token(ctx, SL_PP_RPAREN, &p) == 0) {
+ *ps = p;
+ return 0;
+ }
+ _error(ctx, "expected `)'");
+ return -1;
+ }
+
+ return -1;
+}
+
+
+static int
+_parse_method_call(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ _emit(ctx, &p.out, OP_METHOD);
+ if (_parse_identifier(ctx, &p)) {
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_DOT, &p)) {
+ return -1;
+ }
+ if (_parse_function_call_generic(ctx, &p)) {
+ return -1;
+ }
+ _emit(ctx, &p.out, OP_END);
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_regular_function_call(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ _emit(ctx, &p.out, OP_CALL);
+ if (_parse_function_call_generic(ctx, &p)) {
+ return -1;
+ }
+ _emit(ctx, &p.out, OP_END);
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_function_call(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ if (_parse_regular_function_call(ctx, ps) == 0) {
+ return 0;
+ }
+
+ if (_parse_method_call(ctx, ps) == 0) {
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int
+_parse_expression(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_assignment_expression(ctx, &p)) {
+ return -1;
+ }
+
+ for (;;) {
+ *ps = p;
+ if (_parse_token(ctx, SL_PP_COMMA, &p)) {
+ return 0;
+ }
+ if (_parse_assignment_expression(ctx, &p)) {
+ return 0;
+ }
+ _emit(ctx, &p.out, OP_SEQUENCE);
+ }
+}
+
+
+static int
+_parse_postfix_expression(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p;
+
+ if (_parse_function_call(ctx, ps)) {
+ if (_parse_primary_expression(ctx, ps)) {
+ return -1;
+ }
+ }
+
+ for (p = *ps;;) {
+ *ps = p;
+ if (_parse_token(ctx, SL_PP_INCREMENT, &p) == 0) {
+ _emit(ctx, &p.out, OP_POSTINCREMENT);
+ } else if (_parse_token(ctx, SL_PP_DECREMENT, &p) == 0) {
+ _emit(ctx, &p.out, OP_POSTDECREMENT);
+ } else if (_parse_token(ctx, SL_PP_LBRACKET, &p) == 0) {
+ if (_parse_expression(ctx, &p)) {
+ _error(ctx, "expected an integral expression");
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_RBRACKET, &p)) {
+ _error(ctx, "expected `]'");
+ return -1;
+ }
+ _emit(ctx, &p.out, OP_SUBSCRIPT);
+ } else if (_parse_token(ctx, SL_PP_DOT, &p) == 0) {
+ _emit(ctx, &p.out, OP_FIELD);
+ if (_parse_identifier(ctx, &p)) {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ }
+}
+
+
+static int
+_parse_unary_expression(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p;
+ unsigned int op;
+
+ if (_parse_postfix_expression(ctx, ps) == 0) {
+ return 0;
+ }
+
+ p = *ps;
+ if (_parse_token(ctx, SL_PP_INCREMENT, &p) == 0) {
+ op = OP_PREINCREMENT;
+ } else if (_parse_token(ctx, SL_PP_DECREMENT, &p) == 0) {
+ op = OP_PREDECREMENT;
+ } else if (_parse_token(ctx, SL_PP_PLUS, &p) == 0) {
+ op = OP_PLUS;
+ } else if (_parse_token(ctx, SL_PP_MINUS, &p) == 0) {
+ op = OP_MINUS;
+ } else if (_parse_token(ctx, SL_PP_NOT, &p) == 0) {
+ op = OP_NOT;
+ } else {
+ return -1;
+ }
+
+ if (_parse_unary_expression(ctx, &p)) {
+ return -1;
+ }
+ _emit(ctx, &p.out, op);
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_multiplicative_expression(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_unary_expression(ctx, &p)) {
+ return -1;
+ }
+ for (;;) {
+ unsigned int op;
+
+ *ps = p;
+ if (_parse_token(ctx, SL_PP_STAR, &p) == 0) {
+ op = OP_MULTIPLY;
+ } else if (_parse_token(ctx, SL_PP_SLASH, &p) == 0) {
+ op = OP_DIVIDE;
+ } else {
+ return 0;
+ }
+ if (_parse_unary_expression(ctx, &p)) {
+ return 0;
+ }
+ _emit(ctx, &p.out, op);
+ }
+}
+
+
+static int
+_parse_additive_expression(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_multiplicative_expression(ctx, &p)) {
+ return -1;
+ }
+ for (;;) {
+ unsigned int op;
+
+ *ps = p;
+ if (_parse_token(ctx, SL_PP_PLUS, &p) == 0) {
+ op = OP_ADD;
+ } else if (_parse_token(ctx, SL_PP_MINUS, &p) == 0) {
+ op = OP_SUBTRACT;
+ } else {
+ return 0;
+ }
+ if (_parse_multiplicative_expression(ctx, &p)) {
+ return 0;
+ }
+ _emit(ctx, &p.out, op);
+ }
+}
+
+
+static int
+_parse_relational_expression(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_additive_expression(ctx, &p)) {
+ return -1;
+ }
+ for (;;) {
+ unsigned int op;
+
+ *ps = p;
+ if (_parse_token(ctx, SL_PP_LESS, &p) == 0) {
+ op = OP_LESS;
+ } else if (_parse_token(ctx, SL_PP_GREATER, &p) == 0) {
+ op = OP_GREATER;
+ } else if (_parse_token(ctx, SL_PP_LESSEQUAL, &p) == 0) {
+ op = OP_LESSEQUAL;
+ } else if (_parse_token(ctx, SL_PP_GREATEREQUAL, &p) == 0) {
+ op = OP_GREATEREQUAL;
+ } else {
+ return 0;
+ }
+ if (_parse_additive_expression(ctx, &p)) {
+ return 0;
+ }
+ _emit(ctx, &p.out, op);
+ }
+}
+
+
+static int
+_parse_equality_expression(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_relational_expression(ctx, &p)) {
+ return -1;
+ }
+ for (;;) {
+ unsigned int op;
+
+ *ps = p;
+ if (_parse_token(ctx, SL_PP_EQUAL, &p) == 0) {
+ op = OP_EQUAL;
+ } else if (_parse_token(ctx, SL_PP_NOTEQUAL, &p) == 0) {
+ op = OP_NOTEQUAL;
+ } else {
+ return 0;
+ }
+ if (_parse_relational_expression(ctx, &p)) {
+ return -1;
+ }
+ _emit(ctx, &p.out, op);
+ }
+}
+
+
+static int
+_parse_logical_and_expression(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_equality_expression(ctx, &p)) {
+ return -1;
+ }
+ for (;;) {
+ *ps = p;
+ if (_parse_token(ctx, SL_PP_AND, &p)) {
+ return 0;
+ }
+ if (_parse_equality_expression(ctx, &p)) {
+ return 0;
+ }
+ _emit(ctx, &p.out, OP_LOGICALAND);
+ }
+}
+
+
+static int
+_parse_logical_xor_expression(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_logical_and_expression(ctx, &p)) {
+ return -1;
+ }
+ for (;;) {
+ *ps = p;
+ if (_parse_token(ctx, SL_PP_XOR, &p)) {
+ return 0;
+ }
+ if (_parse_logical_and_expression(ctx, &p)) {
+ return 0;
+ }
+ _emit(ctx, &p.out, OP_LOGICALXOR);
+ }
+}
+
+
+static int
+_parse_logical_or_expression(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_logical_xor_expression(ctx, &p)) {
+ return -1;
+ }
+ for (;;) {
+ *ps = p;
+ if (_parse_token(ctx, SL_PP_OR, &p)) {
+ return 0;
+ }
+ if (_parse_logical_xor_expression(ctx, &p)) {
+ return 0;
+ }
+ _emit(ctx, &p.out, OP_LOGICALOR);
+ }
+}
+
+
+static int
+_parse_conditional_expression(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_logical_or_expression(ctx, &p)) {
+ return -1;
+ }
+ for (;;) {
+ *ps = p;
+ if (_parse_token(ctx, SL_PP_QUESTION, &p)) {
+ return 0;
+ }
+ if (_parse_expression(ctx, &p)) {
+ return 0;
+ }
+ if (_parse_token(ctx, SL_PP_COLON, &p)) {
+ return 0;
+ }
+ if (_parse_conditional_expression(ctx, &p)) {
+ return 0;
+ }
+ _emit(ctx, &p.out, OP_SELECT);
+ }
+}
+
+
+static int
+_parse_constant_expression(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ if (_parse_conditional_expression(ctx, ps)) {
+ return -1;
+ }
+ _emit(ctx, &ps->out, OP_END);
+ return 0;
+}
+
+
+static int
+_parse_parameter_declarator_array(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_token(ctx, SL_PP_LBRACKET, &p)) {
+ return -1;
+ }
+ if (_parse_constant_expression(ctx, &p)) {
+ _error(ctx, "expected constant integral expression");
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_RBRACKET, &p)) {
+ _error(ctx, "expected `]'");
+ return -1;
+ }
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_parameter_declarator(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+ unsigned int e;
+
+ if (_parse_type_specifier(ctx, &p)) {
+ return -1;
+ }
+ if (_parse_identifier(ctx, &p)) {
+ return -1;
+ }
+ e = _emit(ctx, &p.out, PARAMETER_ARRAY_PRESENT);
+ if (_parse_parameter_declarator_array(ctx, &p)) {
+ _update(ctx, e, PARAMETER_ARRAY_NOT_PRESENT);
+ }
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_parameter_type_specifier_array(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_token(ctx, SL_PP_LBRACKET, &p)) {
+ return -1;
+ }
+ if (_parse_constant_expression(ctx, &p)) {
+ _error(ctx, "expected constant integral expression");
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_RBRACKET, &p)) {
+ _error(ctx, "expected `]'");
+ return -1;
+ }
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_parameter_type_specifier(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+ unsigned int e;
+
+ if (_parse_type_specifier(ctx, &p)) {
+ return -1;
+ }
+ _emit(ctx, &p.out, '\0');
+
+ e = _emit(ctx, &p.out, PARAMETER_ARRAY_PRESENT);
+ if (_parse_parameter_type_specifier_array(ctx, &p)) {
+ _update(ctx, e, PARAMETER_ARRAY_NOT_PRESENT);
+ }
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_parameter_declaration(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+ unsigned int e = _emit(ctx, &p.out, PARAMETER_NEXT);
+
+ (void) e;
+
+ if (_parse_type_qualifier(ctx, &p)) {
+ _emit(ctx, &p.out, TYPE_QUALIFIER_NONE);
+ }
+ _parse_parameter_qualifier(ctx, &p);
+ if (_parse_precision(ctx, &p)) {
+ _emit(ctx, &p.out, PRECISION_DEFAULT);
+ }
+ if (_parse_parameter_declarator(ctx, &p) == 0) {
+ *ps = p;
+ return 0;
+ }
+ if (_parse_parameter_type_specifier(ctx, &p) == 0) {
+ *ps = p;
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int
+_parse_function_header_with_parameters(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_function_header(ctx, &p)) {
+ return -1;
+ }
+ if (_parse_parameter_declaration(ctx, &p)) {
+ return -1;
+ }
+
+ for (;;) {
+ *ps = p;
+ if (_parse_token(ctx, SL_PP_COMMA, &p)) {
+ return 0;
+ }
+ if (_parse_parameter_declaration(ctx, &p)) {
+ return 0;
+ }
+ }
+}
+
+
+static int
+_parse_function_declarator(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ if (_parse_function_header_with_parameters(ctx, ps) == 0) {
+ return 0;
+ }
+
+ if (_parse_function_header(ctx, ps) == 0) {
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int
+_parse_function_prototype(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_function_header(ctx, &p) == 0) {
+ if (_parse_id(ctx, ctx->dict._void, &p) == 0) {
+ if (_parse_token(ctx, SL_PP_RPAREN, &p) == 0) {
+ _emit(ctx, &p.out, PARAMETER_NONE);
+ *ps = p;
+ return 0;
+ }
+ _error(ctx, "expected `)'");
+ return -1;
+ }
+ }
+
+ p = *ps;
+ if (_parse_function_declarator(ctx, &p) == 0) {
+ if (_parse_token(ctx, SL_PP_RPAREN, &p) == 0) {
+ _emit(ctx, &p.out, PARAMETER_NONE);
+ *ps = p;
+ return 0;
+ }
+ _error(ctx, "expected `)'");
+ return -1;
+ }
+
+ return -1;
+}
+
+
+static int
+_parse_precision(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ int id;
+ unsigned int precision;
+
+ if (ctx->input[ps->in].token != SL_PP_IDENTIFIER) {
+ return -1;
+ }
+ id = ctx->input[ps->in].data.identifier;
+
+ if (id == ctx->dict.lowp) {
+ precision = PRECISION_LOW;
+ } else if (id == ctx->dict.mediump) {
+ precision = PRECISION_MEDIUM;
+ } else if (id == ctx->dict.highp) {
+ precision = PRECISION_HIGH;
+ } else {
+ return -1;
+ }
+
+ _parse_token(ctx, SL_PP_IDENTIFIER, ps);
+ _emit(ctx, &ps->out, precision);
+ return 0;
+}
+
+
+static int
+_parse_prectype(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ int id;
+ unsigned int type;
+
+ if (ctx->input[ps->in].token != SL_PP_IDENTIFIER) {
+ return -1;
+ }
+ id = ctx->input[ps->in].data.identifier;
+
+ if (id == ctx->dict._int) {
+ type = TYPE_SPECIFIER_INT;
+ } else if (id == ctx->dict._float) {
+ type = TYPE_SPECIFIER_FLOAT;
+ } else if (id == ctx->dict.sampler1D) {
+ type = TYPE_SPECIFIER_SAMPLER1D;
+ } else if (id == ctx->dict.sampler2D) {
+ type = TYPE_SPECIFIER_SAMPLER2D;
+ } else if (id == ctx->dict.sampler3D) {
+ type = TYPE_SPECIFIER_SAMPLER3D;
+ } else if (id == ctx->dict.samplerCube) {
+ type = TYPE_SPECIFIER_SAMPLERCUBE;
+ } else if (id == ctx->dict.sampler1DShadow) {
+ type = TYPE_SPECIFIER_SAMPLER1DSHADOW;
+ } else if (id == ctx->dict.sampler2DShadow) {
+ type = TYPE_SPECIFIER_SAMPLER2DSHADOW;
+ } else if (id == ctx->dict.sampler2DRect) {
+ type = TYPE_SPECIFIER_SAMPLER2DRECT;
+ } else if (id == ctx->dict.sampler2DRectShadow) {
+ type = TYPE_SPECIFIER_SAMPLER2DRECTSHADOW;
+ } else {
+ return -1;
+ }
+
+ _parse_token(ctx, SL_PP_IDENTIFIER, ps);
+ _emit(ctx, &ps->out, type);
+ return 0;
+}
+
+
+static int
+_parse_precision_stmt(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_id(ctx, ctx->dict.precision, &p)) {
+ return -1;
+ }
+ if (_parse_precision(ctx, &p)) {
+ return -1;
+ }
+ if (_parse_prectype(ctx, &p)) {
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_SEMICOLON, &p)) {
+ return -1;
+ }
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_floatconstant(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ _emit(ctx, &p.out, OP_PUSH_FLOAT);
+ if (_parse_float(ctx, &p)) {
+ return -1;
+ }
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_intconstant(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ _emit(ctx, &p.out, OP_PUSH_INT);
+ if (_parse_uint(ctx, &p)) {
+ return -1;
+ }
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_boolconstant(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ if (_parse_id(ctx, ctx->dict._false, ps) == 0) {
+ _emit(ctx, &ps->out, OP_PUSH_BOOL);
+ _emit(ctx, &ps->out, 2); /* radix */
+ _emit(ctx, &ps->out, '0');
+ _emit(ctx, &ps->out, '\0');
+ return 0;
+ }
+
+ if (_parse_id(ctx, ctx->dict._true, ps) == 0) {
+ _emit(ctx, &ps->out, OP_PUSH_BOOL);
+ _emit(ctx, &ps->out, 2); /* radix */
+ _emit(ctx, &ps->out, '1');
+ _emit(ctx, &ps->out, '\0');
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int
+_parse_variable_identifier(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ _emit(ctx, &p.out, OP_PUSH_IDENTIFIER);
+ if (_parse_identifier(ctx, &p)) {
+ return -1;
+ }
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_primary_expression(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p;
+
+ if (_parse_floatconstant(ctx, ps) == 0) {
+ return 0;
+ }
+ if (_parse_boolconstant(ctx, ps) == 0) {
+ return 0;
+ }
+ if (_parse_intconstant(ctx, ps) == 0) {
+ return 0;
+ }
+ if (_parse_variable_identifier(ctx, ps) == 0) {
+ return 0;
+ }
+
+ p = *ps;
+ if (_parse_token(ctx, SL_PP_LPAREN, &p)) {
+ return -1;
+ }
+ if (_parse_expression(ctx, &p)) {
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_RPAREN, &p)) {
+ return -1;
+ }
+
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_asm_argument(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ if (_parse_variable_identifier(ctx, ps) == 0) {
+ struct parse_state p = *ps;
+
+ if (_parse_token(ctx, SL_PP_DOT, &p)) {
+ return 0;
+ }
+ _emit(ctx, &p.out, OP_FIELD);
+ if (_parse_identifier(ctx, &p)) {
+ return 0;
+ }
+ *ps = p;
+ return 0;
+ }
+
+ if (_parse_floatconstant(ctx, ps) == 0) {
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int
+_parse_asm_arguments(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_asm_argument(ctx, &p)) {
+ return -1;
+ }
+ _emit(ctx, &p.out, OP_END);
+
+ for (;;) {
+ *ps = p;
+ if (_parse_token(ctx, SL_PP_COMMA, &p)) {
+ return 0;
+ }
+ if (_parse_asm_argument(ctx, &p)) {
+ return 0;
+ }
+ _emit(ctx, &p.out, OP_END);
+ }
+}
+
+
+static int
+_parse_asm_statement(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_id(ctx, ctx->dict.___asm, &p)) {
+ return -1;
+ }
+ if (_parse_identifier(ctx, &p)) {
+ return -1;
+ }
+ if (_parse_asm_arguments(ctx, &p)) {
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_SEMICOLON, &p)) {
+ return -1;
+ }
+ _emit(ctx, &p.out, OP_END);
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_selection_statement(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ _emit(ctx, &p.out, OP_IF);
+ if (_parse_id(ctx, ctx->dict._if, &p)) {
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_LPAREN, &p)) {
+ _error(ctx, "expected `('");
+ return -1;
+ }
+ if (_parse_expression(ctx, &p)) {
+ _error(ctx, "expected an expression");
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_RPAREN, &p)) {
+ _error(ctx, "expected `)'");
+ return -1;
+ }
+ _emit(ctx, &p.out, OP_END);
+ if (_parse_statement(ctx, &p)) {
+ return -1;
+ }
+
+ *ps = p;
+ if (_parse_id(ctx, ctx->dict._else, &p) == 0) {
+ if (_parse_statement(ctx, &p) == 0) {
+ *ps = p;
+ return 0;
+ }
+ }
+
+ _emit(ctx, &ps->out, OP_EXPRESSION);
+ _emit(ctx, &ps->out, OP_PUSH_VOID);
+ _emit(ctx, &ps->out, OP_END);
+ return 0;
+}
+
+
+static int
+_parse_expression_statement(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_expression(ctx, &p)) {
+ _emit(ctx, &p.out, OP_PUSH_VOID);
+ }
+ if (_parse_token(ctx, SL_PP_SEMICOLON, &p)) {
+ return -1;
+ }
+ _emit(ctx, &p.out, OP_END);
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_for_init_statement(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+ unsigned int e = _emit(ctx, &p.out, OP_EXPRESSION);
+
+ if (_parse_expression_statement(ctx, &p) == 0) {
+ *ps = p;
+ return 0;
+ }
+
+ if (_parse_declaration(ctx, &p) == 0) {
+ _update(ctx, e, OP_DECLARE);
+ *ps = p;
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int
+_parse_initializer(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ if (_parse_assignment_expression(ctx, ps) == 0) {
+ _emit(ctx, &ps->out, OP_END);
+ return 0;
+ }
+ return -1;
+}
+
+
+static int
+_parse_condition_initializer(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ _emit(ctx, &p.out, OP_DECLARE);
+ _emit(ctx, &p.out, DECLARATION_INIT_DECLARATOR_LIST);
+ if (_parse_fully_specified_type(ctx, &p)) {
+ return -1;
+ }
+ _emit(ctx, &p.out, VARIABLE_IDENTIFIER);
+ if (_parse_identifier(ctx, &p)) {
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_ASSIGN, &p)) {
+ _error(ctx, "expected `='");
+ return -1;
+ }
+ _emit(ctx, &p.out, VARIABLE_INITIALIZER);
+ if (_parse_initializer(ctx, &p)) {
+ _error(ctx, "expected an initialiser");
+ return -1;
+ }
+ _emit(ctx, &p.out, DECLARATOR_NONE);
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_condition(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p;
+
+ if (_parse_condition_initializer(ctx, ps) == 0) {
+ return 0;
+ }
+
+ p = *ps;
+ _emit(ctx, &p.out, OP_EXPRESSION);
+ if (_parse_expression(ctx, &p) == 0) {
+ _emit(ctx, &p.out, OP_END);
+ *ps = p;
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int
+_parse_for_rest_statement(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_condition(ctx, &p)) {
+ _emit(ctx, &p.out, OP_EXPRESSION);
+ _emit(ctx, &p.out, OP_PUSH_BOOL);
+ _emit(ctx, &p.out, 2);
+ _emit(ctx, &p.out, '1');
+ _emit(ctx, &p.out, '\0');
+ _emit(ctx, &p.out, OP_END);
+ }
+ if (_parse_token(ctx, SL_PP_SEMICOLON, &p)) {
+ return -1;
+ }
+ if (_parse_expression(ctx, &p)) {
+ _emit(ctx, &p.out, OP_PUSH_VOID);
+ }
+ _emit(ctx, &p.out, OP_END);
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_iteration_statement(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_id(ctx, ctx->dict._while, &p) == 0) {
+ _emit(ctx, &p.out, OP_WHILE);
+ if (_parse_token(ctx, SL_PP_LPAREN, &p)) {
+ _error(ctx, "expected `('");
+ return -1;
+ }
+ if (_parse_condition(ctx, &p)) {
+ _error(ctx, "expected an expression");
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_RPAREN, &p)) {
+ _error(ctx, "expected `)'");
+ return -1;
+ }
+ if (_parse_statement(ctx, &p)) {
+ return -1;
+ }
+ *ps = p;
+ return 0;
+ }
+
+ if (_parse_id(ctx, ctx->dict._do, &p) == 0) {
+ _emit(ctx, &p.out, OP_DO);
+ if (_parse_statement(ctx, &p)) {
+ return -1;
+ }
+ if (_parse_id(ctx, ctx->dict._while, &p)) {
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_LPAREN, &p)) {
+ _error(ctx, "expected `('");
+ return -1;
+ }
+ if (_parse_expression(ctx, &p)) {
+ _error(ctx, "expected an expression");
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_RPAREN, &p)) {
+ _error(ctx, "expected `)'");
+ return -1;
+ }
+ _emit(ctx, &p.out, OP_END);
+ if (_parse_token(ctx, SL_PP_SEMICOLON, &p)) {
+ _error(ctx, "expected `;'");
+ return -1;
+ }
+ *ps = p;
+ return 0;
+ }
+
+ if (_parse_id(ctx, ctx->dict._for, &p) == 0) {
+ _emit(ctx, &p.out, OP_FOR);
+ if (_parse_token(ctx, SL_PP_LPAREN, &p)) {
+ _error(ctx, "expected `('");
+ return -1;
+ }
+ if (_parse_for_init_statement(ctx, &p)) {
+ return -1;
+ }
+ if (_parse_for_rest_statement(ctx, &p)) {
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_RPAREN, &p)) {
+ _error(ctx, "expected `)'");
+ return -1;
+ }
+ if (_parse_statement(ctx, &p)) {
+ return -1;
+ }
+ *ps = p;
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int
+_parse_jump_statement(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+ unsigned int e = _emit(ctx, &p.out, 0);
+
+ if (_parse_id(ctx, ctx->dict._continue, &p) == 0) {
+ _update(ctx, e, OP_CONTINUE);
+ } else if (_parse_id(ctx, ctx->dict._break, &p) == 0) {
+ _update(ctx, e, OP_BREAK);
+ } else if (_parse_id(ctx, ctx->dict._return, &p) == 0) {
+ _update(ctx, e, OP_RETURN);
+ if (_parse_expression(ctx, &p)) {
+ _emit(ctx, &p.out, OP_PUSH_VOID);
+ }
+ _emit(ctx, &p.out, OP_END);
+ } else if (ctx->shader_type == 1 && _parse_id(ctx, ctx->dict.discard, &p) == 0) {
+ _update(ctx, e, OP_DISCARD);
+ } else {
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_SEMICOLON, &p)) {
+ return -1;
+ }
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_simple_statement(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p;
+ unsigned int e;
+
+ if (_parse_selection_statement(ctx, ps) == 0) {
+ return 0;
+ }
+
+ if (_parse_iteration_statement(ctx, ps) == 0) {
+ return 0;
+ }
+
+ if (_parse_jump_statement(ctx, ps) == 0) {
+ return 0;
+ }
+
+ p = *ps;
+ e = _emit(ctx, &p.out, OP_EXPRESSION);
+ if (_parse_expression_statement(ctx, &p) == 0) {
+ *ps = p;
+ return 0;
+ }
+
+ if (_parse_precision_stmt(ctx, &p) == 0) {
+ _update(ctx, e, OP_PRECISION);
+ *ps = p;
+ return 0;
+ }
+
+ if (ctx->parsing_builtin && _parse_asm_statement(ctx, &p) == 0) {
+ _update(ctx, e, OP_ASM);
+ *ps = p;
+ return 0;
+ }
+
+ if (_parse_declaration(ctx, &p) == 0) {
+ _update(ctx, e, OP_DECLARE);
+ *ps = p;
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int
+_parse_compound_statement(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_token(ctx, SL_PP_LBRACE, &p)) {
+ return -1;
+ }
+ _emit(ctx, &p.out, OP_BLOCK_BEGIN_NEW_SCOPE);
+ _parse_statement_list(ctx, &p);
+ if (_parse_token(ctx, SL_PP_RBRACE, &p)) {
+ return -1;
+ }
+ _emit(ctx, &p.out, OP_END);
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_statement(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ if (_parse_compound_statement(ctx, ps) == 0) {
+ return 0;
+ }
+
+ if (_parse_simple_statement(ctx, ps) == 0) {
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int
+_parse_statement_list(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_statement(ctx, &p)) {
+ return -1;
+ }
+
+ for (;;) {
+ *ps = p;
+ if (_parse_statement(ctx, &p)) {
+ return 0;
+ }
+ }
+}
+
+
+static int
+_parse_compound_statement_no_new_scope(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_token(ctx, SL_PP_LBRACE, &p)) {
+ return -1;
+ }
+ _emit(ctx, &p.out, OP_BLOCK_BEGIN_NO_NEW_SCOPE);
+ _parse_statement_list(ctx, &p);
+ if (_parse_token(ctx, SL_PP_RBRACE, &p)) {
+ return -1;
+ }
+ _emit(ctx, &p.out, OP_END);
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_function_definition(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_function_prototype(ctx, &p)) {
+ return -1;
+ }
+ if (_parse_compound_statement_no_new_scope(ctx, &p)) {
+ return -1;
+ }
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_invariant_stmt(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_id(ctx, ctx->dict.invariant, &p)) {
+ return -1;
+ }
+ if (_parse_identifier(ctx, &p)) {
+ return -1;
+ }
+ if (_parse_token(ctx, SL_PP_SEMICOLON, &p)) {
+ return -1;
+ }
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_single_declaration(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+ unsigned int e;
+
+ if (_parse_fully_specified_type(ctx, &p)) {
+ return -1;
+ }
+
+ e = _emit(ctx, &p.out, VARIABLE_IDENTIFIER);
+ if (_parse_identifier(ctx, &p)) {
+ _update(ctx, e, VARIABLE_NONE);
+ *ps = p;
+ return 0;
+ }
+
+ e = _emit(ctx, &p.out, VARIABLE_NONE);
+ *ps = p;
+
+ if (_parse_token(ctx, SL_PP_ASSIGN, &p) == 0) {
+ _update(ctx, e, VARIABLE_INITIALIZER);
+ if (_parse_initializer(ctx, &p) == 0) {
+ *ps = p;
+ return 0;
+ }
+ _error(ctx, "expected an initialiser");
+ return -1;
+ }
+ p = *ps;
+
+ if (_parse_token(ctx, SL_PP_LBRACKET, &p) == 0) {
+ if (_parse_constant_expression(ctx, &p)) {
+ _update(ctx, e, VARIABLE_ARRAY_UNKNOWN);
+ } else {
+ _update(ctx, e, VARIABLE_ARRAY_EXPLICIT);
+ }
+ if (_parse_token(ctx, SL_PP_RBRACKET, &p) == 0) {
+ *ps = p;
+ return 0;
+ }
+ _error(ctx, "expected `]'");
+ return -1;
+ }
+ return 0;
+}
+
+
+static int
+_parse_init_declarator_list(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+
+ if (_parse_single_declaration(ctx, &p)) {
+ return -1;
+ }
+
+ for (;;) {
+ unsigned int e;
+
+ *ps = p;
+ if (_parse_token(ctx, SL_PP_COMMA, &p)) {
+ break;
+ }
+ _emit(ctx, &p.out, DECLARATOR_NEXT);
+ _emit(ctx, &p.out, VARIABLE_IDENTIFIER);
+ if (_parse_identifier(ctx, &p)) {
+ break;
+ }
+
+ e = _emit(ctx, &p.out, VARIABLE_NONE);
+ *ps = p;
+
+ if (_parse_token(ctx, SL_PP_ASSIGN, &p) == 0) {
+ if (_parse_initializer(ctx, &p) == 0) {
+ _update(ctx, e, VARIABLE_INITIALIZER);
+ *ps = p;
+ continue;
+ }
+ _error(ctx, "expected an initialiser");
+ break;
+ }
+ p = *ps;
+
+ if (_parse_token(ctx, SL_PP_LBRACKET, &p) == 0) {
+ unsigned int arr;
+
+ if (_parse_constant_expression(ctx, &p)) {
+ arr = VARIABLE_ARRAY_UNKNOWN;
+ } else {
+ arr = VARIABLE_ARRAY_EXPLICIT;
+ }
+ if (_parse_token(ctx, SL_PP_RBRACKET, &p) == 0) {
+ _update(ctx, e, arr);
+ *ps = p;
+ continue;
+ }
+ _error(ctx, "expected `]'");
+ break;
+ }
+ p = *ps;
+ }
+
+ _emit(ctx, &ps->out, DECLARATOR_NONE);
+ return 0;
+}
+
+
+static int
+_parse_declaration(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+ unsigned int e = _emit(ctx, &p.out, DECLARATION_FUNCTION_PROTOTYPE);
+
+ if (_parse_function_prototype(ctx, &p)) {
+ if (_parse_init_declarator_list(ctx, &p)) {
+ return -1;
+ }
+ _update(ctx, e, DECLARATION_INIT_DECLARATOR_LIST);
+ }
+ if (_parse_token(ctx, SL_PP_SEMICOLON, &p)) {
+ _error(ctx, "expected `;'");
+ return -1;
+ }
+ *ps = p;
+ return 0;
+}
+
+
+static int
+_parse_external_declaration(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ struct parse_state p = *ps;
+ unsigned int e = _emit(ctx, &p.out, 0);
+
+ if (_parse_precision_stmt(ctx, &p) == 0) {
+ _update(ctx, e, DEFAULT_PRECISION);
+ *ps = p;
+ return 0;
+ }
+
+ if (_parse_function_definition(ctx, &p) == 0) {
+ _update(ctx, e, EXTERNAL_FUNCTION_DEFINITION);
+ *ps = p;
+ return 0;
+ }
+
+ if (_parse_invariant_stmt(ctx, &p) == 0) {
+ _update(ctx, e, INVARIANT_STMT);
+ *ps = p;
+ return 0;
+ }
+
+ if (_parse_declaration(ctx, &p) == 0) {
+ _update(ctx, e, EXTERNAL_DECLARATION);
+ *ps = p;
+ return 0;
+ }
+
+ _error(ctx, "expected an identifier");
+ return -1;
+}
+
+
+static int
+_parse_translation_unit(struct parse_context *ctx,
+ struct parse_state *ps)
+{
+ _emit(ctx, &ps->out, REVISION);
+ if (_parse_external_declaration(ctx, ps)) {
+ return -1;
+ }
+ while (_parse_external_declaration(ctx, ps) == 0) {
+ }
+ _emit(ctx, &ps->out, EXTERNAL_NULL);
+ if (_parse_token(ctx, SL_PP_EOF, ps)) {
+ return -1;
+ }
+ return 0;
+}
+
+
+#define ADD_NAME_STR(CTX, NAME, STR)\
+ do {\
+ (CTX).dict.NAME = sl_pp_context_add_unique_str((CTX).context, (STR));\
+ if ((CTX).dict.NAME == -1) {\
+ return -1;\
+ }\
+ } while (0)
+
+#define ADD_NAME(CTX, NAME) ADD_NAME_STR(CTX, NAME, #NAME)
+
+
+int
+sl_cl_compile(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int shader_type,
+ unsigned int parsing_builtin,
+ unsigned char **output,
+ unsigned int *cboutput,
+ char *error,
+ unsigned int cberror)
+{
+ struct parse_context ctx;
+ struct parse_state ps;
+
+ ctx.context = context;
+ ctx.input = input;
+
+ ADD_NAME_STR(ctx, _void, "void");
+ ADD_NAME_STR(ctx, _float, "float");
+ ADD_NAME_STR(ctx, _int, "int");
+ ADD_NAME_STR(ctx, _bool, "bool");
+ ADD_NAME(ctx, vec2);
+ ADD_NAME(ctx, vec3);
+ ADD_NAME(ctx, vec4);
+ ADD_NAME(ctx, bvec2);
+ ADD_NAME(ctx, bvec3);
+ ADD_NAME(ctx, bvec4);
+ ADD_NAME(ctx, ivec2);
+ ADD_NAME(ctx, ivec3);
+ ADD_NAME(ctx, ivec4);
+ ADD_NAME(ctx, mat2);
+ ADD_NAME(ctx, mat3);
+ ADD_NAME(ctx, mat4);
+ ADD_NAME(ctx, mat2x3);
+ ADD_NAME(ctx, mat3x2);
+ ADD_NAME(ctx, mat2x4);
+ ADD_NAME(ctx, mat4x2);
+ ADD_NAME(ctx, mat3x4);
+ ADD_NAME(ctx, mat4x3);
+ ADD_NAME(ctx, sampler1D);
+ ADD_NAME(ctx, sampler2D);
+ ADD_NAME(ctx, sampler3D);
+ ADD_NAME(ctx, samplerCube);
+ ADD_NAME(ctx, sampler1DShadow);
+ ADD_NAME(ctx, sampler2DShadow);
+ ADD_NAME(ctx, sampler2DRect);
+ ADD_NAME(ctx, sampler2DRectShadow);
+
+ ADD_NAME(ctx, invariant);
+
+ ADD_NAME(ctx, centroid);
+
+ ADD_NAME(ctx, precision);
+ ADD_NAME(ctx, lowp);
+ ADD_NAME(ctx, mediump);
+ ADD_NAME(ctx, highp);
+
+ ADD_NAME_STR(ctx, _const, "const");
+ ADD_NAME(ctx, attribute);
+ ADD_NAME(ctx, varying);
+ ADD_NAME(ctx, uniform);
+ ADD_NAME(ctx, __fixed_output);
+ ADD_NAME(ctx, __fixed_input);
+
+ ADD_NAME(ctx, in);
+ ADD_NAME(ctx, out);
+ ADD_NAME(ctx, inout);
+
+ ADD_NAME_STR(ctx, _struct, "struct");
+
+ ADD_NAME(ctx, __constructor);
+ ADD_NAME(ctx, __operator);
+ ADD_NAME_STR(ctx, ___asm, "__asm");
+
+ ADD_NAME_STR(ctx, _if, "if");
+ ADD_NAME_STR(ctx, _else, "else");
+ ADD_NAME_STR(ctx, _for, "for");
+ ADD_NAME_STR(ctx, _while, "while");
+ ADD_NAME_STR(ctx, _do, "do");
+
+ ADD_NAME_STR(ctx, _continue, "continue");
+ ADD_NAME_STR(ctx, _break, "break");
+ ADD_NAME_STR(ctx, _return, "return");
+ ADD_NAME(ctx, discard);
+
+ ADD_NAME_STR(ctx, _false, "false");
+ ADD_NAME_STR(ctx, _true, "true");
+
+ ctx.out_buf = NULL;
+ ctx.out_cap = 0;
+
+ ctx.shader_type = shader_type;
+ ctx.parsing_builtin = 1;
+
+ ctx.error[0] = '\0';
+
+ ps.in = 0;
+ ps.out = 0;
+
+ if (_parse_translation_unit(&ctx, &ps)) {
+ strncpy(error, ctx.error, cberror);
+ return -1;
+ }
+
+ *output = ctx.out_buf;
+ *cboutput = ps.out;
+ return 0;
+}
diff --git a/src/glsl/cl/sl_cl_parse.h b/src/glsl/cl/sl_cl_parse.h
new file mode 100644
index 0000000000..23a0d5fee0
--- /dev/null
+++ b/src/glsl/cl/sl_cl_parse.h
@@ -0,0 +1,41 @@
+/**************************************************************************
+ *
+ * Copyright 2009 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef SL_CL_PARSE_H
+#define SL_CL_PARSE_H
+
+int
+sl_cl_compile(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int shader_type,
+ unsigned int parsing_builtin,
+ unsigned char **output,
+ unsigned int *cboutput,
+ char *error,
+ unsigned int cberror);
+
+#endif /* SL_CL_PARSE_H */
diff --git a/src/glsl/pp/Makefile b/src/glsl/pp/Makefile
new file mode 100644
index 0000000000..819079f625
--- /dev/null
+++ b/src/glsl/pp/Makefile
@@ -0,0 +1,26 @@
+#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_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 0000000000..afc1b84d16
--- /dev/null
+++ b/src/glsl/pp/sl_pp_context.c
@@ -0,0 +1,155 @@
+/**************************************************************************
+ *
+ * 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(void)
+{
+ 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 = malloc(64 * sizeof(char));
+ if (!context->getc_buf) {
+ 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->line = 1;
+ context->file = 0;
+
+ 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);
+ free(context);
+ }
+}
+
+const char *
+sl_pp_context_error_message(const struct sl_pp_context *context)
+{
+ return context->error_msg;
+}
+
+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 0000000000..d95d29e275
--- /dev/null
+++ b/src/glsl/pp/sl_pp_context.h
@@ -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.
+ *
+ **************************************************************************/
+
+#ifndef SL_PP_CONTEXT_H
+#define SL_PP_CONTEXT_H
+
+#include "sl_pp_dict.h"
+#include "sl_pp_macro.h"
+#include "sl_pp_purify.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 line;
+ unsigned int file;
+
+ struct sl_pp_purify_state pure;
+
+ char *getc_buf;
+ unsigned int getc_buf_size;
+ unsigned int getc_buf_capacity;
+};
+
+#endif /* SL_PP_CONTEXT_H */
diff --git a/src/glsl/pp/sl_pp_define.c b/src/glsl/pp/sl_pp_define.c
new file mode 100644
index 0000000000..e004c9f95b
--- /dev/null
+++ b/src/glsl/pp/sl_pp_define.c
@@ -0,0 +1,237 @@
+/**************************************************************************
+ *
+ * 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_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 0000000000..062139e6ac
--- /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 0000000000..875217bd30
--- /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 0000000000..a9eeff98ba
--- /dev/null
+++ b/src/glsl/pp/sl_pp_error.c
@@ -0,0 +1,269 @@
+/**************************************************************************
+ *
+ * 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_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 0000000000..ec904787dd
--- /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 0000000000..377d5b4cbd
--- /dev/null
+++ b/src/glsl/pp/sl_pp_expression.h
@@ -0,0 +1,40 @@
+/**************************************************************************
+ *
+ * Copyright 2009 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef SL_PP_EXPRESSION_H
+#define SL_PP_EXPRESSION_H
+
+#include "sl_pp_context.h"
+#include "sl_pp_token.h"
+
+
+int
+sl_pp_execute_expression(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ int *result);
+
+#endif /* SL_PP_EXPRESSION_H */
diff --git a/src/glsl/pp/sl_pp_extension.c b/src/glsl/pp/sl_pp_extension.c
new file mode 100644
index 0000000000..67b24404d4
--- /dev/null
+++ b/src/glsl/pp/sl_pp_extension.c
@@ -0,0 +1,170 @@
+/**************************************************************************
+ *
+ * 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_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 0000000000..6610bc69f3
--- /dev/null
+++ b/src/glsl/pp/sl_pp_if.c
@@ -0,0 +1,349 @@
+/**************************************************************************
+ *
+ * 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 void
+skip_whitespace(const struct sl_pp_token_info *input,
+ unsigned int *pi)
+{
+ while (input[*pi].token == SL_PP_WHITESPACE) {
+ (*pi)++;
+ }
+}
+
+static int
+_parse_defined(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int *pi,
+ struct sl_pp_process_state *state)
+{
+ int parens = 0;
+ int macro_name;
+ struct sl_pp_macro *macro;
+ int defined = 0;
+ struct sl_pp_token_info result;
+
+ skip_whitespace(input, pi);
+ if (input[*pi].token == SL_PP_LPAREN) {
+ (*pi)++;
+ skip_whitespace(input, pi);
+ parens = 1;
+ }
+
+ if (input[*pi].token != SL_PP_IDENTIFIER) {
+ strcpy(context->error_msg, "expected an identifier");
+ return -1;
+ }
+
+ macro_name = input[*pi].data.identifier;
+ for (macro = context->macro; macro; macro = macro->next) {
+ if (macro->name == macro_name) {
+ defined = 1;
+ break;
+ }
+ }
+ (*pi)++;
+
+ if (parens) {
+ skip_whitespace(input, pi);
+ if (input[*pi].token != SL_PP_RPAREN) {
+ strcpy(context->error_msg, "expected `)'");
+ return -1;
+ }
+ (*pi)++;
+ }
+
+ result.token = SL_PP_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,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last)
+{
+ unsigned int i;
+ struct sl_pp_process_state state;
+ struct sl_pp_token_info eof;
+ int result;
+
+ if (!context->if_ptr) {
+ strcpy(context->error_msg, "`#if' nesting too deep");
+ return -1;
+ }
+
+ memset(&state, 0, sizeof(state));
+ for (i = first; i < last;) {
+ switch (input[i].token) {
+ case SL_PP_WHITESPACE:
+ i++;
+ break;
+
+ case SL_PP_IDENTIFIER:
+ if (input[i].data.identifier == context->dict.defined) {
+ i++;
+ if (_parse_defined(context, input, &i, &state)) {
+ free(state.out);
+ return -1;
+ }
+ } else {
+ if (sl_pp_macro_expand(context, input, &i, NULL, &state, sl_pp_macro_expand_unknown_to_0)) {
+ free(state.out);
+ return -1;
+ }
+ }
+ break;
+
+ default:
+ if (sl_pp_process_out(&state, &input[i])) {
+ strcpy(context->error_msg, "out of memory");
+ free(state.out);
+ return -1;
+ }
+ i++;
+ }
+ }
+
+ eof.token = SL_PP_EOF;
+ if (sl_pp_process_out(&state, &eof)) {
+ strcpy(context->error_msg, "out of memory");
+ free(state.out);
+ return -1;
+ }
+
+ if (sl_pp_execute_expression(context, state.out, &result)) {
+ free(state.out);
+ return -1;
+ }
+
+ free(state.out);
+
+ context->if_ptr--;
+ context->if_stack[context->if_ptr] = result ? 1 : 0;
+ context->if_value = _evaluate_if_stack(context);
+
+ return 0;
+}
+
+static int
+_parse_else(struct sl_pp_context *context)
+{
+ if (context->if_ptr == SL_PP_MAX_IF_NESTING) {
+ strcpy(context->error_msg, "no matching `#if'");
+ return -1;
+ }
+
+ /* Bit b1 indicates we already went through #else. */
+ if (context->if_stack[context->if_ptr] & 2) {
+ strcpy(context->error_msg, "no matching `#if'");
+ return -1;
+ }
+
+ /* Invert current condition value and mark that we are in the #else block. */
+ context->if_stack[context->if_ptr] = (1 - (context->if_stack[context->if_ptr] & 1)) | 2;
+ context->if_value = _evaluate_if_stack(context);
+
+ return 0;
+}
+
+int
+sl_pp_process_if(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last)
+{
+ return _parse_if(context, input, first, last);
+}
+
+int
+sl_pp_process_ifdef(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last)
+{
+ unsigned int i;
+
+ if (!context->if_ptr) {
+ strcpy(context->error_msg, "`#if' nesting too deep");
+ return -1;
+ }
+
+ for (i = first; i < last; i++) {
+ switch (input[i].token) {
+ case SL_PP_IDENTIFIER:
+ {
+ struct sl_pp_macro *macro;
+ int macro_name = input[i].data.identifier;
+ int defined = 0;
+
+ for (macro = context->macro; macro; macro = macro->next) {
+ if (macro->name == macro_name) {
+ defined = 1;
+ break;
+ }
+ }
+
+ context->if_ptr--;
+ context->if_stack[context->if_ptr] = defined ? 1 : 0;
+ context->if_value = _evaluate_if_stack(context);
+ }
+ return 0;
+
+ case SL_PP_WHITESPACE:
+ break;
+
+ default:
+ strcpy(context->error_msg, "expected an identifier");
+ return -1;
+ }
+ }
+
+ strcpy(context->error_msg, "expected an identifier");
+ return -1;
+}
+
+int
+sl_pp_process_ifndef(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last)
+{
+ unsigned int i;
+
+ if (!context->if_ptr) {
+ strcpy(context->error_msg, "`#if' nesting too deep");
+ return -1;
+ }
+
+ for (i = first; i < last; i++) {
+ switch (input[i].token) {
+ case SL_PP_IDENTIFIER:
+ {
+ struct sl_pp_macro *macro;
+ int macro_name = input[i].data.identifier;
+ int defined = 0;
+
+ for (macro = context->macro; macro; macro = macro->next) {
+ if (macro->name == macro_name) {
+ defined = 1;
+ break;
+ }
+ }
+
+ context->if_ptr--;
+ context->if_stack[context->if_ptr] = defined ? 0 : 1;
+ context->if_value = _evaluate_if_stack(context);
+ }
+ return 0;
+
+ case SL_PP_WHITESPACE:
+ break;
+
+ default:
+ strcpy(context->error_msg, "expected an identifier");
+ return -1;
+ }
+ }
+
+ strcpy(context->error_msg, "expected an identifier");
+ return -1;
+}
+
+int
+sl_pp_process_elif(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last)
+{
+ if (_parse_else(context)) {
+ return -1;
+ }
+
+ if (context->if_stack[context->if_ptr] & 1) {
+ context->if_ptr++;
+ if (_parse_if(context, input, first, last)) {
+ return -1;
+ }
+ }
+
+ /* We are still in the #if block. */
+ context->if_stack[context->if_ptr] = context->if_stack[context->if_ptr] & ~2;
+
+ return 0;
+}
+
+int
+sl_pp_process_else(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last)
+{
+ return _parse_else(context);
+}
+
+int
+sl_pp_process_endif(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last)
+{
+ if (context->if_ptr == SL_PP_MAX_IF_NESTING) {
+ strcpy(context->error_msg, "no matching `#if'");
+ return -1;
+ }
+
+ context->if_ptr++;
+ context->if_value = _evaluate_if_stack(context);
+
+ return 0;
+}
diff --git a/src/glsl/pp/sl_pp_line.c b/src/glsl/pp/sl_pp_line.c
new file mode 100644
index 0000000000..ed5acc697c
--- /dev/null
+++ b/src/glsl/pp/sl_pp_line.c
@@ -0,0 +1,121 @@
+/**************************************************************************
+ *
+ * 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_process.h"
+
+
+int
+sl_pp_process_line(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last,
+ struct sl_pp_process_state *pstate)
+{
+ unsigned int i;
+ struct sl_pp_process_state state;
+ int line_number = -1;
+ int file_number = -1;
+ unsigned int line;
+ unsigned int file;
+
+ memset(&state, 0, sizeof(state));
+ for (i = first; i < last;) {
+ switch (input[i].token) {
+ case SL_PP_WHITESPACE:
+ i++;
+ break;
+
+ case SL_PP_IDENTIFIER:
+ if (sl_pp_macro_expand(context, input, &i, NULL, &state, sl_pp_macro_expand_normal)) {
+ free(state.out);
+ return -1;
+ }
+ break;
+
+ default:
+ if (sl_pp_process_out(&state, &input[i])) {
+ strcpy(context->error_msg, "out of memory");
+ free(state.out);
+ return -1;
+ }
+ i++;
+ }
+ }
+
+ if (state.out_len > 0 && state.out[0].token == SL_PP_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 0000000000..08b44c7cbe
--- /dev/null
+++ b/src/glsl/pp/sl_pp_macro.c
@@ -0,0 +1,397 @@
+/**************************************************************************
+ *
+ * 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_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 void
+skip_whitespace(const struct sl_pp_token_info *input,
+ unsigned int *pi)
+{
+ while (input[*pi].token == SL_PP_WHITESPACE) {
+ (*pi)++;
+ }
+}
+
+static int
+_out_number(struct sl_pp_context *context,
+ struct sl_pp_process_state *state,
+ unsigned int number)
+{
+ char buf[32];
+ struct sl_pp_token_info ti;
+
+ sprintf(buf, "%u", number);
+
+ ti.token = SL_PP_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,
+ const struct sl_pp_token_info *input,
+ unsigned int *pi,
+ 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);
+ int macro_name;
+ struct sl_pp_macro *macro = NULL;
+ struct sl_pp_macro *actual_arg = NULL;
+ unsigned int j;
+
+ if (input[*pi].token != SL_PP_IDENTIFIER) {
+ strcpy(context->error_msg, "expected an identifier");
+ return -1;
+ }
+
+ macro_name = input[*pi].data.identifier;
+
+ /* First look for predefined macros.
+ */
+
+ if (macro_name == context->dict.___LINE__) {
+ if (!mute && _out_number(context, state, context->line)) {
+ return -1;
+ }
+ (*pi)++;
+ return 0;
+ }
+ if (macro_name == context->dict.___FILE__) {
+ if (!mute && _out_number(context, state, context->file)) {
+ return -1;
+ }
+ (*pi)++;
+ return 0;
+ }
+ if (macro_name == context->dict.___VERSION__) {
+ if (!mute && _out_number(context, state, 110)) {
+ return -1;
+ }
+ (*pi)++;
+ return 0;
+ }
+
+ 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;
+ }
+ }
+ (*pi)++;
+ 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;
+ }
+ (*pi)++;
+ return 0;
+ }
+ }
+
+ /* TODO: For FEATURE_es2_glsl, expand to 1 the following symbols.
+ * GL_ES
+ * GL_FRAGMENT_PRECISION_HIGH
+ */
+
+ if (local) {
+ for (macro = local; macro; macro = macro->next) {
+ if (macro->name == macro_name) {
+ break;
+ }
+ }
+ }
+
+ if (!macro) {
+ for (macro = context->macro; macro; macro = macro->next) {
+ if (macro->name == macro_name) {
+ break;
+ }
+ }
+ }
+
+ if (!macro) {
+ if (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[*pi])) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+ }
+ (*pi)++;
+ return 0;
+ }
+
+ (*pi)++;
+
+ if (macro->num_args >= 0) {
+ skip_whitespace(input, pi);
+ if (input[*pi].token != SL_PP_LPAREN) {
+ strcpy(context->error_msg, "expected `('");
+ return -1;
+ }
+ (*pi)++;
+ skip_whitespace(input, pi);
+ }
+
+ if (macro->num_args > 0) {
+ struct sl_pp_macro_formal_arg *formal_arg = macro->arg;
+ struct sl_pp_macro **pmacro = &actual_arg;
+
+ for (j = 0; j < (unsigned int)macro->num_args; j++) {
+ struct sl_pp_process_state arg_state;
+ unsigned int i;
+ int done = 0;
+ unsigned int paren_nesting = 0;
+ struct sl_pp_token_info eof;
+
+ memset(&arg_state, 0, sizeof(arg_state));
+
+ for (i = *pi; !done;) {
+ switch (input[i].token) {
+ case SL_PP_WHITESPACE:
+ i++;
+ break;
+
+ case SL_PP_COMMA:
+ if (!paren_nesting) {
+ if (j < (unsigned int)macro->num_args - 1) {
+ done = 1;
+ i++;
+ } else {
+ strcpy(context->error_msg, "too many actual macro arguments");
+ return -1;
+ }
+ } else {
+ if (sl_pp_process_out(&arg_state, &input[i])) {
+ strcpy(context->error_msg, "out of memory");
+ free(arg_state.out);
+ return -1;
+ }
+ i++;
+ }
+ break;
+
+ case SL_PP_LPAREN:
+ paren_nesting++;
+ if (sl_pp_process_out(&arg_state, &input[i])) {
+ strcpy(context->error_msg, "out of memory");
+ free(arg_state.out);
+ return -1;
+ }
+ i++;
+ break;
+
+ case SL_PP_RPAREN:
+ if (!paren_nesting) {
+ if (j == (unsigned int)macro->num_args - 1) {
+ done = 1;
+ i++;
+ } else {
+ strcpy(context->error_msg, "too few actual macro arguments");
+ return -1;
+ }
+ } else {
+ paren_nesting--;
+ if (sl_pp_process_out(&arg_state, &input[i])) {
+ strcpy(context->error_msg, "out of memory");
+ free(arg_state.out);
+ return -1;
+ }
+ i++;
+ }
+ break;
+
+ case SL_PP_IDENTIFIER:
+ if (sl_pp_macro_expand(context, input, &i, local, &arg_state, sl_pp_macro_expand_normal)) {
+ free(arg_state.out);
+ return -1;
+ }
+ break;
+
+ case SL_PP_EOF:
+ strcpy(context->error_msg, "too few actual macro arguments");
+ return -1;
+
+ default:
+ if (sl_pp_process_out(&arg_state, &input[i])) {
+ strcpy(context->error_msg, "out of memory");
+ free(arg_state.out);
+ return -1;
+ }
+ i++;
+ }
+ }
+
+ (*pi) = i;
+
+ eof.token = SL_PP_EOF;
+ if (sl_pp_process_out(&arg_state, &eof)) {
+ strcpy(context->error_msg, "out of memory");
+ free(arg_state.out);
+ return -1;
+ }
+
+ *pmacro = sl_pp_macro_new();
+ if (!*pmacro) {
+ strcpy(context->error_msg, "out of memory");
+ free(arg_state.out);
+ return -1;
+ }
+
+ (**pmacro).name = formal_arg->name;
+ (**pmacro).body = arg_state.out;
+
+ formal_arg = formal_arg->next;
+ pmacro = &(**pmacro).next;
+ }
+ }
+
+ /* Right paren for non-empty argument list has already been eaten. */
+ if (macro->num_args == 0) {
+ skip_whitespace(input, pi);
+ if (input[*pi].token != SL_PP_RPAREN) {
+ strcpy(context->error_msg, "expected `)'");
+ return -1;
+ }
+ (*pi)++;
+ }
+
+ for (j = 0;;) {
+ switch (macro->body[j].token) {
+ case SL_PP_NEWLINE:
+ if (sl_pp_process_out(state, &macro->body[j])) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+ j++;
+ break;
+
+ case SL_PP_IDENTIFIER:
+ if (sl_pp_macro_expand(context, macro->body, &j, actual_arg, state, behaviour)) {
+ return -1;
+ }
+ break;
+
+ case SL_PP_EOF:
+ sl_pp_macro_free(actual_arg);
+ return 0;
+
+ default:
+ if (!mute) {
+ if (sl_pp_process_out(state, &macro->body[j])) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+ }
+ j++;
+ }
+ }
+}
diff --git a/src/glsl/pp/sl_pp_macro.h b/src/glsl/pp/sl_pp_macro.h
new file mode 100644
index 0000000000..3ad3438236
--- /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_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,
+ const struct sl_pp_token_info *input,
+ unsigned int *pi,
+ 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 0000000000..489eb17b8e
--- /dev/null
+++ b/src/glsl/pp/sl_pp_pragma.c
@@ -0,0 +1,108 @@
+/**************************************************************************
+ *
+ * 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_process.h"
+
+
+int
+sl_pp_process_pragma(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last,
+ struct sl_pp_process_state *state)
+{
+ int pragma_name = -1;
+ struct sl_pp_token_info out;
+ int arg_name = -1;
+
+ if (first < last && input[first].token == SL_PP_IDENTIFIER) {
+ pragma_name = input[first].data.identifier;
+ first++;
+ }
+ if (pragma_name == -1) {
+ return 0;
+ }
+
+ if (pragma_name == context->dict.optimize) {
+ out.token = SL_PP_PRAGMA_OPTIMIZE;
+ } else if (pragma_name == context->dict.debug) {
+ out.token = SL_PP_PRAGMA_DEBUG;
+ } else {
+ return 0;
+ }
+
+ while (first < last && input[first].token == SL_PP_WHITESPACE) {
+ first++;
+ }
+
+ if (first < last && input[first].token == SL_PP_LPAREN) {
+ first++;
+ } else {
+ return 0;
+ }
+
+ while (first < last && input[first].token == SL_PP_WHITESPACE) {
+ first++;
+ }
+
+ if (first < last && input[first].token == SL_PP_IDENTIFIER) {
+ arg_name = input[first].data.identifier;
+ first++;
+ }
+ if (arg_name == -1) {
+ return 0;
+ }
+
+ if (arg_name == context->dict.off) {
+ out.data.pragma = 0;
+ } else if (arg_name == context->dict.on) {
+ out.data.pragma = 1;
+ } else {
+ return 0;
+ }
+
+ while (first < last && input[first].token == SL_PP_WHITESPACE) {
+ first++;
+ }
+
+ if (first < last && input[first].token == SL_PP_RPAREN) {
+ first++;
+ } else {
+ return 0;
+ }
+
+ /* Ignore the tokens that follow. */
+
+ if (sl_pp_process_out(state, &out)) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/glsl/pp/sl_pp_process.c b/src/glsl/pp/sl_pp_process.c
new file mode 100644
index 0000000000..e2adc2a021
--- /dev/null
+++ b/src/glsl/pp/sl_pp_process.c
@@ -0,0 +1,286 @@
+/**************************************************************************
+ *
+ * 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_process.h"
+#include "sl_pp_public.h"
+
+
+static void
+skip_whitespace(const struct sl_pp_token_info *input,
+ unsigned int *pi)
+{
+ while (input[*pi].token == SL_PP_WHITESPACE) {
+ (*pi)++;
+ }
+}
+
+int
+sl_pp_process_out(struct sl_pp_process_state *state,
+ const struct sl_pp_token_info *token)
+{
+ if (state->out_len >= state->out_max) {
+ unsigned int new_max = state->out_max;
+
+ if (new_max < 0x100) {
+ new_max = 0x100;
+ } else if (new_max < 0x10000) {
+ new_max *= 2;
+ } else {
+ new_max += 0x10000;
+ }
+
+ state->out = realloc(state->out, new_max * sizeof(struct sl_pp_token_info));
+ if (!state->out) {
+ return -1;
+ }
+ state->out_max = new_max;
+ }
+
+ state->out[state->out_len++] = *token;
+ return 0;
+}
+
+int
+sl_pp_process(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ struct sl_pp_token_info **output)
+{
+ unsigned int i = 0;
+ int found_eof = 0;
+ struct sl_pp_process_state state;
+
+ memset(&state, 0, sizeof(state));
+
+ if (context->line > 1) {
+ struct sl_pp_token_info ti;
+
+ ti.token = SL_PP_LINE;
+ ti.data.line.lineno = context->line - 1;
+ ti.data.line.fileno = context->file;
+ if (sl_pp_process_out(&state, &ti)) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+
+ ti.token = SL_PP_NEWLINE;
+ if (sl_pp_process_out(&state, &ti)) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+ }
+
+ while (!found_eof) {
+ skip_whitespace(input, &i);
+ if (input[i].token == SL_PP_HASH) {
+ i++;
+ skip_whitespace(input, &i);
+ switch (input[i].token) {
+ case SL_PP_IDENTIFIER:
+ {
+ int name;
+ int found_eol = 0;
+ unsigned int first;
+ unsigned int last;
+ struct sl_pp_token_info endof;
+
+ /* Directive name. */
+ name = input[i].data.identifier;
+ i++;
+ skip_whitespace(input, &i);
+
+ first = i;
+
+ while (!found_eol) {
+ switch (input[i].token) {
+ case SL_PP_NEWLINE:
+ /* Preserve newline just for the sake of line numbering. */
+ endof = input[i];
+ i++;
+ found_eol = 1;
+ break;
+
+ case SL_PP_EOF:
+ endof = input[i];
+ i++;
+ found_eof = 1;
+ found_eol = 1;
+ break;
+
+ default:
+ i++;
+ }
+ }
+
+ last = i - 1;
+
+ if (name == context->dict._if) {
+ if (sl_pp_process_if(context, input, first, last)) {
+ return -1;
+ }
+ } else if (name == context->dict.ifdef) {
+ if (sl_pp_process_ifdef(context, input, first, last)) {
+ return -1;
+ }
+ } else if (name == context->dict.ifndef) {
+ if (sl_pp_process_ifndef(context, input, first, last)) {
+ return -1;
+ }
+ } else if (name == context->dict.elif) {
+ if (sl_pp_process_elif(context, input, first, last)) {
+ return -1;
+ }
+ } else if (name == context->dict._else) {
+ if (sl_pp_process_else(context, input, first, last)) {
+ return -1;
+ }
+ } else if (name == context->dict.endif) {
+ if (sl_pp_process_endif(context, input, first, last)) {
+ return -1;
+ }
+ } else if (context->if_value) {
+ if (name == context->dict.define) {
+ if (sl_pp_process_define(context, input, first, last)) {
+ return -1;
+ }
+ } else if (name == context->dict.error) {
+ sl_pp_process_error(context, input, first, last);
+ return -1;
+ } else if (name == context->dict.extension) {
+ if (sl_pp_process_extension(context, input, first, last, &state)) {
+ return -1;
+ }
+ } else if (name == context->dict.line) {
+ if (sl_pp_process_line(context, input, first, last, &state)) {
+ return -1;
+ }
+ } else if (name == context->dict.pragma) {
+ if (sl_pp_process_pragma(context, input, first, last, &state)) {
+ return -1;
+ }
+ } else if (name == context->dict.undef) {
+ if (sl_pp_process_undef(context, input, first, last)) {
+ return -1;
+ }
+ } else {
+ strcpy(context->error_msg, "unrecognised directive name");
+ return -1;
+ }
+ }
+
+ if (sl_pp_process_out(&state, &endof)) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+ context->line++;
+ }
+ break;
+
+ case SL_PP_NEWLINE:
+ /* Empty directive. */
+ if (sl_pp_process_out(&state, &input[i])) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+ context->line++;
+ i++;
+ break;
+
+ case SL_PP_EOF:
+ /* Empty directive. */
+ if (sl_pp_process_out(&state, &input[i])) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+ i++;
+ found_eof = 1;
+ break;
+
+ default:
+ strcpy(context->error_msg, "expected a directive name");
+ return -1;
+ }
+ } else {
+ int found_eol = 0;
+
+ while (!found_eol) {
+ switch (input[i].token) {
+ case SL_PP_WHITESPACE:
+ /* Drop whitespace all together at this point. */
+ i++;
+ break;
+
+ case SL_PP_NEWLINE:
+ /* Preserve newline just for the sake of line numbering. */
+ if (sl_pp_process_out(&state, &input[i])) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+ context->line++;
+ i++;
+ found_eol = 1;
+ break;
+
+ case SL_PP_EOF:
+ if (sl_pp_process_out(&state, &input[i])) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+ i++;
+ found_eof = 1;
+ found_eol = 1;
+ break;
+
+ case SL_PP_IDENTIFIER:
+ if (sl_pp_macro_expand(context, input, &i, NULL, &state,
+ context->if_value ? sl_pp_macro_expand_normal : sl_pp_macro_expand_mute)) {
+ return -1;
+ }
+ break;
+
+ default:
+ if (context->if_value) {
+ if (sl_pp_process_out(&state, &input[i])) {
+ strcpy(context->error_msg, "out of memory");
+ return -1;
+ }
+ }
+ i++;
+ }
+ }
+ }
+ }
+
+ if (context->if_ptr != SL_PP_MAX_IF_NESTING) {
+ strcpy(context->error_msg, "expected `#endif' directive");
+ return -1;
+ }
+
+ *output = state.out;
+ return 0;
+}
diff --git a/src/glsl/pp/sl_pp_process.h b/src/glsl/pp/sl_pp_process.h
new file mode 100644
index 0000000000..24311bab60
--- /dev/null
+++ b/src/glsl/pp/sl_pp_process.h
@@ -0,0 +1,121 @@
+/**************************************************************************
+ *
+ * Copyright 2009 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef SL_PP_PROCESS_H
+#define SL_PP_PROCESS_H
+
+#include "sl_pp_context.h"
+#include "sl_pp_macro.h"
+#include "sl_pp_token.h"
+
+
+struct sl_pp_process_state {
+ struct sl_pp_token_info *out;
+ unsigned int out_len;
+ unsigned int out_max;
+};
+
+int
+sl_pp_process_define(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last);
+
+int
+sl_pp_process_undef(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last);
+
+int
+sl_pp_process_if(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last);
+
+int
+sl_pp_process_ifdef(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last);
+
+int
+sl_pp_process_ifndef(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last);
+
+int
+sl_pp_process_elif(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last);
+
+int
+sl_pp_process_else(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last);
+
+int
+sl_pp_process_endif(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last);
+
+void
+sl_pp_process_error(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last);
+
+int
+sl_pp_process_pragma(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last,
+ struct sl_pp_process_state *state);
+
+int
+sl_pp_process_extension(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last,
+ struct sl_pp_process_state *state);
+
+int
+sl_pp_process_line(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ unsigned int first,
+ unsigned int last,
+ struct sl_pp_process_state *state);
+
+int
+sl_pp_process_out(struct sl_pp_process_state *state,
+ const struct sl_pp_token_info *token);
+
+#endif /* SL_PP_PROCESS_H */
diff --git a/src/glsl/pp/sl_pp_public.h b/src/glsl/pp/sl_pp_public.h
new file mode 100644
index 0000000000..076903649c
--- /dev/null
+++ b/src/glsl/pp/sl_pp_public.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_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(void);
+
+void
+sl_pp_context_destroy(struct sl_pp_context *context);
+
+const char *
+sl_pp_context_error_message(const struct sl_pp_context *context);
+
+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,
+ const struct sl_pp_token_info *input,
+ unsigned int *version,
+ unsigned int *tokens_eaten);
+
+int
+sl_pp_process(struct sl_pp_context *context,
+ const struct sl_pp_token_info *input,
+ 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 0000000000..b50f819251
--- /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 0000000000..c0f55cbfd8
--- /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 0000000000..e9a60b6c50
--- /dev/null
+++ b/src/glsl/pp/sl_pp_token.c
@@ -0,0 +1,859 @@
+/**************************************************************************
+ *
+ * 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;
+ unsigned int current_line;
+
+ if (context->getc_buf_size) {
+ return context->getc_buf[--context->getc_buf_size];
+ }
+
+ if (sl_pp_purify_getc(&context->pure, &c, &current_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;
+}
+
+
+static 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,
+ const char *input,
+ const struct sl_pp_purify_options *options,
+ struct sl_pp_token_info **output)
+{
+ struct sl_pp_token_info *out = NULL;
+ unsigned int out_len = 0;
+ unsigned int out_max = 0;
+
+ sl_pp_purify_state_init(&context->pure, input, options);
+
+ for (;;) {
+ struct sl_pp_token_info info;
+
+ if (sl_pp_token_get(context, &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 0000000000..ba9834a9f2
--- /dev/null
+++ b/src/glsl/pp/sl_pp_token.h
@@ -0,0 +1,131 @@
+/**************************************************************************
+ *
+ * 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_tokenise(struct sl_pp_context *context,
+ const char *input,
+ const struct sl_pp_purify_options *options,
+ struct sl_pp_token_info **output);
+
+#endif /* SL_PP_TOKEN_H */
diff --git a/src/glsl/pp/sl_pp_version.c b/src/glsl/pp/sl_pp_version.c
new file mode 100644
index 0000000000..db06523749
--- /dev/null
+++ b/src/glsl/pp/sl_pp_version.c
@@ -0,0 +1,140 @@
+/**************************************************************************
+ *
+ * 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,
+ const struct sl_pp_token_info *input,
+ unsigned int *version,
+ unsigned int *tokens_eaten)
+{
+ unsigned int i = 0;
+ unsigned int line = context->line;
+
+ /* Default values if `#version' is not present. */
+ *version = 110;
+ *tokens_eaten = 0;
+
+ /* There can be multiple `#version' directives present.
+ * Accept the value of the last one.
+ */
+ for (;;) {
+ int found_hash = 0;
+ int found_version = 0;
+ int found_number = 0;
+ int found_end = 0;
+
+ /* Skip whitespace and newlines and seek for hash. */
+ while (!found_hash) {
+ switch (input[i].token) {
+ case SL_PP_NEWLINE:
+ line++;
+ /* pass thru */
+ case SL_PP_WHITESPACE:
+ i++;
+ break;
+
+ case SL_PP_HASH:
+ i++;
+ found_hash = 1;
+ break;
+
+ default:
+ return 0;
+ }
+ }
+
+ /* Skip whitespace and seek for `version'. */
+ while (!found_version) {
+ switch (input[i].token) {
+ case SL_PP_WHITESPACE:
+ i++;
+ break;
+
+ case SL_PP_IDENTIFIER:
+ if (input[i].data.identifier != context->dict.version) {
+ return 0;
+ }
+ i++;
+ found_version = 1;
+ break;
+
+ default:
+ return 0;
+ }
+ }
+
+ /* Skip whitespace and seek for version number. */
+ while (!found_number) {
+ switch (input[i].token) {
+ case SL_PP_WHITESPACE:
+ i++;
+ break;
+
+ case SL_PP_UINT:
+ *version = atoi(sl_pp_context_cstr(context, input[i].data._uint));
+ i++;
+ found_number = 1;
+ break;
+
+ default:
+ strcpy(context->error_msg, "expected version number after `#version'");
+ return -1;
+ }
+ }
+
+ /* Skip whitespace and seek for either newline or eof. */
+ while (!found_end) {
+ switch (input[i].token) {
+ case SL_PP_WHITESPACE:
+ i++;
+ break;
+
+ case SL_PP_NEWLINE:
+ line++;
+ /* pass thru */
+ case SL_PP_EOF:
+ i++;
+ *tokens_eaten = i;
+ context->line = line;
+ found_end = 1;
+ break;
+
+ default:
+ strcpy(context->error_msg, "expected end of line after version number");
+ return -1;
+ }
+ }
+ }
+
+ /* Should not get here. */
+}