diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/mesa/main/arbparse.c | 5717 | ||||
| -rw-r--r-- | src/mesa/main/arbparse.h | 83 | ||||
| -rw-r--r-- | src/mesa/main/arbparse_syn.h | 1219 | ||||
| -rw-r--r-- | src/mesa/swrast/s_nvfragprog.c | 14 | 
4 files changed, 7029 insertions, 4 deletions
| diff --git a/src/mesa/main/arbparse.c b/src/mesa/main/arbparse.c new file mode 100644 index 0000000000..33b31db590 --- /dev/null +++ b/src/mesa/main/arbparse.c @@ -0,0 +1,5717 @@ +/* + * Mesa 3-D graphics library + * Version:  5.1 + * + * Copyright (C) 1999-2003  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. + */ + +#define DEBUG_PARSING 0 + +/** + * \file arbparse.c + * ARB_*_program parser core + * \author Michal Krol, Karl Rasche + */ + + +#include "mtypes.h" +#include "glheader.h" +#include "context.h" +#include "hash.h" +#include "imports.h" +#include "macros.h" +#include "program.h" +#include "nvvertprog.h" +#include "nvfragprog.h" +#include "arbparse.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* TODO: + *    Fragment Program Stuff: + *    ----------------------------------------------------- + *    - How does negating on SWZ work?? If any of the components have a -, negate? + *    - how does thing like 'foo[N]' work in src registers? + * + *    - things from Michal's email + *       + overflow on atoi + *       + not-overflowing floats (don't use parse_integer..) + * + *       + fix multiple cases in switches, that might change  + *          (these are things that are #defined to the same value, but occur  + *           only on fp or vp's, which funkifies the switch statements) + *          - STATE_TEX_* STATE_CLIP_PLANE, etc and PRECISION_HINT_FASTEST/PositionInvariant + *           + *    - check all limits of number of various variables + *      + parameters + *      + modelview matrix number + * + *    - test! test! test!     + * + *    Vertex Program Stuff: + *    ----------------------------------------------------- + *    - Add in cases for vp attribs + *       + VERTEX_ATTRIB_MATRIXINDEX -- ?? + *       + VERTEX_ATTRIB_GENERIC + *          * Test for input alias error --> bleh! + * + *    - ARRAY_INDEX_RELATIVE + *    - grep for XXX + *     + *    Mesa Stuff + *    ----------------------------------------------------- + *    - vp_src swizzle is GLubyte, fp_src swizzle is GLuint + *    - fetch state listed in program_parameters list + *       + WTF should this go??? + *       + currently in nvvertexec.c and s_nvfragprog.c  + * + *    - allow for multiple address registers (and fetch address regs properly) + * + *    Cosmetic Stuff + *    ----------------------------------------------------- + *      - fix compiler warnings  + * 	- remove any leftover unused grammer.c stuff (dict_ ?) + * 	- fix grammer.c error handling so its not static + * 	- #ifdef around stuff pertaining to extentions + * + *    Outstanding Questions: + *    ----------------------------------------------------- + *    - palette matrix?  do we support this extension? what is the extention? + *    - When can we fetch env/local params from their own register files, and when + *        to we have to fetch them into the main state register file? (think arrays) + * + *    Grammar Changes: + *    ----------------------------------------------------- + *    - changed optional_exponent rule from: + *         " exponent .or .true .emit '1' .emit 0x00;\n" + *      to + *         " exponent .or .true .emit '1' .emit 0x00 .emit $;\n" + * + *    - XXX: need to recognize "1" as a valid float ? + */ + +typedef unsigned char byte; +typedef byte *production; + +/*----------------------------------------------------------------------- + * From here on down is the syntax checking portion  + */ + +/* VERSION: 0.3 */ + +/* +	INTRODUCTION +	------------ + +	The task is to check the syntax of an input string. Input string is a stream of ASCII +	characters terminated with null-character ('\0'). Checking it using C language is +	difficult and hard to implement without bugs. It is hard to maintain and change prior +	to further syntax changes. + +	This is because of high redundancy of the C code. Large blocks of code are duplicated with +	only small changes. Even using macros does not solve the problem, because macros cannot +	erase the complexity of the code. + +	The resolution is to create a new language that will be highly oriented to our task. Once +	we describe particular syntax, we are done. We can then focus on the code that implements +	the language. The size and complexity of it is relatively small than the code that directly +	checks the syntax. + +	First, we must implement our new language. Here, the language is implemented in C, but it +	could also be implemented in any other language. The code is listed below. We must take +	a good care that it is bug free. This is simple because the code is simple and clean. + +	Next, we must describe the syntax of our new language in itself. Once created and checked +	manually that it is correct, we can use it to check another scripts. + +	Note that our new language loading code does not have to check the syntax. It is because we +	assume that the script describing itself is correct, and other scripts can be syntactically +	checked by the former script. The loading code must only do semantic checking which leads us to +	simple resolving references. + +	THE LANGUAGE +	------------ + +	Here I will describe the syntax of the new language (further called "Synek"). It is mainly a +	sequence of declarations terminated by a semicolon. The declaration consists of a symbol, +	which is an identifier, and its definition. A definition is in turn a sequence of specifiers +	connected with ".and" or ".or" operator. These operators cannot be mixed together in a one +	definition. Specifier can be a symbol, string, character, character range or a special +	keyword ".true" or ".false". + +	On the very beginning of the script there is a declaration of a root symbol and is in the form: +		.syntax <root_symbol>; +	The <root_symbol> must be on of the symbols in declaration sequence. The syntax is correct if +	the root symbol evaluates to true. A symbol evaluates to true if the definition associated with +	the symbol evaluates to true. Definition evaluation depends on the operator used to connect +	specifiers in the definition. If ".and" operator is used, definition evaluates to true if and +	only if all the specifiers evaluate to true. If ".or" operator is used, definition evalutes to +	true if any of the specifiers evaluates to true. If definition contains only one specifier, +	it is evaluated as if it was connected with ".true" keyword by ".and" operator. + +	If specifier is a ".true" keyword, it always evaluates to true. + +	If specifier is a ".false" keyword, it always evaluates to false. Specifier evaluates to false +	when it does not evaluate to true. + +	Character range specifier is in the form: +		'<first_character>' - '<second_character>' +	If specifier is a character range, it evaluates to true if character in the stream is greater +	or equal to <first_character> and less or equal to <second_character>. In that situation  +	the stream pointer is advanced to point to next character in the stream. All C-style escape +	sequences are supported although trigraph sequences are not. The comparisions are performed +	on 8-bit unsigned integers. + +	Character specifier is in the form: +		'<single_character>' +	It evaluates to true if the following character range specifier evaluates to true: +		'<single_character>' - '<single_character>' + +	String specifier is in the form: +		"<string>" +	Let N be the number of characters in <string>. Let <string>[i] designate i-th character in +	<string>. Then the string specifier evaluates to true if and only if for i in the range [0, N) +	the following character specifier evaluates to true: +		'<string>[i]' +	If <string>[i] is a quotation mark, '<string>[i]' is replaced with '\<string>[i]'. + +	Symbol specifier can be optionally preceded by a ".loop" keyword in the form: +		.loop <symbol>					(1) +	where <symbol> is defined as follows: +		<symbol> <definition>;			(2) +	Construction (1) is replaced by the following code: +		<symbol$1> +	and declaration (2) is replaced by the following: +		<symbol$1> <symbol$2> .or .true; +		<symbol$2> <symbol> .and <symbol$1>; +		<symbol> <definition>; + +	ESCAPE SEQUENCES +	---------------- + +	Synek supports all escape sequences in character specifiers. The mapping table is listed below. +	All occurences of the characters in the first column are replaced with the corresponding +	character in the second column. + +		Escape sequence			Represents +	------------------------------------------------------------------------------------------------ +		\a						Bell (alert) +		\b						Backspace +		\f						Formfeed +		\n						New line +		\r						Carriage return +		\t						Horizontal tab +		\v						Vertical tab +		\'						Single quotation mark +		\"						Double quotation mark +		\\						Backslash +		\?						Literal question mark +		\ooo					ASCII character in octal notation +		\xhhh					ASCII character in hexadecimal notation +	------------------------------------------------------------------------------------------------ + +	RAISING ERRORS +	-------------- + +	Any specifier can be followed by a special construction that is executed when the specifier +	evaluates to false. The construction is in the form: +		.error <ERROR_TEXT> +	<ERROR_TEXT> is an identifier declared earlier by error text declaration. The declaration is +	in the form: +		.errtext <ERROR_TEXT> "<error_desc>" +	When specifier evaluates to false and this construction is present, parsing is stopped +	immediately and <error_desc> is returned as a result of parsing. The error position is also +	returned and it is meant as an offset from the beggining of the stream to the character that +	was valid so far. Example: + +		(**** syntax script ****) + +		.syntax program; +		.errtext MISSING_SEMICOLON		"missing ';'" +		program			declaration .and .loop space .and ';' .error MISSING_SEMICOLON .and +						.loop space .and '\0'; +		declaration		"declare" .and .loop space .and identifier; +		space			' '; + +		(**** sample code ****) + +		declare foo , + +	In the example above checking the sample code will result in error message "missing ';'" and +	error position 12. The sample code is not correct. Note the presence of '\0' specifier to +	assure that there is no code after semicolon - only spaces. +	<error_desc> can optionally contain identifier surrounded by dollar signs $. In such a case, +	the identifier and dollar signs are replaced by a string retrieved by invoking symbol with +	the identifier name. The starting position is the error position. The lenght of the resulting +	string is the position after invoking the symbol. + +	PRODUCTION +	---------- + +	Synek not only checks the syntax but it can also produce (emit) bytes associated with specifiers +	that evaluate to true. That is, every specifier and optional error construction can be followed +	by a number of emit constructions that are in the form: +		.emit <parameter> +	<paramater> can be a HEX number, identifier, a star * or a dollar $. HEX number is preceded by +    0x or 0X. If <parameter> is an identifier, it must be earlier declared by emit code declaration +    in the form: +		.emtcode <identifier> <hex_number> + +	When given specifier evaluates to true, all emits associated with the specifier are output +	in order they were declared. A star means that last-read character should be output instead +	of constant value. Example: + +		(**** syntax script ****) + +		.syntax foobar; +		.emtcode WORD_FOO		0x01 +		.emtcode WORD_BAR		0x02 +		foobar		FOO .emit WORD_FOO .or BAR .emit WORD_BAR .or .true .emit 0x00; +		FOO			"foo" .and SPACE; +		BAR			"bar" .and SPACE; +		SPACE		' ' .or '\0'; + +		(**** sample text 1 ****) + +		foo + +		(**** sample text 2 ****) + +		foobar + +	For both samples the result will be one-element array. For first sample text it will be +	value 1, for second - 0. Note that every text will be accepted because of presence of +	.true as an alternative. + +	Another example: + +		(**** syntax script ****) + +		.syntax declaration; +		.emtcode VARIABLE		0x01 +		declaration		"declare" .and .loop space .and +						identifier .emit VARIABLE .and			(1) +						.true .emit 0x00 .and					(2) +						.loop space .and ';'; +		space			' ' .or '\t'; +		identifier		.loop id_char .emit *;					(3) +		id_char			'a'-'z' .or 'A'-'Z' .or '_'; + +		(**** sample code ****) + +		declare    fubar; + +	In specifier (1) symbol <identifier> is followed by .emit VARIABLE. If it evaluates to +	true, VARIABLE constant and then production of the symbol is output. Specifier (2) is used +	to terminate the string with null to signal when the string ends. Specifier (3) outputs +	all characters that make declared identifier. The result of sample code will be the +	following array: +		{ 1, 'f', 'u', 'b', 'a', 'r', 0 } + +    If .emit is followed by dollar $, it means that current position should be output. Current +    position is a 32-bit unsigned integer distance from the very beginning of the parsed string to +    first character consumed by the specifier associated with the .emit instruction. Current +    position is stored in the output buffer in Little-Endian convention (the lowest byte comes +    first). +*/ + +/** + * This is the text describing the rules to parse the grammar  + */ +#include "arbparse_syn.h" + +/**  + * These should match up with the values defined in arbparse.syn.h + */ + +#define REVISION                                   0x03 + +/* program type */ +#define FRAGMENT_PROGRAM                           0x01 +#define VERTEX_PROGRAM                             0x02 + +/* program section */ +#define OPTION                                     0x01 +#define INSTRUCTION                                0x02 +#define DECLARATION                                0x03 +#define END                                        0x04 + +/* fragment program option flags */ +#define ARB_PRECISION_HINT_FASTEST                 0x01 +#define ARB_PRECISION_HINT_NICEST                  0x02 +#define ARB_FOG_EXP                                0x04 +#define ARB_FOG_EXP2                               0x08 +#define ARB_FOG_LINEAR                             0x10 + +/* vertex program option flags */ +#define ARB_POSITION_INVARIANT                     0x01 + +/* fragment program instruction class */ +#define F_ALU_INST                                 0x01 +#define F_TEX_INST                                 0x02 + +/* fragment program instruction type */ +#define F_ALU_VECTOR                               0x01 +#define F_ALU_SCALAR                               0x02 +#define F_ALU_BINSC                                0x03 +#define F_ALU_BIN                                  0x04 +#define F_ALU_TRI                                  0x05 +#define F_ALU_SWZ                                  0x06 +#define F_TEX_SAMPLE                               0x07 +#define F_TEX_KIL                                  0x08 + +/* vertex program instruction type */ +#define V_GEN_ARL                                  0x01 +#define V_GEN_VECTOR                               0x02 +#define V_GEN_SCALAR                               0x03 +#define V_GEN_BINSC                                0x04 +#define V_GEN_BIN                                  0x05 +#define V_GEN_TRI                                  0x06 +#define V_GEN_SWZ                                  0x07 + +/* fragment program instruction code */ +#define F_ABS                                      0x00 +#define F_ABS_SAT                                  0x01 +#define F_FLR                                      0x02 +#define F_FLR_SAT                                  0x03 +#define F_FRC                                      0x04 +#define F_FRC_SAT                                  0x05 +#define F_LIT                                      0x06 +#define F_LIT_SAT                                  0x07 +#define F_MOV                                      0x08 +#define F_MOV_SAT                                  0x09 +#define F_COS                                      0x0A +#define F_COS_SAT                                  0x0B +#define F_EX2                                      0x0C +#define F_EX2_SAT                                  0x0D +#define F_LG2                                      0x0E +#define F_LG2_SAT                                  0x0F +#define F_RCP                                      0x10 +#define F_RCP_SAT                                  0x11 +#define F_RSQ                                      0x12 +#define F_RSQ_SAT                                  0x13 +#define F_SIN                                      0x14 +#define F_SIN_SAT                                  0x15 +#define F_SCS                                      0x16 +#define F_SCS_SAT                                  0x17 +#define F_POW                                      0x18 +#define F_POW_SAT                                  0x19 +#define F_ADD                                      0x1A +#define F_ADD_SAT                                  0x1B +#define F_DP3                                      0x1C +#define F_DP3_SAT                                  0x1D +#define F_DP4                                      0x1E +#define F_DP4_SAT                                  0x1F +#define F_DPH                                      0x20 +#define F_DPH_SAT                                  0x21 +#define F_DST                                      0x22 +#define F_DST_SAT                                  0x23 +#define F_MAX                                      0x24 +#define F_MAX_SAT                                  0x25 +#define F_MIN                                      0x26 +#define F_MIN_SAT                                  0x27 +#define F_MUL                                      0x28 +#define F_MUL_SAT                                  0x29 +#define F_SGE                                      0x2A +#define F_SGE_SAT                                  0x2B +#define F_SLT                                      0x2C +#define F_SLT_SAT                                  0x2D +#define F_SUB                                      0x2E +#define F_SUB_SAT                                  0x2F +#define F_XPD                                      0x30 +#define F_XPD_SAT                                  0x31 +#define F_CMP                                      0x32 +#define F_CMP_SAT                                  0x33 +#define F_LRP                                      0x34 +#define F_LRP_SAT                                  0x35 +#define F_MAD                                      0x36 +#define F_MAD_SAT                                  0x37 +#define F_SWZ                                      0x38 +#define F_SWZ_SAT                                  0x39 +#define F_TEX                                      0x3A +#define F_TEX_SAT                                  0x3B +#define F_TXB                                      0x3C +#define F_TXB_SAT                                  0x3D +#define F_TXP                                      0x3E +#define F_TXP_SAT                                  0x3F +#define F_KIL                                      0x40 + +/* vertex program instruction code */ +#define V_ARL                                      0x01 +#define V_ABS                                      0x02 +#define V_FLR                                      0x03 +#define V_FRC                                      0x04 +#define V_LIT                                      0x05 +#define V_MOV                                      0x06 +#define V_EX2                                      0x07 +#define V_EXP                                      0x08 +#define V_LG2                                      0x09 +#define V_LOG                                      0x0A +#define V_RCP                                      0x0B +#define V_RSQ                                      0x0C +#define V_POW                                      0x0D +#define V_ADD                                      0x0E +#define V_DP3                                      0x0F +#define V_DP4                                      0x10 +#define V_DPH                                      0x11 +#define V_DST                                      0x12 +#define V_MAX                                      0x13 +#define V_MIN                                      0x14 +#define V_MUL                                      0x15 +#define V_SGE                                      0x16 +#define V_SLT                                      0x17 +#define V_SUB                                      0x18 +#define V_XPD                                      0x19 +#define V_MAD                                      0x1A +#define V_SWZ                                      0x1B + +/* fragment attribute binding */ +#define FRAGMENT_ATTRIB_COLOR                      0x01 +#define FRAGMENT_ATTRIB_TEXCOORD                   0x02 +#define FRAGMENT_ATTRIB_FOGCOORD                   0x03 +#define FRAGMENT_ATTRIB_POSITION                   0x04 + +/* vertex attribute binding */ +#define VERTEX_ATTRIB_POSITION                     0x01 +#define VERTEX_ATTRIB_WEIGHT                       0x02 +#define VERTEX_ATTRIB_NORMAL                       0x03 +#define VERTEX_ATTRIB_COLOR                        0x04 +#define VERTEX_ATTRIB_FOGCOORD                     0x05 +#define VERTEX_ATTRIB_TEXCOORD                     0x06 +#define VERTEX_ATTRIB_MATRIXINDEX                  0x07 +#define VERTEX_ATTRIB_GENERIC                      0x08 + +/* fragment result binding */ +#define FRAGMENT_RESULT_COLOR                      0x01 +#define FRAGMENT_RESULT_DEPTH                      0x02 + +/* vertex result binding */ +#define VERTEX_RESULT_POSITION                     0x01 +#define VERTEX_RESULT_COLOR                        0x02 +#define VERTEX_RESULT_FOGCOORD                     0x03 +#define VERTEX_RESULT_POINTSIZE                    0x04 +#define VERTEX_RESULT_TEXCOORD                     0x05 + +/* texture target */ +#define TEXTARGET_1D                               0x01 +#define TEXTARGET_2D                               0x02 +#define TEXTARGET_3D                               0x03 +#define TEXTARGET_RECT                             0x04 +#define TEXTARGET_CUBE                             0x05 + +/* sign */ +/* +$3: removed. '+' and '-' are used instead. +*/ +/* +#define SIGN_PLUS                                  0x00 +#define SIGN_MINUS                                 0x01 +*/ + +/* face type */ +#define FACE_FRONT                                 0x00 +#define FACE_BACK                                  0x01 + +/* color type */ +#define COLOR_PRIMARY                              0x00 +#define COLOR_SECONDARY                            0x01 + +/* component */ +/* +$3: Added enumerants. +*/ +#define COMPONENT_X                                0x00 +#define COMPONENT_Y                                0x01 +#define COMPONENT_Z                                0x02 +#define COMPONENT_W                                0x03 +#define COMPONENT_0                                0x04 +#define COMPONENT_1                                0x05 + +#define ARRAY_INDEX_ABSOLUTE                       0x00 +#define ARRAY_INDEX_RELATIVE                       0x01 + +/* matrix name */ +#define MATRIX_MODELVIEW                           0x01 +#define MATRIX_PROJECTION                          0x02 +#define MATRIX_MVP                                 0x03 +#define MATRIX_TEXTURE                             0x04 +#define MATRIX_PALETTE                             0x05 +#define MATRIX_PROGRAM                             0x06 + +/* matrix modifier */ +#define MATRIX_MODIFIER_IDENTITY                   0x00 +#define MATRIX_MODIFIER_INVERSE                    0x01 +#define MATRIX_MODIFIER_TRANSPOSE                  0x02 +#define MATRIX_MODIFIER_INVTRANS                   0x03 + +/* constant type */ +#define CONSTANT_SCALAR                            0x01 +#define CONSTANT_VECTOR                            0x02 + +/* program param type */ +#define PROGRAM_PARAM_ENV                          0x01 +#define PROGRAM_PARAM_LOCAL                        0x02 + +/* register type */ +#define REGISTER_ATTRIB                            0x01 +#define REGISTER_PARAM                             0x02 +#define REGISTER_RESULT                            0x03 +#define REGISTER_ESTABLISHED_NAME                  0x04 + +/* param binding */ +#define PARAM_NULL                                 0x00 +#define PARAM_ARRAY_ELEMENT                        0x01 +#define PARAM_STATE_ELEMENT                        0x02 +#define PARAM_PROGRAM_ELEMENT                      0x03 +#define PARAM_PROGRAM_ELEMENTS                     0x04 +#define PARAM_CONSTANT                             0x05 + +/* param state property */ +#define STATE_MATERIAL_PARSER                      0x01 +#define STATE_LIGHT_PARSER                         0x02 +#define STATE_LIGHT_MODEL                          0x03 +#define STATE_LIGHT_PROD                           0x04 +#define STATE_FOG                                  0x05 +#define STATE_MATRIX_ROWS                          0x06 +/* fragment program only */ +#define STATE_TEX_ENV                              0x07 +#define STATE_DEPTH                                0x08 +/* vertex program only */ +#define STATE_TEX_GEN                              0x07 +#define STATE_CLIP_PLANE                           0x08 +#define STATE_POINT                                0x09 + +/* state material property */ +#define MATERIAL_AMBIENT                           0x01 +#define MATERIAL_DIFFUSE                           0x02 +#define MATERIAL_SPECULAR                          0x03 +#define MATERIAL_EMISSION                          0x04 +#define MATERIAL_SHININESS                         0x05 + +/* state light property */ +#define LIGHT_AMBIENT                              0x01 +#define LIGHT_DIFFUSE                              0x02 +#define LIGHT_SPECULAR                             0x03 +#define LIGHT_POSITION                             0x04 +#define LIGHT_ATTENUATION                          0x05 +#define LIGHT_HALF                                 0x06 +#define LIGHT_SPOT_DIRECTION                       0x07 + +/* state light model property */ +#define LIGHT_MODEL_AMBIENT                        0x01 +#define LIGHT_MODEL_SCENECOLOR                     0x02 + +/* state light product property */ +#define LIGHT_PROD_AMBIENT                         0x01 +#define LIGHT_PROD_DIFFUSE                         0x02 +#define LIGHT_PROD_SPECULAR                        0x03 + +/* state texture environment property */ +#define TEX_ENV_COLOR                              0x01 + +/* state texture generation coord property */ +#define TEX_GEN_EYE                                0x01 +#define TEX_GEN_OBJECT                             0x02 + +/* state fog property */ +#define FOG_COLOR                                  0x01 +#define FOG_PARAMS                                 0x02 + +/* state depth property */ +#define DEPTH_RANGE                                0x01 + +/* state point parameters property */ +#define POINT_SIZE                                 0x01 +#define POINT_ATTENUATION                          0x02 + +/* declaration */ +#define ATTRIB                                     0x01 +#define PARAM                                      0x02 +#define TEMP                                       0x03 +#define OUTPUT                                     0x04 +#define ALIAS                                      0x05 +/* vertex program 1.0 only */ +#define ADDRESS                                    0x06 + +/* +	memory management routines +*/ +static GLvoid *mem_alloc (GLsizei); +static GLvoid mem_free (GLvoid **); +static GLvoid *mem_realloc (GLvoid *, GLsizei, GLsizei); +static byte *str_duplicate (const byte *); + +/* +	internal error messages +*/ +static const byte *OUT_OF_MEMORY = +   (byte *) "internal error 1001: out of physical memory"; +static const byte *UNRESOLVED_REFERENCE = +   (byte *) "internal error 1002: unresolved reference '$'"; +static const byte *INVALID_PARAMETER = +   (byte *) "internal error 1003: invalid parameter"; + +static const byte *error_message = NULL; +static byte *error_param = NULL;        /* this is inserted into error_message in place of $ */ +static GLint error_position = -1; + +static byte *unknown = (byte *) "???"; + +static GLvoid +clear_last_error () +{ +   /* reset error message */ +   error_message = NULL; + +   /* free error parameter - if error_param is a "???" don't free it - it's static */ +   if (error_param != unknown) +      mem_free ((GLvoid **) & error_param); +   else +      error_param = NULL; + +   /* reset error position */ +   error_position = -1; +} + +static GLvoid +set_last_error (const byte * msg, byte * param, GLint pos) +{ +   if (error_message != NULL) +      return; + +   error_message = msg; +   if (param != NULL) +      error_param = param; +   else +      error_param = unknown; + +   error_position = pos; +} + +/* +	memory management routines +*/ +static GLvoid * +mem_alloc (GLsizei size) +{ +   GLvoid *ptr = _mesa_malloc (size); +   if (ptr == NULL) +      set_last_error (OUT_OF_MEMORY, NULL, -1); +   return ptr; +} + +static GLvoid +mem_free (GLvoid ** ptr) +{ +   _mesa_free (*ptr); +   *ptr = NULL; +} + +static GLvoid * +mem_realloc (GLvoid * ptr, GLsizei old_size, GLsizei new_size) +{ +   GLvoid *ptr2 = _mesa_realloc (ptr, old_size, new_size); +   if (ptr2 == NULL) +      set_last_error (OUT_OF_MEMORY, NULL, -1); +   return ptr2; +} + +static byte * +str_duplicate (const byte * str) +{ +   return (byte *) _mesa_strdup ((const char *) str); +} + +/* +	emit type typedef +*/ +typedef enum emit_type_ +{ +   et_byte,                     /* explicit number */ +   et_stream,                   /* eaten character */ +   et_position                  /* current position */ +} +emit_type; + +/* +	emit typedef +*/ +typedef struct emit_ +{ +   emit_type m_emit_type; +   byte m_byte;                 /* et_byte */ +   struct emit_ *m_next; +} +emit; + +static GLvoid +emit_create (emit ** em) +{ +   *em = mem_alloc (sizeof (emit)); +   if (*em) { +      (**em).m_emit_type = et_byte; +      (**em).m_byte = 0; +      (**em).m_next = NULL; +   } +} + +static GLvoid +emit_destroy (emit ** em) +{ +   if (*em) { +      emit_destroy (&(**em).m_next); +      mem_free ((GLvoid **) em); +   } +} + +static GLvoid +emit_append (emit ** em, emit ** ne) +{ +   if (*em) +      emit_append (&(**em).m_next, ne); +   else +      *em = *ne; +} + +/* + * error typedef + */ +typedef struct error_ +{ +   byte *m_text; +   byte *m_token_name; +   struct defntn_ *m_token; +} +error; + +static GLvoid +error_create (error ** er) +{ +   *er = mem_alloc (sizeof (error)); +   if (*er) { +      (**er).m_text = NULL; +      (**er).m_token_name = NULL; +      (**er).m_token = NULL; +   } +} + +static GLvoid +error_destroy (error ** er) +{ +   if (*er) { +      mem_free ((GLvoid **) & (**er).m_text); +      mem_free ((GLvoid **) & (**er).m_token_name); +      mem_free ((GLvoid **) er); +   } +} + +struct dict_; +static byte *error_get_token (error *, struct dict_ *, const byte *, GLuint); + +/* + * specifier type typedef +*/ +typedef enum spec_type_ +{ +   st_false, +   st_true, +   st_byte, +   st_byte_range, +   st_string, +   st_identifier, +   st_identifier_loop, +   st_debug +} spec_type; + + +/* + * specifier typedef + */ +typedef struct spec_ +{ +   spec_type m_spec_type; +   byte m_byte[2];              /* st_byte, st_byte_range */ +   byte *m_string;              /* st_string */ +   struct defntn_ *m_defntn;    /* st_identifier, st_identifier_loop */ +   emit *m_emits; +   error *m_errtext; +   struct spec_ *m_next; +} spec; + + +static GLvoid +spec_create (spec ** sp) +{ +   *sp = mem_alloc (sizeof (spec)); +   if (*sp) { +      (**sp).m_spec_type = st_false; +      (**sp).m_byte[0] = '\0'; +      (**sp).m_byte[1] = '\0'; +      (**sp).m_string = NULL; +      (**sp).m_defntn = NULL; +      (**sp).m_emits = NULL; +      (**sp).m_errtext = NULL; +      (**sp).m_next = NULL; +   } +} + +static GLvoid +spec_destroy (spec ** sp) +{ +   if (*sp) { +      spec_destroy (&(**sp).m_next); +      emit_destroy (&(**sp).m_emits); +      error_destroy (&(**sp).m_errtext); +      mem_free ((GLvoid **) & (**sp).m_string); +      mem_free ((GLvoid **) sp); +   } +} + +static GLvoid +spec_append (spec ** sp, spec ** ns) +{ +   if (*sp) +      spec_append (&(**sp).m_next, ns); +   else +      *sp = *ns; +} + +/* + * operator typedef + */ +typedef enum oper_ +{ +   op_none, +   op_and, +   op_or +} oper; + + +/* + * definition typedef + */ +typedef struct defntn_ +{ +   oper m_oper; +   spec *m_specs; +   struct defntn_ *m_next; +#ifndef NDEBUG +   GLint m_referenced; +#endif +} defntn; + + +static GLvoid +defntn_create (defntn ** de) +{ +   *de = mem_alloc (sizeof (defntn)); +   if (*de) { +      (**de).m_oper = op_none; +      (**de).m_specs = NULL; +      (**de).m_next = NULL; +#ifndef NDEBUG +      (**de).m_referenced = 0; +#endif +   } +} + +static GLvoid +defntn_destroy (defntn ** de) +{ +   if (*de) { +      defntn_destroy (&(**de).m_next); +      spec_destroy (&(**de).m_specs); +      mem_free ((GLvoid **) de); +   } +} + +static GLvoid +defntn_append (defntn ** de, defntn ** nd) +{ +   if (*de) +      defntn_append (&(**de).m_next, nd); +   else +      *de = *nd; +} + +/* + * dictionary typedef + */ +typedef struct dict_ +{ +   defntn *m_defntns; +   defntn *m_syntax; +   defntn *m_string; +   struct dict_ *m_next; +} dict; + + +static GLvoid +dict_create (dict ** di) +{ +   *di = mem_alloc (sizeof (dict)); +   if (*di) { +      (**di).m_defntns = NULL; +      (**di).m_syntax = NULL; +      (**di).m_string = NULL; +      (**di).m_next = NULL; +   } +} + +static GLvoid +dict_destroy (dict ** di) +{ +   if (*di) { +      dict_destroy (&(**di).m_next); +      defntn_destroy (&(**di).m_defntns); +      mem_free ((GLvoid **) di); +   } +} + +/* + * byte array typedef + */ +typedef struct barray_ +{ +   byte *data; +   GLuint len; +} barray; + + +static GLvoid +barray_create (barray ** ba) +{ +   *ba = mem_alloc (sizeof (barray)); +   if (*ba) { +      (**ba).data = NULL; +      (**ba).len = 0; +   } +} + +static GLvoid +barray_destroy (barray ** ba) +{ +   if (*ba) { +      mem_free ((GLvoid **) & (**ba).data); +      mem_free ((GLvoid **) ba); +   } +} + +/* + * reallocates byte array to requested size, + * returns 0 on success, + * returns 1 otherwise + */ +static GLint +barray_resize (barray ** ba, GLuint nlen) +{ +   byte *new_pointer; + +   if (nlen == 0) { +      mem_free ((void **) &(**ba).data); +      (**ba).data = NULL; +      (**ba).len = 0; + +      return 0; +   } +   else { +      new_pointer = +         mem_realloc ((**ba).data, (**ba).len * sizeof (byte), +                      nlen * sizeof (byte)); +      if (new_pointer) { +         (**ba).data = new_pointer; +         (**ba).len = nlen; + +         return 0; +      } +   } + +   return 1; +} + +/* + * adds byte array pointed by *nb to the end of array pointed by *ba, + * returns 0 on success, + * returns 1 otherwise + */ +static GLint +barray_append (barray ** ba, barray ** nb) +{ +   GLuint i; +   const GLuint len = (**ba).len; + +   if (barray_resize (ba, (**ba).len + (**nb).len)) +      return 1; + +   for (i = 0; i < (**nb).len; i++) +      (**ba).data[len + i] = (**nb).data[i]; + +   return 0; +} + +/* + * adds emit chain pointed by em to the end of array pointed by *ba, + * returns 0 on success, + * returns 1 otherwise + */ +static GLint +barray_push (barray ** ba, emit * em, byte c, GLuint pos) +{ +   emit *temp = em; +   GLuint count = 0; + +   while (temp) { +      if (temp->m_emit_type == et_position) +         count += 4;            /* position is a 32-bit unsigned integer */ +      else +         count++; + +      temp = temp->m_next; +   } + +   if (barray_resize (ba, (**ba).len + count)) +      return 1; + +   while (em) { +      if (em->m_emit_type == et_byte) +         (**ba).data[(**ba).len - count--] = em->m_byte; +      else if (em->m_emit_type == et_stream) +         (**ba).data[(**ba).len - count--] = c; + +      /* This is where the position is emitted into the stream */ +      else {                    /* em->type == et_position */ +#if 0 +         (**ba).data[(**ba).len - count--] = (byte) pos, +            (**ba).data[(**ba).len - count--] = (byte) (pos >> 8), +            (**ba).data[(**ba).len - count--] = (byte) (pos >> 16), +            (**ba).data[(**ba).len - count--] = (byte) (pos >> 24); +#else +         (**ba).data[(**ba).len - count--] = (byte) pos; +         (**ba).data[(**ba).len - count--] = (byte) (pos / 0x100); +         (**ba).data[(**ba).len - count--] = (byte) (pos / 0x10000); +         (**ba).data[(**ba).len - count--] = (byte) (pos / 0x1000000); +#endif +      } + +      em = em->m_next; +   } + +   return 0; +} + +/* + * string to string map typedef + */ +typedef struct map_str_ +{ +   byte *key; +   byte *data; +   struct map_str_ *next; +} map_str; + + +static GLvoid +map_str_create (map_str ** ma) +{ +   *ma = mem_alloc (sizeof (map_str)); +   if (*ma) { +      (**ma).key = NULL; +      (**ma).data = NULL; +      (**ma).next = NULL; +   } +} + +static GLvoid +map_str_destroy (map_str ** ma) +{ +   if (*ma) { +      map_str_destroy (&(**ma).next); +      mem_free ((GLvoid **) & (**ma).key); +      mem_free ((GLvoid **) & (**ma).data); +      mem_free ((GLvoid **) ma); +   } +} + +static GLvoid +map_str_append (map_str ** ma, map_str ** nm) +{ +   if (*ma) +      map_str_append (&(**ma).next, nm); +   else +      *ma = *nm; +} + +/* + * searches the map for specified key, + * if the key is matched, *data is filled with data associated with the key, + * returns 0 if the key is matched, + * returns 1 otherwise + */ +static GLint +map_str_find (map_str ** ma, const byte * key, byte ** data) +{ +   while (*ma) { +      if (strcmp ((const char *) (**ma).key, (const char *) key) == 0) { +         *data = str_duplicate ((**ma).data); +         if (*data == NULL) +            return 1; + +         return 0; +      } + +      ma = &(**ma).next; +   } + +   set_last_error (UNRESOLVED_REFERENCE, str_duplicate (key), -1); +   return 1; +} + +/* + * string to byte map typedef + */ +typedef struct map_byte_ +{ +   byte *key; +   byte data; +   struct map_byte_ *next; +} map_byte; + +static GLvoid +map_byte_create (map_byte ** ma) +{ +   *ma = mem_alloc (sizeof (map_byte)); +   if (*ma) { +      (**ma).key = NULL; +      (**ma).data = 0; +      (**ma).next = NULL; +   } +} + +static GLvoid +map_byte_destroy (map_byte ** ma) +{ +   if (*ma) { +      map_byte_destroy (&(**ma).next); +      mem_free ((GLvoid **) & (**ma).key); +      mem_free ((GLvoid **) ma); +   } +} + +static GLvoid +map_byte_append (map_byte ** ma, map_byte ** nm) +{ +   if (*ma) +      map_byte_append (&(**ma).next, nm); +   else +      *ma = *nm; +} + +/* + * searches the map for specified key, + * if the key is matched, *data is filled with data associated with the key, + * returns 0 if the is matched, + * returns 1 otherwise + */ +static GLint +map_byte_find (map_byte ** ma, const byte * key, byte * data) +{ +   while (*ma) { +      if (strcmp ((const char *) (**ma).key, (const char *) key) == 0) { +         *data = (**ma).data; +         return 0; +      } + +      ma = &(**ma).next; +   } + +   set_last_error (UNRESOLVED_REFERENCE, str_duplicate (key), -1); +   return 1; +} + +/* + * string to defntn map typedef + */ +typedef struct map_def_ +{ +   byte *key; +   defntn *data; +   struct map_def_ *next; +} map_def; + +static GLvoid +map_def_create (map_def ** ma) +{ +   *ma = mem_alloc (sizeof (map_def)); +   if (*ma) { +      (**ma).key = NULL; +      (**ma).data = NULL; +      (**ma).next = NULL; +   } +} + +static GLvoid +map_def_destroy (map_def ** ma) +{ +   if (*ma) { +      map_def_destroy (&(**ma).next); +      mem_free ((GLvoid **) & (**ma).key); +      mem_free ((GLvoid **) ma); +   } +} + +static GLvoid +map_def_append (map_def ** ma, map_def ** nm) +{ +   if (*ma) +      map_def_append (&(**ma).next, nm); +   else +      *ma = *nm; +} + +/* + * searches the map for specified key, + * if the key is matched, *data is filled with data associated with the key, + * returns 0 if the is matched, + * returns 1 otherwise + */ +static GLint +map_def_find (map_def ** ma, const byte * key, defntn ** data) +{ +   while (*ma) { +      if (_mesa_strcmp ((const char *) (**ma).key, (const char *) key) == 0) { +         *data = (**ma).data; + +         return 0; +      } + +      ma = &(**ma).next; +   } + +   set_last_error (UNRESOLVED_REFERENCE, str_duplicate (key), -1); +   return 1; +} + +/* + * returns 1 if given character is a space, + * returns 0 otherwise + */ +static GLint +is_space (byte c) +{ +   return c == ' ' || c == '\t' || c == '\n' || c == '\r'; +} + +/* + * advances text pointer by 1 if character pointed by *text is a space, + * returns 1 if a space has been eaten, + * returns 0 otherwise + */ +static GLint +eat_space (const byte ** text) +{ +   if (is_space (**text)) { +      (*text)++; + +      return 1; +   } + +   return 0; +} + +/* + * returns 1 if text points to C-style comment start string "/ *", + * returns 0 otherwise + */ +static GLint +is_comment_start (const byte * text) +{ +   return text[0] == '/' && text[1] == '*'; +} + +/* + * advances text pointer to first character after C-style comment block - if any, + * returns 1 if C-style comment block has been encountered and eaten, + * returns 0 otherwise + */ +static GLint +eat_comment (const byte ** text) +{ +   if (is_comment_start (*text)) { +      /* *text points to comment block - skip two characters to enter comment body */ +      *text += 2; +      /* skip any character except consecutive '*' and '/' */ +      while (!((*text)[0] == '*' && (*text)[1] == '/')) +         (*text)++; +      /* skip those two terminating characters */ +      *text += 2; + +      return 1; +   } + +   return 0; +} + +/* + * advances text pointer to first character that is neither space nor C-style comment block + */ +static GLvoid +eat_spaces (const byte ** text) +{ +   while (eat_space (text) || eat_comment (text)); +} + +/* + * resizes string pointed by *ptr to successfully add character c to the end of the string, + * returns 0 on success, + * returns 1 otherwise + */ +static GLint +string_grow (byte ** ptr, GLuint * len, byte c) +{ +   /* reallocate the string in 16-length increments */ +   if ((*len & 0x0F) == 0x0F || *ptr == NULL) { +      byte *tmp = mem_realloc (*ptr, (*len) * sizeof (byte), +                               ((*len + 1 + 1 + +                                 0x0F) & ~0x0F) * sizeof (byte)); +      if (tmp == NULL) +         return 1; + +      *ptr = tmp; +   } + +   if (c) { +      /* append given character */ +      (*ptr)[*len] = c; +      (*len)++; +   } +   (*ptr)[*len] = '\0'; + +   return 0; +} + +/* + * returns 1 if given character is valid identifier character a-z, A-Z, 0-9 or _ + * returns 0 otherwise + */ +static GLint +is_identifier (byte c) +{ +   return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || +      (c >= '0' && c <= '9') || c == '_'; +} + +/* + * copies characters from *text to *id until non-identifier character is encountered, + * assumes that *id points to NULL object - caller is responsible for later freeing the string, + * text pointer is advanced to point past the copied identifier, + * returns 0 if identifier was successfully copied, + * returns 1 otherwise + */ +static GLint +get_identifier (const byte ** text, byte ** id) +{ +   const byte *t = *text; +   byte *p = NULL; +   GLuint len = 0; + +   if (string_grow (&p, &len, '\0')) +      return 1; + +   /* loop while next character in buffer is valid for identifiers */ +   while (is_identifier (*t)) { +      if (string_grow (&p, &len, *t++)) { +         mem_free ((GLvoid **) & p); +         return 1; +      } +   } + +   *text = t; +   *id = p; + +   return 0; +} + +/* + * returns 1 if given character is HEX digit 0-9, A-F or a-f, + * returns 0 otherwise + */ +static GLint +is_hex (byte c) +{ +   return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' +                                                               && c <= 'f'); +} + +/* + * returns value of passed character as if it was HEX digit + */ +static GLuint +hex2dec (byte c) +{ +   if (c >= '0' && c <= '9') +      return c - '0'; +   if (c >= 'A' && c <= 'F') +      return c - 'A' + 10; +   return c - 'a' + 10; +} + +/* + * converts sequence of HEX digits pointed by *text until non-HEX digit is encountered, + * advances text pointer past the converted sequence, + * returns the converted value + */ +static GLuint +hex_convert (const byte ** text) +{ +   GLuint value = 0; + +   while (is_hex (**text)) { +      value = value * 0x10 + hex2dec (**text); +      (*text)++; +   } + +   return value; +} + +/* + * returns 1 if given character is OCT digit 0-7, + * returns 0 otherwise + */ +static GLint +is_oct (byte c) +{ +   return c >= '0' && c <= '7'; +} + +/* + * returns value of passed character as if it was OCT digit + */ +static GLint +oct2dec (byte c) +{ +   return c - '0'; +} + +static byte +get_escape_sequence (const byte ** text) +{ +   GLint value = 0; + +   /* skip '\' character */ +   (*text)++; + +   switch (*(*text)++) { +      case '\'': +         return '\''; +      case '"': +         return '\"'; +      case '?': +         return '\?'; +      case '\\': +         return '\\'; +      case 'a': +         return '\a'; +      case 'b': +         return '\b'; +      case 'f': +         return '\f'; +      case 'n': +         return '\n'; +      case 'r': +         return '\r'; +      case 't': +         return '\t'; +      case 'v': +         return '\v'; +      case 'x': +         return (byte) hex_convert (text); +   } + +   (*text)--; +   if (is_oct (**text)) { +      value = oct2dec (*(*text)++); +      if (is_oct (**text)) { +         value = value * 010 + oct2dec (*(*text)++); +         if (is_oct (**text)) +            value = value * 010 + oct2dec (*(*text)++); +      } +   } + +   return (byte) value; +} + +/* + * copies characters from *text to *str until " or ' character is encountered, + * assumes that *str points to NULL object - caller is responsible for later freeing the string, + * assumes that *text points to " or ' character that starts the string, + * text pointer is advanced to point past the " or ' character, + * returns 0 if string was successfully copied, + * returns 1 otherwise + */ +static GLint +get_string (const byte ** text, byte ** str) +{ +   const byte *t = *text; +   byte *p = NULL; +   GLuint len = 0; +   byte term_char; + +   if (string_grow (&p, &len, '\0')) +      return 1; + +   /* read " or ' character that starts the string */ +   term_char = *t++; +   /* while next character is not the terminating character */ +   while (*t && *t != term_char) { +      byte c; + +      if (*t == '\\') +         c = get_escape_sequence (&t); +      else +         c = *t++; + +      if (string_grow (&p, &len, c)) { +         mem_free ((GLvoid **) & p); +         return 1; +      } +   } + +   /* skip " or ' character that ends the string */ +   t++; + +   *text = t; +   *str = p; +   return 0; +} + +/* + * gets emit code, the syntax is: ".emtcode" " " <symbol> " " ("0x" | "0X") <hex_value> + * assumes that *text already points to <symbol>, + * returns 0 if emit code is successfully read, + * returns 1 otherwise + */ +static GLint +get_emtcode (const byte ** text, map_byte ** ma) +{ +   const byte *t = *text; +   map_byte *m = NULL; + +   map_byte_create (&m); +   if (m == NULL) +      return 1; + +   if (get_identifier (&t, &m->key)) { +      map_byte_destroy (&m); +      return 1; +   } +   eat_spaces (&t); + +   if (*t == '\'') { +      byte *c; + +      if (get_string (&t, &c)) { +         map_byte_destroy (&m); +         return 1; +      } + +      m->data = (byte) c[0]; +      mem_free ((GLvoid **) & c); +   } +   else { +      /* skip HEX "0x" or "0X" prefix */ +      t += 2; +      m->data = (byte) hex_convert (&t); +   } + +   eat_spaces (&t); + +   *text = t; +   *ma = m; +   return 0; +} + +/* + * returns 0 on success, + * returns 1 otherwise + */ +static GLint +get_errtext (const byte ** text, map_str ** ma) +{ +   const byte *t = *text; +   map_str *m = NULL; + +   map_str_create (&m); +   if (m == NULL) +      return 1; + +   if (get_identifier (&t, &m->key)) { +      map_str_destroy (&m); +      return 1; +   } +   eat_spaces (&t); + +   if (get_string (&t, &m->data)) { +      map_str_destroy (&m); +      return 1; +   } +   eat_spaces (&t); + +   *text = t; +   *ma = m; +   return 0; +} + +/* + * returns 0 on success, + * returns 1 otherwise, + */ +static GLint +get_error (const byte ** text, error ** er, map_str * maps) +{ +   const byte *t = *text; +   byte *temp = NULL; + +   if (*t != '.') +      return 0; + +   t++; +   if (get_identifier (&t, &temp)) +      return 1; +   eat_spaces (&t); + +   if (_mesa_strcmp ("error", (char *) temp) != 0) { +      mem_free ((GLvoid **) & temp); +      return 0; +   } + +   mem_free ((GLvoid **) & temp); + +   error_create (er); +   if (*er == NULL) +      return 1; + +   if (*t == '\"') { +      if (get_string (&t, &(**er).m_text)) { +         error_destroy (er); +         return 1; +      } +      eat_spaces (&t); +   } +   else { +      if (get_identifier (&t, &temp)) { +         error_destroy (er); +         return 1; +      } +      eat_spaces (&t); + +      if (map_str_find (&maps, temp, &(**er).m_text)) { +         mem_free ((GLvoid **) & temp); +         error_destroy (er); +         return 1; +      } + +      mem_free ((GLvoid **) & temp); +   } + +   /* try to extract "token" from "...$token$..." */ +   { +      char *processed = NULL; +      GLuint len = 0, i = 0; + +      if (string_grow ((byte **) (&processed), &len, '\0')) { +         error_destroy (er); +         return 1; +      } + +      while (i < _mesa_strlen ((char *) ((**er).m_text))) { +         /* check if the dollar sign is repeated - if so skip it */ +         if ((**er).m_text[i] == '$' && (**er).m_text[i + 1] == '$') { +            if (string_grow ((byte **) (&processed), &len, '$')) { +               mem_free ((GLvoid **) & processed); +               error_destroy (er); +               return 1; +            } + +            i += 2; +         } +         else if ((**er).m_text[i] != '$') { +            if (string_grow ((byte **) (&processed), &len, (**er).m_text[i])) { +               mem_free ((GLvoid **) & processed); +               error_destroy (er); +               return 1; +            } + +            i++; +         } +         else { +            if (string_grow ((byte **) (&processed), &len, '$')) { +               mem_free ((GLvoid **) & processed); +               error_destroy (er); +               return 1; +            } + +            { +               /* length of token being extracted */ +               GLuint tlen = 0; + +               if (string_grow (&(**er).m_token_name, &tlen, '\0')) { +                  mem_free ((GLvoid **) & processed); +                  error_destroy (er); +                  return 1; +               } + +               /* skip the dollar sign */ +               i++; + +               while ((**er).m_text[i] != '$') { +                  if (string_grow +                      (&(**er).m_token_name, &tlen, (**er).m_text[i])) { +                     mem_free ((GLvoid **) & processed); +                     error_destroy (er); +                     return 1; +                  } + +                  i++; +               } + +               /* skip the dollar sign */ +               i++; +            } +         } +      } + +      mem_free ((GLvoid **) & (**er).m_text); +      (**er).m_text = (byte *) processed; +   } + +   *text = t; +   return 0; +} + +/* + * returns 0 on success, + * returns 1 otherwise, + */ +static GLint +get_emits (const byte ** text, emit ** em, map_byte * mapb) +{ +   const byte *t = *text; +   byte *temp = NULL; +   emit *e = NULL; + +   if (*t != '.') +      return 0; + +   t++; +   if (get_identifier (&t, &temp)) +      return 1; +   eat_spaces (&t); + +   /* .emit */ +   if (_mesa_strcmp ("emit", (char *) temp) != 0) { +      mem_free ((GLvoid **) & temp); +      return 0; +   } + +   mem_free ((GLvoid **) & temp); + +   emit_create (&e); +   if (e == NULL) +      return 1; + +   /* 0xNN */ +   if (*t == '0') { +      t += 2; +      e->m_byte = (byte) hex_convert (&t); + +      e->m_emit_type = et_byte; +   } +   /* * */ +   else if (*t == '*') { +      t++; + +      e->m_emit_type = et_stream; +   } +   /* $ */ +   else if (*t == '$') { +      t++; + +      e->m_emit_type = et_position; +   } +   /* 'c' */ +   else if (*t == '\'') { +      if (get_string (&t, &temp)) { +         emit_destroy (&e); +         return 1; +      } +      e->m_byte = (byte) temp[0]; + +      mem_free ((GLvoid **) & temp); + +      e->m_emit_type = et_byte; +   } +   else { +      if (get_identifier (&t, &temp)) { +         emit_destroy (&e); +         return 1; +      } + +      if (map_byte_find (&mapb, temp, &e->m_byte)) { +         mem_free ((GLvoid **) & temp); +         emit_destroy (&e); +         return 1; +      } + +      mem_free ((GLvoid **) & temp); + +      e->m_emit_type = et_byte; +   } + +   eat_spaces (&t); + +   if (get_emits (&t, &e->m_next, mapb)) { +      emit_destroy (&e); +      return 1; +   } + +   *text = t; +   *em = e; +   return 0; +} + +/* + * returns 0 on success, + * returns 1 otherwise, + */ +static GLint +get_spec (const byte ** text, spec ** sp, map_str * maps, map_byte * mapb) +{ +   const byte *t = *text; +   spec *s = NULL; + +   spec_create (&s); +   if (s == NULL) +      return 1; + +   if (*t == '\'') { +      byte *temp = NULL; + +      if (get_string (&t, &temp)) { +         spec_destroy (&s); +         return 1; +      } +      eat_spaces (&t); + +      if (*t == '-') { +         byte *temp2 = NULL; + +         /* skip the '-' character */ +         t++; +         eat_spaces (&t); + +         if (get_string (&t, &temp2)) { +            mem_free ((GLvoid **) & temp); +            spec_destroy (&s); +            return 1; +         } +         eat_spaces (&t); + +         s->m_spec_type = st_byte_range; +         s->m_byte[0] = *temp; +         s->m_byte[1] = *temp2; + +         mem_free ((GLvoid **) & temp2); +      } +      else { +         s->m_spec_type = st_byte; +         *s->m_byte = *temp; +      } + +      mem_free ((GLvoid **) & temp); +   } +   else if (*t == '"') { +      if (get_string (&t, &s->m_string)) { +         spec_destroy (&s); +         return 1; +      } +      eat_spaces (&t); + +      s->m_spec_type = st_string; +   } +   else if (*t == '.') { +      byte *keyword = NULL; + +      /* skip the dot */ +      t++; + +      if (get_identifier (&t, &keyword)) { +         spec_destroy (&s); +         return 1; +      } +      eat_spaces (&t); + +      /* .true */ +      if (_mesa_strcmp ("true", (char *) keyword) == 0) { +         s->m_spec_type = st_true; +      } +      /* .false */ +      else if (_mesa_strcmp ("false", (char *) keyword) == 0) { +         s->m_spec_type = st_false; +      } +      /* .debug */ +      else if (_mesa_strcmp ("debug", (char *) keyword) == 0) { +         s->m_spec_type = st_debug; +      } +      /* .loop */ +      else if (_mesa_strcmp ("loop", (char *) keyword) == 0) { +         if (get_identifier (&t, &s->m_string)) { +            mem_free ((GLvoid **) & keyword); +            spec_destroy (&s); +            return 1; +         } +         eat_spaces (&t); + +         s->m_spec_type = st_identifier_loop; +      } + +      mem_free ((GLvoid **) & keyword); +   } +   else { +      if (get_identifier (&t, &s->m_string)) { +         spec_destroy (&s); +         return 1; +      } +      eat_spaces (&t); + +      s->m_spec_type = st_identifier; +   } + +   if (get_error (&t, &s->m_errtext, maps)) { +      spec_destroy (&s); +      return 1; +   } + +   if (get_emits (&t, &s->m_emits, mapb)) { +      spec_destroy (&s); +      return 1; +   } + +   *text = t; +   *sp = s; +   return 0; +} + +/* + * returns 0 on success, + * returns 1 otherwise, + */ +static GLint +get_definition (const byte ** text, defntn ** de, map_str * maps, +                map_byte * mapb) +{ +   const byte *t = *text; +   defntn *d = NULL; + +   defntn_create (&d); +   if (d == NULL) +      return 1; + +   if (get_spec (&t, &d->m_specs, maps, mapb)) { +      defntn_destroy (&d); +      return 1; +   } + +   while (*t != ';') { +      byte *op = NULL; +      spec *sp = NULL; + +      /* skip the dot that precedes "and" or "or" */ +      t++; + +      /* read "and" or "or" keyword */ +      if (get_identifier (&t, &op)) { +         defntn_destroy (&d); +         return 1; +      } +      eat_spaces (&t); + +      if (d->m_oper == op_none) { +         /* .and */ +         if (_mesa_strcmp ("and", (char *) op) == 0) +            d->m_oper = op_and; +         /* .or */ +         else +            d->m_oper = op_or; +      } + +      mem_free ((GLvoid **) & op); + +      if (get_spec (&t, &sp, maps, mapb)) { +         defntn_destroy (&d); +         return 1; +      } + +      spec_append (&d->m_specs, &sp); +   } + +   /* skip the semicolon */ +   t++; +   eat_spaces (&t); + +   *text = t; +   *de = d; +   return 0; +} + +/* + * returns 0 on success, + * returns 1 otherwise, + */ +static GLint +update_dependency (map_def * mapd, byte * symbol, defntn ** def) +{ +   if (map_def_find (&mapd, symbol, def)) +      return 1; + +#ifndef NDEBUG +   (**def).m_referenced = 1; +#endif + +   return 0; +} + +/* + * returns 0 on success, + * returns 1 otherwise, + */ +static GLint +update_dependencies (dict * di, map_def * mapd, byte ** syntax_symbol, +                     byte ** string_symbol) +{ +   defntn *de = di->m_defntns; + +   if (update_dependency (mapd, *syntax_symbol, &di->m_syntax) || +       (*string_symbol != NULL +        && update_dependency (mapd, *string_symbol, &di->m_string))) +      return 1; + +   mem_free ((GLvoid **) syntax_symbol); +   mem_free ((GLvoid **) string_symbol); + +   while (de) { +      spec *sp = de->m_specs; + +      while (sp) { +         if (sp->m_spec_type == st_identifier +             || sp->m_spec_type == st_identifier_loop) { +            if (update_dependency (mapd, sp->m_string, &sp->m_defntn)) +               return 1; + +            mem_free ((GLvoid **) & sp->m_string); +         } + +         if (sp->m_errtext && sp->m_errtext->m_token_name) { +            if (update_dependency +                (mapd, sp->m_errtext->m_token_name, &sp->m_errtext->m_token)) +               return 1; + +            mem_free ((GLvoid **) & sp->m_errtext->m_token_name); +         } + +         sp = sp->m_next; +      } + +      de = de->m_next; +   } + +   return 0; +} + +typedef enum match_result_ +{ +   mr_not_matched,              /* the examined string does not match */ +   mr_matched,                  /* the examined string matches */ +   mr_error_raised,             /* mr_not_matched + error has been raised */ +   mr_dont_emit,                /* used by identifier loops only */ +   mr_internal_error            /* an internal error has occured such as out of memory */ +} match_result; + +static match_result +match (dict * di, const byte * text, GLuint * index, defntn * de, +       barray ** ba, GLint filtering_string) +{ +   GLuint ind = *index; +   match_result status = mr_not_matched; +   spec *sp = de->m_specs; + +   /* for every specifier in the definition */ +   while (sp) { +      GLuint i, len, save_ind = ind; +      barray *array = NULL; + +      switch (sp->m_spec_type) { +         case st_identifier: +            barray_create (&array); +            if (array == NULL) +               return mr_internal_error; + +            status = +               match (di, text, &ind, sp->m_defntn, &array, filtering_string); +            if (status == mr_internal_error) { +               barray_destroy (&array); +               return mr_internal_error; +            } +            break; +         case st_string: +            len = _mesa_strlen ((char *) (sp->m_string)); + +            /* prefilter the stream */ +            if (!filtering_string && di->m_string) { +               barray *ba; +               GLuint filter_index = 0; +               match_result result; + +               barray_create (&ba); +               if (ba == NULL) +                  return mr_internal_error; + +               result = +                  match (di, text + ind, &filter_index, di->m_string, &ba, 1); + +               if (result == mr_internal_error) { +                  barray_destroy (&ba); +                  return mr_internal_error; +               } + +               if (result != mr_matched) { +                  barray_destroy (&ba); +                  status = mr_not_matched; +                  break; +               } + +               barray_destroy (&ba); + +               if (filter_index != len +                   || _mesa_strncmp ((char *)sp->m_string, (char *)(text + ind), len)) { +                  status = mr_not_matched; +                  break; +               } + +               status = mr_matched; +               ind += len; +            } +            else { +               status = mr_matched; +               for (i = 0; status == mr_matched && i < len; i++) +                  if (text[ind + i] != sp->m_string[i]) +                     status = mr_not_matched; +               if (status == mr_matched) +                  ind += len; +            } +            break; +         case st_byte: +            status = text[ind] == *sp->m_byte ? mr_matched : mr_not_matched; +            if (status == mr_matched) +               ind++; +            break; +         case st_byte_range: +            status = (text[ind] >= sp->m_byte[0] +                      && text[ind] <= +                      sp->m_byte[1]) ? mr_matched : mr_not_matched; +            if (status == mr_matched) +               ind++; +            break; +         case st_true: +            status = mr_matched; +            break; +         case st_false: +            status = mr_not_matched; +            break; +         case st_debug: +            status = mr_matched; +            break; +         case st_identifier_loop: +            barray_create (&array); +            if (array == NULL) +               return mr_internal_error; + +            status = mr_dont_emit; +            for (;;) { +               match_result result; + +               save_ind = ind; +               result = +                  match (di, text, &ind, sp->m_defntn, &array, +                         filtering_string); + +               if (result == mr_error_raised) { +                  status = result; +                  break; +               } +               else if (result == mr_matched) { +                  if (barray_push (ba, sp->m_emits, text[ind - 1], save_ind) +                      || barray_append (ba, &array)) { +                     barray_destroy (&array); +                     return mr_internal_error; +                  } +                  barray_destroy (&array); +                  barray_create (&array); +                  if (array == NULL) +                     return mr_internal_error; +               } +               else if (result == mr_internal_error) { +                  barray_destroy (&array); +                  return mr_internal_error; +               } +               else +                  break; +            } +            break; +      }; + +      if (status == mr_error_raised) { +         barray_destroy (&array); + +         return mr_error_raised; +      } + +      if (de->m_oper == op_and && status != mr_matched +          && status != mr_dont_emit) { +         barray_destroy (&array); + +         if (sp->m_errtext) { +            set_last_error (sp->m_errtext->m_text, +                            error_get_token (sp->m_errtext, di, text, ind), +                            ind); + +            return mr_error_raised; +         } + +         return mr_not_matched; +      } + +      if (status == mr_matched) { +         if (sp->m_emits) +            if (barray_push (ba, sp->m_emits, text[ind - 1], save_ind)) { +               barray_destroy (&array); +               return mr_internal_error; +            } + +         if (array) +            if (barray_append (ba, &array)) { +               barray_destroy (&array); +               return mr_internal_error; +            } +      } + +      barray_destroy (&array); + +      if (de->m_oper == op_or +          && (status == mr_matched || status == mr_dont_emit)) { +         *index = ind; +         return mr_matched; +      } + +      sp = sp->m_next; +   } + +   if (de->m_oper == op_and +       && (status == mr_matched || status == mr_dont_emit)) { +      *index = ind; +      return mr_matched; +   } + +   return mr_not_matched; +} + +static byte * +error_get_token (error * er, dict * di, const byte * text, unsigned int ind) +{ +   byte *str = NULL, *result = NULL; + +   if (er->m_token) { +      barray *ba; +      unsigned int filter_index = 0; + +      barray_create (&ba); +      if (ba != NULL) { +         if (match (di, text + ind, &filter_index, er->m_token, &ba, 0) == +             mr_matched && filter_index) { +            str = mem_alloc (filter_index + 1); +            if (str != NULL) { +               _mesa_strncpy ((char *) str, (char *) (text + ind), +                              filter_index); +               str[filter_index] = '\0'; +            } +         } +         barray_destroy (&ba); +      } +   } + +   return str; +} + +typedef struct grammar_load_state_ +{ +   dict *di; +   byte *syntax_symbol; +   byte *string_symbol; +   map_str *maps; +   map_byte *mapb; +   map_def *mapd; +} grammar_load_state; + + +static GLvoid +grammar_load_state_create (grammar_load_state ** gr) +{ +   *gr = mem_alloc (sizeof (grammar_load_state)); +   if (*gr) { +      (**gr).di = NULL; +      (**gr).syntax_symbol = NULL; +      (**gr).string_symbol = NULL; +      (**gr).maps = NULL; +      (**gr).mapb = NULL; +      (**gr).mapd = NULL; +   } +} + +static GLvoid +grammar_load_state_destroy (grammar_load_state ** gr) +{ +   if (*gr) { +      dict_destroy (&(**gr).di); +      mem_free ((GLvoid **) &(**gr).syntax_symbol); +      mem_free ((GLvoid **) &(**gr).string_symbol); +      map_str_destroy (&(**gr).maps); +      map_byte_destroy (&(**gr).mapb); +      map_def_destroy (&(**gr).mapd); +      mem_free ((GLvoid **) gr); +   } +} + +/* + * the API + */ + +/* + * loads grammar script from null-terminated ASCII text + * returns the grammar object + * returns NULL if an error occurs (call grammar_get_last_error to retrieve the error text) + */ + +static dict * +grammar_load_from_text (const byte * text) +{ +   dict *d = NULL; +   grammar_load_state *g = NULL; + +   clear_last_error (); + +   grammar_load_state_create (&g); +   if (g == NULL) +      return NULL; + +   dict_create (&g->di); +   if (g->di == NULL) { +      grammar_load_state_destroy (&g); +      return NULL; +   } + +   eat_spaces (&text); + +   /* skip ".syntax" keyword */ +   text += 7; +   eat_spaces (&text); + +   /* retrieve root symbol */ +   if (get_identifier (&text, &g->syntax_symbol)) { +      grammar_load_state_destroy (&g); +      return NULL; +   } +   eat_spaces (&text); + +   /* skip semicolon */ +   text++; +   eat_spaces (&text); + +   while (*text) { +      byte *symbol = NULL; +      GLint is_dot = *text == '.'; + +      if (is_dot) +         text++; + +      if (get_identifier (&text, &symbol)) { +         grammar_load_state_destroy (&g); +         return NULL; +      } +      eat_spaces (&text); + +      /* .emtcode */ +      if (is_dot && _mesa_strcmp ((char *) symbol, "emtcode") == 0) { +         map_byte *ma = NULL; + +         mem_free ((void **) &symbol); + +         if (get_emtcode (&text, &ma)) { +            grammar_load_state_destroy (&g); +            return NULL; +         } + +         map_byte_append (&g->mapb, &ma); +      } +      /* .errtext */ +      else if (is_dot && _mesa_strcmp ((char *) symbol, "errtext") == 0) { +         map_str *ma = NULL; + +         mem_free ((GLvoid **) &symbol); + +         if (get_errtext (&text, &ma)) { +            grammar_load_state_destroy (&g); +            return NULL; +         } + +         map_str_append (&g->maps, &ma); +      } +      /* .string */ +      else if (is_dot && _mesa_strcmp ((char *) symbol, "string") == 0) { +         mem_free ((GLvoid **) (&symbol)); + +         if (g->di->m_string != NULL) { +            grammar_load_state_destroy (&g); +            return NULL; +         } + +         if (get_identifier (&text, &g->string_symbol)) { +            grammar_load_state_destroy (&g); +            return NULL; +         } + +         /* skip semicolon */ +         eat_spaces (&text); +         text++; +         eat_spaces (&text); +      } +      else { +         defntn *de = NULL; +         map_def *ma = NULL; + +         if (get_definition (&text, &de, g->maps, g->mapb)) { +            grammar_load_state_destroy (&g); +            return NULL; +         } + +         defntn_append (&g->di->m_defntns, &de); + +         /* if definition consist of only one specifier, give it an ".and" operator */ +         if (de->m_oper == op_none) +            de->m_oper = op_and; + +         map_def_create (&ma); +         if (ma == NULL) { +            grammar_load_state_destroy (&g); +            return NULL; +         } + +         ma->key = symbol; +         ma->data = de; +         map_def_append (&g->mapd, &ma); +      } +   } + +   if (update_dependencies +       (g->di, g->mapd, &g->syntax_symbol, &g->string_symbol)) { +      grammar_load_state_destroy (&g); +      return NULL; +   } + +   d = g->di; +   g->di = NULL; + +   grammar_load_state_destroy (&g); + +   return d; +} + +/** + * checks if a null-terminated text matches given grammar + * returns 0 on error (call grammar_get_last_error to retrieve the error text) + * returns 1 on success, the prod points to newly allocated buffer with production and size + * is filled with the production size + * + * \param id         - The grammar returned from grammar_load_from_text() + * \param text       - The program string + * \param production - The return parameter for the binary array holding the parsed results + * \param size       - The return parameter for the size of production  + * + * \return 1 on sucess, 0 on parser error + */ +static GLint +grammar_check (dict * di, const byte * text, byte ** production, +               GLuint *size) +{ +   barray *ba = NULL; +   GLuint index = 0; + +   clear_last_error (); + +   barray_create (&ba); +   if (ba == NULL) +      return 0; + +   *production = NULL; +   *size = 0; + +   if (match (di, text, &index, di->m_syntax, &ba, 0) != mr_matched) { +      barray_destroy (&ba); +      return 0; +   } + +   *production = mem_alloc (ba->len * sizeof (byte)); +   if (*production == NULL) { +      barray_destroy (&ba); +      return 0; +   } + +   memcpy (*production, ba->data, ba->len * sizeof (byte)); +   *size = ba->len; +   barray_destroy (&ba); + +   return 1; +} + +static GLvoid +grammar_get_last_error (byte * text, int size, int *pos) +{ +   GLint len = 0, dots_made = 0; +   const byte *p = error_message; + +   *text = '\0'; +#define APPEND_CHARACTER(x) if (dots_made == 0) {\ +   if (len < size - 1) {\ +      text[len++] = (x); text[len] = '\0';\ +   } else {\ +      int i;\ +      for (i = 0; i < 3; i++)\ +         if (--len >= 0)\ +      text[len] = '.';\ +      dots_made = 1;\ +   }\ +} + +   if (p) { +      while (*p) { +         if (*p == '$') { +            const byte *r = error_param; + +            while (*r) { +               APPEND_CHARACTER (*r) +                  r++; +            } + +            p++; +         } +         else { +            APPEND_CHARACTER (*p) +               p++; +         } +      } +   } +   *pos = error_position; +} + +/*----------------------------------------------------------------------- + * From here on down is the semantic checking portion  + * + */ + +/** + * Variable Table Handling functions  + */ +typedef enum +{ +   vt_none, +   vt_address, +   vt_attrib, +   vt_param, +   vt_temp, +   vt_output, +   vt_alias +} var_type; + + +/*  + * Setting an explicit field for each of the binding properties is a bit wasteful + * of space, but it should be much more clear when reading later on.. + */ +struct var_cache +{ +   byte *name; +   var_type type; +   GLuint address_binding;      /* The index of the address register we should  +                                 * be using                                        */ +   GLuint attrib_binding;       /* For type vt_attrib, see nvfragprog.h for values */ +   GLuint attrib_binding_idx;   /* The index into the attrib register file corresponding +                                 * to the state in attrib_binding                  */ +   GLuint temp_binding;         /* The index of the temp register we are to use    */ +   GLuint output_binding;       /* For type vt_output, see nvfragprog.h for values */ +   GLuint output_binding_idx;   /* This is the index into the result register file +                                 * corresponding to the bound result state         */ +   struct var_cache *alias_binding;     /* For type vt_alias, points to the var_cache entry +                                         * * that this is aliased to                         */ +   GLuint param_binding_type;   /* {PROGRAM_STATE_VAR, PROGRAM_LOCAL_PARAM,  +                                 *    PROGRAM_ENV_PARAM}                           */ +   GLuint param_binding_begin;  /* This is the offset into the program_parameter_list where +                                 * the tokens representing our bound state (or constants) +                                 * start */ +   GLuint param_binding_length; /* This is how many entries in the the program_parameter_list +                                 * we take up with our state tokens or constants. Note that +                                 * this is _not_ the same as the number of param registers +                                 * we eventually use */ +   struct var_cache *next; +}; + +static GLvoid +var_cache_create (struct var_cache **va) +{ +   *va = _mesa_malloc (sizeof (struct var_cache)); +   if (*va) { +      (**va).name = NULL; +      (**va).type = vt_none; +      (**va).attrib_binding = -1; +      (**va).temp_binding = -1; +      (**va).output_binding = -1; +      (**va).output_binding_idx = -1; +      (**va).param_binding_type = -1; +      (**va).param_binding_begin = -1; +      (**va).param_binding_length = -1; +      (**va).alias_binding = NULL; +      (**va).next = NULL; +   } +} + +static GLvoid +var_cache_destroy (struct var_cache **va) +{ +   if (*va) { +      var_cache_destroy (&(**va).next); +      _mesa_free (*va); +      *va = NULL; +   } +} + +static GLvoid +var_cache_append (struct var_cache **va, struct var_cache *nv) +{ +   if (*va) +      var_cache_append (&(**va).next, nv); +   else +      *va = nv; +} + +static struct var_cache * +var_cache_find (struct var_cache *va, byte * name) +{ +   struct var_cache *first = va; + +   while (va) { +      if (!strcmp (name, va->name)) { +         if (va->type == vt_alias) +            return var_cache_find (first, va->name); +         return va; +      } + +      va = va->next; +   } + +   return NULL; +} + +/** + * constructs an integer from 4 bytes in LE format + */ +static GLuint +parse_position (byte ** inst) +{ +   GLuint value; + +   value =  (GLuint) (*(*inst)++); +   value += (GLuint) (*(*inst)++) * 0x100; +   value += (GLuint) (*(*inst)++) * 0x10000; +   value += (GLuint) (*(*inst)++) * 0x1000000; + +   return value; +} + +/** + * This will, given a string, lookup the string as a variable name in the + * var cache. If the name is found, the var cache node corresponding to the + * var name is returned. If it is not found, a new entry is allocated + * + * \param  I     Points into the binary array where the string identifier begins + * \param  found 1 if the string was found in the var_cache, 0 if it was allocated + * \return       The location on the var_cache corresponding the the string starting at I + */ +static struct var_cache * +parse_string (byte ** inst, struct var_cache **vc_head, +              struct arb_program *Program, GLuint * found) +{ +   byte *i = *inst; +   struct var_cache *va = NULL; + +   *inst += _mesa_strlen ((char *) i) + 1; + +   va = var_cache_find (*vc_head, i); + +   if (va) { +      *found = 1; +      return va; +   } + +   *found = 0; +   var_cache_create (&va); +   va->name = i; + +   var_cache_append (vc_head, va); + +   return va; +} + +static char * +parse_string_without_adding (byte ** inst, struct arb_program *Program) +{ +   byte *i = *inst; + +   *inst += _mesa_strlen ((char *) i) + 1; + +   return (char *) i; +} + +/** + * \return 0 if sign is plus, 1 if sign is minus + */ +static GLuint +parse_sign (byte ** inst) +{ +   /*return *(*inst)++ != '+'; */ + +   if (**inst == '-') { +      *(*inst)++; +      return 1; +   } +   else if (**inst == '+') { +      *(*inst)++; +      return 0; +   } + +   return 0; +} + +/** + * parses and returns signed integer + */ +static GLint +parse_integer (byte ** inst, struct arb_program *Program) +{ +   GLint sign; +   GLint value; + +   /* check if *inst points to '+' or '-' +    * if yes, grab the sign and increment *inst +    */ +   sign = parse_sign (inst); + +   /* now check if *inst points to 0 +    * if yes, increment the *inst and return the default value +    */ +   if (**inst == 0) { +      *(*inst)++; +      return 0; +   } + +   /* parse the integer as you normally would do it */ +   value = _mesa_atoi (parse_string_without_adding (inst, Program)); + +   /* now, after terminating 0 there is a position +    * to parse it - parse_position() +    */ +   Program->Position = parse_position (inst); + +   if (sign) +      value *= -1; + +   return value; +} + +/** + */ +static GLfloat +parse_float (byte ** inst, struct arb_program *Program) +{ +   GLint tmp[5], denom; +   GLfloat value = 0; + +#if 0 +   tmp[0] = parse_sign (inst);  /* This is the sign of the number + - >0, - -> 1 */ +#endif +   tmp[1] = parse_integer (inst, Program);   /* This is the integer portion of the number */ +   tmp[2] = parse_integer (inst, Program);   /* This is the fractional portion of the number */ +   tmp[3] = parse_sign (inst);               /* This is the sign of the exponent */ +   tmp[4] = parse_integer (inst, Program);   /* This is the exponent */ + +   value = (GLfloat) tmp[1]; +   denom = 1; +   while (denom < tmp[2]) +      denom *= 10; +   value += (GLfloat) tmp[2] / (GLfloat) denom; +#if 0 +   if (tmp[0]) +      value *= -1; +#endif +   value *= _mesa_pow (10, (GLfloat) tmp[3] * (GLfloat) tmp[4]); + +   return value; +} + +/** + */ +static GLfloat +parse_signed_float (byte ** inst, struct arb_program *Program) +{ +   GLint negate; +   GLfloat value; + +   negate = parse_sign (inst); + +   value = parse_float (inst, Program); + +   if (negate) +      value *= -1; + +   return value; +} + +/** + * This picks out a constant value from the parsed array. The constant vector is r + * returned in the *values array, which should be of length 4. + * + * \param values - The 4 component vector with the constant value in it  + */ +static GLvoid +parse_constant (byte ** inst, GLfloat *values, struct arb_program *Program, +                GLboolean use) +{ +   GLuint components, i; + + +   switch (*(*inst)++) { +      case CONSTANT_SCALAR: +         if (use == GL_TRUE) { +            values[0] = +               values[1] = +               values[2] = values[3] = parse_float (inst, Program); +         } +         else { +            values[0] = +               values[1] = +               values[2] = values[3] = parse_signed_float (inst, Program); +         } + +         break; +      case CONSTANT_VECTOR: +         values[0] = values[1] = values[2] = 0; +         values[3] = 1; +         components = *(*inst)++; +         for (i = 0; i < components; i++) { +            values[i] = parse_signed_float (inst, Program); +         } +         break; +   } +} + + +/** + * \param  color 0 if color type is primary, 1 if color type is secondary + * \return 0 on sucess, 1 on error + */ +static GLuint +parse_color_type (GLcontext * ctx, byte ** inst, struct arb_program *Program, +                  GLint * color) +{ +   *color = *(*inst)++ != COLOR_PRIMARY; +   return 0; +} + +/** + * \param coord The texture unit index + * \return 0 on sucess, 1 on error  + */ +static GLuint +parse_texcoord_num (GLcontext * ctx, byte ** inst, +                    struct arb_program *Program, GLuint * coord) +{ +   *coord = parse_integer (inst, Program); + +   if ((*coord < 0) || (*coord >= ctx->Const.MaxTextureUnits)) { +      _mesa_set_program_error (ctx, Program->Position, +                               "Invalid texture unit index"); +      _mesa_error (ctx, GL_INVALID_OPERATION, "Invalid texture unit index"); +      return 1; +   } + +   Program->TexturesUsed[*coord] = 1; +   return 0; +} + +/** + * \param coord The weight index + * \return 0 on sucess, 1 on error  + */ +static GLuint +parse_weight_num (GLcontext * ctx, byte ** inst, struct arb_program *Program, +                  GLint * coord) +{ +   *coord = parse_integer (inst, Program); + +   if ((*coord < 0) || (*coord >= 1)) { +      _mesa_set_program_error (ctx, Program->Position, +                               "Invalid weight index"); +      _mesa_error (ctx, GL_INVALID_OPERATION, "Invalid weight index"); +      return 1; +   } + +   return 0; +} + +/** + * \param coord The clip plane index + * \return 0 on sucess, 1 on error  + */ +static GLuint +parse_clipplane_num (GLcontext * ctx, byte ** inst, +                     struct arb_program *Program, GLint * coord) +{ +   *coord = parse_integer (inst, Program); + +   if ((*coord < 0) || (*coord >= ctx->Const.MaxClipPlanes)) { +      _mesa_set_program_error (ctx, Program->Position, +                               "Invalid clip plane index"); +      _mesa_error (ctx, GL_INVALID_OPERATION, "Invalid clip plane index"); +      return 1; +   } + +   return 0; +} + + + + +/** + * \return 0 on front face, 1 on back face + */ +static GLuint +parse_face_type (byte ** inst) +{ +   switch (*(*inst)++) { +      case FACE_FRONT: +         return 0; + +      case FACE_BACK: +         return 1; +   } +} + +/** + * Given a matrix and a modifier token on the binary array, return tokens + * that _mesa_fetch_state() [program.c] can understand. + * + * \param matrix - the matrix we are talking about + * \param matrix_idx - the index of the matrix we have (for texture & program matricies) + * \param matrix_modifier - the matrix modifier (trans, inv, etc) + * \return 0 on sucess, 1 on failure + */ +static GLuint +parse_matrix (GLcontext * ctx, byte ** inst, struct arb_program *Program, +              GLint * matrix, GLint * matrix_idx, GLint * matrix_modifier) +{ +   byte mat = *(*inst)++; + +   *matrix_idx = 0; + +   switch (mat) { +      case MATRIX_MODELVIEW: +         *matrix = STATE_MODELVIEW; +         *matrix_idx = parse_integer (inst, Program); +         /* XXX: if (*matrix_idx >= ctx->Const. */ +         break; + +      case MATRIX_PROJECTION: +         *matrix = STATE_PROJECTION; +         break; + +      case MATRIX_MVP: +         *matrix = STATE_MVP; +         break; + +      case MATRIX_TEXTURE: +         *matrix = STATE_TEXTURE; +         *matrix_idx = parse_integer (inst, Program); +         if (*matrix_idx >= ctx->Const.MaxTextureUnits) { +            _mesa_set_program_error (ctx, Program->Position, +                                     "Invalid Texture Unit"); +            _mesa_error (ctx, GL_INVALID_OPERATION, +                         "Invalid Texture Unit: %d", *matrix_idx); +            return 1; +         } +         break; + +         /* XXX: How should we handle the palette matrix? */ +      case MATRIX_PALETTE: +         *matrix_idx = parse_integer (inst, Program); +         break; + +      case MATRIX_PROGRAM: +         *matrix = STATE_PROGRAM; +         *matrix_idx = parse_integer (inst, Program); +         if (*matrix_idx >= ctx->Const.MaxProgramMatrices) { +            _mesa_set_program_error (ctx, Program->Position, +                                     "Invalid Program Matrix"); +            _mesa_error (ctx, GL_INVALID_OPERATION, +                         "Invalid Program Matrix: %d", *matrix_idx); +            return 1; +         } +         break; +   } + +   switch (*(*inst)++) { +      case MATRIX_MODIFIER_IDENTITY: +         *matrix_modifier = 0; +         break; +      case MATRIX_MODIFIER_INVERSE: +         *matrix_modifier = STATE_MATRIX_INVERSE; +         break; +      case MATRIX_MODIFIER_TRANSPOSE: +         *matrix_modifier = STATE_MATRIX_TRANSPOSE; +         break; +      case MATRIX_MODIFIER_INVTRANS: +         *matrix_modifier = STATE_MATRIX_INVTRANS; +         break; +   } + +   return 0; +} + + +/** + * This parses a state string (rather, the binary version of it) into + * a 6-token sequence as described in _mesa_fetch_state() [program.c] + * + * \param inst         - the start in the binary arry to start working from + * \param state_tokens - the storage for the 6-token state description + * \return             - 0 on sucess, 1 on error + */ +static GLuint +parse_state_single_item (GLcontext * ctx, byte ** inst, +                         struct arb_program *Program, GLint * state_tokens) +{ +   switch (*(*inst)++) { +      case STATE_MATERIAL_PARSER: +         state_tokens[0] = STATE_MATERIAL; +         state_tokens[1] = parse_face_type (inst); +         switch (*(*inst)++) { +            case MATERIAL_AMBIENT: +               state_tokens[2] = STATE_AMBIENT; +               break; +            case MATERIAL_DIFFUSE: +               state_tokens[2] = STATE_DIFFUSE; +               break; +            case MATERIAL_SPECULAR: +               state_tokens[2] = STATE_SPECULAR; +               break; +            case MATERIAL_EMISSION: +               state_tokens[2] = STATE_EMISSION; +	       break; +            case MATERIAL_SHININESS: +               state_tokens[2] = STATE_SHININESS; +               break; +         } +         break; + +      case STATE_LIGHT_PARSER: +         state_tokens[0] = STATE_LIGHT; +         state_tokens[1] = parse_integer (inst, Program); + +         /* Check the value of state_tokens[1] against the # of lights */ +         if (state_tokens[1] >= ctx->Const.MaxLights) { +            _mesa_set_program_error (ctx, Program->Position, +                                     "Invalid Light Number"); +            _mesa_error (ctx, GL_INVALID_OPERATION, +                         "Invalid Light Number: %d", state_tokens[1]); +            return 1; +         } + +         switch (*(*inst)++) { +            case LIGHT_AMBIENT: +               state_tokens[2] = STATE_AMBIENT; +               break; +            case LIGHT_DIFFUSE: +               state_tokens[2] = STATE_DIFFUSE; +               break; +            case LIGHT_SPECULAR: +               state_tokens[2] = STATE_SPECULAR; +               break; +            case LIGHT_POSITION: +               state_tokens[2] = STATE_POSITION; +               break; +            case LIGHT_ATTENUATION: +               state_tokens[2] = STATE_ATTENUATION; +               break; +            case LIGHT_HALF: +               state_tokens[2] = STATE_HALF; +               break; +            case LIGHT_SPOT_DIRECTION: +               state_tokens[2] = STATE_SPOT_DIRECTION; +               break; +         } +         break; + +      case STATE_LIGHT_MODEL: +         switch (*(*inst)++) { +            case LIGHT_MODEL_AMBIENT: +               state_tokens[0] = STATE_LIGHTMODEL_AMBIENT; +               break; +            case LIGHT_MODEL_SCENECOLOR: +               state_tokens[0] = STATE_LIGHTMODEL_SCENECOLOR; +               state_tokens[1] = parse_face_type (inst); +               break; +         } +         break; + +      case STATE_LIGHT_PROD: +         state_tokens[0] = STATE_LIGHTPROD; +         state_tokens[1] = parse_integer (inst, Program); + +         /* Check the value of state_tokens[1] against the # of lights */ +         if (state_tokens[1] >= ctx->Const.MaxLights) { +            _mesa_set_program_error (ctx, Program->Position, +                                     "Invalid Light Number"); +            _mesa_error (ctx, GL_INVALID_OPERATION, +                         "Invalid Light Number: %d", state_tokens[1]); +            return 1; +         } + +         state_tokens[2] = parse_face_type (inst); +         switch (*(*inst)++) { +            case LIGHT_PROD_AMBIENT: +               state_tokens[3] = STATE_AMBIENT; +               break; +            case LIGHT_PROD_DIFFUSE: +               state_tokens[3] = STATE_DIFFUSE; +               break; +            case LIGHT_PROD_SPECULAR: +               state_tokens[3] = STATE_SPECULAR; +               break; +         } +         break; + + +      case STATE_FOG: +         switch (*(*inst)++) { +            case FOG_COLOR: +               state_tokens[0] = STATE_FOG_COLOR; +               break; +            case FOG_PARAMS: +               state_tokens[0] = STATE_FOG_PARAMS; +               break; +         } +         break; + +         /* STATE_TEX_ENV == STATE_TEX_GEN */ +      case STATE_TEX_ENV: +         if (Program->type == GL_FRAGMENT_PROGRAM_ARB) { +            state_tokens[1] = parse_integer (inst, Program); +            switch (*(*inst)++) { +               case TEX_ENV_COLOR: +                  state_tokens[0] = STATE_TEXENV_COLOR; +                  break; +            } +         } +         /* For vertex programs, this case is STATE_TEX_GEN */ +         else { +            GLuint type, coord; + +            state_tokens[0] = STATE_TEXGEN; +            /*state_tokens[1] = parse_integer (inst, Program);*/    /* Texture Unit */ + +            if (parse_texcoord_num (ctx, inst, Program, &coord)) +               return 1; +	    state_tokens[1] = coord; +	     +            /* EYE or OBJECT */ +            type = *(*inst++); + +            /* 0 - s, 1 - t, 2 - r, 3 - q */ +            coord = *(*inst++); + +            if (type == TEX_GEN_EYE) { +               switch (coord) { +                  case COMPONENT_X: +                     state_tokens[2] = STATE_TEXGEN_EYE_S; +                     break; +                  case COMPONENT_Y: +                     state_tokens[2] = STATE_TEXGEN_EYE_T; +                     break; +                  case COMPONENT_Z: +                     state_tokens[2] = STATE_TEXGEN_EYE_R; +                     break; +                  case COMPONENT_W: +                     state_tokens[2] = STATE_TEXGEN_EYE_Q; +                     break; +               } +            } +            else { +               switch (coord) { +                  case COMPONENT_X: +                     state_tokens[2] = STATE_TEXGEN_OBJECT_S; +                     break; +                  case COMPONENT_Y: +                     state_tokens[2] = STATE_TEXGEN_OBJECT_T; +                     break; +                  case COMPONENT_Z: +                     state_tokens[2] = STATE_TEXGEN_OBJECT_R; +                     break; +                  case COMPONENT_W: +                     state_tokens[2] = STATE_TEXGEN_OBJECT_Q; +                     break; +               } +            } +         } +         break; + +         /* STATE_DEPTH = STATE_CLIP_PLANE */ +      case STATE_DEPTH: +         if (Program->type == GL_FRAGMENT_PROGRAM_ARB) { +            switch (*(*inst)++) { +               case DEPTH_RANGE: +                  state_tokens[0] = STATE_DEPTH_RANGE; +                  break; +            } +         } +         /* for vertex programs, we want STATE_CLIP_PLANE */ +         else { +            state_tokens[0] = STATE_CLIPPLANE; +            state_tokens[1] = parse_integer (inst, Program); +            if (parse_clipplane_num (ctx, inst, Program, &state_tokens[1])) +               return 1; +         } +         break; + +      case STATE_POINT: +         switch (*(*inst++)) { +            case POINT_SIZE: +               state_tokens[0] = STATE_POINT_SIZE; +               break; + +            case POINT_ATTENUATION: +               state_tokens[0] = STATE_POINT_ATTENUATION; +               break; +         } +         break; + +         /* XXX: I think this is the correct format for a matrix row */ +      case STATE_MATRIX_ROWS: +         state_tokens[0] = STATE_MATRIX; + +         if (parse_matrix +             (ctx, inst, Program, &state_tokens[1], &state_tokens[2], +              &state_tokens[5])) +            return 1; + +         state_tokens[3] = parse_integer (inst, Program);       /* The first row to grab */ + +         state_tokens[4] = parse_integer (inst, Program);       /* Either the last row, 0 */ +         if (state_tokens[4] == 0) { +            state_tokens[4] = state_tokens[3]; +         } +         break; +   } + +   return 0; +} + +/** + * This parses a state string (rather, the binary version of it) into + * a 6-token similar for the state fetching code in program.c + * + * One might ask, why fetch these parameters into just like  you fetch + * state when they are already stored in other places?  + * + * Because of array offsets -> We can stick env/local parameters in the + * middle of a parameter array and then index someplace into the array + * when we execute.  + * + * One optimization might be to only do this for the cases where the  + * env/local parameters end up inside of an array, and leave the  + * single parameters (or arrays of pure env/local pareameters) in their + * respective register files. + *  + * For ENV parameters, the format is: + *    state_tokens[0] = STATE_FRAGMENT_PROGRAM / STATE_VERTEX_PROGRAM + *    state_tokens[1] = STATE_ENV + *    state_tokens[2] = the parameter index + * + * for LOCAL parameters, the format is: + *    state_tokens[0] = STATE_FRAGMENT_PROGRAM / STATE_VERTEX_PROGRAM + *    state_tokens[1] = STATE_LOCAL + *    state_tokens[2] = the parameter index + * + * \param inst         - the start in the binary arry to start working from + * \param state_tokens - the storage for the 6-token state description + * \return             - 0 on sucess, 1 on failure + */ +static GLuint +parse_program_single_item (GLcontext * ctx, byte ** inst, +                           struct arb_program *Program, GLint * state_tokens) +{ +   if (Program->type == GL_FRAGMENT_PROGRAM_ARB) +      state_tokens[0] = STATE_FRAGMENT_PROGRAM; +   else +      state_tokens[0] = STATE_VERTEX_PROGRAM; + + +   switch (*(*inst)++) { +      case PROGRAM_PARAM_ENV: +         state_tokens[1] = STATE_ENV; +         state_tokens[2] = parse_integer (inst, Program); +         /* Check state_tokens[2] against the number of ENV parameters available */ +         if (((Program->type == GL_FRAGMENT_PROGRAM_ARB) && +              (state_tokens[2] >= ctx->Const.MaxFragmentProgramEnvParams)) +             || +             ((Program->type == GL_VERTEX_PROGRAM_ARB) && +              (state_tokens[2] >= ctx->Const.MaxVertexProgramEnvParams))) { +            _mesa_set_program_error (ctx, Program->Position, +                                     "Invalid Program Env Parameter"); +            _mesa_error (ctx, GL_INVALID_OPERATION, +                         "Invalid Program Env Parameter: %d", +                         state_tokens[2]); +            return 1; +         } + +         break; + +      case PROGRAM_PARAM_LOCAL: +         state_tokens[1] = STATE_LOCAL; +         state_tokens[2] = parse_integer (inst, Program); +         /* Check state_tokens[2] against the number of LOCAL parameters available */ +         if (((Program->type == GL_FRAGMENT_PROGRAM_ARB) && +              (state_tokens[2] >= ctx->Const.MaxFragmentProgramLocalParams)) +             || +             ((Program->type == GL_VERTEX_PROGRAM_ARB) && +              (state_tokens[2] >= ctx->Const.MaxVertexProgramLocalParams))) { +            _mesa_set_program_error (ctx, Program->Position, +                                     "Invalid Program Local Parameter"); +            _mesa_error (ctx, GL_INVALID_OPERATION, +                         "Invalid Program Local Parameter: %d", +                         state_tokens[2]); +            return 1; +         } +         break; +   } + +   return 0; +} + + +/** + * This will handle the binding side of an ATTRIB var declaration + * + * \param binding     - the fragment input register state, defined in nvfragprog.h + * \param binding_idx - the index in the attrib register file that binding is associated with 	 + * \return returns 0 on sucess, 1 on error + * + * See nvfragparse.c for attrib register file layout + */ +static GLuint +parse_attrib_binding (GLcontext * ctx, byte ** inst, +                      struct arb_program *Program, GLuint * binding, +                      GLuint * binding_idx) +{ +   GLuint texcoord;	 +   GLint coord; +   GLint err = 0; + +   if (Program->type == GL_FRAGMENT_PROGRAM_ARB) { +      switch (*(*inst)++) { +         case FRAGMENT_ATTRIB_COLOR: +            err = parse_color_type (ctx, inst, Program, &coord); +            *binding = FRAG_ATTRIB_COL0 + coord; +            *binding_idx = 1 + coord; +            break; + +         case FRAGMENT_ATTRIB_TEXCOORD: +            err = parse_texcoord_num (ctx, inst, Program, &texcoord); +            *binding = FRAG_ATTRIB_TEX0 + texcoord; +            *binding_idx = 4 + texcoord; +            break; + +         case FRAGMENT_ATTRIB_FOGCOORD: +            *binding = FRAG_ATTRIB_FOGC; +            *binding_idx = 3; +            break; + +         case FRAGMENT_ATTRIB_POSITION: +            *binding = FRAG_ATTRIB_WPOS; +            *binding_idx = 0; +            break; + +         default: +            err = 1; +            break; +      } +   } +   else { +      switch (*(*inst)++) { +         case VERTEX_ATTRIB_POSITION: +            *binding = VERT_ATTRIB_POS; +            *binding_idx = 0; +            break; + +         case VERTEX_ATTRIB_WEIGHT: +            { +               GLint weight; + +               err = parse_weight_num (ctx, inst, Program, &weight); +               *binding = VERT_ATTRIB_WEIGHT; +               *binding_idx = 1; +            } +            break; + +         case VERTEX_ATTRIB_NORMAL: +            *binding = VERT_ATTRIB_NORMAL; +            *binding_idx = 2; +            break; + +         case VERTEX_ATTRIB_COLOR: +            { +               GLint color; + +               err = parse_color_type (ctx, inst, Program, &color); +               if (color) { +                  *binding = VERT_ATTRIB_COLOR1; +                  *binding_idx = 4; +               } +               else { +                  *binding = VERT_ATTRIB_COLOR0; +                  *binding_idx = 3; +               } +            } +            break; + +         case VERTEX_ATTRIB_FOGCOORD: +            *binding = VERT_ATTRIB_FOG; +            *binding_idx = 5; +            break; + +         case VERTEX_ATTRIB_TEXCOORD: +            { +               GLuint unit; + +               err = parse_texcoord_num (ctx, inst, Program, &unit); +               *binding = VERT_ATTRIB_TEX0 + unit; +               *binding_idx = 8 + unit; +            } +            break; + +            /* XXX: It looks like we don't support this at all, atm */ +         case VERTEX_ATTRIB_MATRIXINDEX: +            parse_integer (inst, Program); +            break; + +            /* XXX: */ +         case VERTEX_ATTRIB_GENERIC: +            break; + +         default: +            err = 1; +            break; +      } +   } + +   /* Can this even happen? */ +   if (err) { +      _mesa_set_program_error (ctx, Program->Position, +                               "Bad attribute binding"); +      _mesa_error (ctx, GL_INVALID_OPERATION, "Bad attribute binding"); +   } + +   Program->InputsRead |= (1 << *binding_idx); + +   return err; +} + +/** + * This translates between a binary token for an output variable type + * and the mesa token for the same thing. + * + * + * XXX: What is the 'name' for vertex program state? -> do we need it? + *         I don't think we do; + * + * See nvfragprog.h for definitions  + * + * \param inst        - The parsed tokens + * \param binding     - The name of the state we are binding too + * \param binding_idx - The index into the result register file that this is bound too + * + * See nvfragparse.c for the register file layout for fragment programs + * See nvvertparse.c for the register file layout for vertex programs + */ +static GLuint +parse_result_binding (GLcontext * ctx, byte ** inst, GLuint * binding, +                      GLuint * binding_idx, struct arb_program *Program) +{ +   GLint a; +   GLuint b; + +   switch (*(*inst)++) { +      case FRAGMENT_RESULT_COLOR: +         /* for frag programs, this is FRAGMENT_RESULT_COLOR */ +         if (Program->type == GL_FRAGMENT_PROGRAM_ARB) { +            *binding = FRAG_OUTPUT_COLR; +            *binding_idx = 0; +         } +         /* for vtx programs, this is VERTEX_RESULT_POSITION */ +         else { +            *binding_idx = 0; +         } +         break; + +      case FRAGMENT_RESULT_DEPTH: +         /* for frag programs, this is FRAGMENT_RESULT_DEPTH */ +         if (Program->type == GL_FRAGMENT_PROGRAM_ARB) { +            *binding = FRAG_OUTPUT_DEPR; +            *binding_idx = 2; +         } +         /* for vtx programs, this is VERTEX_RESULT_COLOR */ +         else { +            GLint color_type; + +            /* back face */ +            if (parse_face_type (inst)) { +               if (parse_color_type (ctx, inst, Program, &color_type)) +                  return 1; + +               /* secondary color */ +               if (color_type) { +                  *binding_idx = 4; +               } +               /*  primary color */ +               else { +                  *binding_idx = 3; +               } +            } +            /* front face */ +            else { +               /* secondary color */ +               if (color_type) { +                  *binding_idx = 2; +               } +               /* primary color */ +               else { +                  *binding_idx = 1; +               } +            } +         } +         break; + +      case VERTEX_RESULT_FOGCOORD: +         *binding_idx = 5; +         break; + +      case VERTEX_RESULT_POINTSIZE: +         *binding_idx = 6; +         break; + +      case VERTEX_RESULT_TEXCOORD: +         if (parse_texcoord_num (ctx, inst, Program, &b)) +            return 1; +         *binding_idx = 7 + b; +         break; +   } + +   Program->OutputsWritten |= (1 << *binding_idx); + +   return 0; +} + +/** + * This handles the declaration of ATTRIB variables + * + * XXX: Still needs  + *      parse_vert_attrib_binding(), or something like that + * + * \return 0 on sucess, 1 on error + */ +static GLint +parse_attrib (GLcontext * ctx, byte ** inst, struct var_cache **vc_head, +              struct arb_program *Program) +{ +   GLuint found; +   char *error_msg; +   struct var_cache *attrib_var; + +   attrib_var = parse_string (inst, vc_head, Program, &found); +   Program->Position = parse_position (inst); +   if (found) { +      error_msg = +         _mesa_malloc (_mesa_strlen ((char *) attrib_var->name) + 40); +      _mesa_sprintf (error_msg, "Duplicate Varible Declaration: %s", +                     attrib_var->name); + +      _mesa_set_program_error (ctx, Program->Position, error_msg); +      _mesa_error (ctx, GL_INVALID_OPERATION, error_msg); + +      _mesa_free (error_msg); +      return 1; +   } + +   attrib_var->type = vt_attrib; + +   /* I think this is ok now - karl */ +   /* XXX: */ +   /*if (Program->type == GL_FRAGMENT_PROGRAM_ARB) */ +   { +      if (parse_attrib_binding +          (ctx, inst, Program, &attrib_var->attrib_binding, +           &attrib_var->attrib_binding_idx)) +         return 1; +   } + +   Program->Base.NumAttributes++; +   return 0; +} + +/** + * \param use -- TRUE if we're called when declaring implicit parameters, + *               FALSE if we're declaraing variables. This has to do with + *               if we get a signed or unsigned float for scalar constants + */ +static GLuint +parse_param_elements (GLcontext * ctx, byte ** inst, +                      struct var_cache *param_var, +                      struct arb_program *Program, GLboolean use) +{ +   GLint idx; +   GLuint found, specified_length, err; +   GLint state_tokens[6]; +   GLfloat const_values[4]; +   char *error_msg; + +   err = 0; + +   switch (*(*inst)++) { +      case PARAM_STATE_ELEMENT: +         if (parse_state_single_item (ctx, inst, Program, state_tokens)) +            return 1; + +         /* If we adding STATE_MATRIX that has multiple rows, we need to +          * unroll it and call _mesa_add_state_reference() for each row +          */ +         if ((state_tokens[0] == STATE_MATRIX) +             && (state_tokens[3] != state_tokens[4])) { +            GLint row; +            GLint first_row = state_tokens[3]; +            GLint last_row = state_tokens[4]; + +            for (row = first_row; row <= last_row; row++) { +               state_tokens[3] = state_tokens[4] = row; + +               idx = +                  _mesa_add_state_reference (Program->Parameters, +                                             state_tokens); +               if (param_var->param_binding_begin == -1) +                  param_var->param_binding_begin = idx; +               param_var->param_binding_length++; +               Program->Base.NumParameters++; +            } +         } +         else { +            idx = +               _mesa_add_state_reference (Program->Parameters, state_tokens); +            if (param_var->param_binding_begin == -1) +               param_var->param_binding_begin = idx; +            param_var->param_binding_length++; +            Program->Base.NumParameters++; +         } +         break; + +      case PARAM_PROGRAM_ELEMENT: +         if (parse_program_single_item (ctx, inst, Program, state_tokens)) +            return 1; +         idx = _mesa_add_state_reference (Program->Parameters, state_tokens); +         if (param_var->param_binding_begin == -1) +            param_var->param_binding_begin = idx; +         param_var->param_binding_length++; +         Program->Base.NumParameters++; + +         /* Check if there is more: 0 -> we're done, else its an integer */ +         if (**inst) { +            GLuint out_of_range, new_idx; +            GLuint start_idx = state_tokens[2] + 1; +            GLuint end_idx = parse_integer (inst, Program); + +            out_of_range = 0; +            if (Program->type == GL_FRAGMENT_PROGRAM_ARB) { +               if (((state_tokens[1] == STATE_ENV) +                    && (end_idx >= ctx->Const.MaxFragmentProgramEnvParams)) +                   || ((state_tokens[1] == STATE_LOCAL) +                       && (end_idx >= +                           ctx->Const.MaxFragmentProgramLocalParams))) +                  out_of_range = 1; +            } +            else { +               if (((state_tokens[1] == STATE_ENV) +                    && (end_idx >= ctx->Const.MaxFragmentProgramEnvParams)) +                   || ((state_tokens[1] == STATE_LOCAL) +                       && (end_idx >= +                           ctx->Const.MaxFragmentProgramLocalParams))) +                  out_of_range = 1; +            } +            if (out_of_range) { +               _mesa_set_program_error (ctx, Program->Position, +                                        "Invalid Program Parameter"); +               _mesa_error (ctx, GL_INVALID_OPERATION, +                            "Invalid Program Parameter: %d", end_idx); +               return 1; +            } + +            for (new_idx = start_idx; new_idx <= end_idx; new_idx++) { +               state_tokens[2] = new_idx; +               idx = +                  _mesa_add_state_reference (Program->Parameters, +                                             state_tokens); +               param_var->param_binding_length++; +               Program->Base.NumParameters++; +            } +         } +         break; + +      case PARAM_CONSTANT: +         parse_constant (inst, const_values, Program, use); +         idx = +            _mesa_add_named_constant (Program->Parameters, +                                      (char *) param_var->name, const_values); +         if (param_var->param_binding_begin == -1) +            param_var->param_binding_begin = idx; +         param_var->param_binding_length++; +         Program->Base.NumParameters++; +         break; + +      default: +         _mesa_set_program_error (ctx, Program->Position, +                                  "Unexpected token in parse_param_elements()"); +         _mesa_error (ctx, GL_INVALID_OPERATION, +                      "Unexpected token in parse_param_elements()"); +         return 1; +   } + +   /* Make sure we haven't blown past our parameter limits */ +   if (((Program->type == GL_VERTEX_PROGRAM_ARB) && +        (Program->Base.NumParameters >= +         ctx->Const.MaxVertexProgramLocalParams)) +       || ((Program->type == GL_FRAGMENT_PROGRAM_ARB) +           && (Program->Base.NumParameters >= +               ctx->Const.MaxFragmentProgramLocalParams))) { +      _mesa_set_program_error (ctx, Program->Position, +                               "Too many parameter variables"); +      _mesa_error (ctx, GL_INVALID_OPERATION, "Too many parameter variables"); +      return 1; +   } + +   return err; +} + +/** + * This picks out PARAM program parameter bindings. + * + * XXX: This needs to be stressed & tested + * + * \return 0 on sucess, 1 on error + */ +static GLuint +parse_param (GLcontext * ctx, byte ** inst, struct var_cache **vc_head, +             struct arb_program *Program) +{ +   GLuint found, specified_length, err; +   GLint state_tokens[6]; +   GLfloat const_values[4]; +   char *error_msg; +   struct var_cache *param_var; + +   err = 0; +   param_var = parse_string (inst, vc_head, Program, &found); +   Program->Position = parse_position (inst); + +   if (found) { +      error_msg = _mesa_malloc (_mesa_strlen ((char *) param_var->name) + 40); +      _mesa_sprintf (error_msg, "Duplicate Varible Declaration: %s", +                     param_var->name); + +      _mesa_set_program_error (ctx, Program->Position, error_msg); +      _mesa_error (ctx, GL_INVALID_OPERATION, error_msg); + +      _mesa_free (error_msg); +      return 1; +   } + +   specified_length = parse_integer (inst, Program); + +   if (specified_length < 0) { +      _mesa_set_program_error (ctx, Program->Position, +                               "Negative parameter array length"); +      _mesa_error (ctx, GL_INVALID_OPERATION, +                   "Negative parameter array length: %d", specified_length); +      return 1; +   } + +   param_var->type = vt_param; +   param_var->param_binding_length = 0; + +   /* Right now, everything is shoved into the main state register file. +    *  +    * In the future, it would be nice to leave things ENV/LOCAL params +    * in their respective register files, if possible  +    */ +   param_var->param_binding_type = PROGRAM_STATE_VAR; + +   /* Remember to: +    * *   - add each guy to the parameter list +    * *   - increment the param_var->param_binding_len +    * *   - store the param_var->param_binding_begin for the first one +    * *   - compare the actual len to the specified len at the end +    */ +   while (**inst != PARAM_NULL) { +      if (parse_param_elements (ctx, inst, param_var, Program, GL_FALSE)) +         return 1; +   } + +   /* Test array length here! */ +   if (specified_length) { +      if (specified_length != param_var->param_binding_length) { +         _mesa_set_program_error (ctx, Program->Position, +                                  "Declared parameter array lenght does not match parameter list"); +         _mesa_error (ctx, GL_INVALID_OPERATION, +                      "Declared parameter array lenght does not match parameter list"); +      } +   } + +   (*inst)++; + +   return 0; +} + +/** + * + */ +static GLuint +parse_param_use (GLcontext * ctx, byte ** inst, struct var_cache **vc_head, +                 struct arb_program *Program, struct var_cache **new_var) +{ +   struct var_cache *param_var; + +   /* First, insert a dummy entry into the var_cache */ +   var_cache_create (¶m_var); +   param_var->name = (byte *) _mesa_strdup (" "); +   param_var->type = vt_param; + +   param_var->param_binding_length = 0; +   /* Don't fill in binding_begin; We use the default value of -1 +    * to tell if its already initialized, elsewhere. +    * +    * param_var->param_binding_begin  = 0; +    */ +   param_var->param_binding_type = PROGRAM_STATE_VAR; + + +   var_cache_append (vc_head, param_var); + +   /* Then fill it with juicy parameter goodness */ +   if (parse_param_elements (ctx, inst, param_var, Program, GL_TRUE)) +      return 1; + +   *new_var = param_var; + +   return 0; +} + + +/** + * This handles the declaration of TEMP variables + * + * \return 0 on sucess, 1 on error + */ +static GLuint +parse_temp (GLcontext * ctx, byte ** inst, struct var_cache **vc_head, +            struct arb_program *Program) +{ +   GLuint found; +   struct var_cache *temp_var; +   char *error_msg; + +   while (**inst != 0) { +      temp_var = parse_string (inst, vc_head, Program, &found); +      Program->Position = parse_position (inst); +      if (found) { +         error_msg = +            _mesa_malloc (_mesa_strlen ((char *) temp_var->name) + 40); +         _mesa_sprintf (error_msg, "Duplicate Varible Declaration: %s", +                        temp_var->name); + +         _mesa_set_program_error (ctx, Program->Position, error_msg); +         _mesa_error (ctx, GL_INVALID_OPERATION, error_msg); + +         _mesa_free (error_msg); +         return 1; +      } + +      temp_var->type = vt_temp; + +      if (((Program->type == GL_FRAGMENT_PROGRAM_ARB) && +           (Program->Base.NumTemporaries >= +            ctx->Const.MaxFragmentProgramTemps)) +          || ((Program->type == GL_VERTEX_PROGRAM_ARB) +              && (Program->Base.NumTemporaries >= +                  ctx->Const.MaxVertexProgramTemps))) { +         _mesa_set_program_error (ctx, Program->Position, +                                  "Too many TEMP variables declared"); +         _mesa_error (ctx, GL_INVALID_OPERATION, +                      "Too many TEMP variables declared"); +         return 1; +      } + +      temp_var->temp_binding = Program->Base.NumTemporaries; +      Program->Base.NumTemporaries++; +   } +   (*inst)++; + +   return 0; +} + +/** + * This handles variables of the OUTPUT variety + * + * \return 0 on sucess, 1 on error + */ +static GLuint +parse_output (GLcontext * ctx, byte ** inst, struct var_cache **vc_head, +              struct arb_program *Program) +{ +   GLuint found; +   struct var_cache *output_var; + +   output_var = parse_string (inst, vc_head, Program, &found); +   Program->Position = parse_position (inst); +   if (found) { +      char *error_msg; +      error_msg = +         _mesa_malloc (_mesa_strlen ((char *) output_var->name) + 40); +      _mesa_sprintf (error_msg, "Duplicate Varible Declaration: %s", +                     output_var->name); + +      _mesa_set_program_error (ctx, Program->Position, error_msg); +      _mesa_error (ctx, GL_INVALID_OPERATION, error_msg); + +      _mesa_free (error_msg); +      return 1; +   } + +   output_var->type = vt_output; +   return parse_result_binding (ctx, inst, &output_var->output_binding, +                                &output_var->output_binding_idx, Program); +} + +/** + * This handles variables of the ALIAS kind + * + * \return 0 on sucess, 1 on error + */ +static GLuint +parse_alias (GLcontext * ctx, byte ** inst, struct var_cache **vc_head, +             struct arb_program *Program) +{ +   GLuint found; +   struct var_cache *temp_var; +   char *error_msg; + +   while (**inst != 0) { +      temp_var = parse_string (inst, vc_head, Program, &found); +      Program->Position = parse_position (inst); +      if (found) { +         error_msg = +            _mesa_malloc (_mesa_strlen ((char *) temp_var->name) + 40); +         _mesa_sprintf (error_msg, "Duplicate Varible Declaration: %s", +                        temp_var->name); + +         _mesa_set_program_error (ctx, Program->Position, error_msg); +         _mesa_error (ctx, GL_INVALID_OPERATION, error_msg); + +         _mesa_free (error_msg); +         return 1; +      } + +      temp_var->type = vt_temp; + +      if (((Program->type == GL_FRAGMENT_PROGRAM_ARB) && +           (Program->Base.NumTemporaries >= +            ctx->Const.MaxFragmentProgramTemps)) +          || ((Program->type == GL_VERTEX_PROGRAM_ARB) +              && (Program->Base.NumTemporaries >= +                  ctx->Const.MaxVertexProgramTemps))) { +         _mesa_set_program_error (ctx, Program->Position, +                                  "Too many TEMP variables declared"); +         _mesa_error (ctx, GL_INVALID_OPERATION, +                      "Too many TEMP variables declared"); +         return 1; +      } + +      temp_var->temp_binding = Program->Base.NumTemporaries; +      Program->Base.NumTemporaries++; +   } +   (*inst)++; + +   return 0; +} + +/** + * This handles variables of the ADDRESS kind + * + * \return 0 on sucess, 1 on error + */ +static GLuint +parse_address (GLcontext * ctx, byte ** inst, struct var_cache **vc_head, +               struct arb_program *Program) +{ +   GLuint found; +   struct var_cache *temp_var; +   char *error_msg; + +   while (**inst != 0) { +      temp_var = parse_string (inst, vc_head, Program, &found); +      Program->Position = parse_position (inst); +      if (found) { +         error_msg = +            _mesa_malloc (_mesa_strlen ((char *) temp_var->name) + 40); +         _mesa_sprintf (error_msg, "Duplicate Varible Declaration: %s", +                        temp_var->name); + +         _mesa_set_program_error (ctx, Program->Position, error_msg); +         _mesa_error (ctx, GL_INVALID_OPERATION, error_msg); + +         _mesa_free (error_msg); +         return 1; +      } + +      temp_var->type = vt_address; + +      if (Program->Base.NumAddressRegs >= +          ctx->Const.MaxVertexProgramAddressRegs) { +         _mesa_set_program_error (ctx, Program->Position, +                                  "Too many ADDRESS variables declared"); +         _mesa_error (ctx, GL_INVALID_OPERATION, +                      "Too many ADDRESS variables declared"); +         return 1; +      } + +      temp_var->address_binding = Program->Base.NumAddressRegs; +      Program->Base.NumAddressRegs++; +   } +   (*inst)++; + +   return 0; +} + +/** + * Parse a program declaration  + * + * \return 0 on sucess, 1 on error + */ +static GLint +parse_declaration (GLcontext * ctx, byte ** inst, struct var_cache **vc_head, +                   struct arb_program *Program) +{ +   GLint err = 0; + +   switch (*(*inst)++) { +      case ADDRESS: +         err = parse_address (ctx, inst, vc_head, Program); +         break; + +      case ALIAS: +         err = parse_alias (ctx, inst, vc_head, Program); +         break; + +      case ATTRIB: +         err = parse_attrib (ctx, inst, vc_head, Program); +         break; + +      case OUTPUT: +         err = parse_output (ctx, inst, vc_head, Program); +         break; + +      case PARAM: +         err = parse_param (ctx, inst, vc_head, Program); +         break; + +      case TEMP: +         err = parse_temp (ctx, inst, vc_head, Program); +         break; +   } + +   return err; +} + +/** + * Handle the parsing out of a masked destination register + * + * \param File      - The register file we write to + * \param Index     - The register index we write to + * \param WriteMask - The mask controlling which components we write (1->write) + * + * \return 0 on sucess, 1 on error + */ +static GLuint +parse_masked_dst_reg (GLcontext * ctx, byte ** inst, +                      struct var_cache **vc_head, struct arb_program *Program, +                      GLint * File, GLint * Index, GLboolean * WriteMask) +{ +   GLuint err, result; +   byte mask; +   struct var_cache *dst; + +   /* We either have a result register specified, or a +    * variable that may or may not be writable  +    */ +   switch (*(*inst)++) { +      case REGISTER_RESULT: +         if (parse_result_binding +             (ctx, inst, &result, (GLuint *) Index, Program)) +            return 1; +         *File = PROGRAM_OUTPUT; +         break; + +      case REGISTER_ESTABLISHED_NAME: +         dst = parse_string (inst, vc_head, Program, &result); +         Program->Position = parse_position (inst); + +         /* If the name has never been added to our symbol table, we're hosed */ +         if (!result) { +            _mesa_set_program_error (ctx, Program->Position, +                                     "Undefined variable"); +            _mesa_error (ctx, GL_INVALID_OPERATION, "Undefined variable: %s", +                         dst->name); +            return 1; +         } + +         switch (dst->type) { +            case vt_output: +               *File = PROGRAM_OUTPUT; +               *Index = dst->output_binding_idx; +               break; + +            case vt_temp: +               *File = PROGRAM_TEMPORARY; +               *Index = dst->temp_binding; +               break; + +               /* If the var type is not vt_output or vt_temp, no go */ +            default: +               _mesa_set_program_error (ctx, Program->Position, +                                        "Destination register is read only"); +               _mesa_error (ctx, GL_INVALID_OPERATION, +                            "Destination register is read only: %s", +                            dst->name); +               return 1; +         } +         break; + +      default: +         _mesa_set_program_error (ctx, Program->Position, +                                  "Unexpected opcode in parse_masked_dst_reg()"); +         _mesa_error (ctx, GL_INVALID_OPERATION, +                      "Unexpected opcode in parse_masked_dst_reg()"); +         return 1; +   } + +   /* And then the mask. +    *  w,a -> bit 0 +    *  z,b -> bit 1 +    *  y,g -> bit 2 +    *  x,r -> bit 3 +    */ +   mask = *(*inst)++; + +   WriteMask[0] = (mask & (1 << 3)) >> 3; +   WriteMask[1] = (mask & (1 << 2)) >> 2; +   WriteMask[2] = (mask & (1 << 1)) >> 1; +   WriteMask[3] = (mask & (1)); + +   return 0; +} + +/** + * Handle the parsing out of a masked address register + * + * \param Index     - The register index we write to + * \param WriteMask - The mask controlling which components we write (1->write) + * + * \return 0 on sucess, 1 on error + */ +static GLuint +parse_masked_address_reg (GLcontext * ctx, byte ** inst, +                          struct var_cache **vc_head, +                          struct arb_program *Program, GLint * Index, +                          GLboolean * WriteMask) +{ +   GLuint err, result; +   byte mask; +   struct var_cache *dst; + +   dst = parse_string (inst, vc_head, Program, &result); +   Program->Position = parse_position (inst); + +   /* If the name has never been added to our symbol table, we're hosed */ +   if (!result) { +      _mesa_set_program_error (ctx, Program->Position, "Undefined variable"); +      _mesa_error (ctx, GL_INVALID_OPERATION, "Undefined variable: %s", +                   dst->name); +      return 1; +   } + +   if (dst->type != vt_address) { +      _mesa_set_program_error (ctx, Program->Position, +                               "Variable is not of type ADDRESS"); +      _mesa_error (ctx, GL_INVALID_OPERATION, +                   "Variable: %s is not of type ADDRESS", dst->name); +      return 1; +   } + +   /* Writemask of .x is implied */ +   WriteMask[0] = 1; +   WriteMask[1] = WriteMask[2] = WriteMask[3] = 0; + +   return 0; +} + +/**  + * Parse out a swizzle mask. + * + * The values in the input stream are:  + *   COMPONENT_X -> x/r + *   COMPONENT_Y -> y/g + *   COMPONENT_Z-> z/b + *   COMPONENT_W-> w/a + * + * The values in the output mask are: + *   0 -> x/r + *   1 -> y/g + *   2 -> z/b + *   3 -> w/a + * + * The len parameter allows us to grab 4 components for a vector + * swizzle, or just 1 component for a scalar src register selection + */ +static GLuint +parse_swizzle_mask (byte ** inst, GLubyte * mask, GLint len) +{ +   GLint a; + +   for (a = 0; a < 4; a++) +      mask[a] = a; + +   for (a = 0; a < len; a++) { +      switch (*(*inst)++) { +         case COMPONENT_X: +            mask[a] = 0; +            break; + +         case COMPONENT_Y: +            mask[a] = 1; +            break; + +         case COMPONENT_Z: +            mask[a] = 2; +            break; + +         case COMPONENT_W: +            mask[a] = 3; +            break; +      } +   } + +   return 0; +} + +/**  + */ +static GLuint +parse_extended_swizzle_mask (byte ** inst, GLubyte * mask, GLboolean * Negate) +{ +   GLint a; +   byte swz; + +   *Negate = GL_FALSE; +   for (a = 0; a < 4; a++) { +      if (parse_sign (inst)) +         *Negate = GL_TRUE; + +      swz = *(*inst)++; + +      switch (swz) { +         case COMPONENT_0: +            mask[a] = SWIZZLE_ZERO; +            break; +         case COMPONENT_1: +            mask[a] = SWIZZLE_ONE; +            break; +         case COMPONENT_X: +            mask[a] = 0; +            break; +         case COMPONENT_Y: +            mask[a] = 1; +            break; +         case COMPONENT_Z: +            mask[a] = 2; +            break; +         case COMPONENT_W: +            mask[a] = 3; +            break; + +      } +#if 0 +      if (swz == 0) +         mask[a] = SWIZZLE_ZERO; +      else if (swz == 1) +         mask[a] = SWIZZLE_ONE; +      else +         mask[a] = swz - 2; +#endif + +   } + +   return 0; +} + + +static GLuint +parse_src_reg (GLcontext * ctx, byte ** inst, struct var_cache **vc_head, +               struct arb_program *Program, GLint * File, GLint * Index) +{ +   struct var_cache *src; +   GLuint binding_state, binding_idx, found, offset; + +   /* And the binding for the src */ +   switch (*(*inst)++) { +      case REGISTER_ATTRIB: +         if (parse_attrib_binding +             (ctx, inst, Program, &binding_state, &binding_idx)) +            return 1; +         *File = PROGRAM_INPUT; +         *Index = binding_idx; +         break; + +      case REGISTER_PARAM: + +         switch (**inst) { +            case PARAM_ARRAY_ELEMENT: +               *(*inst)++; +               src = parse_string (inst, vc_head, Program, &found); +               Program->Position = parse_position (inst); + +               if (!found) { +                  _mesa_set_program_error (ctx, Program->Position, +                                           "Undefined variable"); +                  _mesa_error (ctx, GL_INVALID_OPERATION, +                               "Undefined variable: %s", src->name); +                  return 1; +               } + +               *File = src->param_binding_type; + +               switch (*(*inst)++) { +                  case ARRAY_INDEX_ABSOLUTE: +                     offset = parse_integer (inst, Program); + +                     if ((offset < 0) +                         || (offset >= src->param_binding_length)) { +                        _mesa_set_program_error (ctx, Program->Position, +                                                 "Index out of range"); +                        _mesa_error (ctx, GL_INVALID_OPERATION, +                                     "Index %d out of range for %s", offset, +                                     src->name); +                        return 1; +                     } + +                     *Index = src->param_binding_begin + offset; +                     break; + +                     /* XXX: */ +                  case ARRAY_INDEX_RELATIVE: +                     break; +               } +               break; + +            default: +               if (parse_param_use (ctx, inst, vc_head, Program, &src)) +                  return 1; + +               *File = src->param_binding_type; +               *Index = src->param_binding_begin; +               break; +         } +         break; + +      case REGISTER_ESTABLISHED_NAME: +         src = parse_string (inst, vc_head, Program, &found); +         Program->Position = parse_position (inst); + +         /* If the name has never been added to our symbol table, we're hosed */ +         if (!found) { +            _mesa_set_program_error (ctx, Program->Position, +                                     "Undefined variable"); +            _mesa_error (ctx, GL_INVALID_OPERATION, "Undefined variable: %s", +                         src->name); +            return 1; +         } + +         switch (src->type) { +            case vt_attrib: +               *File = PROGRAM_INPUT; +               *Index = src->attrib_binding_idx; +               break; + +               /* XXX: We have to handle offsets someplace in here!  -- or are those above? */ +            case vt_param: +               *File = src->param_binding_type; +               *Index = src->param_binding_begin; +               break; + +            case vt_temp: +               *File = PROGRAM_TEMPORARY; +               *Index = src->temp_binding; +               break; + +               /* If the var type is vt_output no go */ +            default: +               _mesa_set_program_error (ctx, Program->Position, +                                        "destination register is read only"); +               _mesa_error (ctx, GL_INVALID_OPERATION, +                            "destination register is read only: %s", +                            src->name); +               return 1; +         } +         break; + +      default: +         _mesa_set_program_error (ctx, Program->Position, +                                  "Unknown token in parse_src_reg"); +         _mesa_error (ctx, GL_INVALID_OPERATION, +                      "Unknown token in parse_src_reg"); +         return 1; +   } + +   return 0; +} + +/** + */ +static GLuint +parse_vector_src_reg (GLcontext * ctx, byte ** inst, +                      struct var_cache **vc_head, struct arb_program *Program, +                      GLint * File, GLint * Index, GLboolean * Negate, +                      GLubyte * Swizzle) +{ +   /* Grab the sign */ +   *Negate = parse_sign (inst); + +   /* And the src reg */ +   if (parse_src_reg (ctx, inst, vc_head, Program, File, Index)) +      return 1; + +   /* finally, the swizzle */ +   parse_swizzle_mask (inst, Swizzle, 4); + +   return 0; +} + +/** + */ +static GLuint +parse_scalar_src_reg (GLcontext * ctx, byte ** inst, +                      struct var_cache **vc_head, struct arb_program *Program, +                      GLint * File, GLint * Index, GLboolean * Negate, +                      GLubyte * Swizzle) +{ +   GLint a; + +   /* Grab the sign */ +   *Negate = parse_sign (inst); + +   /* And the src reg */ +   if (parse_src_reg (ctx, inst, vc_head, Program, File, Index)) +      return 1; + +   /* Now, get the component and shove it into all the swizzle slots  */ +   parse_swizzle_mask (inst, Swizzle, 1); + +   return 0; +} + +/** + * This is a big mother that handles getting opcodes into the instruction + * and handling the src & dst registers for fragment program instructions + */ +static GLuint +parse_fp_instruction (GLcontext * ctx, byte ** inst, +                      struct var_cache **vc_head, struct arb_program *Program, +                      struct fp_instruction *fp) +{ +   GLint a, b; +   GLubyte swz[4]; /* FP's swizzle mask is a GLubyte, while VP's is GLuint */ +   GLuint texcoord; +   byte class, type, code; + +   /* No condition codes in ARB_fp */ +   fp->UpdateCondRegister = 0; + +   /* Record the position in the program string for debugging */ +   fp->StringPos = Program->Position; + +   /* F_ALU_INST or F_TEX_INST */ +   class = *(*inst)++; + +   /* F_ALU_{VECTOR, SCALAR, BINSC, BIN, TRI, SWZ},  +    * F_TEX_{SAMPLE, KIL} +    */ +   type = *(*inst)++; + +   /* The actual opcode name */ +   code = *(*inst)++; + + +   /* Increment the correct count */ +   switch (class) { +      case F_ALU_INST: +         Program->NumAluInstructions++; +         break; +      case F_TEX_INST: +         Program->NumTexInstructions++; +         break; +   } + +   fp->Saturate = 0; +   fp->Precision = FLOAT32; + +   fp->DstReg.CondMask = COND_TR; + +   switch (type) { +      case F_ALU_VECTOR: +         switch (code) { +            case F_ABS_SAT: +               fp->Saturate = 1; +            case F_ABS: +               fp->Opcode = FP_OPCODE_ABS; +               break; + +            case F_FLR_SAT: +               fp->Saturate = 1; +            case F_FLR: +               fp->Opcode = FP_OPCODE_FLR; +               break; + +            case F_FRC_SAT: +               fp->Saturate = 1; +            case F_FRC: +               fp->Opcode = FP_OPCODE_FRC; +               break; + +            case F_LIT_SAT: +               fp->Saturate = 1; +            case F_LIT: +               fp->Opcode = FP_OPCODE_LIT; +               break; + +            case F_MOV_SAT: +               fp->Saturate = 1; +            case F_MOV: +               fp->Opcode = FP_OPCODE_MOV; +               break; +         } + +         if (parse_masked_dst_reg +             (ctx, inst, vc_head, Program, (GLint *) & fp->DstReg.File, +              &fp->DstReg.Index, fp->DstReg.WriteMask)) +            return 1; + +         fp->SrcReg[0].Abs = GL_FALSE; +         fp->SrcReg[0].NegateAbs = GL_FALSE; +         if (parse_vector_src_reg +             (ctx, inst, vc_head, Program, (GLint *) & fp->SrcReg[0].File, +              &fp->SrcReg[0].Index, &fp->SrcReg[0].NegateBase, +              swz)) +            return 1; +         for (b=0; b<4; b++) +            fp->SrcReg[0].Swizzle[b] = swz[b]; +         break; + +      case F_ALU_SCALAR: +         switch (code) { +            case F_COS_SAT: +               fp->Saturate = 1; +            case F_COS: +               fp->Opcode = FP_OPCODE_COS; +               break; + +            case F_EX2_SAT: +               fp->Saturate = 1; +            case F_EX2: +               fp->Opcode = FP_OPCODE_EX2; +               break; + +            case F_LG2_SAT: +               fp->Saturate = 1; +            case F_LG2: +               fp->Opcode = FP_OPCODE_LG2; +               break; + +            case F_RCP_SAT: +               fp->Saturate = 1; +            case F_RCP: +               fp->Opcode = FP_OPCODE_RCP; +               break; + +            case F_RSQ_SAT: +               fp->Saturate = 1; +            case F_RSQ: +               fp->Opcode = FP_OPCODE_RSQ; +               break; + +            case F_SIN_SAT: +               fp->Saturate = 1; +            case F_SIN: +               fp->Opcode = FP_OPCODE_SIN; +               break; + +            case F_SCS_SAT: +               fp->Saturate = 1; +            case F_SCS: +               fp->Opcode = FP_OPCODE_SCS; +               break; +         } + +         if (parse_masked_dst_reg +             (ctx, inst, vc_head, Program, (GLint *) & fp->DstReg.File, +              &fp->DstReg.Index, fp->DstReg.WriteMask)) +            return 1; +         fp->SrcReg[0].Abs = GL_FALSE; +         fp->SrcReg[0].NegateAbs = GL_FALSE; +         if (parse_scalar_src_reg +             (ctx, inst, vc_head, Program, (GLint *) & fp->SrcReg[0].File, +              &fp->SrcReg[0].Index, &fp->SrcReg[0].NegateBase, +              swz)) +            return 1; +         for (b=0; b<4; b++) +            fp->SrcReg[0].Swizzle[b] = swz[b]; +         break; + +      case F_ALU_BINSC: +         switch (code) { +            case F_POW_SAT: +               fp->Saturate = 1; +            case F_POW: +               fp->Opcode = FP_OPCODE_POW; +               break; +         } + +         if (parse_masked_dst_reg +             (ctx, inst, vc_head, Program, (GLint *) & fp->DstReg.File, +              &fp->DstReg.Index, fp->DstReg.WriteMask)) +            return 1; +         for (a = 0; a < 2; a++) { +            fp->SrcReg[a].Abs = GL_FALSE; +            fp->SrcReg[a].NegateAbs = GL_FALSE; +            if (parse_scalar_src_reg +                (ctx, inst, vc_head, Program, (GLint *) & fp->SrcReg[a].File, +                 &fp->SrcReg[a].Index, &fp->SrcReg[a].NegateBase, +                 swz)) +               return 1; +            for (b=0; b<4; b++) +               fp->SrcReg[a].Swizzle[b] = swz[b]; +         } +         break; + + +      case F_ALU_BIN: +         switch (code) { +            case F_ADD_SAT: +               fp->Saturate = 1; +            case F_ADD: +               fp->Opcode = FP_OPCODE_ADD; +               break; + +            case F_DP3_SAT: +               fp->Saturate = 1; +            case F_DP3: +               fp->Opcode = FP_OPCODE_DP3; +               break; + +            case F_DP4_SAT: +               fp->Saturate = 1; +            case F_DP4: +               fp->Opcode = FP_OPCODE_DP4; +               break; + +            case F_DPH_SAT: +               fp->Saturate = 1; +            case F_DPH: +               fp->Opcode = FP_OPCODE_DPH; +               break; + +            case F_DST_SAT: +               fp->Saturate = 1; +            case F_DST: +               fp->Opcode = FP_OPCODE_DST; +               break; + +            case F_MAX_SAT: +               fp->Saturate = 1; +            case F_MAX: +               fp->Opcode = FP_OPCODE_MAX; +               break; + +            case F_MIN_SAT: +               fp->Saturate = 1; +            case F_MIN: +               fp->Opcode = FP_OPCODE_MIN; +               break; + +            case F_MUL_SAT: +               fp->Saturate = 1; +            case F_MUL: +               fp->Opcode = FP_OPCODE_MUL; +               break; + +            case F_SGE_SAT: +               fp->Saturate = 1; +            case F_SGE: +               fp->Opcode = FP_OPCODE_SGE; +               break; + +            case F_SLT_SAT: +               fp->Saturate = 1; +            case F_SLT: +               fp->Opcode = FP_OPCODE_SLT; +               break; + +            case F_SUB_SAT: +               fp->Saturate = 1; +            case F_SUB: +               fp->Opcode = FP_OPCODE_SUB; +               break; + +            case F_XPD_SAT: +               fp->Saturate = 1; +            case F_XPD: +               fp->Opcode = FP_OPCODE_X2D; +               break; +         } + +         if (parse_masked_dst_reg +             (ctx, inst, vc_head, Program, (GLint *) & fp->DstReg.File, +              &fp->DstReg.Index, fp->DstReg.WriteMask)) +            return 1; +         for (a = 0; a < 2; a++) { +            fp->SrcReg[a].Abs = GL_FALSE; +            fp->SrcReg[a].NegateAbs = GL_FALSE; +            if (parse_vector_src_reg +                (ctx, inst, vc_head, Program, (GLint *) & fp->SrcReg[a].File, +                 &fp->SrcReg[a].Index, &fp->SrcReg[a].NegateBase, +                 swz)) +               return 1; +            for (b=0; b<4; b++) +               fp->SrcReg[a].Swizzle[b] = swz[b]; +         } +         break; + +      case F_ALU_TRI: +         switch (code) { +            case F_CMP_SAT: +               fp->Saturate = 1; +            case F_CMP: +               fp->Opcode = FP_OPCODE_CMP; +               break; + +            case F_LRP_SAT: +               fp->Saturate = 1; +            case F_LRP: +               fp->Opcode = FP_OPCODE_LRP; +               break; + +            case F_MAD_SAT: +               fp->Saturate = 1; +            case F_MAD: +               fp->Opcode = FP_OPCODE_MAD; +               break; +         } + +         if (parse_masked_dst_reg +             (ctx, inst, vc_head, Program, (GLint *) & fp->DstReg.File, +              &fp->DstReg.Index, fp->DstReg.WriteMask)) +            return 1; +         for (a = 0; a < 3; a++) { +            fp->SrcReg[a].Abs = GL_FALSE; +            fp->SrcReg[a].NegateAbs = GL_FALSE; +            if (parse_vector_src_reg +                (ctx, inst, vc_head, Program, (GLint *) & fp->SrcReg[a].File, +                 &fp->SrcReg[a].Index, &fp->SrcReg[a].NegateBase, +                 swz)) +               return 1; +            for (b=0; b<4; b++) +               fp->SrcReg[a].Swizzle[b] = swz[b]; +         } +         break; + +      case F_ALU_SWZ: +         switch (code) { +            case F_SWZ_SAT: +               fp->Saturate = 1; +            case F_SWZ: +               fp->Opcode = FP_OPCODE_SWZ; +               break; +         } +         if (parse_masked_dst_reg +             (ctx, inst, vc_head, Program, (GLint *) & fp->DstReg.File, +              &fp->DstReg.Index, fp->DstReg.WriteMask)) +            return 1; + +         if (parse_src_reg +             (ctx, inst, vc_head, Program, (GLint *) & fp->SrcReg[0].File, +              &fp->SrcReg[0].Index)) +            return 1; +         parse_extended_swizzle_mask (inst, swz, +                                      &fp->SrcReg[0].NegateBase); +         for (b=0; b<4; b++) +            fp->SrcReg[0].Swizzle[b] = swz[b]; +         break; + +      case F_TEX_SAMPLE: +         switch (code) { +            case F_TEX_SAT: +               fp->Saturate = 1; +            case F_TEX: +               fp->Opcode = FP_OPCODE_TEX; +               break; + +            case F_TXP_SAT: +               fp->Saturate = 1; +            case F_TXP: +               fp->Opcode = FP_OPCODE_TXP; +               break; + +            case F_TXB_SAT: +               fp->Saturate = 1; +            case F_TXB: +               fp->Opcode = FP_OPCODE_TXB; +               break; +         } + +         if (parse_masked_dst_reg +             (ctx, inst, vc_head, Program, (GLint *) & fp->DstReg.File, +              &fp->DstReg.Index, fp->DstReg.WriteMask)) +            return 1; +         fp->SrcReg[0].Abs = GL_FALSE; +         fp->SrcReg[0].NegateAbs = GL_FALSE; +         if (parse_vector_src_reg +             (ctx, inst, vc_head, Program, (GLint *) & fp->SrcReg[0].File, +              &fp->SrcReg[0].Index, &fp->SrcReg[0].NegateBase, +              swz)) +            return 1; +         for (b=0; b<4; b++) +            fp->SrcReg[0].Swizzle[b] = swz[b]; + +         /* texImageUnit */ +         if (parse_texcoord_num (ctx, inst, Program, &texcoord)) +            return 1; +         fp->TexSrcUnit = texcoord; + +         /* texTarget */ +         switch (*(*inst)) { +            case TEXTARGET_1D: +               fp->TexSrcBit = TEXTURE_1D_BIT; +               break; +            case TEXTARGET_2D: +               fp->TexSrcBit = TEXTURE_2D_BIT; +               break; +            case TEXTARGET_3D: +               fp->TexSrcBit = TEXTURE_3D_BIT; +               break; +            case TEXTARGET_RECT: +               fp->TexSrcBit = TEXTURE_RECT_BIT; +               break; +            case TEXTARGET_CUBE: +               fp->TexSrcBit = TEXTURE_CUBE_BIT; +               break; +         } +         break; + +      case F_TEX_KIL: +         fp->Opcode = FP_OPCODE_KIL; +         fp->SrcReg[0].Abs = GL_FALSE; +         fp->SrcReg[0].NegateAbs = GL_FALSE; +         if (parse_vector_src_reg +             (ctx, inst, vc_head, Program, (GLint *) & fp->SrcReg[0].File, +              &fp->SrcReg[0].Index, &fp->SrcReg[0].NegateBase, +              swz)) +            return 1; +         for (b=0; b<4; b++) +            fp->SrcReg[0].Swizzle[b] = swz[b]; +         break; +   } + +   return 0; +} + +/** + * This is a big mother that handles getting opcodes into the instruction + * and handling the src & dst registers for vertex program instructions + */ +static GLuint +parse_vp_instruction (GLcontext * ctx, byte ** inst, +                      struct var_cache **vc_head, struct arb_program *Program, +                      struct vp_instruction *vp) +{ +   GLint a; +   byte type, code; + +   /* V_GEN_{ARL, VECTOR, SCALAR, BINSC, BIN, TRI, SWZ} */ +   type = *(*inst)++; + +   /* The actual opcode name */ +   code = *(*inst)++; + +   vp->SrcReg[0].RelAddr = vp->SrcReg[1].RelAddr = vp->SrcReg[2].RelAddr = 0; + +   for (a = 0; a < 4; a++) { +      vp->SrcReg[0].Swizzle[a] = a; +      vp->SrcReg[1].Swizzle[a] = a; +      vp->SrcReg[2].Swizzle[a] = a; +      vp->DstReg.WriteMask[a] = 1; +   } + +   switch (type) { +         /* XXX: */ +      case V_GEN_ARL: +         vp->Opcode = VP_OPCODE_ARL; + +         /* Remember to set SrcReg.RelAddr; */ + +         /* Get the masked address register [dst] */ +         if (parse_masked_address_reg +             (ctx, inst, vc_head, Program, &vp->DstReg.Index, +              vp->DstReg.WriteMask)) +            return 1; +         vp->DstReg.File = PROGRAM_ADDRESS; + + +         /* Get a scalar src register */ +         if (parse_scalar_src_reg +             (ctx, inst, vc_head, Program, (GLint *) & vp->SrcReg[0].File, +              &vp->SrcReg[0].Index, &vp->SrcReg[0].Negate, +              vp->SrcReg[0].Swizzle)) +            return 1; + +         break; + +      case V_GEN_VECTOR: +         switch (code) { +            case V_ABS: +               vp->Opcode = VP_OPCODE_ABS; +               break; +            case V_FLR: +               vp->Opcode = VP_OPCODE_FLR; +               break; +            case V_FRC: +               vp->Opcode = VP_OPCODE_FRC; +               break; +            case V_LIT: +               vp->Opcode = VP_OPCODE_LIT; +               break; +            case V_MOV: +               vp->Opcode = VP_OPCODE_MOV; +               break; +         } +         if (parse_masked_dst_reg +             (ctx, inst, vc_head, Program, (GLint *) & vp->DstReg.File, +              &vp->DstReg.Index, vp->DstReg.WriteMask)) +            return 1; +         if (parse_vector_src_reg +             (ctx, inst, vc_head, Program, (GLint *) & vp->SrcReg[0].File, +              &vp->SrcReg[0].Index, &vp->SrcReg[0].Negate, +              vp->SrcReg[0].Swizzle)) +            return 1; +         break; + +      case V_GEN_SCALAR: +         switch (code) { +            case V_EX2: +               vp->Opcode = VP_OPCODE_EX2; +               break; +            case V_EXP: +               vp->Opcode = VP_OPCODE_EXP; +               break; +            case V_LG2: +               vp->Opcode = VP_OPCODE_LG2; +               break; +            case V_LOG: +               vp->Opcode = VP_OPCODE_LOG; +               break; +            case V_RCP: +               vp->Opcode = VP_OPCODE_RCP; +               break; +            case V_RSQ: +               vp->Opcode = VP_OPCODE_RSQ; +               break; +         } +         if (parse_masked_dst_reg +             (ctx, inst, vc_head, Program, (GLint *) & vp->DstReg.File, +              &vp->DstReg.Index, vp->DstReg.WriteMask)) +            return 1; +         if (parse_scalar_src_reg +             (ctx, inst, vc_head, Program, (GLint *) & vp->SrcReg[0].File, +              &vp->SrcReg[0].Index, &vp->SrcReg[0].Negate, +              vp->SrcReg[0].Swizzle)) +            return 1; +         break; + +      case V_GEN_BINSC: +         switch (code) { +            case V_POW: +               vp->Opcode = VP_OPCODE_POW; +               break; +         } +         if (parse_masked_dst_reg +             (ctx, inst, vc_head, Program, (GLint *) & vp->DstReg.File, +              &vp->DstReg.Index, vp->DstReg.WriteMask)) +            return 1; +         for (a = 0; a < 2; a++) { +            if (parse_scalar_src_reg +                (ctx, inst, vc_head, Program, (GLint *) & vp->SrcReg[a].File, +                 &vp->SrcReg[a].Index, &vp->SrcReg[a].Negate, +                 vp->SrcReg[a].Swizzle)) +               return 1; +         } +         break; + +      case V_GEN_BIN: +         switch (code) { +            case V_ADD: +               vp->Opcode = VP_OPCODE_ADD; +               break; +            case V_DP3: +               vp->Opcode = VP_OPCODE_DP3; +               break; +            case V_DP4: +               vp->Opcode = VP_OPCODE_DP4; +               break; +            case V_DPH: +               vp->Opcode = VP_OPCODE_DPH; +               break; +            case V_DST: +               vp->Opcode = VP_OPCODE_DST; +               break; +            case V_MAX: +               vp->Opcode = VP_OPCODE_MAX; +               break; +            case V_MIN: +               vp->Opcode = VP_OPCODE_MIN; +               break; +            case V_MUL: +               vp->Opcode = VP_OPCODE_MUL; +               break; +            case V_SGE: +               vp->Opcode = VP_OPCODE_SGE; +               break; +            case V_SLT: +               vp->Opcode = VP_OPCODE_SLT; +               break; +            case V_SUB: +               vp->Opcode = VP_OPCODE_SUB; +               break; +            case V_XPD: +               vp->Opcode = VP_OPCODE_XPD; +               break; +         } +         if (parse_masked_dst_reg +             (ctx, inst, vc_head, Program, (GLint *) & vp->DstReg.File, +              &vp->DstReg.Index, vp->DstReg.WriteMask)) +            return 1; +         for (a = 0; a < 2; a++) { +            if (parse_vector_src_reg +                (ctx, inst, vc_head, Program, (GLint *) & vp->SrcReg[a].File, +                 &vp->SrcReg[a].Index, &vp->SrcReg[a].Negate, +                 vp->SrcReg[a].Swizzle)) +               return 1; +         } +         break; + +      case V_GEN_TRI: +         switch (code) { +            case V_MAD: +               vp->Opcode = VP_OPCODE_MAD; +               break; +         } + +         if (parse_masked_dst_reg +             (ctx, inst, vc_head, Program, (GLint *) & vp->DstReg.File, +              &vp->DstReg.Index, vp->DstReg.WriteMask)) +            return 1; +         for (a = 0; a < 3; a++) { +            if (parse_vector_src_reg +                (ctx, inst, vc_head, Program, (GLint *) & vp->SrcReg[a].File, +                 &vp->SrcReg[a].Index, &vp->SrcReg[a].Negate, +                 vp->SrcReg[a].Swizzle)) +               return 1; +         } +         break; + +      case V_GEN_SWZ: +         switch (code) { +            case V_SWZ: +               vp->Opcode = VP_OPCODE_SWZ; +               break; +         } +         if (parse_masked_dst_reg +             (ctx, inst, vc_head, Program, (GLint *) & vp->DstReg.File, +              &vp->DstReg.Index, vp->DstReg.WriteMask)) +            return 1; + +         if (parse_src_reg +             (ctx, inst, vc_head, Program, (GLint *) & vp->SrcReg[0].File, +              &vp->SrcReg[0].Index)) +            return 1; +         parse_extended_swizzle_mask (inst, vp->SrcReg[0].Swizzle, +                                      &vp->SrcReg[0].Negate); +         break; +   } +   return 0; +} + +#if DEBUG_PARSING + +static GLvoid +print_state_token (GLint token) +{ +   switch (token) { +      case STATE_MATERIAL: +         fprintf (stderr, "STATE_MATERIAL "); +         break; +      case STATE_LIGHT: +         fprintf (stderr, "STATE_LIGHT "); +         break; + +      case STATE_LIGHTMODEL_AMBIENT: +         fprintf (stderr, "STATE_AMBIENT "); +         break; + +      case STATE_LIGHTMODEL_SCENECOLOR: +         fprintf (stderr, "STATE_SCENECOLOR "); +         break; + +      case STATE_LIGHTPROD: +         fprintf (stderr, "STATE_LIGHTPROD "); +         break; + +      case STATE_TEXGEN: +         fprintf (stderr, "STATE_TEXGEN "); +         break; + +      case STATE_FOG_COLOR: +         fprintf (stderr, "STATE_FOG_COLOR "); +         break; + +      case STATE_FOG_PARAMS: +         fprintf (stderr, "STATE_FOG_PARAMS "); +         break; + +      case STATE_CLIPPLANE: +         fprintf (stderr, "STATE_CLIPPLANE "); +         break; + +      case STATE_POINT_SIZE: +         fprintf (stderr, "STATE_POINT_SIZE "); +         break; + +      case STATE_POINT_ATTENUATION: +         fprintf (stderr, "STATE_ATTENUATION "); +         break; + +      case STATE_MATRIX: +         fprintf (stderr, "STATE_MATRIX "); +         break; + +      case STATE_MODELVIEW: +         fprintf (stderr, "STATE_MODELVIEW "); +         break; + +      case STATE_PROJECTION: +         fprintf (stderr, "STATE_PROJECTION "); +         break; + +      case STATE_MVP: +         fprintf (stderr, "STATE_MVP "); +         break; + +      case STATE_TEXTURE: +         fprintf (stderr, "STATE_TEXTURE "); +         break; + +      case STATE_PROGRAM: +         fprintf (stderr, "STATE_PROGRAM "); +         break; + +      case STATE_MATRIX_INVERSE: +         fprintf (stderr, "STATE_INVERSE "); +         break; + +      case STATE_MATRIX_TRANSPOSE: +         fprintf (stderr, "STATE_TRANSPOSE "); +         break; + +      case STATE_MATRIX_INVTRANS: +         fprintf (stderr, "STATE_INVTRANS "); +         break; + +      case STATE_AMBIENT: +         fprintf (stderr, "STATE_AMBIENT "); +         break; + +      case STATE_DIFFUSE: +         fprintf (stderr, "STATE_DIFFUSE "); +         break; + +      case STATE_SPECULAR: +         fprintf (stderr, "STATE_SPECULAR "); +         break; + +      case STATE_EMISSION: +         fprintf (stderr, "STATE_EMISSION "); +         break; + +      case STATE_SHININESS: +         fprintf (stderr, "STATE_SHININESS "); +         break; + +      case STATE_HALF: +         fprintf (stderr, "STATE_HALF "); +         break; + +      case STATE_POSITION: +         fprintf (stderr, "STATE_POSITION "); +         break; + +      case STATE_ATTENUATION: +         fprintf (stderr, "STATE_ATTENUATION "); +         break; + +      case STATE_SPOT_DIRECTION: +         fprintf (stderr, "STATE_DIRECTION "); +         break; + +      case STATE_TEXGEN_EYE_S: +         fprintf (stderr, "STATE_TEXGEN_EYE_S "); +         break; + +      case STATE_TEXGEN_EYE_T: +         fprintf (stderr, "STATE_TEXGEN_EYE_T "); +         break; + +      case STATE_TEXGEN_EYE_R: +         fprintf (stderr, "STATE_TEXGEN_EYE_R "); +         break; + +      case STATE_TEXGEN_EYE_Q: +         fprintf (stderr, "STATE_TEXGEN_EYE_Q "); +         break; + +      case STATE_TEXGEN_OBJECT_S: +         fprintf (stderr, "STATE_TEXGEN_EYE_S "); +         break; + +      case STATE_TEXGEN_OBJECT_T: +         fprintf (stderr, "STATE_TEXGEN_OBJECT_T "); +         break; + +      case STATE_TEXGEN_OBJECT_R: +         fprintf (stderr, "STATE_TEXGEN_OBJECT_R "); +         break; + +      case STATE_TEXGEN_OBJECT_Q: +         fprintf (stderr, "STATE_TEXGEN_OBJECT_Q "); +         break; + +      case STATE_TEXENV_COLOR: +         fprintf (stderr, "STATE_TEXENV_COLOR "); +         break; + +      case STATE_DEPTH_RANGE: +         fprintf (stderr, "STATE_DEPTH_RANGE "); +         break; + +      case STATE_VERTEX_PROGRAM: +         fprintf (stderr, "STATE_VERTEX_PROGRAM "); +         break; + +      case STATE_FRAGMENT_PROGRAM: +         fprintf (stderr, "STATE_FRAGMENT_PROGRAM "); +         break; + +      case STATE_ENV: +         fprintf (stderr, "STATE_ENV "); +         break; + +      case STATE_LOCAL: +         fprintf (stderr, "STATE_LOCAL "); +         break; + +   } +   fprintf (stderr, "[%d] ", token); +} + + + + +static GLvoid +debug_variables (GLcontext * ctx, struct var_cache *vc_head, +                 struct arb_program *Program) +{ +   struct var_cache *vc; +   GLint a, b; + +   fprintf (stderr, "debug_variables, vc_head: %x\n", vc_head); + +   /* First of all, print out the contents of the var_cache */ +   vc = vc_head; +   while (vc) { +      fprintf (stderr, "[%x]\n", vc); +      switch (vc->type) { +         case vt_none: +            fprintf (stderr, "UNDEFINED %s\n", vc->name); +            break; +         case vt_attrib: +            fprintf (stderr, "ATTRIB    %s\n", vc->name); +            fprintf (stderr, "          binding: 0x%x\n", vc->attrib_binding); +            break; +         case vt_param: +            fprintf (stderr, "PARAM     %s  begin: %d len: %d\n", vc->name, +                     vc->param_binding_begin, vc->param_binding_length); +            b = vc->param_binding_begin; +            for (a = 0; a < vc->param_binding_length; a++) { +               fprintf (stderr, "%s\n", +                        Program->Parameters->Parameters[a + b].Name); +               if (Program->Parameters->Parameters[a + b].Type == STATE) { +                  print_state_token (Program->Parameters->Parameters[a + b]. +                                     StateIndexes[0]); +                  print_state_token (Program->Parameters->Parameters[a + b]. +                                     StateIndexes[1]); +                  print_state_token (Program->Parameters->Parameters[a + b]. +                                     StateIndexes[2]); +                  print_state_token (Program->Parameters->Parameters[a + b]. +                                     StateIndexes[3]); +                  print_state_token (Program->Parameters->Parameters[a + b]. +                                     StateIndexes[4]); +                  print_state_token (Program->Parameters->Parameters[a + b]. +                                     StateIndexes[5]); +               } +               else +                  fprintf (stderr, "%f %f %f %f\n", +                           Program->Parameters->Parameters[a + b].Values[0], +                           Program->Parameters->Parameters[a + b].Values[1], +                           Program->Parameters->Parameters[a + b].Values[2], +                           Program->Parameters->Parameters[a + b].Values[3]); +            } +            break; +         case vt_temp: +            fprintf (stderr, "TEMP      %s\n", vc->name); +            fprintf (stderr, "          binding: 0x%x\n", vc->temp_binding); +            break; +         case vt_output: +            fprintf (stderr, "OUTPUT    %s\n", vc->name); +            fprintf (stderr, "          binding: 0x%x\n", vc->output_binding); +            break; +         case vt_alias: +            fprintf (stderr, "ALIAS     %s\n", vc->name); +            fprintf (stderr, "          binding: 0x%x (%s)\n", +                     vc->alias_binding, vc->alias_binding->name); +            break; +      } +      vc = vc->next; +   } +} + +#endif + +/**  + * The main loop for parsing a fragment or vertex program + *  + * \return 0 on sucess, 1 on error + */ + +static GLint +parse_arb_program (GLcontext * ctx, byte * inst, struct var_cache **vc_head, +                   struct arb_program *Program) +{ +   GLint err = 0; + +   Program->MajorVersion = (GLuint) * inst++; +   Program->MinorVersion = (GLuint) * inst++; + +   while (*inst != END) { +      switch (*inst++) { +            /* XXX: */ +         case OPTION: + +            if (Program->type == GL_FRAGMENT_PROGRAM_ARB) { +               switch (*inst++) { +                  case ARB_PRECISION_HINT_FASTEST: +                     Program->HintPrecisionFastest = 1; +                     break; + +                  case ARB_PRECISION_HINT_NICEST: +                     Program->HintPrecisionNicest = 1; +                     break; + +                  case ARB_FOG_EXP: +                     Program->HintFogExp = 1; +                     break; + +                  case ARB_FOG_EXP2: +                     Program->HintFogExp2 = 1; +                     break; + +                  case ARB_FOG_LINEAR: +                     Program->HintFogLinear = 1; +                     break; +               } +            } +            else { +               switch (*inst++) { +                  case ARB_POSITION_INVARIANT: +                     Program->HintPositionInvariant = 1; +                     break; +               } +            } +            break; + +         case INSTRUCTION: +            Program->Position = parse_position (&inst); + +            if (Program->type == GL_FRAGMENT_PROGRAM_ARB) { +               /* Realloc Program->FPInstructions */ +               Program->FPInstructions = +                  (struct fp_instruction *) _mesa_realloc (Program->FPInstructions, +                                                           Program->Base.NumInstructions*sizeof(struct fp_instruction), +                                                           (Program->Base.NumInstructions+1)*sizeof (struct fp_instruction)); + +               /* parse the current instruction   */ +               err = parse_fp_instruction (ctx, &inst, vc_head, Program, +                                           &Program->FPInstructions[Program->Base.NumInstructions]); +                                                                     +            } +            else { +               /* Realloc Program->VPInstructions */ +               Program->VPInstructions = +                  (struct vp_instruction *) _mesa_realloc (Program->VPInstructions, +                                                           Program->Base.NumInstructions*sizeof(struct vp_instruction), +                                                           (Program->Base.NumInstructions +1)*sizeof(struct vp_instruction)); + +               /* parse the current instruction   */ +               err = parse_vp_instruction (ctx, &inst, vc_head, Program, +                                           &Program->VPInstructions[Program->Base.NumInstructions]); +            } + +            /* increment Program->Base.NumInstructions */ +            Program->Base.NumInstructions++; +            break; + +         case DECLARATION: +            err = parse_declaration (ctx, &inst, vc_head, Program); +            break; + +         default: +            break; +      } + +      if (err) +         break; +   } + +   /* Finally, tag on an OPCODE_END instruction */ +   if (Program->type == GL_FRAGMENT_PROGRAM_ARB) { +      Program->FPInstructions = +         (struct fp_instruction *) _mesa_realloc (Program->FPInstructions, +						  Program->Base.NumInstructions*sizeof(struct fp_instruction), +                                                  (Program->Base.NumInstructions+1)*sizeof(struct fp_instruction)); + +      Program->FPInstructions[Program->Base.NumInstructions].Opcode = FP_OPCODE_END; +   } +   else { +      Program->VPInstructions = +         (struct vp_instruction *) _mesa_realloc (Program->VPInstructions, +                                                  Program->Base.NumInstructions*sizeof(struct vp_instruction), +                                                  (Program->Base.NumInstructions+1)*sizeof(struct vp_instruction)); + +      Program->VPInstructions[Program->Base.NumInstructions].Opcode = VP_OPCODE_END; +   } + +   /* increment Program->Base.NumInstructions */ +   Program->Base.NumInstructions++; + +   return err; +} + +/**  + * This kicks everything off. + * + * \param ctx - The GL Context + * \param str - The program string + * \param len - The program string length + * \param Program - The arb_program struct to return all the parsed info in + * \return 0 on sucess, 1 on error + */ +GLuint +_mesa_parse_arb_program (GLcontext * ctx, const GLubyte * str, GLsizei len, +                         struct arb_program * Program) +{ +   GLint a, err, error_pos; +   char error_msg[300]; +   GLuint parsed_len; +   struct var_cache *vc_head; +   dict *dt; +   byte *parsed, *inst; + +#if DEBUG_PARSING +   fprintf (stderr, "Loading grammar text!\n"); +#endif +   dt = grammar_load_from_text ((byte *) arb_grammar_text); +   if (!dt) { +      grammar_get_last_error ((byte *) error_msg, 300, &error_pos); +      _mesa_set_program_error (ctx, error_pos, error_msg); +      _mesa_error (ctx, GL_INVALID_OPERATION, +                   "Error loading grammer rule set"); +      return 1; +   } + +#if DEBUG_PARSING +   printf ("Checking Grammar!\n"); +#endif +   err = grammar_check (dt, str, &parsed, &parsed_len); + + +   /* Syntax parse error */ +   if (err == 0) { +      grammar_get_last_error ((byte *) error_msg, 300, &error_pos); +      _mesa_set_program_error (ctx, error_pos, error_msg); +      _mesa_error (ctx, GL_INVALID_OPERATION, "Parse Error"); + +      dict_destroy (&dt); +      return 1; +   } + +#if DEBUG_PARSING +   printf ("Destroying grammer dict [parse retval: %d]\n", err); +#endif +   dict_destroy (&dt); + +   /* Initialize the arb_program struct */ +   Program->Base.NumInstructions = +   Program->Base.NumTemporaries = +   Program->Base.NumParameters = +   Program->Base.NumAttributes = Program->Base.NumAddressRegs = 0; +   Program->Parameters = _mesa_new_parameter_list (); +   Program->InputsRead = 0; +   Program->OutputsWritten = 0; +   Program->Position = 0; +   Program->MajorVersion = Program->MinorVersion = 0; +   Program->HintPrecisionFastest = +   Program->HintPrecisionNicest = +   Program->HintFogExp2 = +   Program->HintFogExp = +   Program->HintFogLinear = Program->HintPositionInvariant = 0; +   for (a = 0; a < MAX_TEXTURE_IMAGE_UNITS; a++) +      Program->TexturesUsed[a] = 0; +   Program->NumAluInstructions = +   Program->NumTexInstructions =  +   Program->NumTexIndirections = 0; + +   Program->FPInstructions = NULL; +   Program->VPInstructions = NULL; + +   vc_head = NULL; +   err = 0; + +   /* Start examining the tokens in the array */ +   inst = parsed; + +   /* Check the grammer rev */ +   if (*inst++ != REVISION) { +      _mesa_set_program_error (ctx, 0, "Grammar version mismatch"); +      _mesa_error (ctx, GL_INVALID_OPERATION, "Grammar verison mismatch"); +      err = 1; +   } +   else { +      switch (*inst++) { +         case FRAGMENT_PROGRAM: +            Program->type = GL_FRAGMENT_PROGRAM_ARB; +            break; + +         case VERTEX_PROGRAM: +            Program->type = GL_VERTEX_PROGRAM_ARB; +            break; +      } + +      err = parse_arb_program (ctx, inst, &vc_head, Program); +#if DEBUG_PARSING +      fprintf (stderr, "Symantic analysis returns %d [1 is bad!]\n", err); +#endif +   } + +   /*debug_variables(ctx, vc_head, Program); */ + +   /* We're done with the parsed binary array */ +   var_cache_destroy (&vc_head); + +   _mesa_free (parsed); +#if DEBUG_PARSING +   printf ("_mesa_parse_arb_program() done\n"); +#endif +   return err; +} diff --git a/src/mesa/main/arbparse.h b/src/mesa/main/arbparse.h new file mode 100644 index 0000000000..e6c43b9a98 --- /dev/null +++ b/src/mesa/main/arbparse.h @@ -0,0 +1,83 @@ +/* + * Mesa 3-D graphics library + * Version:  5.1 + * + * Copyright (C) 1999-2003  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. + * + * Authors: + *    Brian Paul + */ + + +#ifndef ARBPARSE_H +#define ARBPARSE_H + +#include "context.h" +#include "mtypes.h" +#include "nvvertprog.h" +#include "nvfragprog.h" + +/** + * This is basically a union of the vertex_program and fragment_program + * structs that we can use to parse the program into + * + * XXX: this should go into mtypes.h? + */ +struct arb_program +{ +	GLuint type; /* FRAGMENT_PROGRAM_ARB or VERTEX_PROGRAM_ARB */ + +	struct program Base; +   struct program_parameter_list *Parameters;  +	GLuint InputsRead; +	GLuint OutputsWritten; + +	GLuint Position;       /* Just used for error reporting while parsing */ +	GLuint MajorVersion; +	GLuint MinorVersion; + +	/* ARB_vertex_program specifics */  +	struct vp_instruction *VPInstructions; + +	/* Options currently recognized by the parser */ +	/* ARB_fp */ +	GLboolean HintPrecisionFastest; +	GLboolean HintPrecisionNicest; +	GLboolean HintFogExp2; +	GLboolean HintFogExp; +	GLboolean HintFogLinear; + +	/* ARB_fp & _vp */ +	GLboolean HintPositionInvariant; + +	/* ARB_fragment_program sepecifics */ +	struct fp_instruction *FPInstructions; +   GLuint TexturesUsed[MAX_TEXTURE_IMAGE_UNITS];  +   GLuint NumAluInstructions;  +   GLuint NumTexInstructions; +   GLuint NumTexIndirections; +}; + +extern GLuint  +_mesa_parse_arb_program( GLcontext *ctx, const GLubyte *str, GLsizei len,  +                                 struct arb_program *Program ); +                           + +#endif diff --git a/src/mesa/main/arbparse_syn.h b/src/mesa/main/arbparse_syn.h new file mode 100644 index 0000000000..e8b9e933d2 --- /dev/null +++ b/src/mesa/main/arbparse_syn.h @@ -0,0 +1,1219 @@ +static char arb_grammar_text[] = ".syntax program;\n" +".emtcode REVISION 0x03\n" +".emtcode FRAGMENT_PROGRAM 0x01\n" +".emtcode VERTEX_PROGRAM 0x02\n" +".emtcode OPTION 0x01\n" +".emtcode INSTRUCTION 0x02\n" +".emtcode DECLARATION 0x03\n" +".emtcode END 0x04\n" +".emtcode ARB_PRECISION_HINT_FASTEST 0x01\n" +".emtcode ARB_PRECISION_HINT_NICEST 0x02\n" +".emtcode ARB_FOG_EXP 0x04\n" +".emtcode ARB_FOG_EXP2 0x08\n" +".emtcode ARB_FOG_LINEAR 0x10\n" +".emtcode ARB_POSITION_INVARIANT 0x01\n" +".emtcode F_ALU_INST 0x01\n" +".emtcode F_TEX_INST 0x02\n" +".emtcode F_ALU_VECTOR 0x01\n" +".emtcode F_ALU_SCALAR 0x02\n" +".emtcode F_ALU_BINSC 0x03\n" +".emtcode F_ALU_BIN 0x04\n" +".emtcode F_ALU_TRI 0x05\n" +".emtcode F_ALU_SWZ 0x06\n" +".emtcode F_TEX_SAMPLE 0x07\n" +".emtcode F_TEX_KIL 0x08\n" +".emtcode V_GEN_ARL 0x01\n" +".emtcode V_GEN_VECTOR 0x02\n" +".emtcode V_GEN_SCALAR 0x03\n" +".emtcode V_GEN_BINSC 0x04\n" +".emtcode V_GEN_BIN 0x05\n" +".emtcode V_GEN_TRI 0x06\n" +".emtcode V_GEN_SWZ 0x07\n" +".emtcode F_ABS 0x00\n" +".emtcode F_ABS_SAT 0x01\n" +".emtcode F_FLR 0x02\n" +".emtcode F_FLR_SAT 0x03\n" +".emtcode F_FRC 0x04\n" +".emtcode F_FRC_SAT 0x05\n" +".emtcode F_LIT 0x06\n" +".emtcode F_LIT_SAT 0x07\n" +".emtcode F_MOV 0x08\n" +".emtcode F_MOV_SAT 0x09\n" +".emtcode F_COS 0x0A\n" +".emtcode F_COS_SAT 0x0B\n" +".emtcode F_EX2 0x0C\n" +".emtcode F_EX2_SAT 0x0D\n" +".emtcode F_LG2 0x0E\n" +".emtcode F_LG2_SAT 0x0F\n" +".emtcode F_RCP 0x10\n" +".emtcode F_RCP_SAT 0x11\n" +".emtcode F_RSQ 0x12\n" +".emtcode F_RSQ_SAT 0x13\n" +".emtcode F_SIN 0x14\n" +".emtcode F_SIN_SAT 0x15\n" +".emtcode F_SCS 0x16\n" +".emtcode F_SCS_SAT 0x17\n" +".emtcode F_POW 0x18\n" +".emtcode F_POW_SAT 0x19\n" +".emtcode F_ADD 0x1A\n" +".emtcode F_ADD_SAT 0x1B\n" +".emtcode F_DP3 0x1C\n" +".emtcode F_DP3_SAT 0x1D\n" +".emtcode F_DP4 0x1E\n" +".emtcode F_DP4_SAT 0x1F\n" +".emtcode F_DPH 0x20\n" +".emtcode F_DPH_SAT 0x21\n" +".emtcode F_DST 0x22\n" +".emtcode F_DST_SAT 0x23\n" +".emtcode F_MAX 0x24\n" +".emtcode F_MAX_SAT 0x25\n" +".emtcode F_MIN 0x26\n" +".emtcode F_MIN_SAT 0x27\n" +".emtcode F_MUL 0x28\n" +".emtcode F_MUL_SAT 0x29\n" +".emtcode F_SGE 0x2A\n" +".emtcode F_SGE_SAT 0x2B\n" +".emtcode F_SLT 0x2C\n" +".emtcode F_SLT_SAT 0x2D\n" +".emtcode F_SUB 0x2E\n" +".emtcode F_SUB_SAT 0x2F\n" +".emtcode F_XPD 0x30\n" +".emtcode F_XPD_SAT 0x31\n" +".emtcode F_CMP 0x32\n" +".emtcode F_CMP_SAT 0x33\n" +".emtcode F_LRP 0x34\n" +".emtcode F_LRP_SAT 0x35\n" +".emtcode F_MAD 0x36\n" +".emtcode F_MAD_SAT 0x37\n" +".emtcode F_SWZ 0x38\n" +".emtcode F_SWZ_SAT 0x39\n" +".emtcode F_TEX 0x3A\n" +".emtcode F_TEX_SAT 0x3B\n" +".emtcode F_TXB 0x3C\n" +".emtcode F_TXB_SAT 0x3D\n" +".emtcode F_TXP 0x3E\n" +".emtcode F_TXP_SAT 0x3F\n" +".emtcode F_KIL 0x40\n" +".emtcode V_ARL 0x01\n" +".emtcode V_ABS 0x02\n" +".emtcode V_FLR 0x03\n" +".emtcode V_FRC 0x04\n" +".emtcode V_LIT 0x05\n" +".emtcode V_MOV 0x06\n" +".emtcode V_EX2 0x07\n" +".emtcode V_EXP 0x08\n" +".emtcode V_LG2 0x09\n" +".emtcode V_LOG 0x0A\n" +".emtcode V_RCP 0x0B\n" +".emtcode V_RSQ 0x0C\n" +".emtcode V_POW 0x0D\n" +".emtcode V_ADD 0x0E\n" +".emtcode V_DP3 0x0F\n" +".emtcode V_DP4 0x10\n" +".emtcode V_DPH 0x11\n" +".emtcode V_DST 0x12\n" +".emtcode V_MAX 0x13\n" +".emtcode V_MIN 0x14\n" +".emtcode V_MUL 0x15\n" +".emtcode V_SGE 0x16\n" +".emtcode V_SLT 0x17\n" +".emtcode V_SUB 0x18\n" +".emtcode V_XPD 0x19\n" +".emtcode V_MAD 0x1A\n" +".emtcode V_SWZ 0x1B\n" +".emtcode FRAGMENT_ATTRIB_COLOR 0x01\n" +".emtcode FRAGMENT_ATTRIB_TEXCOORD 0x02\n" +".emtcode FRAGMENT_ATTRIB_FOGCOORD 0x03\n" +".emtcode FRAGMENT_ATTRIB_POSITION 0x04\n" +".emtcode VERTEX_ATTRIB_POSITION 0x01\n" +".emtcode VERTEX_ATTRIB_WEIGHT 0x02\n" +".emtcode VERTEX_ATTRIB_NORMAL 0x03\n" +".emtcode VERTEX_ATTRIB_COLOR 0x04\n" +".emtcode VERTEX_ATTRIB_FOGCOORD 0x05\n" +".emtcode VERTEX_ATTRIB_TEXCOORD 0x06\n" +".emtcode VERTEX_ATTRIB_MATRIXINDEX 0x07\n" +".emtcode VERTEX_ATTRIB_GENERIC 0x08\n" +".emtcode FRAGMENT_RESULT_COLOR 0x01\n" +".emtcode FRAGMENT_RESULT_DEPTH 0x02\n" +".emtcode VERTEX_RESULT_POSITION 0x01\n" +".emtcode VERTEX_RESULT_COLOR 0x02\n" +".emtcode VERTEX_RESULT_FOGCOORD 0x03\n" +".emtcode VERTEX_RESULT_POINTSIZE 0x04\n" +".emtcode VERTEX_RESULT_TEXCOORD 0x05\n" +".emtcode TEXTARGET_1D 0x01\n" +".emtcode TEXTARGET_2D 0x02\n" +".emtcode TEXTARGET_3D 0x03\n" +".emtcode TEXTARGET_RECT 0x04\n" +".emtcode TEXTARGET_CUBE 0x05\n" +".emtcode FACE_FRONT 0x00\n" +".emtcode FACE_BACK 0x01\n" +".emtcode COLOR_PRIMARY 0x00\n" +".emtcode COLOR_SECONDARY 0x01\n" +".emtcode COMPONENT_X 0x00\n" +".emtcode COMPONENT_Y 0x01\n" +".emtcode COMPONENT_Z 0x02\n" +".emtcode COMPONENT_W 0x03\n" +".emtcode COMPONENT_0 0x04\n" +".emtcode COMPONENT_1 0x05\n" +".emtcode ARRAY_INDEX_ABSOLUTE 0x00\n" +".emtcode ARRAY_INDEX_RELATIVE 0x01\n" +".emtcode MATRIX_MODELVIEW 0x01\n" +".emtcode MATRIX_PROJECTION 0x02\n" +".emtcode MATRIX_MVP 0x03\n" +".emtcode MATRIX_TEXTURE 0x04\n" +".emtcode MATRIX_PALETTE 0x05\n" +".emtcode MATRIX_PROGRAM 0x06\n" +".emtcode MATRIX_MODIFIER_IDENTITY 0x00\n" +".emtcode MATRIX_MODIFIER_INVERSE 0x01\n" +".emtcode MATRIX_MODIFIER_TRANSPOSE 0x02\n" +".emtcode MATRIX_MODIFIER_INVTRANS 0x03\n" +".emtcode CONSTANT_SCALAR 0x01\n" +".emtcode CONSTANT_VECTOR 0x02\n" +".emtcode PROGRAM_PARAM_ENV 0x01\n" +".emtcode PROGRAM_PARAM_LOCAL 0x02\n" +".emtcode REGISTER_ATTRIB 0x01\n" +".emtcode REGISTER_PARAM 0x02\n" +".emtcode REGISTER_RESULT 0x03\n" +".emtcode REGISTER_ESTABLISHED_NAME 0x04\n" +".emtcode PARAM_NULL 0x00\n" +".emtcode PARAM_ARRAY_ELEMENT 0x01\n" +".emtcode PARAM_STATE_ELEMENT 0x02\n" +".emtcode PARAM_PROGRAM_ELEMENT 0x03\n" +".emtcode PARAM_PROGRAM_ELEMENTS 0x04\n" +".emtcode PARAM_CONSTANT 0x05\n" +".emtcode STATE_MATERIAL 0x01\n" +".emtcode STATE_LIGHT 0x02\n" +".emtcode STATE_LIGHT_MODEL 0x03\n" +".emtcode STATE_LIGHT_PROD 0x04\n" +".emtcode STATE_FOG 0x05\n" +".emtcode STATE_MATRIX_ROWS 0x06\n" +".emtcode STATE_TEX_ENV 0x07\n" +".emtcode STATE_DEPTH 0x08\n" +".emtcode STATE_TEX_GEN 0x07\n" +".emtcode STATE_CLIP_PLANE 0x08\n" +".emtcode STATE_POINT 0x09\n" +".emtcode MATERIAL_AMBIENT 0x01\n" +".emtcode MATERIAL_DIFFUSE 0x02\n" +".emtcode MATERIAL_SPECULAR 0x03\n" +".emtcode MATERIAL_EMISSION 0x04\n" +".emtcode MATERIAL_SHININESS 0x05\n" +".emtcode LIGHT_AMBIENT 0x01\n" +".emtcode LIGHT_DIFFUSE 0x02\n" +".emtcode LIGHT_SPECULAR 0x03\n" +".emtcode LIGHT_POSITION 0x04\n" +".emtcode LIGHT_ATTENUATION 0x05\n" +".emtcode LIGHT_HALF 0x06\n" +".emtcode LIGHT_SPOT_DIRECTION 0x07\n" +".emtcode LIGHT_MODEL_AMBIENT 0x01\n" +".emtcode LIGHT_MODEL_SCENECOLOR 0x02\n" +".emtcode LIGHT_PROD_AMBIENT 0x01\n" +".emtcode LIGHT_PROD_DIFFUSE 0x02\n" +".emtcode LIGHT_PROD_SPECULAR 0x03\n" +".emtcode TEX_ENV_COLOR 0x01\n" +".emtcode TEX_GEN_EYE 0x01\n" +".emtcode TEX_GEN_OBJECT 0x02\n" +".emtcode FOG_COLOR 0x01\n" +".emtcode FOG_PARAMS 0x02\n" +".emtcode DEPTH_RANGE 0x01\n" +".emtcode POINT_SIZE 0x01\n" +".emtcode POINT_ATTENUATION 0x02\n" +".emtcode ATTRIB 0x01\n" +".emtcode PARAM 0x02\n" +".emtcode TEMP 0x03\n" +".emtcode OUTPUT 0x04\n" +".emtcode ALIAS 0x05\n" +".emtcode ADDRESS 0x06\n" +".errtext UNKNOWN_PROGRAM_SIGNATURE \"1001: '$e_signature$': unknown program signature\"\n" +".errtext MISSING_END_OR_INVALID_STATEMENT \"1002: '$e_statement$': invalid statement\"\n" +".errtext CODE_AFTER_END \"1003: '$e_statement$': code after 'END' keyword\"\n" +".errtext INVALID_PROGRAM_OPTION \"1004: '$e_identifier$': invalid program option\"\n" +".errtext EXT_SWIZ_COMP_EXPECTED \"1005: extended swizzle component expected but '$e_token$' found\"\n" +".errtext TEX_TARGET_EXPECTED \"1006: texture target expected but '$e_token$' found\"\n" +".errtext TEXTURE_EXPECTED \"1007: 'texture' expected but '$e_identifier$' found\"\n" +".errtext SOURCE_REGISTER_EXPECTED \"1008: source register expected but '$e_token$' found\"\n" +".errtext DESTINATION_REGISTER_EXPECTED \"1009: destination register expected but '$e_token$' found\"\n" +".errtext INVALID_ADDRESS_COMPONENT \"1010: '$e_identifier$': invalid address component\"\n" +".errtext INVALID_ADDRESS_WRITEMASK \"1011: '$e_identifier$': invalid address writemask\"\n" +".errtext INVALID_COMPONENT \"1012: '$e_charordigit$': invalid component\"\n" +".errtext INVALID_SUFFIX \"1013: '$e_identifier$': invalid suffix\"\n" +".errtext INVALID_WRITEMASK \"1014: '$e_identifier$': invalid writemask\"\n" +".errtext FRAGMENT_EXPECTED \"1015: 'fragment' expected but '$e_identifier$' found\"\n" +".errtext VERTEX_EXPECTED \"1016: 'vertex' expected but '$e_identifier$' found\"\n" +".errtext INVALID_FRAGMENT_PROPERTY \"1017: '$e_identifier$': invalid fragment property\"\n" +".errtext INVALID_VERTEX_PROPERTY \"1018: '$e_identifier$': invalid vertex property\"\n" +".errtext INVALID_STATE_PROPERTY \"1019: '$e_identifier$': invalid state property\"\n" +".errtext INVALID_MATERIAL_PROPERTY \"1020: '$e_identifier$': invalid material property\"\n" +".errtext INVALID_LIGHT_PROPERTY \"1021: '$e_identifier$': invalid light property\"\n" +".errtext INVALID_SPOT_PROPERTY \"1022: '$e_identifier$': invalid spot property\"\n" +".errtext INVALID_LIGHTMODEL_PROPERTY \"1023: '$e_identifier$': invalid light model property\"\n" +".errtext INVALID_LIGHTPROD_PROPERTY \"1024: '$e_identifier$': invalid light product property\"\n" +".errtext INVALID_TEXENV_PROPERTY \"1025: '$e_identifier$': invalid texture environment property\"\n" +".errtext INVALID_TEXGEN_PROPERTY \"1026: '$e_identifier$': invalid texture generating property\"\n" +".errtext INVALID_TEXGEN_COORD \"1027: '$e_identifier$': invalid texture generating coord\"\n" +".errtext INVALID_FOG_PROPERTY \"1028: '$e_identifier$': invalid fog property\"\n" +".errtext INVALID_DEPTH_PROPERTY \"1029: '$e_identifier$': invalid depth property\"\n" +".errtext INVALID_CLIPPLANE_PROPERTY \"1030: '$e_identifier$': invalid clip plane property\"\n" +".errtext INVALID_POINT_PROPERTY \"1031: '$e_identifier$': invalid point property\"\n" +".errtext MATRIX_ROW_SELECTOR_OR_MODIFIER_EXPECTED \"1032: matrix row selector or modifier expected but '$e_token$' found\"\n" +".errtext INVALID_MATRIX_NAME \"1033: '$e_identifier$': invalid matrix name\"\n" +".errtext INVALID_PROGRAM_PROPERTY \"1034: '$e_identifier$': invalid program property\"\n" +".errtext RESULT_EXPECTED \"1035: 'result' expected but '$e_token$' found\"\n" +".errtext INVALID_RESULT_PROPERTY \"1036: '$e_identifier$': invalid result property\"\n" +".errtext INVALID_FACE_PROPERTY \"1037: '$e_identifier$': invalid face property\"\n" +".errtext INVALID_COLOR_PROPERTY \"1038: '$e_identifier$': invalid color property\"\n" +".errtext IDENTIFIER_EXPECTED \"1039: identifier expected but '$e_token$' found\"\n" +".errtext RESERVED_KEYWORD \"1040: use of reserved keyword as an identifier\"\n" +".errtext INTEGER_EXPECTED \"1041: integer value expected but '$e_token$' found\"\n" +".errtext MISSING_SEMICOLON \"1042: ';' expected but '$e_token$' found\"\n" +".errtext MISSING_COMMA \"1043: ',' expected but '$e_token$' found\"\n" +".errtext MISSING_LBRACKET \"1044: '[' expected but '$e_token$' found\"\n" +".errtext MISSING_RBRACKET \"1045: ']' expected but '$e_token$' found\"\n" +".errtext MISSING_DOT \"1046: '.' expected but '$e_token$' found\"\n" +".errtext MISSING_EQUAL \"1047: '=' expected but '$e_token$' found\"\n" +".errtext MISSING_LBRACE \"1048: '{' expected but '$e_token$' found\"\n" +".errtext MISSING_RBRACE \"1049: '}' expected but '$e_token$' found\"\n" +".errtext MISSING_DOTDOT \"1050: '..' expected but '$e_token$' found\"\n" +".errtext MISSING_FRACTION_OR_EXPONENT \"1051: missing fraction part or exponent\"\n" +".errtext MISSING_DOT_OR_EXPONENT \"1052: missing '.' or exponent\"\n" +".errtext EXPONENT_VALUE_EXPECTED \"1053: exponent value expected\"\n" +"program\n" +" programs .error UNKNOWN_PROGRAM_SIGNATURE .emit REVISION;\n" +"programs\n" +" frag_program_1_0 .emit FRAGMENT_PROGRAM .emit 0x01 .emit 0x00 .or\n" +" vert_program_1_0 .emit VERTEX_PROGRAM .emit 0x01 .emit 0x00;\n" +"frag_program_1_0\n" +" '!' .and '!' .and 'A' .and 'R' .and 'B' .and 'f' .and 'p' .and '1' .and '.' .and '0' .and\n" +" optional_space .and fp_optionSequence .and fp_statementSequence .and\n" +" \"END\" .error MISSING_END_OR_INVALID_STATEMENT .emit END .and optional_space .and\n" +" '\\0' .error CODE_AFTER_END;\n" +"vert_program_1_0\n" +" '!' .and '!' .and 'A' .and 'R' .and 'B' .and 'v' .and 'p' .and '1' .and '.' .and '0' .and\n" +" optional_space .and vp_optionSequence .and vp_statementSequence .and\n" +" \"END\" .error MISSING_END_OR_INVALID_STATEMENT .emit END .and optional_space .and\n" +" '\\0' .error CODE_AFTER_END;\n" +"fp_optionSequence\n" +" .loop fp_option;\n" +"vp_optionSequence\n" +" .loop vp_option;\n" +"fp_option\n" +" \"OPTION\" .emit OPTION .and space .and fp_optionString .error INVALID_PROGRAM_OPTION .and\n" +" semicolon;\n" +"vp_option\n" +" \"OPTION\" .emit OPTION .and space .and vp_optionString .error INVALID_PROGRAM_OPTION .and\n" +" semicolon;\n" +"fp_optionString\n" +" \"ARB_precision_hint_fastest\" .emit ARB_PRECISION_HINT_FASTEST .or\n" +" \"ARB_precision_hint_nicest\" .emit ARB_PRECISION_HINT_NICEST .or\n" +" \"ARB_fog_exp\" .emit ARB_FOG_EXP .or\n" +" \"ARB_fog_exp2\" .emit ARB_FOG_EXP2 .or\n" +" \"ARB_fog_linear\" .emit ARB_FOG_LINEAR;\n" +"vp_optionString\n" +" \"ARB_position_invariant\" .emit ARB_POSITION_INVARIANT;\n" +"fp_statementSequence\n" +" .loop fp_statement;\n" +"vp_statementSequence\n" +" .loop vp_statement;\n" +"fp_statement\n" +" fp_statement_1 .or fp_statement_2;\n" +"vp_statement\n" +" vp_statement_1 .or vp_statement_2;\n" +"fp_statement_1\n" +" fp_instruction .emit INSTRUCTION .emit $ .and semicolon;\n" +"fp_statement_2\n" +" fp_namingStatement .emit DECLARATION .and semicolon;\n" +"vp_statement_1\n" +" vp_instruction .emit INSTRUCTION .emit $ .and semicolon;\n" +"vp_statement_2\n" +" vp_namingStatement .emit DECLARATION .and semicolon;\n" +"fp_instruction\n" +" ALUInstruction .emit F_ALU_INST .or\n" +" TexInstruction .emit F_TEX_INST;\n" +"vp_instruction\n" +" ARL_instruction .emit V_GEN_ARL .or\n" +" vp_VECTORop_instruction .emit V_GEN_VECTOR .or\n" +" vp_SCALARop_instruction .emit V_GEN_SCALAR .or\n" +" vp_BINSCop_instruction .emit V_GEN_BINSC .or\n" +" vp_BINop_instruction .emit V_GEN_BIN .or\n" +" vp_TRIop_instruction .emit V_GEN_TRI .or\n" +" vp_SWZ_instruction .emit V_GEN_SWZ;\n" +"ALUInstruction\n" +" fp_VECTORop_instruction .emit F_ALU_VECTOR .or\n" +" fp_SCALARop_instruction .emit F_ALU_SCALAR .or\n" +" fp_BINSCop_instruction .emit F_ALU_BINSC .or\n" +" fp_BINop_instruction .emit F_ALU_BIN .or\n" +" fp_TRIop_instruction .emit F_ALU_TRI .or\n" +" fp_SWZ_instruction .emit F_ALU_SWZ;\n" +"TexInstruction\n" +" SAMPLE_instruction .emit F_TEX_SAMPLE .or\n" +" KIL_instruction .emit F_TEX_KIL;\n" +"ARL_instruction\n" +" \"ARL\" .emit V_ARL .and space .and maskedAddrReg .and comma .and vp_scalarSrcReg;\n" +"fp_VECTORop_instruction\n" +" fp_VECTORop .and space .and fp_maskedDstReg .and comma .and vectorSrcReg;\n" +"vp_VECTORop_instruction\n" +" vp_VECTORop .and space .and vp_maskedDstReg .and comma .and swizzleSrcReg;\n" +"fp_VECTORop\n" +" \"ABS\" .emit F_ABS .or \"ABS_SAT\" .emit F_ABS_SAT .or\n" +" \"FLR\" .emit F_FLR .or \"FLR_SAT\" .emit F_FLR_SAT .or\n" +" \"FRC\" .emit F_FRC .or \"FRC_SAT\" .emit F_FRC_SAT .or\n" +" \"LIT\" .emit F_LIT .or \"LIT_SAT\" .emit F_LIT_SAT .or\n" +" \"MOV\" .emit F_MOV .or \"MOV_SAT\" .emit F_MOV_SAT;\n" +"vp_VECTORop\n" +" \"ABS\" .emit V_ABS .or\n" +" \"FLR\" .emit V_FLR .or\n" +" \"FRC\" .emit V_FRC .or\n" +" \"LIT\" .emit V_LIT .or\n" +" \"MOV\" .emit V_MOV;\n" +"fp_SCALARop_instruction\n" +" fp_SCALARop .and space .and fp_maskedDstReg .and comma .and fp_scalarSrcReg;\n" +"vp_SCALARop_instruction\n" +" vp_SCALARop .and space .and vp_maskedDstReg .and comma .and vp_scalarSrcReg;\n" +"fp_SCALARop\n" +" \"COS\" .emit F_COS .or \"COS_SAT\" .emit F_COS_SAT .or\n" +" \"EX2\" .emit F_EX2 .or \"EX2_SAT\" .emit F_EX2_SAT .or\n" +" \"LG2\" .emit F_LG2 .or \"LG2_SAT\" .emit F_LG2_SAT .or\n" +" \"RCP\" .emit F_RCP .or \"RCP_SAT\" .emit F_RCP_SAT .or\n" +" \"RSQ\" .emit F_RSQ .or \"RSQ_SAT\" .emit F_RSQ_SAT .or\n" +" \"SIN\" .emit F_SIN .or \"SIN_SAT\" .emit F_SIN_SAT .or\n" +" \"SCS\" .emit F_SCS .or \"SCS_SAT\" .emit F_SCS_SAT;\n" +"vp_SCALARop\n" +" \"EX2\" .emit V_EX2 .or\n" +" \"EXP\" .emit V_EXP .or\n" +" \"LG2\" .emit V_LG2 .or\n" +" \"LOG\" .emit V_LOG .or\n" +" \"RCP\" .emit V_RCP .or\n" +" \"RSQ\" .emit V_RSQ;\n" +"fp_BINSCop_instruction\n" +" fp_BINSCop .and space .and fp_maskedDstReg .and comma .and fp_scalarSrcReg .and comma .and\n" +" fp_scalarSrcReg;\n" +"vp_BINSCop_instruction\n" +" vp_BINSCop .and space .and vp_maskedDstReg .and comma .and vp_scalarSrcReg .and comma .and\n" +" vp_scalarSrcReg;\n" +"fp_BINSCop\n" +" \"POW\" .emit F_POW .or \"POW_SAT\" .emit F_POW_SAT;\n" +"vp_BINSCop\n" +" \"POW\" .emit V_POW;\n" +"fp_BINop_instruction\n" +" fp_BINop .and space .and fp_maskedDstReg .and comma .and vectorSrcReg .and comma .and\n" +" vectorSrcReg;\n" +"vp_BINop_instruction\n" +" vp_BINop .and space .and vp_maskedDstReg .and comma .and swizzleSrcReg .and comma .and\n" +" swizzleSrcReg;\n" +"fp_BINop\n" +" \"ADD\" .emit F_ADD .or \"ADD_SAT\" .emit F_ADD_SAT .or\n" +" \"DP3\" .emit F_DP3 .or \"DP3_SAT\" .emit F_DP3_SAT .or\n" +" \"DP4\" .emit F_DP4 .or \"DP4_SAT\" .emit F_DP4_SAT .or\n" +" \"DPH\" .emit F_DPH .or \"DPH_SAT\" .emit F_DPH_SAT .or\n" +" \"DST\" .emit F_DST .or \"DST_SAT\" .emit F_DST_SAT .or\n" +" \"MAX\" .emit F_MAX .or \"MAX_SAT\" .emit F_MAX_SAT .or\n" +" \"MIN\" .emit F_MIN .or \"MIN_SAT\" .emit F_MIN_SAT .or\n" +" \"MUL\" .emit F_MUL .or \"MUL_SAT\" .emit F_MUL_SAT .or\n" +" \"SGE\" .emit F_SGE .or \"SGE_SAT\" .emit F_SGE_SAT .or\n" +" \"SLT\" .emit F_SLT .or \"SLT_SAT\" .emit F_SLT_SAT .or\n" +" \"SUB\" .emit F_SUB .or \"SUB_SAT\" .emit F_SUB_SAT .or\n" +" \"XPD\" .emit F_XPD .or \"XPD_SAT\" .emit F_XPD_SAT;\n" +"vp_BINop\n" +" \"ADD\" .emit V_ADD .or\n" +" \"DP3\" .emit V_DP3 .or\n" +" \"DP4\" .emit V_DP4 .or\n" +" \"DPH\" .emit V_DPH .or\n" +" \"DST\" .emit V_DST .or\n" +" \"MAX\" .emit V_MAX .or\n" +" \"MIN\" .emit V_MIN .or\n" +" \"MUL\" .emit V_MUL .or\n" +" \"SGE\" .emit V_SGE .or\n" +" \"SLT\" .emit V_SLT .or\n" +" \"SUB\" .emit V_SUB .or\n" +" \"XPD\" .emit V_XPD;\n" +"fp_TRIop_instruction\n" +" fp_TRIop .and space .and fp_maskedDstReg .and comma .and vectorSrcReg .and comma .and\n" +" vectorSrcReg .and comma .and vectorSrcReg;\n" +"vp_TRIop_instruction\n" +" vp_TRIop .and space .and vp_maskedDstReg .and comma .and swizzleSrcReg .and comma .and\n" +" swizzleSrcReg .and comma .and swizzleSrcReg;\n" +"fp_TRIop\n" +" \"CMP\" .emit F_CMP .or \"CMP_SAT\" .emit F_CMP_SAT .or\n" +" \"LRP\" .emit F_LRP .or \"LRP_SAT\" .emit F_LRP_SAT .or\n" +" \"MAD\" .emit F_MAD .or \"MAD_SAT\" .emit F_MAD_SAT;\n" +"vp_TRIop\n" +" \"MAD\" .emit V_MAD;\n" +"fp_SWZ_instruction\n" +" SWZop .and space .and fp_maskedDstReg .and comma .and fp_srcReg .and comma .and\n" +" fp_extendedSwizzle .error EXT_SWIZ_COMP_EXPECTED;\n" +"vp_SWZ_instruction\n" +" \"SWZ\" .emit V_SWZ .and space .and vp_maskedDstReg .and comma .and vp_srcReg .and comma .and\n" +" vp_extendedSwizzle .error EXT_SWIZ_COMP_EXPECTED;\n" +"SWZop\n" +" \"SWZ\" .emit F_SWZ .or \"SWZ_SAT\" .emit F_SWZ_SAT;\n" +"SAMPLE_instruction\n" +" SAMPLEop .and space .and fp_maskedDstReg .and comma .and vectorSrcReg .and comma .and\n" +" texImageUnit .and comma .and texTarget .error TEX_TARGET_EXPECTED;\n" +"SAMPLEop\n" +" \"TEX\" .emit F_TEX .or \"TEX_SAT\" .emit F_TEX_SAT .or\n" +" \"TXB\" .emit F_TXB .or \"TXB_SAT\" .emit F_TXB_SAT .or\n" +" \"TXP\" .emit F_TXP .or \"TXP_SAT\" .emit F_TXP_SAT;\n" +"KIL_instruction\n" +" \"KIL\" .emit F_KIL .and space .and vectorSrcReg;\n" +"texImageUnit\n" +" \"texture\" .error TEXTURE_EXPECTED .and optTexImageUnitNum;\n" +"texTarget\n" +" \"1D\" .emit TEXTARGET_1D .or\n" +" \"2D\" .emit TEXTARGET_2D .or\n" +" \"3D\" .emit TEXTARGET_3D .or\n" +" \"RECT\" .emit TEXTARGET_RECT .or\n" +" \"CUBE\" .emit TEXTARGET_CUBE;\n" +"optTexImageUnitNum\n" +" optTexImageUnitNum_1 .or .true .emit 0x00;\n" +"optTexImageUnitNum_1\n" +" lbracket_ne .and texImageUnitNum .and rbracket;\n" +"texImageUnitNum\n" +" integer;\n" +"fp_scalarSrcReg\n" +" optionalSign .and fp_srcReg .and fp_scalarSuffix;\n" +"vp_scalarSrcReg\n" +" optionalSign .and vp_srcReg .and vp_scalarSuffix;\n" +"swizzleSrcReg\n" +" optionalSign .and vp_srcReg .and swizzleSuffix;\n" +"vectorSrcReg\n" +" optionalSign .and fp_srcReg .and optionalSuffix;\n" +"fp_maskedDstReg\n" +" fp_dstReg .and fp_optionalMask;\n" +"vp_maskedDstReg\n" +" vp_dstReg .and vp_optionalMask;\n" +"maskedAddrReg\n" +" addrReg .and addrWriteMask;\n" +"fp_extendedSwizzle\n" +" xyzwExtendedSwizzle .or rgbaExtendedSwizzle;\n" +"vp_extendedSwizzle\n" +" extSwizComp .and comma .and\n" +" extSwizComp .error EXT_SWIZ_COMP_EXPECTED .and comma .and\n" +" extSwizComp .error EXT_SWIZ_COMP_EXPECTED .and comma .and\n" +" extSwizComp .error EXT_SWIZ_COMP_EXPECTED;\n" +"xyzwExtendedSwizzle\n" +" xyzwExtSwizComp .and comma .and\n" +" xyzwExtSwizComp .error EXT_SWIZ_COMP_EXPECTED .and comma .and\n" +" xyzwExtSwizComp .error EXT_SWIZ_COMP_EXPECTED .and comma .and\n" +" xyzwExtSwizComp .error EXT_SWIZ_COMP_EXPECTED;\n" +"rgbaExtendedSwizzle\n" +" rgbaExtSwizComp .and comma .and\n" +" rgbaExtSwizComp .error EXT_SWIZ_COMP_EXPECTED .and comma .and\n" +" rgbaExtSwizComp .error EXT_SWIZ_COMP_EXPECTED .and comma .and\n" +" rgbaExtSwizComp .error EXT_SWIZ_COMP_EXPECTED;\n" +"xyzwExtSwizComp\n" +" optionalSign .and xyzwExtSwizSel;\n" +"rgbaExtSwizComp\n" +" optionalSign .and rgbaExtSwizSel;\n" +"extSwizComp\n" +" optionalSign .and extSwizSel;\n" +"xyzwExtSwizSel\n" +" \"0\" .emit COMPONENT_0 .or \"1\" .emit COMPONENT_1 .or xyzwComponent_single;\n" +"rgbaExtSwizSel\n" +" \"0\" .emit COMPONENT_0 .or \"1\" .emit COMPONENT_1 .or rgbaComponent_single;\n" +"extSwizSel\n" +" \"0\" .emit COMPONENT_0 .or \"1\" .emit COMPONENT_1 .or vp_component_single;\n" +"fp_srcReg\n" +" fp_srcReg_1 .error SOURCE_REGISTER_EXPECTED;\n" +"vp_srcReg\n" +" vp_srcReg_1 .error SOURCE_REGISTER_EXPECTED;\n" +"fp_srcReg_1\n" +" fragmentAttribReg .emit REGISTER_ATTRIB .or\n" +" fp_progParamReg .emit REGISTER_PARAM .or\n" +" fp_temporaryReg .emit REGISTER_ESTABLISHED_NAME;\n" +"vp_srcReg_1\n" +" vertexAttribReg .emit REGISTER_ATTRIB .or\n" +" vp_progParamReg .emit REGISTER_PARAM .or\n" +" vp_temporaryReg .emit REGISTER_ESTABLISHED_NAME;\n" +"fp_dstReg\n" +" fp_dstReg_1 .error DESTINATION_REGISTER_EXPECTED;\n" +"vp_dstReg\n" +" vp_dstReg_1 .error DESTINATION_REGISTER_EXPECTED;\n" +"fp_dstReg_1\n" +" fragmentResultReg .emit REGISTER_RESULT .or\n" +" fp_temporaryReg .emit REGISTER_ESTABLISHED_NAME;\n" +"vp_dstReg_1\n" +" vertexResultReg .emit REGISTER_RESULT .or\n" +" vp_temporaryReg .emit REGISTER_ESTABLISHED_NAME;\n" +"fragmentAttribReg\n" +" fragAttribBinding;\n" +"vertexAttribReg\n" +" vtxAttribBinding;\n" +"fp_temporaryReg\n" +" fp_establishedName;\n" +"vp_temporaryReg\n" +" vp_establishedName;\n" +"fp_progParamReg\n" +" fp_paramSingleItemUse .or fp_progParamReg_1;\n" +"vp_progParamReg\n" +" vp_paramSingleItemUse .or vp_progParamReg_1;\n" +"fp_progParamReg_1\n" +" fp_progParamArray .emit PARAM_ARRAY_ELEMENT .and lbracket_ne .and progParamArrayAbs .and\n" +" rbracket;\n" +"vp_progParamReg_1\n" +" vp_progParamArray .emit PARAM_ARRAY_ELEMENT .and lbracket_ne .and progParamArrayMem .and\n" +" rbracket;\n" +"fp_progParamArray\n" +" fp_establishedName;\n" +"vp_progParamArray\n" +" vp_establishedName;\n" +"progParamArrayMem\n" +" progParamArrayAbs .or progParamArrayRel;\n" +"progParamArrayAbs\n" +" integer .emit ARRAY_INDEX_ABSOLUTE;\n" +"progParamArrayRel\n" +" addrReg .emit ARRAY_INDEX_RELATIVE .and addrComponent .and addrRegRelOffset;\n" +"addrRegRelOffset\n" +" addrRegRelOffset_1 .or addrRegRelOffset_2 .or .true .emit 0x00;\n" +"addrRegRelOffset_1\n" +" plus_ne .and addrRegPosOffset;\n" +"addrRegRelOffset_2\n" +" minus_ne .and addrRegNegOffset;\n" +"addrRegPosOffset\n" +" integer_0_63;\n" +"addrRegNegOffset\n" +" integer_0_64;\n" +"fragmentResultReg\n" +" fp_resultBinding;\n" +"vertexResultReg\n" +" vp_resultBinding;\n" +"addrReg\n" +" vp_establishedName;\n" +"addrComponent\n" +" dot .and \"x\" .error INVALID_ADDRESS_COMPONENT .emit COMPONENT_X .emit COMPONENT_X\n" +" .emit COMPONENT_X .emit COMPONENT_X;\n" +"addrWriteMask\n" +" dot .and \"x\" .error INVALID_ADDRESS_WRITEMASK .emit 0x08;\n" +"fp_scalarSuffix\n" +" dot .and fp_component_single .error INVALID_COMPONENT;\n" +"vp_scalarSuffix\n" +" dot .and vp_component_single .error INVALID_COMPONENT;\n" +"swizzleSuffix\n" +" swizzleSuffix_1 .or .true .emit COMPONENT_X .emit COMPONENT_Y .emit COMPONENT_Z\n" +" .emit COMPONENT_W;\n" +"swizzleSuffix_1\n" +" dot_ne .and swizzleSuffix_2 .error INVALID_SUFFIX;\n" +"swizzleSuffix_2\n" +" swizzleSuffix_3 .or swizzleSuffix_4;\n" +"swizzleSuffix_3\n" +" vp_component_multi .and vp_component_multi .and vp_component_multi .error INVALID_COMPONENT .and\n" +" vp_component_multi .error INVALID_COMPONENT;\n" +"swizzleSuffix_4\n" +" \"x\" .emit COMPONENT_X .emit COMPONENT_X .emit COMPONENT_X .emit COMPONENT_X .or\n" +" \"y\" .emit COMPONENT_Y .emit COMPONENT_Y .emit COMPONENT_Y .emit COMPONENT_Y .or\n" +" \"z\" .emit COMPONENT_Z .emit COMPONENT_Z .emit COMPONENT_Z .emit COMPONENT_Z .or\n" +" \"w\" .emit COMPONENT_W .emit COMPONENT_W .emit COMPONENT_W .emit COMPONENT_W;\n" +"optionalSuffix\n" +" optionalSuffix_1 .or .true .emit COMPONENT_X .emit COMPONENT_Y .emit COMPONENT_Z\n" +" .emit COMPONENT_W;\n" +"optionalSuffix_1\n" +" dot_ne .and optionalSuffix_2 .error INVALID_SUFFIX;\n" +"optionalSuffix_2\n" +" optionalSuffix_3 .or optionalSuffix_4 .or optionalSuffix_5;\n" +"optionalSuffix_3\n" +" xyzwComponent_multi .and xyzwComponent_multi .and\n" +" xyzwComponent_multi .error INVALID_COMPONENT .and xyzwComponent_multi .error INVALID_COMPONENT;\n" +"optionalSuffix_4\n" +" rgbaComponent_multi .and rgbaComponent_multi .and\n" +" rgbaComponent_multi .error INVALID_COMPONENT .and rgbaComponent_multi .error INVALID_COMPONENT;\n" +"optionalSuffix_5\n" +" \"x\" .emit COMPONENT_X .emit COMPONENT_X .emit COMPONENT_X .emit COMPONENT_X .or\n" +" \"y\" .emit COMPONENT_Y .emit COMPONENT_Y .emit COMPONENT_Y .emit COMPONENT_Y .or\n" +" \"z\" .emit COMPONENT_Z .emit COMPONENT_Z .emit COMPONENT_Z .emit COMPONENT_Z .or\n" +" \"w\" .emit COMPONENT_W .emit COMPONENT_W .emit COMPONENT_W .emit COMPONENT_W .or\n" +" \"r\" .emit COMPONENT_X .emit COMPONENT_X .emit COMPONENT_X .emit COMPONENT_X .or\n" +" \"g\" .emit COMPONENT_Y .emit COMPONENT_Y .emit COMPONENT_Y .emit COMPONENT_Y .or\n" +" \"b\" .emit COMPONENT_Z .emit COMPONENT_Z .emit COMPONENT_Z .emit COMPONENT_Z .or\n" +" \"a\" .emit COMPONENT_W .emit COMPONENT_W .emit COMPONENT_W .emit COMPONENT_W;\n" +"fp_component_single\n" +" xyzwComponent_single .or rgbaComponent_single;\n" +"vp_component_multi\n" +" 'x' .emit COMPONENT_X .or 'y' .emit COMPONENT_Y .or 'z' .emit COMPONENT_Z .or\n" +" 'w' .emit COMPONENT_W;\n" +"vp_component_single\n" +" \"x\" .emit COMPONENT_X .or \"y\" .emit COMPONENT_Y .or \"z\" .emit COMPONENT_Z .or\n" +" \"w\" .emit COMPONENT_W;\n" +"xyzwComponent_multi\n" +" 'x' .emit COMPONENT_X .or 'y' .emit COMPONENT_Y .or 'z' .emit COMPONENT_Z .or\n" +" 'w' .emit COMPONENT_W;\n" +"xyzwComponent_single\n" +" \"x\" .emit COMPONENT_X .or \"y\" .emit COMPONENT_Y .or \"z\" .emit COMPONENT_Z .or\n" +" \"w\" .emit COMPONENT_W;\n" +"rgbaComponent_multi\n" +" 'r' .emit COMPONENT_X .or 'g' .emit COMPONENT_Y .or 'b' .emit COMPONENT_Z .or\n" +" 'a' .emit COMPONENT_W;\n" +"rgbaComponent_single\n" +" \"r\" .emit COMPONENT_X .or \"g\" .emit COMPONENT_Y .or \"b\" .emit COMPONENT_Z .or\n" +" \"a\" .emit COMPONENT_W;\n" +"fp_optionalMask\n" +" xyzwMask .or rgbaMask .or .true .emit 0x0F;\n" +"vp_optionalMask\n" +" xyzwMask .or .true .emit 0x0F;\n" +"xyzwMask\n" +" dot_ne .and xyzwMask_1 .error INVALID_WRITEMASK;\n" +"xyzwMask_1\n" +" \"xyzw\" .emit 0x0F .or \"xyz\" .emit 0x0E .or \"xyw\" .emit 0x0D .or \"xy\" .emit 0x0C .or\n" +" \"xzw\" .emit 0x0B .or \"xz\" .emit 0x0A .or \"xw\" .emit 0x09 .or \"x\" .emit 0x08 .or\n" +" \"yzw\" .emit 0x07 .or \"yz\" .emit 0x06 .or \"yw\" .emit 0x05 .or \"y\" .emit 0x04 .or\n" +" \"zw\" .emit 0x03 .or \"z\" .emit 0x02 .or \"w\" .emit 0x01;\n" +"rgbaMask\n" +" dot_ne .and rgbaMask_1 .error INVALID_WRITEMASK;\n" +"rgbaMask_1\n" +" \"rgba\" .emit 0x0F .or \"rgb\" .emit 0x0E .or \"rga\" .emit 0x0D .or \"rg\" .emit 0x0C .or\n" +" \"rba\" .emit 0x0B .or \"rb\" .emit 0x0A .or \"ra\" .emit 0x09 .or \"r\" .emit 0x08 .or\n" +" \"gba\" .emit 0x07 .or \"gb\" .emit 0x06 .or \"ga\" .emit 0x05 .or \"g\" .emit 0x04 .or\n" +" \"ba\" .emit 0x03 .or \"b\" .emit 0x02 .or \"a\" .emit 0x01;\n" +"fp_namingStatement\n" +" fp_ATTRIB_statement .emit ATTRIB .or\n" +" fp_PARAM_statement .emit PARAM .or\n" +" fp_TEMP_statement .emit TEMP .or\n" +" fp_OUTPUT_statement .emit OUTPUT .or\n" +" fp_ALIAS_statement .emit ALIAS;\n" +"vp_namingStatement\n" +" vp_ATTRIB_statement .emit ATTRIB .or\n" +" vp_PARAM_statement .emit PARAM .or\n" +" vp_TEMP_statement .emit TEMP .or\n" +" ADDRESS_statement .emit ADDRESS .or\n" +" vp_OUTPUT_statement .emit OUTPUT .or\n" +" vp_ALIAS_statement .emit ALIAS;\n" +"fp_ATTRIB_statement\n" +" \"ATTRIB\" .and space .and fp_establishName .and equal .and\n" +" fragAttribBinding .error FRAGMENT_EXPECTED;\n" +"vp_ATTRIB_statement\n" +" \"ATTRIB\" .and space .and vp_establishName .and equal .and\n" +" vtxAttribBinding .error VERTEX_EXPECTED;\n" +"fragAttribBinding\n" +" \"fragment\" .and dot .and fragAttribItem .error INVALID_FRAGMENT_PROPERTY;\n" +"vtxAttribBinding\n" +" \"vertex\" .and dot .and vtxAttribItem .error INVALID_VERTEX_PROPERTY;\n" +"fragAttribItem\n" +" fragAttribItem_1 .emit FRAGMENT_ATTRIB_COLOR .or\n" +" fragAttribItem_2 .emit FRAGMENT_ATTRIB_TEXCOORD .or\n" +" \"fogcoord\" .emit FRAGMENT_ATTRIB_FOGCOORD .or\n" +" \"position\" .emit FRAGMENT_ATTRIB_POSITION;\n" +"fragAttribItem_1\n" +" \"color\" .and optColorType;\n" +"fragAttribItem_2\n" +" \"texcoord\" .and optTexCoordNum;\n" +"vtxAttribItem\n" +" \"position\" .emit VERTEX_ATTRIB_POSITION .or\n" +" vtxAttribItem_1 .emit VERTEX_ATTRIB_WEIGHT .or\n" +" \"normal\" .emit VERTEX_ATTRIB_NORMAL .or\n" +" vtxAttribItem_2 .emit VERTEX_ATTRIB_COLOR .or\n" +" \"fogcoord\" .emit VERTEX_ATTRIB_FOGCOORD .or\n" +" vtxAttribItem_3 .emit VERTEX_ATTRIB_TEXCOORD .or\n" +" vtxAttribItem_4 .emit VERTEX_ATTRIB_MATRIXINDEX .or\n" +" vtxAttribItem_5 .emit VERTEX_ATTRIB_GENERIC;\n" +"vtxAttribItem_1\n" +" \"weight\" .and vtxOptWeightNum;\n" +"vtxAttribItem_2\n" +" \"color\" .and optColorType;\n" +"vtxAttribItem_3\n" +" \"texcoord\" .and optTexCoordNum;\n" +"vtxAttribItem_4\n" +" \"matrixindex\" .and lbracket .and vtxWeightNum .and rbracket;\n" +"vtxAttribItem_5\n" +" \"attrib\" .and lbracket .and vtxAttribNum .and rbracket;\n" +"vtxAttribNum\n" +" integer;\n" +"vtxOptWeightNum\n" +" vtxOptWeightNum_1 .or .true .emit 0x00;\n" +"vtxOptWeightNum_1\n" +" lbracket_ne .and vtxWeightNum .and rbracket;\n" +"vtxWeightNum\n" +" integer;\n" +"fp_PARAM_statement\n" +" fp_PARAM_multipleStmt .or fp_PARAM_singleStmt;\n" +"vp_PARAM_statement\n" +" vp_PARAM_multipleStmt .or vp_PARAM_singleStmt;\n" +"fp_PARAM_singleStmt\n" +" \"PARAM\" .and space .and fp_establishName .and .true .emit 0x00 .and fp_paramSingleInit .and\n" +" .true .emit PARAM_NULL;\n" +"vp_PARAM_singleStmt\n" +" \"PARAM\" .and space .and vp_establishName .and .true .emit 0x00 .and vp_paramSingleInit .and\n" +" .true .emit PARAM_NULL;\n" +"fp_PARAM_multipleStmt\n" +" \"PARAM\" .and space .and fp_establishName .and lbracket_ne .and optArraySize .and rbracket .and\n" +" fp_paramMultipleInit .and .true .emit PARAM_NULL;\n" +"vp_PARAM_multipleStmt\n" +" \"PARAM\" .and space .and vp_establishName .and lbracket_ne .and optArraySize .and rbracket .and\n" +" vp_paramMultipleInit .and .true .emit PARAM_NULL;\n" +"optArraySize\n" +" optional_integer;\n" +"fp_paramSingleInit\n" +" equal .and fp_paramSingleItemDecl;\n" +"vp_paramSingleInit\n" +" equal .and vp_paramSingleItemDecl;\n" +"fp_paramMultipleInit\n" +" equal .and lbrace .and fp_paramMultInitList .and rbrace;\n" +"vp_paramMultipleInit\n" +" equal .and lbrace .and vp_paramMultInitList .and rbrace;\n" +"fp_paramMultInitList\n" +" fp_paramMultInitList_1 .or fp_paramMultipleItem;\n" +"vp_paramMultInitList\n" +" vp_paramMultInitList_1 .or vp_paramMultipleItem;\n" +"fp_paramMultInitList_1\n" +" fp_paramMultipleItem .and comma_ne .and fp_paramMultInitList;\n" +"vp_paramMultInitList_1\n" +" vp_paramMultipleItem .and comma_ne .and vp_paramMultInitList;\n" +"fp_paramSingleItemDecl\n" +" fp_stateSingleItem .emit PARAM_STATE_ELEMENT .or\n" +" programSingleItem .emit PARAM_PROGRAM_ELEMENT .or\n" +" paramConstDecl .emit PARAM_CONSTANT;\n" +"vp_paramSingleItemDecl\n" +" vp_stateSingleItem .emit PARAM_STATE_ELEMENT .or\n" +" programSingleItem .emit PARAM_PROGRAM_ELEMENT .or\n" +" paramConstDecl .emit PARAM_CONSTANT;\n" +"fp_paramSingleItemUse\n" +" fp_stateSingleItem .emit PARAM_STATE_ELEMENT .or\n" +" programSingleItem .emit PARAM_PROGRAM_ELEMENT .or\n" +" paramConstUse .emit PARAM_CONSTANT;\n" +"vp_paramSingleItemUse\n" +" vp_stateSingleItem .emit PARAM_STATE_ELEMENT .or\n" +" programSingleItem .emit PARAM_PROGRAM_ELEMENT .or\n" +" paramConstUse .emit PARAM_CONSTANT;\n" +"fp_paramMultipleItem\n" +" fp_stateMultipleItem .emit PARAM_STATE_ELEMENT .or\n" +" programMultipleItem .emit PARAM_PROGRAM_ELEMENT .or\n" +" paramConstDecl .emit PARAM_CONSTANT;\n" +"vp_paramMultipleItem\n" +" vp_stateMultipleItem .emit PARAM_STATE_ELEMENT .or\n" +" programMultipleItem .emit PARAM_PROGRAM_ELEMENT .or\n" +" paramConstDecl .emit PARAM_CONSTANT;\n" +"fp_stateMultipleItem\n" +" stateMultipleItem_1 .or fp_stateSingleItem;\n" +"vp_stateMultipleItem\n" +" stateMultipleItem_1 .or vp_stateSingleItem;\n" +"stateMultipleItem_1\n" +" \"state\" .and dot .and stateMatrixRows .emit STATE_MATRIX_ROWS;\n" +"fp_stateSingleItem\n" +" \"state\" .and dot .and fp_stateSingleItem_1 .error INVALID_STATE_PROPERTY;\n" +"vp_stateSingleItem\n" +" \"state\" .and dot .and vp_stateSingleItem_1 .error INVALID_STATE_PROPERTY;\n" +"fp_stateSingleItem_1\n" +" stateSingleItem_1 .or stateSingleItem_2 .or stateSingleItem_3 .or stateSingleItem_4 .or\n" +" stateSingleItem_5 .or stateSingleItem_7 .or stateSingleItem_8 .or stateSingleItem_11;\n" +"vp_stateSingleItem_1\n" +" stateSingleItem_1 .or stateSingleItem_2 .or stateSingleItem_3 .or stateSingleItem_4 .or\n" +" stateSingleItem_6 .or stateSingleItem_7 .or stateSingleItem_9 .or stateSingleItem_10 .or\n" +" stateSingleItem_11;\n" +"stateSingleItem_1\n" +" stateMaterialItem .emit STATE_MATERIAL;\n" +"stateSingleItem_2\n" +" stateLightItem .emit STATE_LIGHT;\n" +"stateSingleItem_3\n" +" stateLightModelItem .emit STATE_LIGHT_MODEL;\n" +"stateSingleItem_4\n" +" stateLightProdItem .emit STATE_LIGHT_PROD;\n" +"stateSingleItem_5\n" +" stateTexEnvItem .emit STATE_TEX_ENV;\n" +"stateSingleItem_6\n" +" stateTexGenItem .emit STATE_TEX_GEN;\n" +"stateSingleItem_7\n" +" stateFogItem .emit STATE_FOG;\n" +"stateSingleItem_8\n" +" stateDepthItem .emit STATE_DEPTH;\n" +"stateSingleItem_9\n" +" stateClipPlaneItem .emit STATE_CLIP_PLANE;\n" +"stateSingleItem_10\n" +" statePointItem .emit STATE_POINT;\n" +"stateSingleItem_11\n" +" stateMatrixRow .emit STATE_MATRIX_ROWS;\n" +"stateMaterialItem\n" +" \"material\" .and optFaceType .and dot .and stateMatProperty .error INVALID_MATERIAL_PROPERTY;\n" +"stateMatProperty\n" +" \"ambient\" .emit MATERIAL_AMBIENT .or\n" +" \"diffuse\" .emit MATERIAL_DIFFUSE .or\n" +" \"specular\" .emit MATERIAL_SPECULAR .or\n" +" \"emission\" .emit MATERIAL_EMISSION .or\n" +" \"shininess\" .emit MATERIAL_SHININESS;\n" +"stateLightItem\n" +" \"light\" .and lbracket .and stateLightNumber .and rbracket .and dot .and\n" +" stateLightProperty .error INVALID_LIGHT_PROPERTY;\n" +"stateLightProperty\n" +" \"ambient\" .emit LIGHT_AMBIENT .or\n" +" \"diffuse\" .emit LIGHT_DIFFUSE .or\n" +" \"specular\" .emit LIGHT_SPECULAR .or\n" +" \"position\" .emit LIGHT_POSITION .or\n" +" \"attenuation\" .emit LIGHT_ATTENUATION .or\n" +" stateLightProperty_1 .emit LIGHT_SPOT_DIRECTION .or\n" +" \"half\" .emit LIGHT_HALF;\n" +"stateLightProperty_1\n" +" \"spot\" .and dot .and stateSpotProperty .error INVALID_SPOT_PROPERTY;\n" +"stateSpotProperty\n" +" \"direction\";\n" +"stateLightModelItem\n" +" \"lightmodel\" .and stateLModProperty .error INVALID_LIGHTMODEL_PROPERTY;\n" +"stateLModProperty\n" +" stateLModProperty_1 .or stateLModProperty_2;\n" +"stateLModProperty_1\n" +" dot .and \"ambient\" .emit LIGHT_MODEL_AMBIENT;\n" +"stateLModProperty_2\n" +" optFaceType .and dot .and \"scenecolor\" .emit LIGHT_MODEL_SCENECOLOR;\n" +"stateLightProdItem\n" +" \"lightprod\" .and lbracket .and stateLightNumber .and rbracket .and optFaceType .and dot .and\n" +" stateLProdProperty .error INVALID_LIGHTPROD_PROPERTY;\n" +"stateLProdProperty\n" +" \"ambient\" .emit LIGHT_PROD_AMBIENT .or\n" +" \"diffuse\" .emit LIGHT_PROD_DIFFUSE .or\n" +" \"specular\" .emit LIGHT_PROD_SPECULAR;\n" +"stateLightNumber\n" +" integer;\n" +"stateTexEnvItem\n" +" \"texenv\" .and optLegacyTexUnitNum .and dot .and\n" +" stateTexEnvProperty .error INVALID_TEXENV_PROPERTY;\n" +"stateTexEnvProperty\n" +" \"color\" .emit TEX_ENV_COLOR;\n" +"optLegacyTexUnitNum\n" +" lbracket_ne .and legacyTexUnitNum .and rbracket;\n" +"legacyTexUnitNum\n" +" integer;\n" +"stateTexGenItem\n" +" \"texgen\" .and optTexCoordNum .and dot .and stateTexGenType .error INVALID_TEXGEN_PROPERTY .and\n" +" dot .and stateTexGenCoord .error INVALID_TEXGEN_COORD;\n" +"stateTexGenType\n" +" \"eye\" .emit TEX_GEN_EYE .or\n" +" \"object\" .emit TEX_GEN_OBJECT;\n" +"stateTexGenCoord\n" +" \"s\" .emit COMPONENT_X .or\n" +" \"t\" .emit COMPONENT_Y .or\n" +" \"r\" .emit COMPONENT_Z .or\n" +" \"q\" .emit COMPONENT_W;\n" +"stateFogItem\n" +" \"fog\" .and dot .and stateFogProperty .error INVALID_FOG_PROPERTY;\n" +"stateFogProperty\n" +" \"color\" .emit FOG_COLOR .or\n" +" \"params\" .emit FOG_PARAMS;\n" +"stateDepthItem\n" +" \"depth\" .and dot .and stateDepthProperty .error INVALID_DEPTH_PROPERTY;\n" +"stateDepthProperty\n" +" \"range\" .emit DEPTH_RANGE;\n" +"stateClipPlaneItem\n" +" \"clip\" .and lbracket .and stateClipPlaneNum .and rbracket .and dot .and\n" +" \"plane\" .error INVALID_CLIPPLANE_PROPERTY;\n" +"stateClipPlaneNum\n" +" integer;\n" +"statePointItem\n" +" \"point\" .and dot .and statePointProperty .error INVALID_POINT_PROPERTY;\n" +"statePointProperty\n" +" \"size\" .emit POINT_SIZE .or\n" +" \"attenuation\" .emit POINT_ATTENUATION;\n" +"stateMatrixRow\n" +" stateMatrixItem .and dot .and \"row\" .error MATRIX_ROW_SELECTOR_OR_MODIFIER_EXPECTED .and\n" +" lbracket .and stateMatrixRowNum .and rbracket .emit 0x0;\n" +"stateMatrixRows\n" +" stateMatrixItem .and optMatrixRows;\n" +"optMatrixRows\n" +" optMatrixRows_1 .or .true .emit 0x0 .emit '3' .emit 0x0 .emit $;\n" +"optMatrixRows_1\n" +" dot_ne .and \"row\" .error MATRIX_ROW_SELECTOR_OR_MODIFIER_EXPECTED .and lbracket .and\n" +" stateMatrixRowNum .and dotdot .and stateMatrixRowNum .and rbracket;\n" +"stateMatrixItem\n" +" \"matrix\" .and dot .and stateMatrixName .error INVALID_MATRIX_NAME .and stateOptMatModifier;\n" +"stateOptMatModifier\n" +" stateOptMatModifier_1 .or .true .emit MATRIX_MODIFIER_IDENTITY;\n" +"stateOptMatModifier_1\n" +" dot_ne .and stateMatModifier;\n" +"stateMatModifier\n" +" \"inverse\" .emit MATRIX_MODIFIER_INVERSE .or\n" +" \"transpose\" .emit MATRIX_MODIFIER_TRANSPOSE .or\n" +" \"invtrans\" .emit MATRIX_MODIFIER_INVTRANS;\n" +"stateMatrixRowNum\n" +" integer_0_3;\n" +"stateMatrixName\n" +" stateMatrixName_1_1 .emit MATRIX_MODELVIEW .or\n" +" \"projection\" .emit MATRIX_PROJECTION .or\n" +" \"mvp\" .emit MATRIX_MVP .or\n" +" stateMatrixName_1_2 .emit MATRIX_TEXTURE .or\n" +" stateMatrixName_1_3 .emit MATRIX_PALETTE .or\n" +" stateMatrixName_1_4 .emit MATRIX_PROGRAM;\n" +"stateMatrixName_1_1\n" +" \"modelview\" .and stateOptModMatNum;\n" +"stateMatrixName_1_2\n" +" \"texture\" .and optTexCoordNum;\n" +"stateMatrixName_1_3\n" +" \"palette\" .and lbracket .and statePaletteMatNum .and rbracket;\n" +"stateMatrixName_1_4\n" +" \"program\" .and lbracket .and stateProgramMatNum .and rbracket;\n" +"stateOptModMatNum\n" +" stateOptModMatNum_1 .or .true .emit 0x00;\n" +"stateOptModMatNum_1\n" +" lbracket_ne .and stateModMatNum .and rbracket;\n" +"stateModMatNum\n" +" integer;\n" +"optTexCoordNum\n" +" optTexCoordNum_1 .or .true .emit 0x00;\n" +"optTexCoordNum_1\n" +" lbracket_ne .and texCoordNum .and rbracket;\n" +"texCoordNum\n" +" integer;\n" +"statePaletteMatNum\n" +" integer;\n" +"stateProgramMatNum\n" +" integer;\n" +"programSingleItem\n" +" \"program\" .and dot .and programSingleItem_1 .error INVALID_PROGRAM_PROPERTY;\n" +"programSingleItem_1\n" +" progEnvParam .or progLocalParam;\n" +"programMultipleItem\n" +" \"program\" .and dot .and programMultipleItem_1 .error INVALID_PROGRAM_PROPERTY;\n" +"programMultipleItem_1\n" +" progEnvParams .or progLocalParams;\n" +"progEnvParams\n" +" \"env\" .emit PROGRAM_PARAM_ENV .and lbracket .and progEnvParamNums .and rbracket;\n" +"progEnvParamNums\n" +" progEnvParamNums_1 .or progEnvParamNums_2;\n" +"progEnvParamNums_1\n" +" progEnvParamNum .and dotdot_ne .and progEnvParamNum;\n" +"progEnvParamNums_2\n" +" progEnvParamNum .and .true .emit 0x00;\n" +"progEnvParam\n" +" \"env\" .emit PROGRAM_PARAM_ENV .and lbracket .and progEnvParamNum .and rbracket;\n" +"progLocalParams\n" +" \"local\" .emit PROGRAM_PARAM_LOCAL .and lbracket .and progLocalParamNums .and rbracket;\n" +"progLocalParamNums\n" +" progLocalParamNums_1 .or progLocalParamNums_2;\n" +"progLocalParamNums_1\n" +" progLocalParamNum .and dotdot_ne .and progLocalParamNum;\n" +"progLocalParamNums_2\n" +" progLocalParamNum .and .true .emit 0x00;\n" +"progLocalParam\n" +" \"local\" .emit PROGRAM_PARAM_LOCAL .and lbracket .and progLocalParamNum .and rbracket;\n" +"progEnvParamNum\n" +" integer;\n" +"progLocalParamNum\n" +" integer;\n" +"paramConstDecl\n" +" paramConstScalarDecl .emit CONSTANT_SCALAR .or paramConstVector .emit CONSTANT_VECTOR;\n" +"paramConstUse\n" +" paramConstScalarUse .emit CONSTANT_SCALAR .or paramConstVector .emit CONSTANT_VECTOR;\n" +"paramConstScalarDecl\n" +" signedFloatConstant;\n" +"paramConstScalarUse\n" +" floatConstant;\n" +"paramConstVector\n" +" paramConstVector_4 .emit 0x04 .or paramConstVector_3 .emit 0x03 .or\n" +" paramConstVector_2 .emit 0x02 .or paramConstVector_1 .emit 0x01;\n" +"paramConstVector_1\n" +" lbrace_ne .and signedFloatConstant .and rbrace;\n" +"paramConstVector_2\n" +" lbrace_ne .and signedFloatConstant .and comma_ne .and signedFloatConstant .and rbrace;\n" +"paramConstVector_3\n" +" lbrace_ne .and signedFloatConstant .and comma_ne .and signedFloatConstant .and comma_ne .and\n" +" signedFloatConstant .and rbrace;\n" +"paramConstVector_4\n" +" lbrace_ne .and signedFloatConstant .and comma_ne .and signedFloatConstant .and comma_ne .and\n" +" signedFloatConstant .and comma_ne .and signedFloatConstant .and rbrace;\n" +"signedFloatConstant\n" +" optionalSign .and floatConstant;\n" +"floatConstant\n" +" float;\n" +"optionalSign\n" +" optional_sign_ne;\n" +"fp_TEMP_statement\n" +" \"TEMP\" .and space .and fp_varNameList .and .true .emit 0x00;\n" +"vp_TEMP_statement\n" +" \"TEMP\" .and space .and vp_varNameList .and .true .emit 0x00;\n" +"ADDRESS_statement\n" +" \"ADDRESS\" .and space .and vp_varNameList .and .true .emit 0x00;\n" +"fp_varNameList\n" +" fp_varNameList_1 .or fp_establishName;\n" +"vp_varNameList\n" +" vp_varNameList_1 .or vp_establishName;\n" +"fp_varNameList_1\n" +" fp_establishName .and comma_ne .and fp_varNameList;\n" +"vp_varNameList_1\n" +" vp_establishName .and comma_ne .and vp_varNameList;\n" +"fp_OUTPUT_statement\n" +" \"OUTPUT\" .and space .and fp_establishName .and equal .and\n" +" fp_resultBinding .error RESULT_EXPECTED;\n" +"vp_OUTPUT_statement\n" +" \"OUTPUT\" .and space .and vp_establishName .and equal .and\n" +" vp_resultBinding .error RESULT_EXPECTED;\n" +"fp_resultBinding\n" +" \"result\" .and dot .and fp_resultBinding_1 .error INVALID_RESULT_PROPERTY;\n" +"vp_resultBinding\n" +" \"result\" .and dot .and vp_resultBinding_1 .error INVALID_RESULT_PROPERTY;\n" +"fp_resultBinding_1\n" +" \"color\" .emit FRAGMENT_RESULT_COLOR .or\n" +" \"depth\" .emit FRAGMENT_RESULT_DEPTH;\n" +"vp_resultBinding_1\n" +" \"position\" .emit VERTEX_RESULT_POSITION .or\n" +" resultColBinding .emit VERTEX_RESULT_COLOR .or\n" +" \"fogcoord\" .emit VERTEX_RESULT_FOGCOORD .or\n" +" \"pointsize\" .emit VERTEX_RESULT_POINTSIZE .or\n" +" vp_resultBinding_2 .emit VERTEX_RESULT_TEXCOORD;\n" +"vp_resultBinding_2\n" +" \"texcoord\" .and optTexCoordNum;\n" +"resultColBinding\n" +" \"color\" .and optFaceType .and optColorType;\n" +"optFaceType\n" +" FaceType .or .true .emit FACE_FRONT;\n" +"FaceType\n" +" dot_ne .and FaceProperty;\n" +"FaceProperty\n" +" \"front\" .emit FACE_FRONT .or \"back\" .emit FACE_BACK;\n" +"optColorType\n" +" ColorType .or .true .emit COLOR_PRIMARY;\n" +"ColorType\n" +" dot_ne .and ColorProperty .error INVALID_COLOR_PROPERTY;\n" +"ColorProperty\n" +" \"primary\" .emit COLOR_PRIMARY .or \"secondary\" .emit COLOR_SECONDARY;\n" +"fp_ALIAS_statement\n" +" \"ALIAS\" .and space .and fp_establishName .and equal .and fp_establishedName;\n" +"vp_ALIAS_statement\n" +" \"ALIAS\" .and space .and vp_establishName .and equal .and vp_establishedName;\n" +"fp_establishName\n" +" fp_identifier;\n" +"vp_establishName\n" +" vp_identifier;\n" +"fp_establishedName\n" +" fp_identifier;\n" +"vp_establishedName\n" +" vp_identifier;\n" +"fp_identifier\n" +" fp_not_reserved_identifier .and identifier_ne .error IDENTIFIER_EXPECTED;\n" +"vp_identifier\n" +" vp_not_reserved_identifier .and identifier_ne .error IDENTIFIER_EXPECTED;\n" +"fp_not_reserved_identifier\n" +" fp_not_reserved_identifier_1 .or .true;\n" +"fp_not_reserved_identifier_1\n" +" fp_reserved_identifier .and .false .error RESERVED_KEYWORD;\n" +"vp_not_reserved_identifier\n" +" vp_not_reserved_identifier_1 .or .true;\n" +"vp_not_reserved_identifier_1\n" +" vp_reserved_identifier .and .false .error RESERVED_KEYWORD;\n" +"fp_reserved_identifier\n" +" \"ABS\" .or \"ABS_SAT\" .or \"ADD\" .or \"ADD_SAT\" .or \"ALIAS\" .or \"ATTRIB\" .or \"CMP\" .or \"CMP_SAT\" .or\n" +" \"COS\" .or \"COS_SAT\" .or \"DP3\" .or \"DP3_SAT\" .or \"DP4\" .or \"DP4_SAT\" .or \"DPH\" .or \"DPH_SAT\" .or\n" +" \"DST\" .or \"DST_SAT\" .or \"END\" .or \"EX2\" .or \"EX2_SAT\" .or \"FLR\" .or \"FLR_SAT\" .or \"FRC\" .or\n" +" \"FRC_SAT\" .or \"KIL\" .or \"LG2\" .or \"LG2_SAT\" .or \"LIT\" .or \"LIT_SAT\" .or \"LRP\" .or \"LRP_SAT\" .or\n" +" \"MAD\" .or \"MAD_SAT\" .or \"MAX\" .or \"MAX_SAT\" .or \"MIN\" .or \"MIN_SAT\" .or \"MOV\" .or \"MOV_SAT\" .or\n" +" \"MUL\" .or \"MUL_SAT\" .or \"OPTION\" .or \"OUTPUT\" .or \"PARAM\" .or \"POW\" .or \"POW_SAT\" .or \"RCP\" .or\n" +" \"RCP_SAT\" .or \"RSQ\" .or \"RSQ_SAT\" .or \"SIN\" .or \"SIN_SAT\" .or \"SCS\" .or \"SCS_SAT\" .or \"SGE\" .or\n" +" \"SGE_SAT\" .or \"SLT\" .or \"SLT_SAT\" .or \"SUB\" .or \"SUB_SAT\" .or \"SWZ\" .or \"SWZ_SAT\" .or \"TEMP\" .or\n" +" \"TEX\" .or \"TEX_SAT\" .or \"TXB\" .or \"TXB_SAT\" .or \"TXP\" .or \"TXP_SAT\" .or \"XPD\" .or \"XPD_SAT\" .or\n" +" \"fragment\" .or \"program\" .or \"result\" .or \"state\" .or \"texture\";\n" +"vp_reserved_identifier\n" +" \"ABS\" .or \"ADD\" .or \"ADDRESS\" .or \"ALIAS\" .or \"ARL\" .or \"ATTRIB\" .or \"DP3\" .or \"DP4\" .or\n" +" \"DPH\" .or \"DST\" .or \"END\" .or \"EX2\" .or \"EXP\" .or \"FLR\" .or \"FRC\" .or \"LG2\" .or \"LIT\" .or\n" +" \"LOG\" .or \"MAD\" .or \"MAX\" .or \"MIN\" .or \"MOV\" .or \"MUL\" .or \"OPTION\" .or \"OUTPUT\" .or\n" +" \"PARAM\" .or \"POW\" .or \"RCP\" .or \"RSQ\" .or \"SGE\" .or \"SLT\" .or \"SUB\" .or \"SWZ\" .or \"TEMP\" .or\n" +" \"XPD\" .or \"program\" .or \"result\" .or \"state\" .or \"vertex\";\n" +"integer\n" +" integer_ne .error INTEGER_EXPECTED;\n" +"integer_0_3\n" +" integer;\n" +"integer_0_63\n" +" integer;\n" +"integer_0_64\n" +" integer;\n" +"optional_space\n" +" space .or .true;\n" +"space\n" +" single_space .and .loop single_space;\n" +"single_space\n" +" white_char .or comment_block;\n" +"white_char\n" +" ' ' .or '\\t' .or '\\n' .or '\\r';\n" +"comment_block\n" +" '#' .and .loop comment_char .and new_line;\n" +"comment_char\n" +" '\\x0E'-'\\xFF' .or '\\x01'-'\\x09' .or '\\x0B'-'\\x0C';\n" +"new_line\n" +" '\\n' .or crlf .or '\\0';\n" +"crlf\n" +" '\\r' .and '\\n';\n" +"semicolon\n" +" optional_space .and ';' .error MISSING_SEMICOLON .and optional_space;\n" +"comma\n" +" optional_space .and ',' .error MISSING_COMMA .and optional_space;\n" +"comma_ne\n" +" optional_space .and ',' .and optional_space;\n" +"lbracket\n" +" optional_space .and '[' .error MISSING_LBRACKET .and optional_space;\n" +"lbracket_ne\n" +" optional_space .and '[' .and optional_space;\n" +"rbracket\n" +" optional_space .and ']' .error MISSING_RBRACKET .and optional_space;\n" +"dot\n" +" optional_space .and '.' .error MISSING_DOT .and optional_space;\n" +"dot_ne\n" +" optional_space .and '.' .and optional_space;\n" +"equal\n" +" optional_space .and '=' .error MISSING_EQUAL .and optional_space;\n" +"lbrace\n" +" optional_space .and '{' .error MISSING_LBRACE .and optional_space;\n" +"lbrace_ne\n" +" optional_space .and '{' .and optional_space;\n" +"rbrace\n" +" optional_space .and '}' .error MISSING_RBRACE .and optional_space;\n" +"dotdot\n" +" optional_space .and '.' .and '.' .error MISSING_DOTDOT .and optional_space;\n" +"dotdot_ne\n" +" optional_space .and '.' .and '.' .and optional_space;\n" +"float\n" +" float_1 .or float_2;\n" +"float_1\n" +" '.' .emit 0x00 .and integer_ne .error MISSING_FRACTION_OR_EXPONENT .and optional_exponent;\n" +"float_2\n" +" integer_ne .and float_3 .error MISSING_DOT_OR_EXPONENT;\n" +"float_3\n" +" float_4 .or float_5;\n" +"float_4\n" +" '.' .and optional_integer .and optional_exponent;\n" +"float_5\n" +" exponent .emit 0x00;\n" +"integer_ne\n" +" integer_ne_1 .and .true .emit 0x00 .emit $;\n" +"integer_ne_1\n" +" digit10 .emit * .and .loop digit10 .emit *;\n" +"optional_integer\n" +" integer_ne .or .true .emit 0x00;\n" +"optional_exponent\n" +" exponent .or .true .emit '1' .emit 0x00 .emit $;\n" +"exponent\n" +" exponent_1 .and optional_sign_ne .and integer_ne .error EXPONENT_VALUE_EXPECTED;\n" +"exponent_1\n" +" 'e' .or 'E';\n" +"optional_sign_ne\n" +" minus_ne .or plus_ne .or .true;\n" +"plus_ne\n" +" optional_space .and '+' .and optional_space;\n" +"minus_ne\n" +" optional_space .and '-' .emit '-' .and optional_space;\n" +"identifier_ne\n" +" first_idchar .emit * .and .loop follow_idchar .emit * .and .true .emit 0x00 .emit $;\n" +"follow_idchar\n" +" first_idchar .or digit10;\n" +"first_idchar\n" +" 'a'-'z' .or 'A'-'Z' .or '_' .or '$';\n" +"digit10\n" +" '0'-'9';\n" +".string __string_filter;\n" +"__string_filter\n" +" .loop __identifier_char;\n" +"__identifier_char\n" +" 'a'-'z' .or 'A'-'Z' .or '_' .or '$' .or '0'-'9';\n" +"e_signature\n" +" e_signature_char .and .loop e_signature_char;\n" +"e_signature_char\n" +" '!' .or '.' .or 'A'-'Z' .or 'a'-'z' .or '0'-'9';\n" +"e_statement\n" +" .loop e_statement_not_term;\n" +"e_statement_not_term\n" +" '\\x3C'-'\\xFF' .or '\\x0E'-'\\x3A' .or '\\x01'-'\\x09' .or '\\x0B'-'\\x0C';\n" +"e_identifier\n" +" e_identifier_first .and .loop e_identifier_next;\n" +"e_identifier_first\n" +" 'a'-'z' .or 'A'-'Z' .or '_' .or '$';\n" +"e_identifier_next\n" +" e_identifier_first .or '0'-'9';\n" +"e_token\n" +" e_identifier .or e_token_number .or '[' .or ']' .or '.' .or '{' .or '}' .or '=' .or '+' .or\n" +" '-' .or ',' .or ';';\n" +"e_token_number\n" +" e_token_digit .and .loop e_token_digit;\n" +"e_token_digit\n" +" '0'-'9';\n" +"e_charordigit\n" +" 'A'-'Z' .or 'a'-'z' .or '0'-'9';\n" +""; diff --git a/src/mesa/swrast/s_nvfragprog.c b/src/mesa/swrast/s_nvfragprog.c index 332edc5c86..94458238b5 100644 --- a/src/mesa/swrast/s_nvfragprog.c +++ b/src/mesa/swrast/s_nvfragprog.c @@ -38,7 +38,6 @@  /* if 1, print some debugging info */  #define DEBUG_FRAG 0 -  /**   * Fetch a texel.   */ @@ -120,13 +119,14 @@ get_register_pointer( GLcontext *ctx,           ASSERT(source->Index < MAX_NV_FRAGMENT_PROGRAM_PARAMS);           src = ctx->FragmentProgram.Parameters[source->Index];           break; + +      case PROGRAM_STATE_VAR: +			/* Fallthrough */ +        case PROGRAM_NAMED_PARAM:           ASSERT(source->Index < (GLint) program->Parameters->NumParameters);           src = program->Parameters->Parameters[source->Index].Values;           break; -      case PROGRAM_STATE_VAR: -         src = NULL; -         break;        default:           _mesa_problem(ctx, "Invalid input register file in fetch_vector4");           src = NULL; @@ -572,6 +572,12 @@ execute_program( GLcontext *ctx,     printf("execute fragment program --------------------\n");  #endif +	/* XXX: This should go someplace else, but it is safe here (and slow!)  +	 *        - karl +	 */ +   _mesa_load_state_parameters(ctx, program->Parameters);  + +     for (pc = 0; pc < maxInst; pc++) {        const struct fp_instruction *inst = program->Instructions + pc; | 
