diff options
Diffstat (limited to 'src/mesa')
| -rw-r--r-- | src/mesa/shader/slang/slang_compile.c | 1826 | ||||
| -rw-r--r-- | src/mesa/shader/slang/slang_compile.h | 235 | 
2 files changed, 2061 insertions, 0 deletions
diff --git a/src/mesa/shader/slang/slang_compile.c b/src/mesa/shader/slang/slang_compile.c new file mode 100644 index 0000000000..e32613c9f6 --- /dev/null +++ b/src/mesa/shader/slang/slang_compile.c @@ -0,0 +1,1826 @@ +/*
 + * Mesa 3-D graphics library
 + * Version:  6.3
 + *
 + * Copyright (C) 2005  Brian Paul   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, sublicense,
 + * 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 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 NONINFRINGEMENT.  IN NO EVENT SHALL
 + * BRIAN PAUL 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.
 + */
 +
 +/**
 + * \file slang_compile.c
 + * slang front-end compiler
 + * \author Michal Krol
 + */
 +
 +#include "imports.h" 
 +#include "slang_compile.h"
 +#include "grammar_mesa.h"
 +
 +/*
 +	This is a straightforward implementation of the slang front-end compiler.
 +	Lots of error-checking functionality is missing but every well-formed shader source should
 +	compile successfully and execute as expected. However, some semantically ill-formed shaders
 +	may be accepted resulting in undefined behaviour.
 +*/
 +
 +void slang_alloc_free (void *ptr)
 +{
 +	_mesa_free (ptr);
 +}
 +
 +void *slang_alloc_malloc (unsigned int size)
 +{
 +	return _mesa_malloc (size);
 +}
 +
 +void *slang_alloc_realloc (void *ptr, unsigned int old_size, unsigned int size)
 +{
 +	return _mesa_realloc (ptr, old_size, size);
 +}
 +
 +int slang_string_compare (const char *str1, const char *str2)
 +{
 +	return _mesa_strcmp (str1, str2);
 +}
 +
 +char *slang_string_copy (char *dst, const char *src)
 +{
 +	return _mesa_strcpy (dst, src);
 +}
 +
 +char *slang_string_concat (char *dst, const char *src)
 +{
 +	return _mesa_strcpy (dst + _mesa_strlen (dst), src);
 +}
 +
 +char *slang_string_duplicate (const char *src)
 +{
 +	return _mesa_strdup (src);
 +}
 +
 +static void slang_variable_construct (slang_variable *);
 +static int slang_variable_copy (slang_variable *, const slang_variable *);
 +static void slang_struct_construct (slang_struct *);
 +static void slang_struct_destruct (slang_struct *);
 +static int slang_struct_copy (slang_struct *, const slang_struct *);
 +static int slang_struct_equal (const slang_struct *, const slang_struct *);
 +static void slang_variable_destruct (slang_variable *);
 +
 +/* slang_type_specifier */
 +
 +static void slang_type_specifier_construct (slang_type_specifier *spec)
 +{
 +	spec->type = slang_spec_void;
 +	spec->_struct = NULL;
 +	spec->_array = NULL;
 +}
 +
 +static void slang_type_specifier_destruct (slang_type_specifier *spec)
 +{
 +	if (spec->_struct != NULL)
 +	{
 +		slang_struct_destruct (spec->_struct);
 +		slang_alloc_free (spec->_struct);
 +	}
 +	if (spec->_array != NULL)
 +	{
 +		slang_type_specifier_destruct (spec->_array);
 +		slang_alloc_free (spec->_array);
 +	}
 +}
 +
 +static int slang_type_specifier_copy (slang_type_specifier *x, const slang_type_specifier *y)
 +{
 +	slang_type_specifier_destruct (x);
 +	slang_type_specifier_construct (x);
 +	x->type = y->type;
 +	if (x->type == slang_spec_struct)
 +	{
 +		x->_struct = (slang_struct *) slang_alloc_malloc (sizeof (slang_struct));
 +		slang_struct_construct (x->_struct);
 +		return slang_struct_copy (x->_struct, y->_struct);
 +	}
 +	if (x->type == slang_spec_array)
 +	{
 +		x->_array = (slang_type_specifier *) slang_alloc_malloc (sizeof (slang_type_specifier));
 +		slang_type_specifier_construct (x->_array);
 +		return slang_type_specifier_copy (x->_array, y->_array);
 +	}
 +	return 1;
 +}
 +
 +static int slang_type_specifier_equal (const slang_type_specifier *x, const slang_type_specifier *y)
 +{
 +	if (x->type != y->type)
 +		return 0;
 +	if (x->type == slang_spec_struct)
 +		return slang_struct_equal (x->_struct, y->_struct);
 +	if (x->type == slang_spec_array)
 +		return slang_type_specifier_equal (x->_array, y->_array);
 +	return 1;
 +}
 +
 +/* slang_fully_specified_type */
 +
 +static void slang_fully_specified_type_construct (slang_fully_specified_type *type)
 +{
 +	type->qualifier = slang_qual_none;
 +	slang_type_specifier_construct (&type->specifier);
 +}
 +
 +static void slang_fully_specified_type_destruct (slang_fully_specified_type *type)
 +{
 +	slang_type_specifier_destruct (&type->specifier);
 +}
 +
 +static int slang_fully_specified_type_copy (slang_fully_specified_type *x,
 +	const slang_fully_specified_type *y)
 +{
 +	slang_fully_specified_type_construct (x);
 +	slang_fully_specified_type_destruct (x);
 +	x->qualifier = y->qualifier;
 +	return slang_type_specifier_copy (&x->specifier, &y->specifier);
 +}
 +
 +/* slang_variable_scope */
 +
 +static void slang_variable_scope_construct (slang_variable_scope *scope)
 +{
 +	scope->variables = NULL;
 +	scope->num_variables = 0;
 +	scope->outer_scope = NULL;
 +}
 +
 +static void slang_variable_scope_destruct (slang_variable_scope *scope)
 +{
 +	unsigned int i;
 +	for (i = 0; i < scope->num_variables; i++)
 +		slang_variable_destruct (scope->variables + i);
 +	slang_alloc_free (scope->variables);
 +}
 +
 +static int slang_variable_scope_copy (slang_variable_scope *x, const slang_variable_scope *y)
 +{
 +	unsigned int i;
 +	slang_variable_scope_destruct (x);
 +	slang_variable_scope_construct (x);
 +	x->variables = (slang_variable *) slang_alloc_malloc (y->num_variables * sizeof (
 +		slang_variable));
 +	if (x->variables == NULL)
 +		return 0;
 +	x->num_variables = y->num_variables;
 +	for (i = 0; i < x->num_variables; i++)
 +		slang_variable_construct (x->variables + i);
 +	for (i = 0; i < x->num_variables; i++)
 +		if (!slang_variable_copy (x->variables + i, y->variables + i))
 +			return 0;
 +	x->outer_scope = y->outer_scope;
 +	return 1;
 +}
 +
 +/* slang_operation */
 +/* XXX mem! */
 +static void slang_operation_construct (slang_operation *oper)
 +{
 +	oper->type = slang_oper_none;
 +	oper->children = NULL;
 +	oper->num_children = 0;
 +	oper->literal = (float) 0;
 +	oper->identifier = NULL;
 +	oper->locals = (slang_variable_scope *) slang_alloc_malloc (sizeof (slang_variable_scope));
 +	slang_variable_scope_construct (oper->locals);
 +}
 +
 +static void slang_operation_destruct (slang_operation *oper)
 +{
 +	unsigned int i;
 +	for (i = 0; i < oper->num_children; i++)
 +		slang_operation_destruct (oper->children + i);
 +	slang_alloc_free (oper->children);
 +	slang_alloc_free (oper->identifier);
 +	slang_variable_scope_destruct (oper->locals);
 +	slang_alloc_free (oper->locals);
 +}
 +
 +static int slang_operation_copy (slang_operation *x, const slang_operation *y)
 +{
 +	unsigned int i;
 +	slang_operation_destruct (x);
 +	slang_operation_construct (x);
 +	x->type = y->type;
 +	x->children = (slang_operation *) slang_alloc_malloc (y->num_children * sizeof (
 +		slang_operation));
 +	if (x->children == NULL)
 +		return 0;
 +	x->num_children = y->num_children;
 +	for (i = 0; i < x->num_children; i++)
 +		slang_operation_construct (x->children + i);
 +	for (i = 0; i < x->num_children; i++)
 +		if (!slang_operation_copy (x->children + i, y->children + i))
 +			return 0;
 +	x->literal = y->literal;
 +	if (y->identifier != NULL)
 +	{
 +		x->identifier = slang_string_duplicate (y->identifier);
 +		if (x->identifier == NULL)
 +			return 0;
 +	}
 +	if (!slang_variable_scope_copy (x->locals, y->locals))
 +		return 0;
 +	return 1;
 +}
 +
 +/* slang_variable */
 +
 +static void slang_variable_construct (slang_variable *var)
 +{
 +	slang_fully_specified_type_construct (&var->type);
 +	var->name = NULL;
 +	var->array_size = NULL;
 +	var->initializer = NULL;
 +}
 +
 +static void slang_variable_destruct (slang_variable *var)
 +{
 +	slang_fully_specified_type_destruct (&var->type);
 +	slang_alloc_free (var->name);
 +	if (var->array_size != NULL)
 +	{
 +		slang_operation_destruct (var->array_size);
 +		slang_alloc_free (var->array_size);
 +	}
 +	if (var->initializer != NULL)
 +	{
 +		slang_operation_destruct (var->initializer);
 +		slang_alloc_free (var->initializer);
 +	}
 +}
 +
 +static int slang_variable_copy (slang_variable *x, const slang_variable *y)
 +{
 +	slang_variable_destruct (x);
 +	slang_variable_construct (x);
 +	if (!slang_fully_specified_type_copy (&x->type, &y->type))
 +		return 0;
 +	if (y->name != NULL)
 +	{
 +		x->name = slang_string_duplicate (y->name);
 +		if (x->name == NULL)
 +			return 0;
 +	}
 +	if (y->array_size != NULL)
 +		if (!slang_operation_copy (x->array_size, y->array_size))
 +			return 0;
 +	if (y->initializer != NULL)
 +		if (!slang_operation_copy (x->initializer, y->initializer))
 +			return 0;
 +	return 1;
 +}
 +
 +/* slang_struct_scope */
 +
 +static void slang_struct_scope_construct (slang_struct_scope *scope)
 +{
 +	scope->structs = NULL;
 +	scope->num_structs = 0;
 +	scope->outer_scope = NULL;
 +}
 +
 +static void slang_struct_scope_destruct (slang_struct_scope *scope)
 +{
 +	unsigned int i;
 +	for (i = 0; i < scope->num_structs; i++)
 +		slang_struct_destruct (scope->structs + i);
 +	slang_alloc_free (scope->structs);
 +}
 +
 +static int slang_struct_scope_copy (slang_struct_scope *x, const slang_struct_scope *y)
 +{
 +	unsigned int i;
 +	slang_struct_scope_destruct (x);
 +	slang_struct_scope_construct (x);
 +	x->structs = (slang_struct *) slang_alloc_malloc (y->num_structs * sizeof (slang_struct));
 +	if (x->structs == NULL)
 +		return 0;
 +	x->num_structs = y->num_structs;
 +	for (i = 0; i < x->num_structs; i++)
 +		slang_struct_construct (x->structs + i);
 +	for (i = 0; i < x->num_structs; i++)
 +		if (!slang_struct_copy (x->structs + i, y->structs + i))
 +			return 0;
 +	x->outer_scope = y->outer_scope;
 +	return 1;
 +}
 +
 +static slang_struct *slang_struct_scope_find (slang_struct_scope *stru, const char *name,
 +	int all_scopes)
 +{
 +	unsigned int i;
 +	for (i = 0; i < stru->num_structs; i++)
 +		if (slang_string_compare (name, stru->structs[i].name) == 0)
 +			return stru->structs + i;
 +	if (all_scopes && stru->outer_scope != NULL)
 +		return slang_struct_scope_find (stru->outer_scope, name, 1);
 +	return NULL;
 +}
 +
 +/* slang_struct */
 +/* XXX mem! */
 +static void slang_struct_construct (slang_struct *stru)
 +{
 +	stru->name = NULL;
 +	stru->fields = (slang_variable_scope *) slang_alloc_malloc (sizeof (slang_variable_scope));
 +	slang_variable_scope_construct (stru->fields);
 +	stru->structs = (slang_struct_scope *) slang_alloc_malloc (sizeof (slang_struct_scope));
 +	slang_struct_scope_construct (stru->structs);
 +}
 +
 +static void slang_struct_destruct (slang_struct *stru)
 +{
 +	slang_alloc_free (stru->name);
 +	slang_variable_scope_destruct (stru->fields);
 +	slang_alloc_free (stru->fields);
 +	slang_struct_scope_destruct (stru->structs);
 +	slang_alloc_free (stru->structs);
 +}
 +
 +static int slang_struct_copy (slang_struct *x, const slang_struct *y)
 +{
 +	slang_struct_destruct (x);
 +	slang_struct_construct (x);
 +	if (y->name != NULL)
 +	{
 +		x->name = slang_string_duplicate (y->name);
 +		if (x->name == NULL)
 +			return 0;
 +	}
 +	if (!slang_variable_scope_copy (x->fields, y->fields))
 +		return 0;
 +	if (!slang_struct_scope_copy (x->structs, y->structs))
 +		return 0;
 +	return 1;
 +}
 +
 +static int slang_struct_equal (const slang_struct *x, const slang_struct *y)
 +{
 +	unsigned int i;
 +	if (x->fields->num_variables != y->fields->num_variables)
 +		return 0;
 +	for (i = 0; i < x->fields->num_variables; i++)
 +	{
 +		slang_variable *varx = x->fields->variables + i;
 +		slang_variable *vary = y->fields->variables + i;
 +		if (slang_string_compare (varx->name, vary->name) != 0)
 +			return 0;
 +		if (!slang_type_specifier_equal (&varx->type.specifier, &vary->type.specifier))
 +			return 0;
 +		if (varx->type.specifier.type == slang_spec_array)
 +		{
 +			/* TODO compare array sizes */
 +		}
 +	}
 +	return 1;
 +}
 +
 +/* slang_function */
 +/* XXX mem! */
 +static void slang_function_construct (slang_function *func)
 +{
 +	func->kind = slang_func_ordinary;
 +	slang_variable_construct (&func->header);
 +	func->parameters = (slang_variable_scope *) slang_alloc_malloc (sizeof (slang_variable_scope));
 +	slang_variable_scope_construct (func->parameters);
 +	func->body = NULL;
 +}
 +
 +static void slang_function_destruct (slang_function *func)
 +{
 +	slang_variable_destruct (&func->header);
 +	slang_variable_scope_destruct (func->parameters);
 +	slang_alloc_free (func->parameters);
 +	if (func->body != NULL)
 +	{
 +		slang_operation_destruct (func->body);
 +		slang_alloc_free (func->body);
 +	}
 +}
 +
 +/* slang_function_scope */
 +
 +static void slang_function_scope_construct (slang_function_scope *scope)
 +{
 +	scope->functions = NULL;
 +	scope->num_functions = 0;
 +	scope->outer_scope = NULL;
 +}
 +
 +static void slang_function_scope_destruct (slang_function_scope *scope)
 +{
 +	unsigned int i;
 +	for (i = 0; i < scope->num_functions; i++)
 +		slang_function_destruct (scope->functions + i);
 +	slang_alloc_free (scope->functions);
 +}
 +
 +static slang_function *slang_function_scope_find (slang_function_scope *funcs, slang_function *fun,
 +	int all_scopes)
 +{
 +	unsigned int i;
 +	for (i = 0; i < funcs->num_functions; i++)
 +	{
 +		slang_function *f = funcs->functions + i;
 +		unsigned int j;
 +		if (slang_string_compare (fun->header.name, f->header.name) != 0)
 +			continue;
 +		if (fun->param_count != f->param_count)
 +			continue;
 +		for (j = 0; j < fun->param_count; j++)
 +		{
 +			if (!slang_type_specifier_equal (&fun->parameters->variables[j].type.specifier,
 +				&f->parameters->variables[j].type.specifier))
 +			{
 +				break;
 +			}
 +		}
 +		if (j == fun->param_count)
 +			return f;
 +	}
 +	if (all_scopes && funcs->outer_scope != NULL)
 +		return slang_function_scope_find (funcs->outer_scope, fun, 1);
 +	return NULL;
 +}
 +
 +/* slang_translation_unit */
 +/* XXX mem! */
 +static void slang_translation_unit_construct (slang_translation_unit *unit)
 +{
 +	unit->globals = (slang_variable_scope *) slang_alloc_malloc (sizeof (slang_variable_scope));
 +	slang_variable_scope_construct (unit->globals);
 +	slang_function_scope_construct (&unit->functions);
 +	unit->structs = (slang_struct_scope *) slang_alloc_malloc (sizeof (slang_struct_scope));
 +	slang_struct_scope_construct (unit->structs);
 +}
 +
 +static void slang_translation_unit_destruct (slang_translation_unit *unit)
 +{
 +	slang_variable_scope_destruct (unit->globals);
 +	slang_alloc_free (unit->globals);
 +	slang_function_scope_destruct (&unit->functions);
 +	slang_struct_scope_destruct (unit->structs);
 +	slang_alloc_free (unit->structs);
 +}
 +
 +static int parse_identifier (const byte **I, char **id)
 +{
 +	*id = slang_string_duplicate ((const char *) *I);
 +	if (*id == NULL)
 +		return 0;
 +	*I += strlen ((const char *) *I) + 1;
 +	return 1;
 +}
 +
 +static int parse_number (const byte **I, int *number)
 +{
 +	const int radix = (int) (*(*I)++);
 +	*number = 0;
 +	while (**I != '\0')
 +	{
 +		int digit;
 +		if (**I >= '0' && **I <= '9')
 +			digit = (int) (**I - '0');
 +		else if (**I >= 'A' && **I <= 'Z')
 +			digit = (int) (**I - 'A') + 10;
 +		else
 +			digit = (int) (**I - 'a') + 10;
 +		*number = *number * radix + digit;
 +		(*I)++;
 +	}
 +	(*I)++;
 +	return 1;
 +}
 +
 +static int parse_float (const byte **I, float *number)
 +{
 +	char *integral = NULL;
 +	char *fractional = NULL;
 +	char *exponent = NULL;
 +	char *whole = NULL;
 +
 +	if (!parse_identifier (I, &integral))
 +		return 0;
 +
 +	if (!parse_identifier (I, &fractional))
 +	{
 +		slang_alloc_free (integral);
 +		return 0;
 +	}
 +
 +	if (!parse_identifier (I, &exponent))
 +	{
 +		slang_alloc_free (fractional);
 +		slang_alloc_free (integral);
 +		return 0;
 +	}
 +
 +	whole = (char *) (slang_alloc_malloc ((strlen (integral) + strlen (fractional) + strlen (
 +		exponent) + 3) * sizeof (char)));
 +	if (whole == NULL)
 +	{
 +		slang_alloc_free (exponent);
 +		slang_alloc_free (fractional);
 +		slang_alloc_free (integral);
 +		return 0;
 +	}
 +
 +	slang_string_copy (whole, integral);
 +	slang_string_concat (whole, ".");
 +	slang_string_concat (whole, fractional);
 +	slang_string_concat (whole, "E");
 +	slang_string_concat (whole, exponent);
 +
 +	*number = (float) (atof (whole));
 +
 +	slang_alloc_free (whole);
 +	slang_alloc_free (exponent);
 +	slang_alloc_free (fractional);
 +	slang_alloc_free (integral);
 +	return 1;
 +}
 +
 +/* revision number - increment after each change affecting emitted output */
 +#define REVISION 2
 +
 +static int check_revision (const byte **I)
 +{
 +	if (**I != REVISION)
 +		return 0;
 +	(*I)++;
 +	return 1;
 +}
 +
 +static int parse_statement (const byte **, slang_operation *, slang_variable_scope *,
 +	slang_struct_scope *);
 +static int parse_expression (const byte **, slang_operation *, slang_variable_scope *,
 +	slang_struct_scope *);
 +
 +/* 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
 +
 +static int parse_type_qualifier (const byte **I, slang_type_qualifier *qual)
 +{
 +	switch (*(*I)++)
 +	{
 +	case TYPE_QUALIFIER_NONE:
 +		*qual = slang_qual_none;
 +		break;
 +	case TYPE_QUALIFIER_CONST:
 +		*qual = slang_qual_const;
 +		break;
 +	case TYPE_QUALIFIER_ATTRIBUTE:
 +		*qual = slang_qual_attribute;
 +		break;
 +	case TYPE_QUALIFIER_VARYING:
 +		*qual = slang_qual_varying;
 +		break;
 +	case TYPE_QUALIFIER_UNIFORM:
 +		*qual = slang_qual_uniform;
 +		break;
 +	case TYPE_QUALIFIER_FIXEDOUTPUT:
 +		*qual = slang_qual_fixedoutput;
 +		break;
 +	case TYPE_QUALIFIER_FIXEDINPUT:
 +		*qual = slang_qual_fixedinput;
 +		break;
 +	default:
 +		return 0;
 +	}
 +	return 1;
 +}
 +
 +/* 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_STRUCT 22
 +#define TYPE_SPECIFIER_TYPENAME 23
 +
 +/* structure field */
 +#define FIELD_NONE 0
 +#define FIELD_NEXT 1
 +#define FIELD_ARRAY 2
 +
 +static int parse_type_specifier (const byte **I, slang_type_specifier *spec,
 +	slang_struct_scope *structs, slang_variable_scope *scope)
 +{
 +	switch (*(*I)++)
 +	{
 +	case TYPE_SPECIFIER_VOID:
 +		spec->type = slang_spec_void;
 +		break;
 +	case TYPE_SPECIFIER_BOOL:
 +		spec->type = slang_spec_bool;
 +		break;
 +	case TYPE_SPECIFIER_BVEC2:
 +		spec->type = slang_spec_bvec2;
 +		break;
 +	case TYPE_SPECIFIER_BVEC3:
 +		spec->type = slang_spec_bvec3;
 +		break;
 +	case TYPE_SPECIFIER_BVEC4:
 +		spec->type = slang_spec_bvec4;
 +		break;
 +	case TYPE_SPECIFIER_INT:
 +		spec->type = slang_spec_int;
 +		break;
 +	case TYPE_SPECIFIER_IVEC2:
 +		spec->type = slang_spec_ivec2;
 +		break;
 +	case TYPE_SPECIFIER_IVEC3:
 +		spec->type = slang_spec_ivec3;
 +		break;
 +	case TYPE_SPECIFIER_IVEC4:
 +		spec->type = slang_spec_ivec4;
 +		break;
 +	case TYPE_SPECIFIER_FLOAT:
 +		spec->type = slang_spec_float;
 +		break;
 +	case TYPE_SPECIFIER_VEC2:
 +		spec->type = slang_spec_vec2;
 +		break;
 +	case TYPE_SPECIFIER_VEC3:
 +		spec->type = slang_spec_vec3;
 +		break;
 +	case TYPE_SPECIFIER_VEC4:
 +		spec->type = slang_spec_vec4;
 +		break;
 +	case TYPE_SPECIFIER_MAT2:
 +		spec->type = slang_spec_mat2;
 +		break;
 +	case TYPE_SPECIFIER_MAT3:
 +		spec->type = slang_spec_mat3;
 +		break;
 +	case TYPE_SPECIFIER_MAT4:
 +		spec->type = slang_spec_mat4;
 +		break;
 +	case TYPE_SPECIFIER_SAMPLER1D:
 +		spec->type = slang_spec_sampler1D;
 +		break;
 +	case TYPE_SPECIFIER_SAMPLER2D:
 +		spec->type = slang_spec_sampler2D;
 +		break;
 +	case TYPE_SPECIFIER_SAMPLER3D:
 +		spec->type = slang_spec_sampler3D;
 +		break;
 +	case TYPE_SPECIFIER_SAMPLERCUBE:
 +		spec->type = slang_spec_samplerCube;
 +		break;
 +	case TYPE_SPECIFIER_SAMPLER1DSHADOW:
 +		spec->type = slang_spec_sampler1DShadow;
 +		break;
 +	case TYPE_SPECIFIER_SAMPLER2DSHADOW:
 +		spec->type = slang_spec_sampler2DShadow;
 +		break;
 +	case TYPE_SPECIFIER_STRUCT:
 +		spec->type = slang_spec_struct;
 +		{
 +			char *name;
 +			if (!parse_identifier (I, &name))
 +				return 0;
 +			if (*name != '\0' && slang_struct_scope_find (structs, name, 0) != NULL)
 +			{
 +				slang_alloc_free (name);
 +				return 0;		/* error: duplicate names */
 +			}
 +			spec->_struct = (slang_struct *) slang_alloc_malloc (sizeof (slang_struct));
 +			if (spec->_struct == NULL)
 +			{
 +				slang_alloc_free (name);
 +				return 0;
 +			}
 +			slang_struct_construct (spec->_struct);
 +			spec->_struct->name = name;
 +			spec->_struct->structs->outer_scope = structs;
 +		}
 +		do
 +		{
 +			slang_type_specifier sp;
 +			slang_type_specifier_construct (&sp);
 +			if (!parse_type_specifier (I, &sp, spec->_struct->structs, scope))
 +			{
 +				slang_type_specifier_destruct (&sp);
 +				return 0;
 +			}
 +			do
 +			{
 +				slang_variable *var;
 +				spec->_struct->fields->variables = (slang_variable *) slang_alloc_realloc (
 +					spec->_struct->fields->variables,
 +					spec->_struct->fields->num_variables * sizeof (slang_variable),
 +					(spec->_struct->fields->num_variables + 1) * sizeof (slang_variable));
 +				if (spec->_struct->fields->variables == NULL)
 +				{
 +					slang_type_specifier_destruct (&sp);
 +					return 0;
 +				}
 +				var = spec->_struct->fields->variables + spec->_struct->fields->num_variables;
 +				spec->_struct->fields->num_variables++;
 +				slang_variable_construct (var);
 +				if (!slang_type_specifier_copy (&var->type.specifier, &sp))
 +				{
 +					slang_type_specifier_destruct (&sp);
 +					return 0;
 +				}
 +				if (!parse_identifier (I, &var->name))
 +				{
 +					slang_type_specifier_destruct (&sp);
 +					return 0;
 +				}
 +				switch (*(*I)++)
 +				{
 +				case FIELD_NONE:
 +					break;
 +				case FIELD_ARRAY:
 +					var->array_size = (slang_operation *) slang_alloc_malloc (sizeof (
 +						slang_operation));
 +					if (var->array_size == NULL)
 +					{
 +						slang_type_specifier_destruct (&sp);
 +						return 0;
 +					}
 +					slang_operation_construct (var->array_size);
 +					if (!parse_expression (I, var->array_size, scope, structs))
 +					{
 +						slang_type_specifier_destruct (&sp);
 +						return 0;
 +					}
 +					break;
 +				default:
 +					slang_type_specifier_destruct (&sp);
 +					return 0;
 +				}
 +			}
 +			while (*(*I)++ != FIELD_NONE);
 +		}
 +		while (*(*I)++ != FIELD_NONE);
 +		if (*spec->_struct->name != '\0')
 +		{
 +			slang_struct *s;
 +			structs->structs = (slang_struct *) slang_alloc_realloc (structs->structs,
 +				structs->num_structs * sizeof (slang_struct),
 +				(structs->num_structs + 1) * sizeof (slang_struct));
 +			if (structs->structs == NULL)
 +				return 0;
 +			s = structs->structs + structs->num_structs;
 +			structs->num_structs++;
 +			slang_struct_construct (s);
 +			if (!slang_struct_copy (s, spec->_struct))
 +				return 0;
 +		}
 +		break;
 +	case TYPE_SPECIFIER_TYPENAME:
 +		spec->type = slang_spec_struct;
 +		{
 +			char *name;
 +			slang_struct *stru;
 +			if (!parse_identifier (I, &name))
 +				return 0;
 +			stru = slang_struct_scope_find (structs, name, 1);
 +			slang_alloc_free (name);
 +			if (stru == NULL)
 +				return 0;
 +			spec->_struct = (slang_struct *) slang_alloc_malloc (sizeof (slang_struct));
 +			if (spec->_struct == NULL)
 +				return 0;
 +			slang_struct_construct (spec->_struct);
 +			if (!slang_struct_copy (spec->_struct, stru))
 +				return 0;
 +		}
 +		break;
 +	default:
 +		return 0;
 +	}
 +	return 1;
 +}
 +
 +static int parse_fully_specified_type (const byte **I, slang_fully_specified_type *type,
 +	slang_struct_scope *structs, slang_variable_scope *scope)
 +{
 +	if (!parse_type_qualifier (I, &type->qualifier))
 +		return 0;
 +	return parse_type_specifier (I, &type->specifier, structs, scope);
 +}
 +
 +/* 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
 +
 +static int parse_child_operation (const byte **I, slang_operation *oper, int statement,
 +	slang_variable_scope *scope, slang_struct_scope *structs)
 +{
 +	oper->children = (slang_operation *) slang_alloc_realloc (oper->children,
 +		oper->num_children * sizeof (slang_operation),
 +		(oper->num_children + 1) * sizeof (slang_operation));
 +	if (oper->children == NULL)
 +		return 0;
 +	slang_operation_construct (oper->children + oper->num_children);
 +	oper->num_children++;
 +	if (statement)
 +		return parse_statement (I, oper->children + oper->num_children - 1, scope, structs);
 +	return parse_expression (I, oper->children + oper->num_children - 1, scope, structs);
 +}
 +
 +static int parse_declaration (const byte **, slang_variable_scope *, slang_struct_scope *,
 +	slang_function_scope *);
 +
 +static int parse_statement (const byte **I, slang_operation *oper, slang_variable_scope *scope,
 +	slang_struct_scope *structs)
 +{
 +	oper->locals->outer_scope = scope;
 +	switch (*(*I)++)
 +	{
 +	case OP_BLOCK_BEGIN_NO_NEW_SCOPE:
 +		oper->type = slang_oper_block_no_new_scope;
 +		while (**I != OP_END)
 +			if (!parse_child_operation (I, oper, 1, scope, structs))
 +				return 0;
 +		(*I)++;
 +		break;
 +	case OP_BLOCK_BEGIN_NEW_SCOPE:
 +		oper->type = slang_oper_block_new_scope;
 +		while (**I != OP_END)
 +			if (!parse_child_operation (I, oper, 1, oper->locals, structs))
 +				return 0;
 +		(*I)++;
 +		break;
 +	case OP_DECLARE:
 +		oper->type = slang_oper_variable_decl;
 +		{
 +			const unsigned int first_var = scope->num_variables;
 +			if (!parse_declaration (I, scope, structs, NULL))
 +				return 0;
 +			if (first_var < scope->num_variables)
 +			{
 +				const unsigned int num_vars = scope->num_variables - first_var;
 +				unsigned int i;
 +				oper->children = (slang_operation *) slang_alloc_malloc (num_vars * sizeof (
 +					slang_operation));
 +				if (oper->children == NULL)
 +					return 0;
 +				for (i = 0; i < num_vars; i++)
 +					slang_operation_construct (oper->children + i);
 +				oper->num_children = num_vars;
 +				for (i = first_var; i < scope->num_variables; i++)
 +				{
 +					slang_operation *o = oper->children + i - first_var;
 +					o->type = slang_oper_identifier;
 +					o->locals->outer_scope = scope;
 +					o->identifier = slang_string_duplicate (scope->variables[i].name);
 +					if (o->identifier == NULL)
 +						return 0;
 +				}
 +			}
 +		}
 +		break;
 +	case OP_ASM:
 +		oper->type = slang_oper_asm;
 +		if (!parse_identifier (I, &oper->identifier))
 +			return 0;
 +		while (**I != OP_END)
 +			if (!parse_child_operation (I, oper, 0, scope, structs))
 +				return 0;
 +		(*I)++;
 +		break;
 +	case OP_BREAK:
 +		oper->type = slang_oper_break;
 +		break;
 +	case OP_CONTINUE:
 +		oper->type = slang_oper_continue;
 +		break;
 +	case OP_DISCARD:
 +		oper->type = slang_oper_discard;
 +		break;
 +	case OP_RETURN:
 +		oper->type = slang_oper_return;
 +		if (!parse_child_operation (I, oper, 0, scope, structs))
 +			return 0;
 +		break;
 +	case OP_EXPRESSION:
 +		oper->type = slang_oper_expression;
 +		if (!parse_child_operation (I, oper, 0, scope, structs))
 +			return 0;
 +		break;
 +	case OP_IF:
 +		oper->type = slang_oper_if;
 +		if (!parse_child_operation (I, oper, 0, scope, structs))
 +			return 0;
 +		if (!parse_child_operation (I, oper, 1, scope, structs))
 +			return 0;
 +		if (!parse_child_operation (I, oper, 1, scope, structs))
 +			return 0;
 +		break;
 +	case OP_WHILE:
 +		oper->type = slang_oper_while;
 +		if (!parse_child_operation (I, oper, 1, oper->locals, structs))
 +			return 0;
 +		if (!parse_child_operation (I, oper, 1, oper->locals, structs))
 +			return 0;
 +		break;
 +	case OP_DO:
 +		oper->type = slang_oper_do;
 +		if (!parse_child_operation (I, oper, 1, scope, structs))
 +			return 0;
 +		if (!parse_child_operation (I, oper, 0, scope, structs))
 +			return 0;
 +		break;
 +	case OP_FOR:
 +		oper->type = slang_oper_for;
 +		if (!parse_child_operation (I, oper, 1, oper->locals, structs))
 +			return 0;
 +		if (!parse_child_operation (I, oper, 1, oper->locals, structs))
 +			return 0;
 +		if (!parse_child_operation (I, oper, 0, oper->locals, structs))
 +			return 0;
 +		if (!parse_child_operation (I, oper, 1, oper->locals, structs))
 +			return 0;
 +		break;
 +	default:
 +		return 0;
 +	}
 +	return 1;
 +}
 +
 +static int handle_trinary_expression (slang_operation *op, slang_operation **ops,
 +	unsigned int *num_ops)
 +{
 +	op->num_children = 3;
 +	op->children = (slang_operation *) slang_alloc_malloc (3 * sizeof (slang_operation));
 +	if (op->children == NULL)
 +		return 0;
 +	op->children[0] = (*ops)[*num_ops - 4];
 +	op->children[1] = (*ops)[*num_ops - 3];
 +	op->children[2] = (*ops)[*num_ops - 2];
 +	(*ops)[*num_ops - 4] = (*ops)[*num_ops - 1];
 +	*num_ops -= 3;
 +	*ops = (slang_operation *) slang_alloc_realloc (*ops, (*num_ops + 3) * sizeof (slang_operation),
 +		*num_ops * sizeof (slang_operation));
 +	if (*ops == NULL)
 +		return 0;
 +	return 1;
 +}
 +
 +static int handle_binary_expression (slang_operation *op, slang_operation **ops,
 +	unsigned int *num_ops)
 +{
 +	op->num_children = 2;
 +	op->children = (slang_operation *) slang_alloc_malloc (2 * sizeof (slang_operation));
 +	if (op->children == NULL)
 +		return 0;
 +	op->children[0] = (*ops)[*num_ops - 3];
 +	op->children[1] = (*ops)[*num_ops - 2];
 +	(*ops)[*num_ops - 3] = (*ops)[*num_ops - 1];
 +	*num_ops -= 2;
 +	*ops = (slang_operation *) slang_alloc_realloc (*ops, (*num_ops + 2) * sizeof (slang_operation),
 +		*num_ops * sizeof (slang_operation));
 +	if (*ops == NULL)
 +		return 0;
 +	return 1;
 +}
 +
 +static int handle_unary_expression (slang_operation *op, slang_operation **ops, 
 +	unsigned int *num_ops)
 +{
 +	op->num_children = 1;
 +	op->children = (slang_operation *) slang_alloc_malloc (sizeof (slang_operation));
 +	if (op->children == NULL)
 +		return 0;
 +	op->children[0] = (*ops)[*num_ops - 2];
 +	(*ops)[*num_ops - 2] = (*ops)[*num_ops - 1];
 +	(*num_ops)--;
 +	*ops = (slang_operation *) slang_alloc_realloc (*ops, (*num_ops + 1) * sizeof (slang_operation),
 +		*num_ops * sizeof (slang_operation));
 +	if (*ops == NULL)
 +		return 0;
 +	return 1;
 +}
 +
 +static int parse_expression (const byte **I, slang_operation *oper, slang_variable_scope *scope,
 +	slang_struct_scope *structs)
 +{
 +	slang_operation *ops = NULL;
 +	unsigned int num_ops = 0;
 +	int number;
 +
 +	while (**I != OP_END)
 +	{
 +		slang_operation *op;
 +		const unsigned int op_code = *(*I)++;
 +		ops = (slang_operation *) slang_alloc_realloc (ops,
 +			num_ops * sizeof (slang_operation), (num_ops + 1) * sizeof (slang_operation));
 +		if (ops == NULL)
 +			return 0;
 +		op = ops + num_ops;
 +		num_ops++;
 +		slang_operation_construct (op);
 +		op->locals->outer_scope = scope;
 +		switch (op_code)
 +		{
 +		case OP_PUSH_VOID:
 +			op->type = slang_oper_void;
 +			break;
 +		case OP_PUSH_BOOL:
 +			op->type = slang_oper_literal_bool;
 +			if (!parse_number (I, &number))
 +				return 0;
 +			op->literal = (float) number;
 +			break;
 +		case OP_PUSH_INT:
 +			op->type = slang_oper_literal_int;
 +			if (!parse_number (I, &number))
 +				return 0;
 +			op->literal = (float) number;
 +			break;
 +		case OP_PUSH_FLOAT:
 +			op->type = slang_oper_literal_float;
 +			if (!parse_float (I, &op->literal))
 +				return 0;
 +			break;
 +		case OP_PUSH_IDENTIFIER:
 +			op->type = slang_oper_identifier;
 +			if (!parse_identifier (I, &op->identifier))
 +				return 0;
 +			break;
 +		case OP_SEQUENCE:
 +			op->type = slang_oper_sequence;
 +			if (!handle_binary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_ASSIGN:
 +			op->type = slang_oper_assign;
 +			if (!handle_binary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_ADDASSIGN:
 +			op->type = slang_oper_addassign;
 +			if (!handle_binary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_SUBASSIGN:
 +			op->type = slang_oper_subassign;
 +			if (!handle_binary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_MULASSIGN:
 +			op->type = slang_oper_mulassign;
 +			if (!handle_binary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_DIVASSIGN:
 +			op->type = slang_oper_divassign;
 +			if (!handle_binary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		/*case OP_MODASSIGN:*/
 +		/*case OP_LSHASSIGN:*/
 +		/*case OP_RSHASSIGN:*/
 +		/*case OP_ORASSIGN:*/
 +		/*case OP_XORASSIGN:*/
 +		/*case OP_ANDASSIGN:*/
 +		case OP_SELECT:
 +			op->type = slang_oper_select;
 +			if (!handle_trinary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_LOGICALOR:
 +			op->type = slang_oper_logicalor;
 +			if (!handle_binary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_LOGICALXOR:
 +			op->type = slang_oper_logicalxor;
 +			if (!handle_binary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_LOGICALAND:
 +			op->type = slang_oper_logicaland;
 +			if (!handle_binary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		/*case OP_BITOR:*/
 +		/*case OP_BITXOR:*/
 +		/*case OP_BITAND:*/
 +		case OP_EQUAL:
 +			op->type = slang_oper_equal;
 +			if (!handle_binary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_NOTEQUAL:
 +			op->type = slang_oper_notequal;
 +			if (!handle_binary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_LESS:
 +			op->type = slang_oper_less;
 +			if (!handle_binary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_GREATER:
 +			op->type = slang_oper_greater;
 +			if (!handle_binary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_LESSEQUAL:
 +			op->type = slang_oper_lessequal;
 +			if (!handle_binary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_GREATEREQUAL:
 +			op->type = slang_oper_greaterequal;
 +			if (!handle_binary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		/*case OP_LSHIFT:*/
 +		/*case OP_RSHIFT:*/
 +		case OP_ADD:
 +			op->type = slang_oper_add;
 +			if (!handle_binary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_SUBTRACT:
 +			op->type = slang_oper_subtract;
 +			if (!handle_binary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_MULTIPLY:
 +			op->type = slang_oper_multiply;
 +			if (!handle_binary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_DIVIDE:
 +			op->type = slang_oper_divide;
 +			if (!handle_binary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		/*case OP_MODULUS:*/
 +		case OP_PREINCREMENT:
 +			op->type = slang_oper_preincrement;
 +			if (!handle_unary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_PREDECREMENT:
 +			op->type = slang_oper_predecrement;
 +			if (!handle_unary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_PLUS:
 +			op->type = slang_oper_plus;
 +			if (!handle_unary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_MINUS:
 +			op->type = slang_oper_minus;
 +			if (!handle_unary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_NOT:
 +			op->type = slang_oper_not;
 +			if (!handle_unary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		/*case OP_COMPLEMENT:*/
 +		case OP_SUBSCRIPT:
 +			op->type = slang_oper_subscript;
 +			if (!handle_binary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_CALL:
 +			op->type = slang_oper_call;
 +			if (!parse_identifier (I, &op->identifier))
 +				return 0;
 +			while (**I != OP_END)
 +				if (!parse_child_operation (I, op, 0, scope, structs))
 +					return 0;
 +			(*I)++;
 +			break;
 +		case OP_FIELD:
 +			op->type = slang_oper_field;
 +			if (!parse_identifier (I, &op->identifier))
 +				return 0;
 +			if (!handle_unary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_POSTINCREMENT:
 +			op->type = slang_oper_postincrement;
 +			if (!handle_unary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		case OP_POSTDECREMENT:
 +			op->type = slang_oper_postdecrement;
 +			if (!handle_unary_expression (op, &ops, &num_ops))
 +				return 0;
 +			break;
 +		default:
 +			return 0;
 +		}
 +	}
 +	(*I)++;
 +	*oper = *ops;
 +	slang_alloc_free (ops);
 +	return 1;
 +}
 +
 +/* parameter qualifier */
 +#define PARAM_QUALIFIER_IN 0
 +#define PARAM_QUALIFIER_OUT 1
 +#define PARAM_QUALIFIER_INOUT 2
 +
 +/* function parameter array presence */
 +#define PARAMETER_ARRAY_NOT_PRESENT 0
 +#define PARAMETER_ARRAY_PRESENT 1
 +
 +static int parse_parameter_declaration (const byte **I, slang_variable *param,
 +	slang_struct_scope *structs, slang_variable_scope *scope)
 +{
 +	if (!parse_type_qualifier (I, ¶m->type.qualifier))
 +		return 0;
 +	switch (*(*I)++)
 +	{
 +	case PARAM_QUALIFIER_IN:
 +		if (param->type.qualifier != slang_qual_const && param->type.qualifier != slang_qual_none)
 +			return 0;	/* error: type qualifier is invalid */
 +		break;
 +	case PARAM_QUALIFIER_OUT:
 +		if (param->type.qualifier == slang_qual_none)
 +			param->type.qualifier = slang_qual_out;
 +		else
 +			return 0;	/* error: type qualifier is invalid */
 +		break;
 +	case PARAM_QUALIFIER_INOUT:
 +		if (param->type.qualifier == slang_qual_none)
 +			param->type.qualifier = slang_qual_inout;
 +		else
 +			return 0;	/* error: type qualifier is invalid */
 +		break;
 +	default:
 +		return 0;
 +	}
 +	if (!parse_type_specifier (I, ¶m->type.specifier, structs, scope))
 +		return 0;
 +	if (!parse_identifier (I, ¶m->name))
 +		return 0;
 +	if (*(*I)++ == PARAMETER_ARRAY_PRESENT)
 +	{
 +		param->array_size = (slang_operation *) slang_alloc_malloc (sizeof (slang_operation));
 +		slang_operation_construct (param->array_size);
 +		if (!parse_expression (I, param->array_size, scope, structs))
 +			return 0;
 +	}
 +	return 1;
 +}
 +
 +/* function type */
 +#define FUNCTION_ORDINARY 0
 +#define FUNCTION_CONSTRUCTOR 1
 +#define FUNCTION_OPERATOR 2
 +
 +/* function parameter */
 +#define PARAMETER_NONE 0
 +#define PARAMETER_NEXT 1
 +
 +/* operator type */
 +#define OPERATOR_ASSIGN 1
 +#define OPERATOR_ADDASSIGN 2
 +#define OPERATOR_SUBASSIGN 3
 +#define OPERATOR_MULASSIGN 4
 +#define OPERATOR_DIVASSIGN 5
 +/*#define OPERATOR_MODASSIGN 6*/
 +/*#define OPERATOR_LSHASSIGN 7*/
 +/*#define OPERATOR_RSHASSIGN 8*/
 +/*#define OPERATOR_ANDASSIGN 9*/
 +/*#define OPERATOR_XORASSIGN 10*/
 +/*#define OPERATOR_ORASSIGN 11*/
 +#define OPERATOR_LOGICALXOR 12
 +/*#define OPERATOR_BITOR 13*/
 +/*#define OPERATOR_BITXOR 14*/
 +/*#define OPERATOR_BITAND 15*/
 +#define OPERATOR_EQUAL 16
 +#define OPERATOR_NOTEQUAL 17
 +#define OPERATOR_LESS 18
 +#define OPERATOR_GREATER 19
 +#define OPERATOR_LESSEQUAL 20
 +#define OPERATOR_GREATEREQUAL 21
 +/*#define OPERATOR_LSHIFT 22*/
 +/*#define OPERATOR_RSHIFT 23*/
 +#define OPERATOR_MULTIPLY 24
 +#define OPERATOR_DIVIDE 25
 +/*#define OPERATOR_MODULUS 26*/
 +#define OPERATOR_INCREMENT 27
 +#define OPERATOR_DECREMENT 28
 +#define OPERATOR_PLUS 29
 +#define OPERATOR_MINUS 30
 +/*#define OPERATOR_COMPLEMENT 31*/
 +#define OPERATOR_NOT 32
 +
 +/* these must match with slang_type_specifier_type enum */
 +static const char *type_specifier_names[] = {
 +	"void",
 +	"bool",
 +	"bvec2",
 +	"bvec3",
 +	"bvec4",
 +	"int",
 +	"ivec2",
 +	"ivec3",
 +	"ivec4",
 +	"float",
 +	"vec2",
 +	"vec3",
 +	"vec4",
 +	"mat2",
 +	"mat3",
 +	"mat4",
 +	"sampler1D",
 +	"sampler2D",
 +	"sampler3D",
 +	"samplerCube",
 +	"sampler1DShadow",
 +	"sampler2DShadow"
 +};
 +
 +static const struct {
 +	unsigned int o_code;
 +	const char *o_name;
 +} operator_names[] = {
 +	{ OPERATOR_INCREMENT, "++" },
 +	{ OPERATOR_ADDASSIGN, "+=" },
 +	{ OPERATOR_PLUS, "+" },
 +	{ OPERATOR_DECREMENT, "--" },
 +	{ OPERATOR_SUBASSIGN, "-=" },
 +	{ OPERATOR_MINUS, "-" },
 +	{ OPERATOR_NOTEQUAL, "!=" },
 +	{ OPERATOR_NOT, "!" },
 +	{ OPERATOR_MULASSIGN, "*=" },
 +	{ OPERATOR_MULTIPLY, "*" },
 +	{ OPERATOR_DIVASSIGN, "/=" },
 +	{ OPERATOR_DIVIDE, "/" },
 +	{ OPERATOR_LESSEQUAL, "<=" },
 +	/*{ OPERATOR_LSHASSIGN, "<<=" },*/
 +	/*{ OPERATOR_LSHIFT, "<<" },*/
 +	{ OPERATOR_LESS, "<" },
 +	{ OPERATOR_GREATEREQUAL, ">=" },
 +	/*{ OPERATOR_RSHASSIGN, ">>=" },*/
 +	/*{ OPERATOR_RSHIFT, ">>" },*/
 +	{ OPERATOR_GREATER, ">" },
 +	{ OPERATOR_EQUAL, "==" },
 +	{ OPERATOR_ASSIGN, "=" },
 +	/*{ OPERATOR_MODASSIGN, "%=" },*/
 +	/*{ OPERATOR_MODULUS, "%" },*/
 +	/*{ OPERATOR_ANDASSIGN, "&=" },*/
 +	/*{ OPERATOR_BITAND, "&" },*/
 +	/*{ OPERATOR_ORASSIGN, "|=" },*/
 +	/*{ OPERATOR_BITOR, "|" },*/
 +	/*{ OPERATOR_COMPLEMENT, "~" },*/
 +	/*{ OPERATOR_XORASSIGN, "^=" },*/
 +	{ OPERATOR_LOGICALXOR, "^^" }/*,*/
 +	/*{ OPERATOR_BITXOR, "^" }*/
 +};
 +
 +static int parse_operator_name (const byte **I, char **pname)
 +{
 +	unsigned int i;
 +	for (i = 0; i < sizeof (operator_names) / sizeof (*operator_names); i++)
 +		if (operator_names[i].o_code == (unsigned int) (**I))
 +		{
 +			*pname = slang_string_duplicate (operator_names[i].o_name);
 +			if (*pname == NULL)
 +				return 0;
 +			(*I)++;
 +			return 1;
 +		}
 +	return 0;
 +}
 +
 +static int parse_function_prototype (const byte **I, slang_function *func,
 +	slang_struct_scope *structs, slang_variable_scope *scope)
 +{
 +	if (!parse_fully_specified_type (I, &func->header.type, structs, scope))
 +		return 0;
 +	switch (*(*I)++)
 +	{
 +	case FUNCTION_ORDINARY:
 +		func->kind = slang_func_ordinary;
 +		if (!parse_identifier (I, &func->header.name))
 +			return 0;
 +		break;
 +	case FUNCTION_CONSTRUCTOR:
 +		func->kind = slang_func_constructor;
 +		if (func->header.type.specifier.type == slang_spec_struct)
 +			return 0;
 +		func->header.name = slang_string_duplicate (
 +			type_specifier_names[func->header.type.specifier.type]);
 +		if (func->header.name == NULL)
 +			return 0;
 +		break;
 +	case FUNCTION_OPERATOR:
 +		func->kind = slang_func_operator;
 +		if (!parse_operator_name (I, &func->header.name))
 +			return 0;
 +		break;
 +	default:
 +		return 0;
 +	}
 +	func->parameters->outer_scope = scope;
 +	while (*(*I)++ == PARAMETER_NEXT)
 +	{
 +		func->parameters->variables = (slang_variable *) slang_alloc_realloc (
 +			func->parameters->variables,
 +			func->parameters->num_variables * sizeof (slang_variable),
 +			(func->parameters->num_variables + 1) * sizeof (slang_variable));
 +		if (func->parameters->variables == NULL)
 +			return 0;
 +		slang_variable_construct (func->parameters->variables + func->parameters->num_variables);
 +		func->parameters->num_variables++;
 +		if (!parse_parameter_declaration (I, func->parameters->variables +
 +			func->parameters->num_variables - 1, structs, scope))
 +			return 0;
 +	}
 +	func->param_count = func->parameters->num_variables;
 +	return 1;
 +}
 +
 +static int parse_function_definition (const byte **I, slang_function *func,
 +	slang_struct_scope *structs, slang_variable_scope *scope)
 +{
 +	if (!parse_function_prototype (I, func, structs, scope))
 +		return 0;
 +	func->body = (slang_operation *) slang_alloc_malloc (sizeof (slang_operation));
 +	if (func->body == NULL)
 +		return 0;
 +	slang_operation_construct (func->body);
 +	if (!parse_statement (I, func->body, func->parameters, structs))
 +		return 0;
 +	return 1;
 +}
 +
 +/* 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
 +
 +static int parse_init_declarator (const byte **I, const slang_fully_specified_type *type,
 +	slang_variable_scope *vars, slang_struct_scope *structs)
 +{
 +	slang_variable *var;
 +
 +	if (*(*I)++ == VARIABLE_NONE)
 +		return 1;
 +	vars->variables = (slang_variable *) slang_alloc_realloc (vars->variables,
 +		vars->num_variables * sizeof (slang_variable),
 +		(vars->num_variables + 1) * sizeof (slang_variable));
 +	if (vars->variables == NULL)
 +		return 0;
 +	var = vars->variables + vars->num_variables;
 +	vars->num_variables++;
 +	slang_variable_construct (var);
 +	var->type.qualifier = type->qualifier;
 +	if (!parse_identifier (I, &var->name))
 +		return 0;
 +	switch (*(*I)++)
 +	{
 +	case VARIABLE_NONE:
 +		if (!slang_type_specifier_copy (&var->type.specifier, &type->specifier))
 +			return 0;
 +		break;
 +	case VARIABLE_INITIALIZER:
 +		if (!slang_type_specifier_copy (&var->type.specifier, &type->specifier))
 +			return 0;
 +		var->initializer = (slang_operation *) slang_alloc_malloc (sizeof (slang_operation));
 +		if (var->initializer == NULL)
 +			return 0;
 +		slang_operation_construct (var->initializer);
 +		if (!parse_expression (I, var->initializer, vars, structs))
 +			return 0;
 +		break;
 +	case VARIABLE_ARRAY_UNKNOWN:
 +		var->type.specifier.type = slang_spec_array;
 +		var->type.specifier._array = (slang_type_specifier *) slang_alloc_malloc (sizeof (
 +			slang_type_specifier));
 +		if (var->type.specifier._array == NULL)
 +			return 0;
 +		slang_type_specifier_construct (var->type.specifier._array);
 +		if (!slang_type_specifier_copy (var->type.specifier._array, &type->specifier))
 +			return 0;
 +		break;
 +	case VARIABLE_ARRAY_EXPLICIT:
 +		var->type.specifier.type = slang_spec_array;
 +		var->type.specifier._array = (slang_type_specifier *) slang_alloc_malloc (sizeof (
 +			slang_type_specifier));
 +		if (var->type.specifier._array == NULL)
 +			return 0;
 +		slang_type_specifier_construct (var->type.specifier._array);
 +		if (!slang_type_specifier_copy (var->type.specifier._array, &type->specifier))
 +			return 0;
 +		var->array_size = (slang_operation *) slang_alloc_malloc (sizeof (slang_operation));
 +		if (var->array_size == NULL)
 +			return 0;
 +		slang_operation_construct (var->array_size);
 +		if (!parse_expression (I, var->array_size, vars, structs))
 +			return 0;
 +		break;
 +	default:
 +		return 0;
 +	}
 +	return 1;
 +}
 +
 +static int parse_init_declarator_list (const byte **I, slang_variable_scope *vars,
 +	slang_struct_scope *structs)
 +{
 +	slang_fully_specified_type type;
 +
 +	slang_fully_specified_type_construct (&type);
 +	if (!parse_fully_specified_type (I, &type, structs, vars))
 +	{
 +		slang_fully_specified_type_destruct (&type);
 +		return 0;
 +	}
 +	do
 +	{
 +		if (!parse_init_declarator (I, &type, vars, structs))
 +		{
 +			slang_fully_specified_type_destruct (&type);
 +			return 0;
 +		}
 +	}
 +	while (*(*I)++ == DECLARATOR_NEXT);
 +	slang_fully_specified_type_destruct (&type);
 +	return 1;
 +}
 +
 +static int parse_function (const byte **I, int definition, slang_struct_scope *structs,
 +	slang_function_scope *funcs, slang_variable_scope *scope)
 +{
 +	slang_function parsed_func, *found_func;
 +
 +	slang_function_construct (&parsed_func);
 +	if (definition)
 +	{
 +		if (!parse_function_definition (I, &parsed_func, structs, scope))
 +		{
 +			slang_function_destruct (&parsed_func);
 +			return 0;
 +		}
 +	}
 +	else
 +	{
 +		if (!parse_function_prototype (I, &parsed_func, structs, scope))
 +		{
 +			slang_function_destruct (&parsed_func);
 +			return 0;
 +		}
 +	}
 +	found_func = slang_function_scope_find (funcs, &parsed_func, 0);
 +	if (found_func == NULL)
 +	{
 +		funcs->functions = (slang_function *) slang_alloc_realloc (funcs->functions,
 +			funcs->num_functions * sizeof (slang_function), (funcs->num_functions + 1) * sizeof (
 +			slang_function));
 +		if (funcs->functions == NULL)
 +		{
 +			slang_function_destruct (&parsed_func);
 +			return 0;
 +		}
 +		funcs->functions[funcs->num_functions] = parsed_func;
 +		funcs->num_functions++;
 +	}
 +	else
 +	{
 +		/* TODO check function return type qualifiers and specifiers */
 +		if (definition)
 +		{
 +			if (found_func->body != NULL)
 +			{
 +				slang_function_destruct (&parsed_func);
 +				return 0;		/* error: second definition */
 +			}
 +			slang_function_destruct (found_func);
 +			*found_func = parsed_func;
 +		}
 +		else
 +		{
 +			slang_function_destruct (&parsed_func);
 +		}
 +	}
 +	return 1;
 +}
 +
 +/* declaration */
 +#define DECLARATION_FUNCTION_PROTOTYPE 1
 +#define DECLARATION_INIT_DECLARATOR_LIST 2
 +
 +static int parse_declaration (const byte **I, slang_variable_scope *scope,
 +	slang_struct_scope *structs, slang_function_scope *funcs)
 +{
 +	switch (*(*I)++)
 +	{
 +	case DECLARATION_INIT_DECLARATOR_LIST:
 +		if (!parse_init_declarator_list (I, scope, structs))
 +			return 0;
 +		break;
 +	case DECLARATION_FUNCTION_PROTOTYPE:
 +		if (!parse_function (I, 0, structs, funcs, scope))
 +			return 0;
 +		break;
 +	default:
 +		return 0;
 +	}
 +	return 1;
 +}
 +
 +/* external declaration */
 +#define EXTERNAL_NULL 0
 +#define EXTERNAL_FUNCTION_DEFINITION 1
 +#define EXTERNAL_DECLARATION 2
 +
 +static int parse_translation_unit (const byte **I, slang_translation_unit *unit)
 +{
 +	while (**I != EXTERNAL_NULL)
 +	{
 +		switch (*(*I)++)
 +		{
 +		case EXTERNAL_FUNCTION_DEFINITION:
 +			if (!parse_function (I, 1, unit->structs, &unit->functions, unit->globals))
 +				return 0;
 +			break;
 +		case EXTERNAL_DECLARATION:
 +			if (!parse_declaration (I, unit->globals, unit->structs, &unit->functions))
 +				return 0;
 +			break;
 +		default:
 +			return 0;
 +		}
 +	}
 +	(*I)++;
 +	return 1;
 +}
 +
 +static int compile_with_grammar (grammar id, const char *source, slang_translation_unit *unit,
 +	slang_unit_type type)
 +{
 +	byte *prod, *I;
 +	unsigned int size;
 +
 +	slang_translation_unit_construct (unit);
 +	unit->type = type;
 +	if (!grammar_fast_check (id, (const byte *) source, &prod, &size, 65536))
 +		return 0;
 +	I = prod;
 +	if (!check_revision (&I))
 +	{
 +		grammar_alloc_free (prod);
 +		return 0;
 +	}
 +	if (!parse_translation_unit (&I, unit))
 +	{
 +		slang_translation_unit_destruct (unit);
 +		grammar_alloc_free (prod);
 +		return 0;
 +	}
 +	grammar_alloc_free (prod);
 +	return 1;
 +}
 +
 +static const char *slang_shader_syn =
 +#include "library/slang_shader_syn.h"
 +;
 +
 +int _slang_compile (const char *source, slang_translation_unit *unit, slang_unit_type type)
 +{
 +	grammar id;
 +
 +	id = grammar_load_from_text ((const byte *) slang_shader_syn);
 +	if (id == 0)
 +		return 0;
 +
 +	grammar_set_reg8 (id, (const byte *) "parsing_builtin", 1);
 +	if (type == slang_unit_fragment_shader)
 +		grammar_set_reg8 (id, (const byte *) "shader_type", 1);
 +	else
 +		grammar_set_reg8 (id, (const byte *) "shader_type", 2);
 +
 +	if (!compile_with_grammar (id, source, unit, type))
 +	{
 +		grammar_destroy (id);
 +		return 0;
 +	}
 +
 +	grammar_destroy (id);
 +	return 1;
 +}
 +
 diff --git a/src/mesa/shader/slang/slang_compile.h b/src/mesa/shader/slang/slang_compile.h new file mode 100644 index 0000000000..0f49df747f --- /dev/null +++ b/src/mesa/shader/slang/slang_compile.h @@ -0,0 +1,235 @@ +/*
 + * Mesa 3-D graphics library
 + * Version:  6.3
 + *
 + * Copyright (C) 2005  Brian Paul   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, sublicense,
 + * 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 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 NONINFRINGEMENT.  IN NO EVENT SHALL
 + * BRIAN PAUL 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.
 + */
 +
 +#if !defined SLANG_COMPILE_H
 +#define SLANG_COMPILE_H
 +
 +#if defined __cplusplus
 +extern "C" {
 +#endif
 +
 +typedef enum slang_type_qualifier_
 +{
 +	slang_qual_none,
 +	slang_qual_const,
 +	slang_qual_attribute,
 +	slang_qual_varying,
 +	slang_qual_uniform,
 +	slang_qual_out,
 +	slang_qual_inout,
 +	slang_qual_fixedoutput,	/* internal */
 +	slang_qual_fixedinput	/* internal */
 +} slang_type_qualifier;
 +
 +typedef enum slang_type_specifier_type_
 +{
 +	slang_spec_void,
 +	slang_spec_bool,
 +	slang_spec_bvec2,
 +	slang_spec_bvec3,
 +	slang_spec_bvec4,
 +	slang_spec_int,
 +	slang_spec_ivec2,
 +	slang_spec_ivec3,
 +	slang_spec_ivec4,
 +	slang_spec_float,
 +	slang_spec_vec2,
 +	slang_spec_vec3,
 +	slang_spec_vec4,
 +	slang_spec_mat2,
 +	slang_spec_mat3,
 +	slang_spec_mat4,
 +	slang_spec_sampler1D,
 +	slang_spec_sampler2D,
 +	slang_spec_sampler3D,
 +	slang_spec_samplerCube,
 +	slang_spec_sampler1DShadow,
 +	slang_spec_sampler2DShadow,
 +	slang_spec_struct,
 +	slang_spec_array
 +} slang_type_specifier_type;
 +
 +typedef struct slang_type_specifier_
 +{
 +	slang_type_specifier_type type;
 +	struct slang_struct_ *_struct;		/* spec_struct */
 +	struct slang_type_specifier_ *_array;	/* spec_array */
 +} slang_type_specifier;
 +
 +typedef struct slang_fully_specified_type_
 +{
 +	slang_type_qualifier qualifier;
 +	slang_type_specifier specifier;
 +} slang_fully_specified_type;
 +
 +typedef struct slang_variable_scope_
 +{
 +	struct slang_variable_ *variables;
 +	unsigned int num_variables;
 +	struct slang_variable_scope_ *outer_scope;
 +} slang_variable_scope;
 +
 +typedef enum slang_operation_type_
 +{
 +	slang_oper_none,
 +	slang_oper_block_no_new_scope,
 +	slang_oper_block_new_scope,
 +	slang_oper_variable_decl,
 +	slang_oper_asm,
 +	slang_oper_break,
 +	slang_oper_continue,
 +	slang_oper_discard,
 +	slang_oper_return,
 +	slang_oper_expression,
 +	slang_oper_if,
 +	slang_oper_while,
 +	slang_oper_do,
 +	slang_oper_for,
 +	slang_oper_void,
 +	slang_oper_literal_bool,
 +	slang_oper_literal_int,
 +	slang_oper_literal_float,
 +	slang_oper_identifier,
 +	slang_oper_sequence,
 +	slang_oper_assign,
 +	slang_oper_addassign,
 +	slang_oper_subassign,
 +	slang_oper_mulassign,
 +	slang_oper_divassign,
 +	/*slang_oper_modassign,*/
 +	/*slang_oper_lshassign,*/
 +	/*slang_oper_rshassign,*/
 +	/*slang_oper_orassign,*/
 +	/*slang_oper_xorassign,*/
 +	/*slang_oper_andassign,*/
 +	slang_oper_select,
 +	slang_oper_logicalor,
 +	slang_oper_logicalxor,
 +	slang_oper_logicaland,
 +	/*slang_oper_bitor,*/
 +	/*slang_oper_bitxor,*/
 +	/*slang_oper_bitand,*/
 +	slang_oper_equal,
 +	slang_oper_notequal,
 +	slang_oper_less,
 +	slang_oper_greater,
 +	slang_oper_lessequal,
 +	slang_oper_greaterequal,
 +	/*slang_oper_lshift,*/
 +	/*slang_oper_rshift,*/
 +	slang_oper_add,
 +	slang_oper_subtract,
 +	slang_oper_multiply,
 +	slang_oper_divide,
 +	/*slang_oper_modulus,*/
 +	slang_oper_preincrement,
 +	slang_oper_predecrement,
 +	slang_oper_plus,
 +	slang_oper_minus,
 +	/*slang_oper_complement,*/
 +	slang_oper_not,
 +	slang_oper_subscript,
 +	slang_oper_call,
 +	slang_oper_field,
 +	slang_oper_postincrement,
 +	slang_oper_postdecrement
 +} slang_operation_type;
 +
 +typedef struct slang_operation_
 +{
 +	slang_operation_type type;
 +	struct slang_operation_ *children;
 +	unsigned int num_children;
 +	float literal;		/* bool, literal_int, literal_float */
 +	char *identifier;	/* asm, identifier, call, field */
 +	slang_variable_scope *locals;
 +} slang_operation;
 +
 +typedef struct slang_variable_
 +{
 +	slang_fully_specified_type type;
 +	char *name;
 +	slang_operation *array_size;	/* spec_array */
 +	slang_operation *initializer;
 +} slang_variable;
 +
 +typedef struct slang_struct_scope_
 +{
 +	struct slang_struct_ *structs;
 +	unsigned int num_structs;
 +	struct slang_struct_scope_ *outer_scope;
 +} slang_struct_scope;
 +
 +typedef struct slang_struct_
 +{
 +	char *name;
 +	slang_variable_scope *fields;
 +	slang_struct_scope *structs;
 +} slang_struct;
 +
 +typedef enum slang_function_kind_
 +{
 +	slang_func_ordinary,
 +	slang_func_constructor,
 +	slang_func_operator
 +} slang_function_kind;
 +
 +typedef struct slang_function_
 +{
 +	slang_function_kind kind;
 +	slang_variable header;
 +	slang_variable_scope *parameters;
 +	unsigned int param_count;
 +	slang_operation *body;
 +} slang_function;
 +
 +typedef struct slang_function_scope_
 +{
 +	slang_function *functions;
 +	unsigned int num_functions;
 +	struct slang_function_scope_ *outer_scope;
 +} slang_function_scope;
 +
 +typedef enum slang_unit_type_
 +{
 +	slang_unit_fragment_shader,
 +	slang_unit_vertex_shader
 +} slang_unit_type;
 +	
 +typedef struct slang_translation_unit_
 +{
 +	slang_variable_scope *globals;
 +	slang_function_scope functions;
 +	slang_struct_scope *structs;
 +	slang_unit_type type;
 +} slang_translation_unit;
 +
 +int _slang_compile (const char *, slang_translation_unit *, slang_unit_type type);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif
 +
  | 
