/* * 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. */ /** * \file arbvertparse.c * ARB_vertex_program parser. * \author Karl Rasche */ #include "glheader.h" #include "context.h" #include "hash.h" #include "imports.h" #include "macros.h" #include "mtypes.h" #include "nvprogram.h" #include "nvvertparse.h" #include "nvvertprog.h" #include "arbvertparse.h" /** * Overview: * * This is a simple top-down predictive parser. In a nutshell, there are two key * elements to a predictive parser. First, is the 'look ahead' symbol. This is simply * the next token in the input stream. The other component is a stack of symbols. * * Given the grammar, we can derive a look ahead table. This is just a 2D array, * where one axis is the non-terminal on top of the stack and the other axis is * the look ahead. Each entry in the array is the production to apply when the pair * of stack symbol & look ahead is encountered. If no production is listed at * a given entry in the table, a parse error occurs if this combination * is seen. * * Since we want to drive the parsing from a couple of huge tables, we have to * save some information later on for processing (e.g. for code generation). * For this, we explicitly recreate the parse tree representing the derivation. * We can then make several passes over the parse tree to perform all additional * processing, and we can be sure the the parse is valid. * * The stack is initialized by pushing the start symbol onto it. The look ahead * symbol is initially the first token in the program string. * * If there is a non-terminal symbol on top of the stack, the look ahead table * is consulted to find if a production exists for the top of the stack * and the look ahead. * * When we find a matching production, we pop the non-terminal off the top of * the stack (the LHS of the production), and push the tokens on the RHS of * the production onto the stack. Note that we store a pointer to the parse_tree_node * containing the LHS token on the stack. This way, we can setup the children in * the parse tree as we apply the production. * * If there is a terminal symbol on top of the stack, we compare it with the * look ahead symbol. If they match, or we don't care about the value of the * terminal (e.g. we know its an integer, but don't necessairly care what * integer), the terminal symbol is popped off the stack and the look ahead * is advanced. * * There are a few special nasty cases of productions for which we make special * cases. These aren't found in the production/look-ahead tables, but listed * out explicitly. * * After the parse tree has been constructed, we make several recusive passes * over it to perform various tasks. * * The first pass is made to clean up the state bindings. This is done in * parse_tree_fold_bindings(). The goal is to reduce the big mess of a parse tree * created by strings such as: * * result.color.secondary * * and roll them up into one token and fill out some information in a symbol table. * In this case, the token at the root of the derivation becomes BINDING_TOKEN, * and the token attribute is an index into the binding table where this state * is held. * * The next two passes go about associating variables with BINDING_TOKENs. This * takes care of the cases like: * * OUTPUT foo = result.color.secondary; * * by inserting the index in the binding table for result.color.secondary into * the attr field in the identifier table where the 'foo' variable sits. * The second such pass deals with setting up arrays of program parameters, * while the first only deals with scalars. * * We then examine all the information on variables and state that we have * gathered, and layout which 'register' each variable or bit-of-state should use. * * * Finally, we make a recursive pass of the parse tree and generate opcodes * for Mesa to interpret while executing the program. * * It should be noted that each input/stack token has two parts, an 'identifier' * and an 'attribute'. The identifier tells what class the token is, e.g. INTEGER_TOKEN, * or NT_PROGRAM_SINGLE_ITEM_TOKEN. For some tokens, e.g. INTEGER_TOKEN, ID_TOKEN, * FLOAT_TOKEN, or BINDING_TOKEN, the attribute for the token is an index into a table * giving various properties about the token. * */ /** * Here are all of the structs used to hold parse state and symbol * tables used. * * All strings which are not reserved words, floats, ints, or misc * puncuation (ie .) are considered to be [potential] identifiers. * When we encounter such a string while lex'ing, insert it into * the id symbol table, shown below. * * Sometime later, we'll initialize the variable types for identifiers * which really are variables. This gets shoved into the 'type' field. * * For variables, we'll need additional info (e.g. state it is bound to, * variable we're aliased to, etc). This is stored in the 'attr' field. * - For alias variables, the attr is the idx in the id table of * the variable we are bound to. * - For other variables, we need a whole mess of info. This can be * found in the binding symbol table, below. In this case, the * attr field is the idx into the binding table that describes us. * - For uninitialized ids, attr is -1. * * The data field holds the string of the id. * * len is the number of identifiers in the table. */ typedef struct st_id_table { GLint len; GLint *type; GLint *attr; GLubyte **data; } id_table; /** * For PARAM arrays, we need to record the contents for use when * laying out registers and loading state. * * len is the number of arrays in the table. * * num_elements[i] is the number of items in array i. In other words, this * is the number of registers it would require when allocating. * * data[i][n] is the state bound to element n in array i. It is an idx into * the binding table */ typedef struct st_array_table { GLint len; GLint *num_elements; GLint **data; } array_table; /** * For holding all of the data used to describe an identifier, we have the catch * all binding symbol table. * * len is the number of bound items; * * type[i] tells what we are binding too, e.g. ATTRIB_POSITION, FOG_COLOR, or CONSTANT * * offset[i] gives the matrix number for matrix bindings, e.g. MATRIXROWS_MODELVIEW. * Alternativly, it gives the number of the first parameter for PROGRAM_ENV_* and * PROGRAM_LOCAL_*. * * num_rows[i] gives the number of rows for multiple matrix rows, or the number * of parameters in a env/local array. * * consts gives the 4-GLfloat constant value for bindings of type CONSTANT * * reg_num gives the register number which this binding is held in. */ typedef struct st_binding_table { GLint len; GLint *type; GLint *offset; GLint *row; GLint *num_rows; GLfloat **consts; GLint *reg_num; } binding_table; /** * Integers and floats are stored here. */ typedef struct st_int_table { GLint len; GLint *data; } int_table; typedef struct st_float_table { GLint len; GLdouble *data; } float_table; /** * To avoid writing tons of mindless parser code, the parsing is driven by * a few big tables of rules, plus a few special cases. However, this means * that we have to do all of our analysis outside of the parsing step. * * So, the parser will contruct a parse tree describing the program string * which we can then operate on to do things like code generation. * * This struct represents a node in the parse tree. * * If tok is a non-terminal token, tok_attr is not relevant. * If tok is BINDING_TOKEN, tok_attr is the index into the binding table. * if tok is INTEGER_TOKEN or FLOAT_TOKEN, tok_attr is the index in the integer/GLfloat table * * prod_applied is the production number applied to this token in the derivation of * the program string. See arbvp_grammar.txt for a listing of the productions, and * their numbers. */ typedef struct st_parse_tree_node { GLint tok, tok_attr, is_terminal; GLint prod_applied; struct st_parse_tree_node *children[4]; } parse_tree_node; /** This stores tokens that we lex out */ typedef struct st_token_list { GLint tok, tok_attr; parse_tree_node *pt; struct st_token_list *next; } token_list; /** * This holds all of the productions in the grammar. * * lhs is a non-terminal token, e.g. NT_PROGRAM_TOKEN. * rhs is either NULL_TOKEN, another non-terminal token, or a terminal token. * In some cases, we need the RHS to be a certain value, e.g. for the dst reg write masks. * For this, key is used to specify the string. If we don't care about the key, just * specify "". * Int/floats are slightly different, "-1" specifies 'we don't care'. * * lhs is not very useful here, but is is convient for sanity sake when specifing productions. */ typedef struct st_prod_table { GLint lhs; GLint rhs[4]; char *key[4]; } prod_table; /** * This holds the look ahead table to drive the parser. We examine the token on * the top of the stack, as well as the next token in the input stream (the look ahead). * We then match this against the table, and apply the approprate production. If nothing * matches, we have a parse error. * * Here, LHS is the (non-terminal) token to match against the top of the stack. * * la is the token to match against the look ahead. * * If la is ID_TOKEN, we have to match a given keyword (e.g. 'ambient'). This is specified in * la_kw. * * prod_idx is the idx into the prod_table of the production that we are to apply if this * rule matches. */ typedef struct st_look_ahead_table { GLint lhs; GLint la; char *la_kw; GLint prod_idx; } look_ahead_table; /** * This is the general catch-all for the parse state */ typedef struct st_parse_state { char *str; GLint len; /* lex stuff ------ */ GLint start_pos, curr_pos; GLint curr_state; /* ---------------- */ id_table idents; int_table ints; float_table floats; binding_table binds; array_table arrays; token_list *stack_head, *stack_free_list; parse_tree_node *pt_head; } parse_state; /* local prototypes */ static GLint float_table_add(float_table * tab, const char *str, GLint start, GLint end); static GLint int_table_add(int_table * tab, const char *str, GLint start, GLint end); static GLint id_table_add(id_table * tab, const char *str, GLint start, GLint end); static void parse_tree_free_children(parse_tree_node * ptn); /** * Here we have a ton of defined terms that we use to identify productions, * terminals, and nonterminals. */ /** * Terminal tokens */ #define EOF_TOKEN 0 #define ID_TOKEN 1 #define ABS_TOKEN 2 #define ADD_TOKEN 3 #define ADDRESS_TOKEN 4 #define ALIAS_TOKEN 5 #define ARL_TOKEN 6 #define ATTRIB_TOKEN 7 #define DP3_TOKEN 8 #define DP4_TOKEN 9 #define DPH_TOKEN 10 #define DST_TOKEN 11 #define END_TOKEN 12 #define EX2_TOKEN 13 #define EXP_TOKEN 14 #define FLR_TOKEN 15 #define FRC_TOKEN 16 #define LG2_TOKEN 17 #define LIT_TOKEN 18 #define LOG_TOKEN 19 #define MAD_TOKEN 20 #define MAX_TOKEN 21 #define MIN_TOKEN 22 #define MOV_TOKEN 23 #define MUL_TOKEN 24 #define OPTION_TOKEN 25 #define OUTPUT_TOKEN 26 #define PARAM_TOKEN 27 #define POW_TOKEN 28 #define RCP_TOKEN 29 #define RSQ_TOKEN 30 #define SGE_TOKEN 31 #define SLT_TOKEN 32 #define SUB_TOKEN 33 #define SWZ_TOKEN 34 #define TEMP_TOKEN 35 #define XPD_TOKEN 36 #define SEMICOLON_TOKEN 37 #define COMMA_TOKEN 38 #define PLUS_TOKEN 39 #define MINUS_TOKEN 40 #define PERIOD_TOKEN 41 #define DOTDOT_TOKEN 42 #define LBRACKET_TOKEN 43 #define RBRACKET_TOKEN 44 #define LBRACE_TOKEN 45 #define RBRACE_TOKEN 46 #define EQUAL_TOKEN 47 #define INTEGER_TOKEN 48 #define FLOAT_TOKEN 49 #define PROGRAM_TOKEN 50 #define RESULT_TOKEN 51 #define STATE_TOKEN 52 #define VERTEX_TOKEN 53 #define NULL_TOKEN 54 #define BINDING_TOKEN 55 /** * Non-terminal tokens */ #define NT_PROGRAM_TOKEN 100 #define NT_OPTION_SEQUENCE_TOKEN 101 #define NT_OPTION_SEQUENCE2_TOKEN 102 #define NT_OPTION_TOKEN 103 #define NT_STATEMENT_SEQUENCE_TOKEN 104 #define NT_STATEMENT_SEQUENCE2_TOKEN 105 #define NT_STATEMENT_TOKEN 106 #define NT_INSTRUCTION_TOKEN 107 #define NT_ARL_INSTRUCTION_TOKEN 108 #define NT_VECTOROP_INSTRUCTION_TOKEN 109 #define NT_VECTOROP_TOKEN 110 #define NT_SCALAROP_INSTRUCTION_TOKEN 111 #define NT_SCALAROP_TOKEN 112 #define NT_BINSCOP_INSTRUCTION_TOKEN 113 #define NT_BINSCOP_INSTRUCTION2_TOKEN 114 #define NT_BINSCOP_TOKEN 115 #define NT_BINOP_INSTRUCTION_TOKEN 116 #define NT_BINOP_INSTRUCTION2_TOKEN 117 #define NT_BINOP_TOKEN 118 #define NT_TRIOP_INSTRUCTION_TOKEN 119 #define NT_TRIOP_INSTRUCTION2_TOKEN 120 #define NT_TRIOP_INSTRUCTION3_TOKEN 121 #define NT_TRIOP_TOKEN 122 #define NT_SWZ_INSTRUCTION_TOKEN 123 #define NT_SWZ_INSTRUCTION2_TOKEN 124 #define NT_SCALAR_SRC_REG_TOKEN 130 #define NT_SWIZZLE_SRC_REG_TOKEN 131 #define NT_MASKED_DST_REG_TOKEN 132 #define NT_MASKED_ADDR_REG_TOKEN 133 #define NT_EXTENDED_SWIZZLE_TOKEN 134 #define NT_EXTENDED_SWIZZLE2_TOKEN 135 #define NT_EXT_SWIZ_COMP_TOKEN 136 #define NT_EXT_SWIZ_SEL_TOKEN 137 #define NT_SRC_REG_TOKEN 138 #define NT_DST_REG_TOKEN 139 #define NT_VERTEX_ATTRIB_REG_TOKEN 140 #define NT_TEMPORARY_REG_TOKEN 150 #define NT_PROG_PARAM_REG_TOKEN 151 #define NT_PROG_PARAM_SINGLE_TOKEN 152 #define NT_PROG_PARAM_ARRAY_TOKEN 153 #define NT_PROG_PARAM_ARRAY_MEM_TOKEN 154 #define NT_PROG_PARAM_ARRAY_ABS_TOKEN 155 #define NT_PROG_PARAM_ARRAY_REL_TOKEN 156 #define NT_ADDR_REG_REL_OFFSET_TOKEN 157 #define NT_ADDR_REG_POS_OFFSET_TOKEN 158 #define NT_ADDR_REG_NEG_OFFSET_TOKEN 159 #define NT_VERTEX_RESULT_REG_TOKEN 160 #define NT_ADDR_REG_TOKEN 161 #define NT_ADDR_COMPONENT_TOKEN 162 #define NT_ADDR_WRITE_MASK_TOKEN 163 #define NT_SCALAR_SUFFIX_TOKEN 164 #define NT_SWIZZLE_SUFFIX_TOKEN 165 #define NT_COMPONENT_TOKEN 166 #define NT_OPTIONAL_MASK_TOKEN 167 #define NT_OPTIONAL_MASK2_TOKEN 168 #define NT_NAMING_STATEMENT_TOKEN 169 #define NT_ATTRIB_STATEMENT_TOKEN 170 #define NT_VTX_ATTRIB_BINDING_TOKEN 171 #define NT_VTX_ATTRIB_ITEM_TOKEN 172 #define NT_VTX_ATTRIB_NUM_TOKEN 173 #define NT_VTX_OPT_WEIGHT_NUM_TOKEN 174 #define NT_VTX_WEIGHT_NUM_TOKEN 175 #define NT_PARAM_STATEMENT_TOKEN 176 #define NT_PARAM_STATEMENT2_TOKEN 177 #define NT_OPT_ARRAY_SIZE_TOKEN 178 #define NT_PARAM_SINGLE_INIT_TOKEN 179 #define NT_PARAM_MULTIPLE_INIT_TOKEN 180 #define NT_PARAM_MULT_INIT_LIST_TOKEN 181 #define NT_PARAM_MULT_INIT_LIST2_TOKEN 182 #define NT_PARAM_SINGLE_ITEM_DECL_TOKEN 183 #define NT_PARAM_SINGLE_ITEM_USE_TOKEN 184 #define NT_PARAM_MULTIPLE_ITEM_TOKEN 185 #define NT_STATE_MULTIPLE_ITEM_TOKEN 186 #define NT_STATE_MULTIPLE_ITEM2_TOKEN 187 #define NT_FOO_TOKEN 188 #define NT_FOO2_TOKEN 189 #define NT_FOO3_TOKEN 190 #define NT_FOO35_TOKEN 191 #define NT_FOO4_TOKEN 192 #define NT_STATE_SINGLE_ITEM_TOKEN 193 #define NT_STATE_SINGLE_ITEM2_TOKEN 194 #define NT_STATE_MATERIAL_ITEM_TOKEN 195 #define NT_STATE_MATERIAL_ITEM2_TOKEN 196 #define NT_STATE_MAT_PROPERTY_TOKEN 197 #define NT_STATE_LIGHT_ITEM_TOKEN 198 #define NT_STATE_LIGHT_ITEM2_TOKEN 199 #define NT_STATE_LIGHT_PROPERTY_TOKEN 200 #define NT_STATE_SPOT_PROPERTY_TOKEN 201 #define NT_STATE_LIGHT_MODEL_ITEM_TOKEN 202 #define NT_STATE_LMOD_PROPERTY_TOKEN 203 #define NT_STATE_LMOD_PROPERTY2_TOKEN 204 #define NT_STATE_LIGHT_PROD_ITEM_TOKEN 207 #define NT_STATE_LIGHT_PROD_ITEM15_TOKEN 208 #define NT_STATE_LIGHT_PROD_ITEM2_TOKEN 209 #define NT_STATE_LPROD_PROPERTY_TOKEN 210 #define NT_STATE_LIGHT_NUMBER_TOKEN 211 #define NT_STATE_TEX_GEN_ITEM_TOKEN 212 #define NT_STATE_TEX_GEN_ITEM2_TOKEN 213 #define NT_STATE_TEX_GEN_TYPE_TOKEN 214 #define NT_STATE_TEX_GEN_COORD_TOKEN 215 #define NT_STATE_FOG_ITEM_TOKEN 216 #define NT_STATE_FOG_PROPERTY_TOKEN 217 #define NT_STATE_CLIP_PLANE_ITEM_TOKEN 218 #define NT_STATE_CLIP_PLANE_ITEM2_TOKEN 219 #define NT_STATE_CLIP_PLANE_NUM_TOKEN 220 #define NT_STATE_POINT_ITEM_TOKEN 221 #define NT_STATE_POINT_PROPERTY_TOKEN 222 #define NT_STATE_MATRIX_ROW_TOKEN 223 #define NT_STATE_MATRIX_ROW15_TOKEN 224 #define NT_STATE_MATRIX_ROW2_TOKEN 225 #define NT_STATE_MATRIX_ROW3_TOKEN 226 #define NT_STATE_MAT_MODIFIER_TOKEN 227 #define NT_STATE_MATRIX_ROW_NUM_TOKEN 228 #define NT_STATE_MATRIX_NAME_TOKEN 229 #define NT_STATE_OPT_MOD_MAT_NUM_TOKEN 230 #define NT_STATE_MOD_MAT_NUM_TOKEN 231 #define NT_STATE_PALETTE_MAT_NUM_TOKEN 232 #define NT_STATE_PROGRAM_MAT_NUM_TOKEN 233 #define NT_PROGRAM_SINGLE_ITEM_TOKEN 234 #define NT_PROGRAM_SINGLE_ITEM2_TOKEN 235 #define NT_PROGRAM_MULTIPLE_ITEM_TOKEN 236 #define NT_PROGRAM_MULTIPLE_ITEM2_TOKEN 237 #define NT_PROG_ENV_PARAMS_TOKEN 238 #define NT_PROG_ENV_PARAM_NUMS_TOKEN 239 #define NT_PROG_ENV_PARAM_NUMS2_TOKEN 240 #define NT_PROG_ENV_PARAM_TOKEN 250 #define NT_PROG_LOCAL_PARAMS_TOKEN 251 #define NT_PROG_LOCAL_PARAM_NUMS_TOKEN 252 #define NT_PROG_LOCAL_PARAM_NUMS2_TOKEN 253 #define NT_PROG_LOCAL_PARAM_TOKEN 254 #define NT_PROG_ENV_PARAM_NUM_TOKEN 255 #define NT_PROG_LOCAL_PARAM_NUM_TOKEN 256 #define NT_PARAM_CONST_DECL_TOKEN 257 #define NT_PARAM_CONST_USE_TOKEN 258 #define NT_PARAM_CONST_SCALAR_DECL_TOKEN 259 #define NT_PARAM_CONST_SCALAR_USE_TOKEN 260 #define NT_PARAM_CONST_VECTOR_TOKEN 261 #define NT_PARAM_CONST_VECTOR2_TOKEN 262 #define NT_PARAM_CONST_VECTOR3_TOKEN 263 #define NT_PARAM_CONST_VECTOR4_TOKEN 264 #define NT_SIGNED_FLOAT_CONSTANT_TOKEN 265 #define NT_FLOAT_CONSTANT_TOKEN 266 #define NT_OPTIONAL_SIGN_TOKEN 267 #define NT_TEMP_STATEMENT_TOKEN 268 #define NT_ADDRESS_STATEMENT_TOKEN 269 #define NT_VAR_NAME_LIST_TOKEN 270 #define NT_OUTPUT_STATEMENT_TOKEN 271 #define NT_RESULT_BINDING_TOKEN 272 #define NT_RESULT_BINDING2_TOKEN 273 #define NT_RESULT_COL_BINDING_TOKEN 274 #define NT_RESULT_COL_BINDING2_TOKEN 275 #define NT_RESULT_COL_BINDING3_TOKEN 276 #define NT_RESULT_COL_BINDING4_TOKEN 277 #define NT_RESULT_COL_BINDING5_TOKEN 278 #define NT_OPT_FACE_TYPE2_TOKEN 279 #define NT_OPT_COLOR_TYPE_TOKEN 280 #define NT_OPT_COLOR_TYPE2_TOKEN 281 #define NT_OPT_TEX_COORD_NUM_TOKEN 282 #define NT_TEX_COORD_NUM_TOKEN 283 #define NT_ALIAS_STATEMENT_TOKEN 284 #define NT_ESTABLISH_NAME_TOKEN 285 #define NT_ESTABLISHED_NAME_TOKEN 286 #define NT_SWIZZLE_SUFFIX2_TOKEN 287 #define NT_COMPONENT4_TOKEN 288 /** * FSA States for lex * * XXX: These can be turned into enums */ #define STATE_BASE 0 #define STATE_IDENT 1 #define STATE_A 2 #define STATE_AB 3 #define STATE_ABS 4 #define STATE_AD 5 #define STATE_ADD 6 #define STATE_ADDR 7 #define STATE_ADDRE 8 #define STATE_ADDRES 9 #define STATE_ADDRESS 10 #define STATE_AL 11 #define STATE_ALI 12 #define STATE_ALIA 13 #define STATE_ALIAS 14 #define STATE_AR 15 #define STATE_ARL 16 #define STATE_AT 17 #define STATE_ATT 18 #define STATE_ATTR 19 #define STATE_ATTRI 20 #define STATE_ATTRIB 21 #define STATE_D 22 #define STATE_DP 23 #define STATE_DP3 24 #define STATE_DP4 25 #define STATE_DPH 26 #define STATE_DS 27 #define STATE_DST 28 #define STATE_E 29 #define STATE_EN 30 #define STATE_END 31 #define STATE_EX 32 #define STATE_EX2 33 #define STATE_EXP 34 #define STATE_F 35 #define STATE_FL 36 #define STATE_FLR 37 #define STATE_FR 38 #define STATE_FRC 39 #define STATE_L 40 #define STATE_LG 41 #define STATE_LG2 42 #define STATE_LI 43 #define STATE_LIT 44 #define STATE_LO 45 #define STATE_LOG 46 #define STATE_M 47 #define STATE_MA 48 #define STATE_MAD 49 #define STATE_MAX 50 #define STATE_MI 51 #define STATE_MIN 52 #define STATE_MO 53 #define STATE_MOV 54 #define STATE_MU 55 #define STATE_MUL 56 #define STATE_O 57 #define STATE_OP 58 #define STATE_OPT 59 #define STATE_OPTI 60 #define STATE_OPTIO 61 #define STATE_OPTION 62 #define STATE_OU 63 #define STATE_OUT 64 #define STATE_OUTP 65 #define STATE_OUTPU 66 #define STATE_OUTPUT 67 #define STATE_P 68 #define STATE_PA 69 #define STATE_PAR 70 #define STATE_PARA 71 #define STATE_PARAM 72 #define STATE_PO 73 #define STATE_POW 74 #define STATE_R 75 #define STATE_RC 76 #define STATE_RCP 77 #define STATE_RS 78 #define STATE_RSQ 79 #define STATE_S 80 #define STATE_SG 81 #define STATE_SGE 82 #define STATE_SL 83 #define STATE_SLT 84 #define STATE_SU 85 #define STATE_SUB 86 #define STATE_SW 87 #define STATE_SWZ 88 #define STATE_T 89 #define STATE_TE 90 #define STATE_TEM 91 #define STATE_TEMP 92 #define STATE_X 93 #define STATE_XP 94 #define STATE_XPD 95 #define STATE_N1 96 #define STATE_N2 97 #define STATE_N3 98 #define STATE_N4 99 #define STATE_N5 100 #define STATE_N6 101 #define STATE_N7 102 #define STATE_COMMENT 103 /* LC == lower case, as in 'program' */ #define STATE_LC_P 104 #define STATE_LC_PR 105 #define STATE_LC_PRO 106 #define STATE_LC_PROG 107 #define STATE_LC_PROGR 108 #define STATE_LC_PROGRA 109 #define STATE_LC_R 110 #define STATE_LC_RE 111 #define STATE_LC_RES 112 #define STATE_LC_RESU 113 #define STATE_LC_RESUL 114 #define STATE_LC_RESULT 115 #define STATE_LC_S 116 #define STATE_LC_ST 117 #define STATE_LC_STA 118 #define STATE_LC_STAT 119 #define STATE_LC_STATE 120 #define STATE_LC_V 121 #define STATE_LC_VE 122 #define STATE_LC_VER 123 #define STATE_LC_VERT 124 #define STATE_LC_VERTE 125 #define STATE_LC_VERTEX 126 #define STATE_LC_PROGRAM 127 /** * Error codes */ #define ARB_VP_ERROR -1 #define ARB_VP_SUCESS 0 /** * Variable types */ #define TYPE_NONE 0 #define TYPE_ATTRIB 1 #define TYPE_PARAM 2 #define TYPE_PARAM_SINGLE 3 #define TYPE_PARAM_ARRAY 4 #define TYPE_TEMP 5 #define TYPE_ADDRESS 6 #define TYPE_OUTPUT 7 #define TYPE_ALIAS 8 /** * Vertex Attrib Bindings */ #define ATTRIB_POSITION 1 #define ATTRIB_WEIGHT 2 #define ATTRIB_NORMAL 3 #define ATTRIB_COLOR_PRIMARY 4 #define ATTRIB_COLOR_SECONDARY 5 #define ATTRIB_FOGCOORD 6 #define ATTRIB_TEXCOORD 7 #define ATTRIB_MATRIXINDEX 8 #define ATTRIB_ATTRIB 9 /** * Result Bindings */ #define RESULT_POSITION 10 #define RESULT_FOGCOORD 11 #define RESULT_POINTSIZE 12 #define RESULT_COLOR_FRONT_PRIMARY 13 #define RESULT_COLOR_FRONT_SECONDARY 14 #define RESULT_COLOR_BACK_PRIMARY 15 #define RESULT_COLOR_BACK_SECONDARY 16 #define RESULT_TEXCOORD 17 /** * Material Property Bindings */ #define MATERIAL_FRONT_AMBIENT 18 #define MATERIAL_FRONT_DIFFUSE 19 #define MATERIAL_FRONT_SPECULAR 20 #define MATERIAL_FRONT_EMISSION 21 #define MATERIAL_FRONT_SHININESS 22 #define MATERIAL_BACK_AMBIENT 23 #define MATERIAL_BACK_DIFFUSE 24 #define MATERIAL_BACK_SPECULAR 25 #define MATERIAL_BACK_EMISSION 26 #define MATERIAL_BACK_SHININESS 27 /** * Light Property Bindings */ #define LIGHT_AMBIENT 28 #define LIGHT_DIFFUSE 29 #define LIGHT_SPECULAR 30 #define LIGHT_POSITION 31 #define LIGHT_ATTENUATION 32 #define LIGHT_SPOT_DIRECTION 33 #define LIGHT_HALF 34 #define LIGHTMODEL_AMBIENT 35 #define LIGHTMODEL_FRONT_SCENECOLOR 36 #define LIGHTMODEL_BACK_SCENECOLOR 37 #define LIGHTPROD_FRONT_AMBIENT 38 #define LIGHTPROD_FRONT_DIFFUSE 39 #define LIGHTPROD_FRONT_SPECULAR 40 #define LIGHTPROD_BACK_AMBIENT 41 #define LIGHTPROD_BACK_DIFFUSE 42 #define LIGHTPROD_BACK_SPECULAR 43 /** * Texgen Property Bindings */ #define TEXGEN_EYE_S 44 #define TEXGEN_EYE_T 45 #define TEXGEN_EYE_R 46 #define TEXGEN_EYE_Q 47 #define TEXGEN_OBJECT_S 48 #define TEXGEN_OBJECT_T 49 #define TEXGEN_OBJECT_R 50 #define TEXGEN_OBJECT_Q 51 /** * Fog Property Bindings */ #define FOG_COLOR 52 #define FOG_PARAMS 53 /** * Clip Property Bindings */ #define CLIP_PLANE 54 /** * Point Property Bindings */ #define POINT_SIZE 55 #define POINT_ATTENUATION 56 /** * Matrix Row Property Bindings */ #define MATRIXROW_MODELVIEW 57 #define MATRIXROW_MODELVIEW_INVERSE 58 #define MATRIXROW_MODELVIEW_INVTRANS 59 #define MATRIXROW_MODELVIEW_TRANSPOSE 60 #define MATRIXROW_PROJECTION 61 #define MATRIXROW_PROJECTION_INVERSE 62 #define MATRIXROW_PROJECTION_INVTRANS 63 #define MATRIXROW_PROJECTION_TRANSPOSE 64 #define MATRIXROW_MVP 65 #define MATRIXROW_MVP_INVERSE 66 #define MATRIXROW_MVP_INVTRANS 67 #define MATRIXROW_MVP_TRANSPOSE 68 #define MATRIXROW_TEXTURE 69 #define MATRIXROW_TEXTURE_INVERSE 70 #define MATRIXROW_TEXTURE_INVTRANS 71 #define MATRIXROW_TEXTURE_TRANSPOSE 72 #define MATRIXROW_PALETTE 73 #define MATRIXROW_PALETTE_INVERSE 74 #define MATRIXROW_PALETTE_INVTRANS 75 #define MATRIXROW_PALETTE_TRANSPOSE 76 #define MATRIXROW_PROGRAM 77 #define MATRIXROW_PROGRAM_INVERSE 78 #define MATRIXROW_PROGRAM_INVTRANS 79 #define MATRIXROW_PROGRAM_TRANSPOSE 80 #define MATRIXROWS_MODELVIEW 81 #define MATRIXROWS_MODELVIEW_INVERSE 82 #define MATRIXROWS_MODELVIEW_INVTRANS 83 #define MATRIXROWS_MODELVIEW_TRANSPOSE 84 #define MATRIXROWS_PROJECTION 85 #define MATRIXROWS_PROJECTION_INVERSE 86 #define MATRIXROWS_PROJECTION_INVTRANS 87 #define MATRIXROWS_PROJECTION_TRANSPOSE 88 #define MATRIXROWS_MVP 89 #define MATRIXROWS_MVP_INVERSE 90 #define MATRIXROWS_MVP_INVTRANS 91 #define MATRIXROWS_MVP_TRANSPOSE 92 #define MATRIXROWS_TEXTURE 93 #define MATRIXROWS_TEXTURE_INVERSE 94 #define MATRIXROWS_TEXTURE_INVTRANS 95 #define MATRIXROWS_TEXTURE_TRANSPOSE 96 #define MATRIXROWS_PALETTE 97 #define MATRIXROWS_PALETTE_INVERSE 98 #define MATRIXROWS_PALETTE_INVTRANS 99 #define MATRIXROWS_PALETTE_TRANSPOSE 100 #define MATRIXROWS_PROGRAM 101 #define MATRIXROWS_PROGRAM_INVERSE 102 #define MATRIXROWS_PROGRAM_INVTRANS 103 #define MATRIXROWS_PROGRAM_TRANSPOSE 104 #define PROGRAM_ENV_SINGLE 105 #define PROGRAM_LOCAL_SINGLE 106 #define PROGRAM_ENV_MULTI 107 #define PROGRAM_LOCAL_MULTI 108 #define CONSTANT 109 #define IS_WHITESPACE(c) (c == ' ') || (c == '\t') || (c == '\n') #define IS_IDCHAR(c) ((c >= 'A') && (c <= 'Z')) || \ ((c >= 'a') && (c <= 'z')) || \ (c == '_') || (c == '$') #define IS_DIGIT(c) (c >= '0') && (c <= '9') #define IS_CD(c) (IS_DIGIT(c)) || (IS_IDCHAR(c)) #define ADV_TO_STATE(state) s->curr_state = state; s->curr_pos++; #define ADV_OR_FALLBACK(c, state) if (curr == c) { \ ADV_TO_STATE(state); \ } else {\ if (IS_CD(curr)) { \ ADV_TO_STATE(STATE_IDENT); \ } else \ s->curr_state = 1;\ } #define FINISH(tok) *token = tok; s->start_pos = s->curr_pos; s->curr_state = STATE_BASE; return ARB_VP_SUCESS; #define ADV_AND_FINISH(tok) *token = tok; s->start_pos = s->curr_pos+1; s->curr_pos++; \ s->curr_state = STATE_BASE; return ARB_VP_SUCESS; #define FINISH_OR_FALLBACK(tok) if (IS_CD(curr)) {\ ADV_TO_STATE(STATE_IDENT); \ } else { \ FINISH(tok)\ } #define NO_KW {"", "", "", ""} #define NULL2 NULL_TOKEN, NULL_TOKEN #define NULL3 NULL_TOKEN, NULL2 #define NULL4 NULL2, NULL2 /* This uglyness is the production table. See the prod_table struct definition for a description */ prod_table ptab[] = { {NT_PROGRAM_TOKEN, {NT_OPTION_SEQUENCE_TOKEN, NT_STATEMENT_SEQUENCE_TOKEN, END_TOKEN, NULL_TOKEN}, NO_KW}, {NT_OPTION_SEQUENCE_TOKEN, {NT_OPTION_SEQUENCE2_TOKEN, NULL3}, NO_KW}, {NT_OPTION_SEQUENCE2_TOKEN, {NT_OPTION_TOKEN, NT_OPTION_SEQUENCE2_TOKEN, NULL2}, NO_KW}, {NT_OPTION_SEQUENCE2_TOKEN, {NULL4}, NO_KW}, {NT_OPTION_TOKEN, {OPTION_TOKEN, ID_TOKEN, SEMICOLON_TOKEN, NULL_TOKEN}, NO_KW}, /* 5: */ {NT_STATEMENT_SEQUENCE_TOKEN, {NT_STATEMENT_SEQUENCE2_TOKEN, NULL3}, NO_KW}, {NT_STATEMENT_SEQUENCE2_TOKEN, {NT_STATEMENT_TOKEN, NT_STATEMENT_SEQUENCE2_TOKEN, NULL2}, NO_KW}, {NT_STATEMENT_SEQUENCE2_TOKEN, {NULL4}, NO_KW}, {NT_STATEMENT_TOKEN, {NT_INSTRUCTION_TOKEN, SEMICOLON_TOKEN, NULL2}, NO_KW}, {NT_STATEMENT_TOKEN, {NT_NAMING_STATEMENT_TOKEN, SEMICOLON_TOKEN, NULL2}, NO_KW}, /* 10: */ {NT_INSTRUCTION_TOKEN, {NT_ARL_INSTRUCTION_TOKEN, NULL3}, NO_KW}, {NT_INSTRUCTION_TOKEN, {NT_VECTOROP_INSTRUCTION_TOKEN, NULL3}, NO_KW}, {NT_INSTRUCTION_TOKEN, {NT_SCALAROP_INSTRUCTION_TOKEN, NULL3}, NO_KW}, {NT_INSTRUCTION_TOKEN, {NT_BINSCOP_INSTRUCTION_TOKEN, NULL3}, NO_KW}, {NT_INSTRUCTION_TOKEN, {NT_BINOP_INSTRUCTION_TOKEN, NULL3}, NO_KW}, /* 15: */ {NT_INSTRUCTION_TOKEN, {NT_TRIOP_INSTRUCTION_TOKEN, NULL3}, NO_KW}, {NT_INSTRUCTION_TOKEN, {NT_SWZ_INSTRUCTION_TOKEN, NULL3}, NO_KW}, {NT_ARL_INSTRUCTION_TOKEN, {ARL_TOKEN, NT_MASKED_ADDR_REG_TOKEN, COMMA_TOKEN, NT_SCALAR_SRC_REG_TOKEN}, NO_KW}, {NT_VECTOROP_INSTRUCTION_TOKEN, {NT_VECTOROP_TOKEN, NT_MASKED_DST_REG_TOKEN, COMMA_TOKEN, NT_SWIZZLE_SRC_REG_TOKEN}, NO_KW}, {NT_VECTOROP_TOKEN, {ABS_TOKEN, NULL3}, NO_KW}, /* 20: */ {NT_VECTOROP_TOKEN, {FLR_TOKEN, NULL3}, NO_KW}, {NT_VECTOROP_TOKEN, {FRC_TOKEN, NULL3}, NO_KW}, {NT_VECTOROP_TOKEN, {LIT_TOKEN, NULL3}, NO_KW}, {NT_VECTOROP_TOKEN, {MOV_TOKEN, NULL3}, NO_KW}, {NT_SCALAROP_INSTRUCTION_TOKEN, {NT_SCALAROP_TOKEN, NT_MASKED_DST_REG_TOKEN, COMMA_TOKEN, NT_SCALAR_SRC_REG_TOKEN}, NO_KW}, /* 25: */ {NT_SCALAROP_TOKEN, {EX2_TOKEN, NULL3}, NO_KW}, {NT_SCALAROP_TOKEN, {EXP_TOKEN, NULL3}, NO_KW}, {NT_SCALAROP_TOKEN, {LG2_TOKEN, NULL3}, NO_KW}, {NT_SCALAROP_TOKEN, {LOG_TOKEN, NULL3}, NO_KW}, {NT_SCALAROP_TOKEN, {RCP_TOKEN, NULL3}, NO_KW}, /* 30: */ {NT_SCALAROP_TOKEN, {RSQ_TOKEN, NULL3}, NO_KW}, {NT_BINSCOP_INSTRUCTION_TOKEN, {NT_BINSCOP_TOKEN, NT_MASKED_DST_REG_TOKEN, NT_BINSCOP_INSTRUCTION2_TOKEN, NULL_TOKEN}, NO_KW}, {NT_BINSCOP_INSTRUCTION2_TOKEN, {COMMA_TOKEN, NT_SCALAR_SRC_REG_TOKEN, COMMA_TOKEN, NT_SCALAR_SRC_REG_TOKEN}, NO_KW}, {NT_BINSCOP_TOKEN, {POW_TOKEN, NULL3}, NO_KW}, {NT_BINOP_INSTRUCTION_TOKEN, {NT_BINOP_TOKEN, NT_MASKED_DST_REG_TOKEN, NT_BINOP_INSTRUCTION2_TOKEN, NULL_TOKEN}, NO_KW}, /* 35: */ {NT_BINOP_INSTRUCTION2_TOKEN, {COMMA_TOKEN, NT_SWIZZLE_SRC_REG_TOKEN, COMMA_TOKEN, NT_SWIZZLE_SRC_REG_TOKEN}, NO_KW}, {NT_BINOP_TOKEN, {ADD_TOKEN, NULL3}, NO_KW}, {NT_BINOP_TOKEN, {DP3_TOKEN, NULL3}, NO_KW}, {NT_BINOP_TOKEN, {DP4_TOKEN, NULL3}, NO_KW}, {NT_BINOP_TOKEN, {DPH_TOKEN, NULL3}, NO_KW}, /* 40: */ {NT_BINOP_TOKEN, {DST_TOKEN, NULL3}, NO_KW}, {NT_BINOP_TOKEN, {MAX_TOKEN, NULL3}, NO_KW}, {NT_BINOP_TOKEN, {MIN_TOKEN, NULL3}, NO_KW}, {NT_BINOP_TOKEN, {MUL_TOKEN, NULL3}, NO_KW}, {NT_BINOP_TOKEN, {SGE_TOKEN, NULL3}, NO_KW}, /* 45: */ {NT_BINOP_TOKEN, {SLT_TOKEN, NULL3}, NO_KW}, {NT_BINOP_TOKEN, {SUB_TOKEN, NULL3}, NO_KW}, {NT_BINOP_TOKEN, {XPD_TOKEN, NULL3}, NO_KW}, {NT_TRIOP_INSTRUCTION_TOKEN, {NT_TRIOP_TOKEN, NT_MASKED_DST_REG_TOKEN, NT_TRIOP_INSTRUCTION2_TOKEN, NULL_TOKEN}, NO_KW}, {NT_TRIOP_INSTRUCTION2_TOKEN, {COMMA_TOKEN, NT_SWIZZLE_SRC_REG_TOKEN, NT_TRIOP_INSTRUCTION3_TOKEN, NULL_TOKEN}, NO_KW}, /* 50: */ {NT_TRIOP_INSTRUCTION3_TOKEN, {COMMA_TOKEN, NT_SWIZZLE_SRC_REG_TOKEN, COMMA_TOKEN, NT_SWIZZLE_SRC_REG_TOKEN}, NO_KW}, {NT_TRIOP_TOKEN, {MAD_TOKEN, NULL3}, NO_KW}, {NT_SWZ_INSTRUCTION_TOKEN, {SWZ_TOKEN, NT_MASKED_DST_REG_TOKEN, NT_SWZ_INSTRUCTION2_TOKEN, NULL_TOKEN}, NO_KW}, {NT_SWZ_INSTRUCTION2_TOKEN, {COMMA_TOKEN, NT_SRC_REG_TOKEN, COMMA_TOKEN, NT_EXTENDED_SWIZZLE_TOKEN}, NO_KW}, {NT_SCALAR_SRC_REG_TOKEN, {NT_OPTIONAL_SIGN_TOKEN, NT_SRC_REG_TOKEN, NT_SCALAR_SUFFIX_TOKEN, NULL_TOKEN}, NO_KW}, /* 55 */ {NT_SWIZZLE_SRC_REG_TOKEN, {NT_OPTIONAL_SIGN_TOKEN, NT_SRC_REG_TOKEN, NT_SWIZZLE_SUFFIX_TOKEN, NULL_TOKEN}, NO_KW}, {NT_MASKED_DST_REG_TOKEN, {NT_DST_REG_TOKEN, NT_OPTIONAL_MASK_TOKEN, NULL2}, NO_KW}, {NT_MASKED_ADDR_REG_TOKEN, {NT_ADDR_REG_TOKEN, NT_ADDR_WRITE_MASK_TOKEN, NULL2}, NO_KW}, {NT_EXTENDED_SWIZZLE_TOKEN, {NT_EXT_SWIZ_COMP_TOKEN, COMMA_TOKEN, NT_EXT_SWIZ_COMP_TOKEN, NT_EXTENDED_SWIZZLE2_TOKEN}, NO_KW}, {NT_EXTENDED_SWIZZLE2_TOKEN, {COMMA_TOKEN, NT_EXT_SWIZ_COMP_TOKEN, COMMA_TOKEN, NT_EXT_SWIZ_COMP_TOKEN}, NO_KW}, /* 60 */ {NT_EXT_SWIZ_COMP_TOKEN,{NT_OPTIONAL_SIGN_TOKEN, NT_EXT_SWIZ_SEL_TOKEN, NULL2}, NO_KW}, {NT_EXT_SWIZ_SEL_TOKEN, {INTEGER_TOKEN, NULL3}, {"0", "", "", ""}}, {NT_EXT_SWIZ_SEL_TOKEN, {INTEGER_TOKEN, NULL3}, {"1", "", "", ""}}, {NT_EXT_SWIZ_SEL_TOKEN, {NT_COMPONENT_TOKEN, NULL3}, NO_KW}, {NT_SRC_REG_TOKEN, {NT_VERTEX_ATTRIB_REG_TOKEN, NULL3}, NO_KW}, /* 65: */ {NT_SRC_REG_TOKEN, {NT_TEMPORARY_REG_TOKEN, NULL3}, NO_KW}, {NT_SRC_REG_TOKEN, {NT_PROG_PARAM_REG_TOKEN, NULL3}, NO_KW}, {NT_DST_REG_TOKEN, {NT_TEMPORARY_REG_TOKEN, NULL3}, NO_KW}, {NT_DST_REG_TOKEN, {NT_VERTEX_RESULT_REG_TOKEN, NULL3}, NO_KW}, {NT_VERTEX_ATTRIB_REG_TOKEN, {NT_ESTABLISHED_NAME_TOKEN, NULL3}, NO_KW}, /* 70: */ {NT_VERTEX_ATTRIB_REG_TOKEN, {NT_VTX_ATTRIB_BINDING_TOKEN, NULL3}, NO_KW}, {NT_TEMPORARY_REG_TOKEN, {NT_ESTABLISHED_NAME_TOKEN, NULL3}, NO_KW}, {NT_PROG_PARAM_REG_TOKEN, {NT_PROG_PARAM_SINGLE_TOKEN, NULL3}, NO_KW}, {NT_PROG_PARAM_REG_TOKEN, {NT_PROG_PARAM_ARRAY_TOKEN, LBRACKET_TOKEN, NT_PROG_PARAM_ARRAY_MEM_TOKEN, RBRACKET_TOKEN}, NO_KW}, {NT_PROG_PARAM_REG_TOKEN, {NT_PARAM_SINGLE_ITEM_USE_TOKEN, NULL3}, NO_KW}, /* 75: */ {NT_PROG_PARAM_SINGLE_TOKEN, {NT_ESTABLISHED_NAME_TOKEN, NULL3}, NO_KW}, {NT_PROG_PARAM_ARRAY_TOKEN, {NT_ESTABLISHED_NAME_TOKEN, NULL3}, NO_KW}, {NT_PROG_PARAM_ARRAY_MEM_TOKEN, {NT_PROG_PARAM_ARRAY_ABS_TOKEN, NULL3}, NO_KW}, {NT_PROG_PARAM_ARRAY_MEM_TOKEN, {NT_PROG_PARAM_ARRAY_REL_TOKEN, NULL3}, NO_KW}, /* -1 matches all */ {NT_PROG_PARAM_ARRAY_ABS_TOKEN, {INTEGER_TOKEN, NULL3}, {"-1", "", "", ""}}, /* 80: */ {NT_PROG_PARAM_ARRAY_REL_TOKEN, {NT_ADDR_REG_TOKEN, NT_ADDR_COMPONENT_TOKEN, NT_ADDR_REG_REL_OFFSET_TOKEN, NULL_TOKEN}, NO_KW}, {NT_ADDR_REG_REL_OFFSET_TOKEN, {NULL4}, NO_KW}, {NT_ADDR_REG_REL_OFFSET_TOKEN, {PLUS_TOKEN, NT_ADDR_REG_POS_OFFSET_TOKEN, NULL2}, NO_KW}, {NT_ADDR_REG_REL_OFFSET_TOKEN, {MINUS_TOKEN, NT_ADDR_REG_NEG_OFFSET_TOKEN, NULL2}, NO_KW}, {NT_ADDR_REG_POS_OFFSET_TOKEN, {INTEGER_TOKEN, NULL3}, {"-1", "", "", ""}}, /* 85: */ {NT_ADDR_REG_NEG_OFFSET_TOKEN, {INTEGER_TOKEN, NULL3}, {"-1", "", "", ""}}, {NT_VERTEX_RESULT_REG_TOKEN, {NT_ESTABLISHED_NAME_TOKEN, NULL3}, NO_KW}, {NT_VERTEX_RESULT_REG_TOKEN, {NT_RESULT_BINDING_TOKEN, NULL3}, NO_KW}, {NT_ADDR_REG_TOKEN, {NT_ESTABLISHED_NAME_TOKEN, NULL3}, NO_KW}, {NT_ADDR_COMPONENT_TOKEN, {PERIOD_TOKEN, ID_TOKEN, NULL2}, {"", "x", "", ""}}, /* 90: */ {NT_ADDR_WRITE_MASK_TOKEN, {PERIOD_TOKEN, ID_TOKEN, NULL2}, {"", "x", "", ""}}, {NT_SCALAR_SUFFIX_TOKEN, {PERIOD_TOKEN, NT_COMPONENT_TOKEN, NULL2}, {"", "x", "", ""}}, {NT_SWIZZLE_SUFFIX_TOKEN, {NULL4}, NO_KW}, {NT_COMPONENT_TOKEN, {ID_TOKEN, NULL3}, {"x", "", "", ""}}, {NT_COMPONENT_TOKEN, {ID_TOKEN, NULL3}, {"y", "", "", ""}}, /* 95: */ {NT_COMPONENT_TOKEN, {ID_TOKEN, NULL3}, {"z", "", "", ""}}, {NT_COMPONENT_TOKEN, {ID_TOKEN, NULL3}, {"w", "", "", ""}}, {NT_OPTIONAL_MASK_TOKEN, {PERIOD_TOKEN, NT_OPTIONAL_MASK2_TOKEN, NULL2}, NO_KW}, {NT_OPTIONAL_MASK_TOKEN, {NULL4}, NO_KW}, {NT_OPTIONAL_MASK2_TOKEN, {ID_TOKEN, NULL3}, {"x", "", "", ""}}, /* 100: */ {NT_OPTIONAL_MASK2_TOKEN, {ID_TOKEN, NULL3}, {"y", "", "", ""}}, {NT_OPTIONAL_MASK2_TOKEN, {ID_TOKEN, NULL3}, {"xy", "", "", ""}}, {NT_OPTIONAL_MASK2_TOKEN, {ID_TOKEN, NULL3}, {"z", "", "", ""}}, {NT_OPTIONAL_MASK2_TOKEN, {ID_TOKEN, NULL3}, {"xz", "", "", ""}}, {NT_OPTIONAL_MASK2_TOKEN, {ID_TOKEN, NULL3}, {"yz", "", "", ""}}, /* 105: */ {NT_OPTIONAL_MASK2_TOKEN, {ID_TOKEN, NULL3}, {"xyz", "", "", ""}}, {NT_OPTIONAL_MASK2_TOKEN, {ID_TOKEN, NULL3}, {"w", "", "", ""}}, {NT_OPTIONAL_MASK2_TOKEN, {ID_TOKEN, NULL3}, {"xw", "", "", ""}}, {NT_OPTIONAL_MASK2_TOKEN, {ID_TOKEN, NULL3}, {"yw", "", "", ""}}, {NT_OPTIONAL_MASK2_TOKEN, {ID_TOKEN, NULL3}, {"xyw", "", "", ""}}, /* 110: */ {NT_OPTIONAL_MASK2_TOKEN, {ID_TOKEN, NULL3}, {"zw", "", "", ""}}, {NT_OPTIONAL_MASK2_TOKEN, {ID_TOKEN, NULL3}, {"xzw", "", "", ""}}, {NT_OPTIONAL_MASK2_TOKEN, {ID_TOKEN, NULL3}, {"yzw", "", "", ""}}, {NT_OPTIONAL_MASK2_TOKEN, {ID_TOKEN, NULL3}, {"xyzw", "", "", ""}}, {NT_NAMING_STATEMENT_TOKEN, {NT_ATTRIB_STATEMENT_TOKEN, NULL3}, NO_KW}, /* 115: */ {NT_NAMING_STATEMENT_TOKEN, {NT_PARAM_STATEMENT_TOKEN, NULL3}, NO_KW}, {NT_NAMING_STATEMENT_TOKEN, {NT_TEMP_STATEMENT_TOKEN, NULL3}, NO_KW}, {NT_NAMING_STATEMENT_TOKEN, {NT_ADDRESS_STATEMENT_TOKEN, NULL3}, NO_KW}, {NT_NAMING_STATEMENT_TOKEN, {NT_OUTPUT_STATEMENT_TOKEN, NULL3}, NO_KW}, {NT_NAMING_STATEMENT_TOKEN, {NT_ALIAS_STATEMENT_TOKEN, NULL3}, NO_KW}, /* 120: */ {NT_ATTRIB_STATEMENT_TOKEN, {ATTRIB_TOKEN, NT_ESTABLISH_NAME_TOKEN, EQUAL_TOKEN, NT_VTX_ATTRIB_BINDING_TOKEN}, NO_KW}, {NT_VTX_ATTRIB_BINDING_TOKEN, {VERTEX_TOKEN, PERIOD_TOKEN, NT_VTX_ATTRIB_ITEM_TOKEN, NULL_TOKEN}, NO_KW}, {NT_VTX_ATTRIB_ITEM_TOKEN, {ID_TOKEN, NULL3}, {"position", "", "", ""}}, {NT_VTX_ATTRIB_ITEM_TOKEN, {ID_TOKEN, NT_VTX_OPT_WEIGHT_NUM_TOKEN, NULL2},{"weight", "", "", ""}}, {NT_VTX_ATTRIB_ITEM_TOKEN, {ID_TOKEN, NULL3}, {"normal", "", "", ""}}, /* 125: */ {NT_VTX_ATTRIB_ITEM_TOKEN, {ID_TOKEN, NT_OPT_COLOR_TYPE_TOKEN, NULL2}, {"color", "", "", ""}}, {NT_VTX_ATTRIB_ITEM_TOKEN, {ID_TOKEN, NULL3}, {"fogcoord", "", "", ""}}, {NT_VTX_ATTRIB_ITEM_TOKEN, {ID_TOKEN, NT_OPT_TEX_COORD_NUM_TOKEN, NULL2}, {"texcoord", "", "", ""}}, {NT_VTX_ATTRIB_ITEM_TOKEN, {ID_TOKEN, LBRACKET_TOKEN, NT_VTX_WEIGHT_NUM_TOKEN, RBRACKET_TOKEN}, {"matrixindex", "", "", ""}}, {NT_VTX_ATTRIB_ITEM_TOKEN, {ID_TOKEN, LBRACKET_TOKEN, NT_VTX_ATTRIB_NUM_TOKEN, RBRACKET_TOKEN}, {"attrib", "", "", ""}}, /* 130: */ {NT_VTX_ATTRIB_NUM_TOKEN, {INTEGER_TOKEN, NULL3}, {"-1", "", "", ""}}, {NT_VTX_OPT_WEIGHT_NUM_TOKEN, {NULL4}, NO_KW}, {NT_VTX_OPT_WEIGHT_NUM_TOKEN, {LBRACKET_TOKEN, NT_VTX_WEIGHT_NUM_TOKEN, RBRACKET_TOKEN, NULL_TOKEN}, NO_KW}, {NT_VTX_WEIGHT_NUM_TOKEN, {INTEGER_TOKEN, NULL3}, {"-1", "", "", ""}}, {NT_PARAM_STATEMENT_TOKEN, {PARAM_TOKEN, NT_ESTABLISH_NAME_TOKEN, NT_PARAM_STATEMENT2_TOKEN, NULL_TOKEN}, NO_KW}, /* 135: */ {NT_PARAM_STATEMENT2_TOKEN, {NT_PARAM_SINGLE_INIT_TOKEN, NULL3}, NO_KW}, {NT_PARAM_STATEMENT2_TOKEN, {LBRACKET_TOKEN, NT_OPT_ARRAY_SIZE_TOKEN, RBRACKET_TOKEN, NT_PARAM_MULTIPLE_INIT_TOKEN}, NO_KW}, {NT_OPT_ARRAY_SIZE_TOKEN, {NULL4}, NO_KW}, {NT_OPT_ARRAY_SIZE_TOKEN, {INTEGER_TOKEN, NULL3}, {"-1", "", "", ""}}, {NT_PARAM_SINGLE_INIT_TOKEN, {EQUAL_TOKEN, NT_PARAM_SINGLE_ITEM_DECL_TOKEN, NULL2}, NO_KW}, /* 140: */ {NT_PARAM_MULTIPLE_INIT_TOKEN, {EQUAL_TOKEN, LBRACE_TOKEN, NT_PARAM_MULT_INIT_LIST_TOKEN, RBRACE_TOKEN}, NO_KW}, {NT_PARAM_MULT_INIT_LIST_TOKEN, {NT_PARAM_MULTIPLE_ITEM_TOKEN, NT_PARAM_MULT_INIT_LIST2_TOKEN, NULL2}, NO_KW}, {NT_PARAM_MULT_INIT_LIST2_TOKEN, {COMMA_TOKEN, NT_PARAM_MULT_INIT_LIST_TOKEN, NULL2}, NO_KW}, {NT_PARAM_MULT_INIT_LIST2_TOKEN, {NULL4}, NO_KW}, {NT_PARAM_SINGLE_ITEM_DECL_TOKEN, {NT_STATE_SINGLE_ITEM_TOKEN, NULL3}, NO_KW}, /* 145: */ {NT_PARAM_SINGLE_ITEM_DECL_TOKEN, {NT_PROGRAM_SINGLE_ITEM_TOKEN, NULL3}, NO_KW}, {NT_PARAM_SINGLE_ITEM_DECL_TOKEN, {NT_PARAM_CONST_DECL_TOKEN, NULL3}, NO_KW}, {NT_PARAM_SINGLE_ITEM_USE_TOKEN, {NT_STATE_SINGLE_ITEM_TOKEN, NULL3}, NO_KW}, {NT_PARAM_SINGLE_ITEM_USE_TOKEN, {NT_PROGRAM_SINGLE_ITEM_TOKEN, NULL3}, NO_KW}, {NT_PARAM_SINGLE_ITEM_USE_TOKEN, {NT_PARAM_CONST_USE_TOKEN, NULL3}, NO_KW}, /* 150: */ {NT_PARAM_MULTIPLE_ITEM_TOKEN, {NT_STATE_MULTIPLE_ITEM_TOKEN, NULL3}, NO_KW}, {NT_PARAM_MULTIPLE_ITEM_TOKEN, {NT_PROGRAM_MULTIPLE_ITEM_TOKEN, NULL3}, NO_KW}, {NT_PARAM_MULTIPLE_ITEM_TOKEN, {NT_PARAM_CONST_DECL_TOKEN, NULL3}, NO_KW}, {NT_STATE_MULTIPLE_ITEM_TOKEN, {STATE_TOKEN, PERIOD_TOKEN, NT_STATE_MULTIPLE_ITEM2_TOKEN, NULL_TOKEN}, NO_KW}, {NT_STATE_MULTIPLE_ITEM2_TOKEN, {NT_STATE_MATERIAL_ITEM_TOKEN, NULL3}, NO_KW}, /* 155: */ {NT_STATE_MULTIPLE_ITEM2_TOKEN, {NT_STATE_LIGHT_ITEM_TOKEN, NULL3}, NO_KW}, {NT_STATE_MULTIPLE_ITEM2_TOKEN, {NT_STATE_LIGHT_MODEL_ITEM_TOKEN, NULL3}, NO_KW}, {NT_STATE_MULTIPLE_ITEM2_TOKEN, {NT_STATE_LIGHT_PROD_ITEM_TOKEN, NULL3}, NO_KW}, {NT_STATE_MULTIPLE_ITEM2_TOKEN, {NT_STATE_TEX_GEN_ITEM_TOKEN, NULL3}, NO_KW}, {NT_STATE_MULTIPLE_ITEM2_TOKEN, {NT_STATE_FOG_ITEM_TOKEN, NULL3}, NO_KW}, /* 160: */ {NT_STATE_MULTIPLE_ITEM2_TOKEN, {NT_STATE_CLIP_PLANE_ITEM_TOKEN, NULL3}, NO_KW}, {NT_STATE_MULTIPLE_ITEM2_TOKEN, {NT_STATE_POINT_ITEM_TOKEN, NULL3}, NO_KW}, {NT_STATE_MULTIPLE_ITEM2_TOKEN, {ID_TOKEN, PERIOD_TOKEN, NT_STATE_MATRIX_NAME_TOKEN, NT_FOO_TOKEN}, {"matrix", "", "", ""}}, {NT_FOO_TOKEN, {PERIOD_TOKEN, NT_FOO2_TOKEN, NULL2}, NO_KW}, {NT_FOO2_TOKEN, {NT_STATE_MAT_MODIFIER_TOKEN, NT_FOO3_TOKEN, NULL2}, NO_KW}, /* 165: */ {NT_FOO2_TOKEN, {ID_TOKEN, LBRACKET_TOKEN, NT_STATE_MATRIX_ROW_NUM_TOKEN, NT_FOO4_TOKEN}, {"row", "", "", ""}}, {NT_FOO3_TOKEN, {NULL4}, NO_KW}, {NT_FOO3_TOKEN, {PERIOD_TOKEN, ID_TOKEN, LBRACKET_TOKEN, NT_FOO35_TOKEN}, {"", "row", "", ""}}, {NT_FOO35_TOKEN, {NT_STATE_MATRIX_ROW_NUM_TOKEN, NT_FOO4_TOKEN, NULL2}, NO_KW}, {NT_FOO4_TOKEN, {RBRACKET_TOKEN, NULL3}, NO_KW}, /* 170: */ {NT_FOO4_TOKEN, {DOTDOT_TOKEN, NT_STATE_MATRIX_ROW_NUM_TOKEN, RBRACKET_TOKEN, NULL_TOKEN}, NO_KW}, {NT_STATE_SINGLE_ITEM_TOKEN, {STATE_TOKEN, PERIOD_TOKEN, NT_STATE_SINGLE_ITEM2_TOKEN, NULL_TOKEN}, NO_KW}, {NT_STATE_SINGLE_ITEM2_TOKEN, {NT_STATE_MATERIAL_ITEM_TOKEN, NULL3}, NO_KW}, {NT_STATE_SINGLE_ITEM2_TOKEN, {NT_STATE_LIGHT_ITEM_TOKEN, NULL3}, NO_KW}, {NT_STATE_SINGLE_ITEM2_TOKEN, {NT_STATE_LIGHT_MODEL_ITEM_TOKEN, NULL3}, NO_KW}, /* 175: */ {NT_STATE_SINGLE_ITEM2_TOKEN, {NT_STATE_LIGHT_PROD_ITEM_TOKEN, NULL3}, NO_KW}, {NT_STATE_SINGLE_ITEM2_TOKEN, {NT_STATE_TEX_GEN_ITEM_TOKEN, NULL3}, NO_KW}, {NT_STATE_SINGLE_ITEM2_TOKEN, {NT_STATE_FOG_ITEM_TOKEN, NULL3}, NO_KW}, {NT_STATE_SINGLE_ITEM2_TOKEN, {NT_STATE_CLIP_PLANE_ITEM_TOKEN, NULL3}, NO_KW}, {NT_STATE_SINGLE_ITEM2_TOKEN, {NT_STATE_POINT_ITEM_TOKEN, NULL3}, NO_KW}, /* 180: */ {NT_STATE_SINGLE_ITEM2_TOKEN, {NT_STATE_MATRIX_ROW_TOKEN, NULL3}, NO_KW}, {NT_STATE_MATERIAL_ITEM_TOKEN, {ID_TOKEN, PERIOD_TOKEN, NT_STATE_MATERIAL_ITEM2_TOKEN, NULL_TOKEN}, {"material", "", "", ""}}, {NT_STATE_MATERIAL_ITEM2_TOKEN, {NT_STATE_MAT_PROPERTY_TOKEN, NULL3}, NO_KW}, {NT_STATE_MATERIAL_ITEM2_TOKEN, {PERIOD_TOKEN, NT_OPT_FACE_TYPE2_TOKEN, PERIOD_TOKEN, NT_STATE_MAT_PROPERTY_TOKEN}, NO_KW}, {NT_STATE_MAT_PROPERTY_TOKEN, {ID_TOKEN, NULL3}, {"ambient", "", "", ""}}, /* 185 */ {NT_STATE_MAT_PROPERTY_TOKEN, {ID_TOKEN, NULL3}, {"diffuse", "", "", ""}}, {NT_STATE_MAT_PROPERTY_TOKEN, {ID_TOKEN, NULL3}, {"specular", "", "", ""}}, {NT_STATE_MAT_PROPERTY_TOKEN, {ID_TOKEN, NULL3}, {"emission", "", "", ""}}, {NT_STATE_MAT_PROPERTY_TOKEN, {ID_TOKEN, NULL3}, {"shininess", "", "", ""}}, {NT_STATE_LIGHT_ITEM_TOKEN, {ID_TOKEN, LBRACKET_TOKEN, NT_STATE_LIGHT_NUMBER_TOKEN, NT_STATE_LIGHT_ITEM2_TOKEN}, {"light", "", "", ""}}, /* 190: */ {NT_STATE_LIGHT_ITEM2_TOKEN, {RBRACKET_TOKEN, PERIOD_TOKEN, NT_STATE_LIGHT_PROPERTY_TOKEN, NULL_TOKEN}, NO_KW}, {NT_STATE_LIGHT_PROPERTY_TOKEN, {ID_TOKEN, NULL3}, {"ambient", "", "", ""}}, {NT_STATE_LIGHT_PROPERTY_TOKEN, {ID_TOKEN, NULL3}, {"diffuse", "", "", ""}}, {NT_STATE_LIGHT_PROPERTY_TOKEN, {ID_TOKEN, NULL3}, {"specular", "", "", ""}}, {NT_STATE_LIGHT_PROPERTY_TOKEN, {ID_TOKEN, NULL3}, {"position", "", "", ""}}, /* 195: */ {NT_STATE_LIGHT_PROPERTY_TOKEN, {ID_TOKEN, NULL3}, {"attenuation", "", "", ""}}, {NT_STATE_LIGHT_PROPERTY_TOKEN, {ID_TOKEN, PERIOD_TOKEN, NT_STATE_SPOT_PROPERTY_TOKEN, NULL_TOKEN}, {"spot", "", "", ""}}, {NT_STATE_LIGHT_PROPERTY_TOKEN, {ID_TOKEN, NULL3}, {"half", "", "", ""}}, {NT_STATE_SPOT_PROPERTY_TOKEN, {ID_TOKEN, NULL3}, {"direction", "", "", ""}}, {NT_STATE_LIGHT_MODEL_ITEM_TOKEN, {ID_TOKEN, NT_STATE_LMOD_PROPERTY_TOKEN, NULL2}, {"lightmodel", "", "", ""}}, /* 200: */ {NT_STATE_LMOD_PROPERTY_TOKEN, {PERIOD_TOKEN, NT_STATE_LMOD_PROPERTY2_TOKEN, NULL2}, NO_KW}, {NT_STATE_LMOD_PROPERTY2_TOKEN, {ID_TOKEN, NULL3}, {"ambient", "", "", ""}}, {NT_STATE_LMOD_PROPERTY2_TOKEN, {ID_TOKEN, NULL3}, {"scenecolor", "", "", ""}}, {NT_STATE_LMOD_PROPERTY2_TOKEN, {NT_OPT_FACE_TYPE2_TOKEN, PERIOD_TOKEN, ID_TOKEN, NULL_TOKEN}, {"scenecolor", "", "", ""}}, {NT_STATE_LIGHT_PROD_ITEM_TOKEN, {ID_TOKEN, LBRACKET_TOKEN, NT_STATE_LIGHT_NUMBER_TOKEN, NT_STATE_LIGHT_PROD_ITEM15_TOKEN}, {"lightprod", "", "", ""}}, /* 205: */ {NT_STATE_LIGHT_PROD_ITEM15_TOKEN, {RBRACKET_TOKEN, PERIOD_TOKEN, NT_STATE_LIGHT_PROD_ITEM2_TOKEN, NULL_TOKEN}, NO_KW}, {NT_STATE_LIGHT_PROD_ITEM2_TOKEN, {NT_STATE_LPROD_PROPERTY_TOKEN, NULL3}, NO_KW}, {NT_STATE_LIGHT_PROD_ITEM2_TOKEN, {NT_OPT_FACE_TYPE2_TOKEN, PERIOD_TOKEN, NT_STATE_LPROD_PROPERTY_TOKEN, NULL_TOKEN}, NO_KW}, {NT_STATE_LPROD_PROPERTY_TOKEN, {ID_TOKEN, NULL3}, {"diffuse", "", "", ""}}, {NT_STATE_LPROD_PROPERTY_TOKEN, {ID_TOKEN, NULL3}, {"ambient", "", "", ""}}, /* 210: */ {NT_STATE_LPROD_PROPERTY_TOKEN, {ID_TOKEN, NULL3}, {"specular", "", "", ""}}, {NT_STATE_LIGHT_NUMBER_TOKEN, {INTEGER_TOKEN, NULL3}, {"-1", "", "", ""}}, {NT_STATE_TEX_GEN_ITEM_TOKEN, {ID_TOKEN, NT_OPT_TEX_COORD_NUM_TOKEN, NT_STATE_TEX_GEN_ITEM2_TOKEN, NULL_TOKEN}, {"texgen", "", "", ""}}, {NT_STATE_TEX_GEN_ITEM2_TOKEN,{PERIOD_TOKEN, NT_STATE_TEX_GEN_TYPE_TOKEN, PERIOD_TOKEN, NT_STATE_TEX_GEN_COORD_TOKEN}, NO_KW}, {NT_STATE_TEX_GEN_TYPE_TOKEN, {ID_TOKEN, NULL3}, {"eye", "", "", ""}}, /* 215: */ {NT_STATE_TEX_GEN_TYPE_TOKEN, {ID_TOKEN, NULL3}, {"object", "", "", ""}}, {NT_STATE_TEX_GEN_COORD_TOKEN, {ID_TOKEN, NULL3}, {"s", "", "", ""}}, {NT_STATE_TEX_GEN_COORD_TOKEN, {ID_TOKEN, NULL3}, {"t", "", "", ""}}, {NT_STATE_TEX_GEN_COORD_TOKEN, {ID_TOKEN, NULL3}, {"r", "", "", ""}}, {NT_STATE_TEX_GEN_COORD_TOKEN, {ID_TOKEN, NULL3}, {"q", "", "", ""}}, /* 220: */ {NT_STATE_FOG_ITEM_TOKEN, {ID_TOKEN, PERIOD_TOKEN, NT_STATE_FOG_PROPERTY_TOKEN, NULL_TOKEN}, {"fog", "","",""}}, {NT_STATE_FOG_PROPERTY_TOKEN, {ID_TOKEN, NULL3}, {"color", "", "", ""}}, {NT_STATE_FOG_PROPERTY_TOKEN, {ID_TOKEN, NULL3}, {"params", "", "", ""}}, {NT_STATE_CLIP_PLANE_ITEM_TOKEN, {ID_TOKEN, LBRACKET_TOKEN, NT_STATE_CLIP_PLANE_NUM_TOKEN, NT_STATE_CLIP_PLANE_ITEM2_TOKEN}, {"clip", "", "", ""}}, {NT_STATE_CLIP_PLANE_ITEM2_TOKEN, {RBRACKET_TOKEN, PERIOD_TOKEN, ID_TOKEN, NULL_TOKEN}, {"", "", "plane", ""}}, /* 225: */ {NT_STATE_CLIP_PLANE_NUM_TOKEN,{INTEGER_TOKEN, NULL3}, {"-1", "", "", ""}}, {NT_STATE_POINT_ITEM_TOKEN, {ID_TOKEN, PERIOD_TOKEN, NT_STATE_POINT_PROPERTY_TOKEN, NULL_TOKEN}, {"point", "", "", ""}}, {NT_STATE_POINT_PROPERTY_TOKEN, {ID_TOKEN, NULL3}, {"size", "", "", ""}}, {NT_STATE_POINT_PROPERTY_TOKEN, {ID_TOKEN, NULL3}, {"attenuation", "", "", ""}}, {NT_STATE_MATRIX_ROW_TOKEN, {ID_TOKEN, PERIOD_TOKEN, NT_STATE_MATRIX_NAME_TOKEN, NT_STATE_MATRIX_ROW15_TOKEN}, {"matrix", "", "", ""}}, /* 230: */ {NT_STATE_MATRIX_ROW15_TOKEN, {PERIOD_TOKEN, NT_STATE_MATRIX_ROW2_TOKEN, NULL2}, NO_KW}, {NT_STATE_MATRIX_ROW2_TOKEN, {ID_TOKEN, LBRACKET_TOKEN, NT_STATE_MATRIX_ROW_NUM_TOKEN, RBRACKET_TOKEN}, {"row", "", "", ""}}, {NT_STATE_MATRIX_ROW2_TOKEN, {NT_STATE_MAT_MODIFIER_TOKEN, PERIOD_TOKEN, ID_TOKEN, NT_STATE_MATRIX_ROW3_TOKEN}, {"", "", "row", ""}}, {NT_STATE_MATRIX_ROW3_TOKEN, {LBRACKET_TOKEN, NT_STATE_MATRIX_ROW_NUM_TOKEN, RBRACKET_TOKEN, NULL_TOKEN}, NO_KW}, {NT_STATE_MAT_MODIFIER_TOKEN, {ID_TOKEN, NULL3}, {"inverse", "", "", ""}}, /* 235: */ {NT_STATE_MAT_MODIFIER_TOKEN, {ID_TOKEN, NULL3}, {"transpose", "", "", ""}}, {NT_STATE_MAT_MODIFIER_TOKEN, {ID_TOKEN, NULL3}, {"invtrans", "", "", ""}}, {NT_STATE_MATRIX_ROW_NUM_TOKEN, {INTEGER_TOKEN, NULL3}, {"-1", "", "", ""}}, {NT_STATE_MATRIX_NAME_TOKEN, {ID_TOKEN, NT_STATE_OPT_MOD_MAT_NUM_TOKEN, NULL2}, {"modelview", "", "", ""}}, {NT_STATE_MATRIX_NAME_TOKEN, {ID_TOKEN, NULL3}, {"projection", "", "", ""}}, /* 240: */ {NT_STATE_MATRIX_NAME_TOKEN, {ID_TOKEN, NULL3}, {"mvp", "", "", ""}}, {NT_STATE_MATRIX_NAME_TOKEN, {ID_TOKEN, NT_OPT_TEX_COORD_NUM_TOKEN, NULL2}, {"texture", "", "", ""}}, {NT_STATE_MATRIX_NAME_TOKEN, {ID_TOKEN, LBRACKET_TOKEN, NT_STATE_PALETTE_MAT_NUM_TOKEN, RBRACKET_TOKEN}, {"palette", "", "", ""}}, {NT_STATE_MATRIX_NAME_TOKEN, {PROGRAM_TOKEN, LBRACKET_TOKEN, NT_STATE_PROGRAM_MAT_NUM_TOKEN, RBRACKET_TOKEN}, NO_KW}, {NT_STATE_OPT_MOD_MAT_NUM_TOKEN, {NULL4}, NO_KW}, /* 245: */ {NT_STATE_OPT_MOD_MAT_NUM_TOKEN, {LBRACKET_TOKEN, NT_STATE_MOD_MAT_NUM_TOKEN, RBRACKET_TOKEN, NULL_TOKEN}, NO_KW}, {NT_STATE_MOD_MAT_NUM_TOKEN, {INTEGER_TOKEN, NULL3}, {"-1", "", "", ""}}, {NT_STATE_PALETTE_MAT_NUM_TOKEN, {INTEGER_TOKEN, NULL3}, {"-1", "", "", ""}}, {NT_STATE_PROGRAM_MAT_NUM_TOKEN, {INTEGER_TOKEN, NULL3}, {"-1", "", "", ""}}, {NT_PROGRAM_SINGLE_ITEM_TOKEN, {PROGRAM_TOKEN, PERIOD_TOKEN, NT_PROGRAM_SINGLE_ITEM2_TOKEN, NULL_TOKEN}, NO_KW}, /* 250: */ {NT_PROGRAM_SINGLE_ITEM2_TOKEN, {NT_PROG_ENV_PARAM_TOKEN, NULL3}, NO_KW}, {NT_PROGRAM_SINGLE_ITEM2_TOKEN, {NT_PROG_LOCAL_PARAM_TOKEN, NULL3}, NO_KW}, {NT_PROGRAM_MULTIPLE_ITEM_TOKEN, {PROGRAM_TOKEN, PERIOD_TOKEN, NT_PROGRAM_MULTIPLE_ITEM2_TOKEN, NULL_TOKEN}, NO_KW}, {NT_PROGRAM_MULTIPLE_ITEM2_TOKEN, {NT_PROG_ENV_PARAMS_TOKEN, NULL3}, NO_KW}, {NT_PROGRAM_MULTIPLE_ITEM2_TOKEN, {NT_PROG_LOCAL_PARAMS_TOKEN, NULL3}, NO_KW}, /* 255: */ {NT_PROG_ENV_PARAMS_TOKEN, {ID_TOKEN, LBRACKET_TOKEN, NT_PROG_ENV_PARAM_NUMS_TOKEN, RBRACKET_TOKEN}, {"env", "", "", ""}}, {NT_PROG_ENV_PARAM_NUMS_TOKEN, {NT_PROG_ENV_PARAM_NUM_TOKEN, NT_PROG_ENV_PARAM_NUMS2_TOKEN, NULL2}, NO_KW}, {NT_PROG_ENV_PARAM_NUMS2_TOKEN, {DOTDOT_TOKEN, NT_PROG_ENV_PARAM_NUM_TOKEN, NULL2}, NO_KW}, {NT_PROG_ENV_PARAM_NUMS2_TOKEN, {NULL4}, NO_KW}, {NT_PROG_ENV_PARAM_TOKEN, {ID_TOKEN, LBRACKET_TOKEN, NT_PROG_ENV_PARAM_NUM_TOKEN, RBRACKET_TOKEN}, {"env", "", "", ""}}, /* 260: */ {NT_PROG_LOCAL_PARAMS_TOKEN, {ID_TOKEN, LBRACKET_TOKEN, NT_PROG_LOCAL_PARAM_NUMS_TOKEN, RBRACKET_TOKEN}, {"local", "", "", ""}}, {NT_PROG_LOCAL_PARAM_NUMS_TOKEN, {NT_PROG_LOCAL_PARAM_NUM_TOKEN, NT_PROG_LOCAL_PARAM_NUMS2_TOKEN, NULL2}, NO_KW}, {NT_PROG_LOCAL_PARAM_NUMS2_TOKEN, {DOTDOT_TOKEN, NT_PROG_LOCAL_PARAM_NUM_TOKEN, NULL2}, NO_KW}, {NT_PROG_LOCAL_PARAM_NUMS2_TOKEN, {NULL4}, NO_KW}, {NT_PROG_LOCAL_PARAM_TOKEN, {ID_TOKEN, LBRACKET_TOKEN, NT_PROG_LOCAL_PARAM_NUM_TOKEN, RBRACKET_TOKEN}, {"local", "", "", ""}}, /* 265: */ {NT_PROG_ENV_PARAM_NUM_TOKEN, {INTEGER_TOKEN, NULL3}, {"-1", "", "", ""}}, {NT_PROG_LOCAL_PARAM_NUM_TOKEN, {INTEGER_TOKEN, NULL3}, {"-1", "", "", ""}}, {NT_PARAM_CONST_DECL_TOKEN, {NT_PARAM_CONST_SCALAR_DECL_TOKEN, NULL3}, NO_KW}, {NT_PARAM_CONST_DECL_TOKEN, {NT_PARAM_CONST_VECTOR_TOKEN, NULL3}, NO_KW}, {NT_PARAM_CONST_USE_TOKEN, {NT_PARAM_CONST_SCALAR_USE_TOKEN, NULL3}, NO_KW}, /* 270: */ {NT_PARAM_CONST_USE_TOKEN, {NT_PARAM_CONST_VECTOR_TOKEN, NULL3}, NO_KW}, {NT_PARAM_CONST_SCALAR_DECL_TOKEN, {NT_SIGNED_FLOAT_CONSTANT_TOKEN, NULL3}, NO_KW}, {NT_PARAM_CONST_SCALAR_USE_TOKEN, {FLOAT_TOKEN, NULL3}, {"-1", "", "", ""}}, {NT_PARAM_CONST_VECTOR_TOKEN, {LBRACE_TOKEN, NT_SIGNED_FLOAT_CONSTANT_TOKEN, NT_PARAM_CONST_VECTOR2_TOKEN, NULL_TOKEN}, NO_KW}, {NT_PARAM_CONST_VECTOR2_TOKEN,{RBRACE_TOKEN, NULL3}, NO_KW}, /* 275: */ {NT_PARAM_CONST_VECTOR2_TOKEN, {COMMA_TOKEN, NT_SIGNED_FLOAT_CONSTANT_TOKEN, NT_PARAM_CONST_VECTOR3_TOKEN, NULL_TOKEN}, NO_KW}, {NT_PARAM_CONST_VECTOR3_TOKEN, {RBRACE_TOKEN, NULL3}, NO_KW}, {NT_PARAM_CONST_VECTOR3_TOKEN, {COMMA_TOKEN, NT_SIGNED_FLOAT_CONSTANT_TOKEN, NT_PARAM_CONST_VECTOR4_TOKEN, NULL_TOKEN}, NO_KW}, {NT_PARAM_CONST_VECTOR4_TOKEN, {RBRACE_TOKEN, NULL3}, NO_KW}, {NT_PARAM_CONST_VECTOR4_TOKEN, {COMMA_TOKEN, NT_SIGNED_FLOAT_CONSTANT_TOKEN, RBRACE_TOKEN, NULL_TOKEN}, NO_KW}, /* 280: */ {NT_SIGNED_FLOAT_CONSTANT_TOKEN, {NT_OPTIONAL_SIGN_TOKEN, FLOAT_TOKEN, NULL2}, {"", "-1", "", ""}}, {NT_OPTIONAL_SIGN_TOKEN, {NULL4}, NO_KW}, {NT_OPTIONAL_SIGN_TOKEN, {MINUS_TOKEN, NULL3}, NO_KW}, {NT_OPTIONAL_SIGN_TOKEN, {PLUS_TOKEN, NULL3}, NO_KW}, {NT_TEMP_STATEMENT_TOKEN, {TEMP_TOKEN, NT_VAR_NAME_LIST_TOKEN, NULL2}, NO_KW}, /* 285: */ {NT_ADDRESS_STATEMENT_TOKEN, {ADDRESS_TOKEN, NT_VAR_NAME_LIST_TOKEN, NULL2}, NO_KW}, {NT_VAR_NAME_LIST_TOKEN, {NT_ESTABLISH_NAME_TOKEN, NULL3}, NO_KW}, {NT_VAR_NAME_LIST_TOKEN, {NT_ESTABLISH_NAME_TOKEN, COMMA_TOKEN, NT_VAR_NAME_LIST_TOKEN, NULL_TOKEN}, NO_KW}, {NT_OUTPUT_STATEMENT_TOKEN, {OUTPUT_TOKEN, NT_ESTABLISH_NAME_TOKEN, EQUAL_TOKEN, NT_RESULT_BINDING_TOKEN}, NO_KW}, {NT_RESULT_BINDING_TOKEN, {RESULT_TOKEN, PERIOD_TOKEN, NT_RESULT_BINDING2_TOKEN, NULL_TOKEN}, NO_KW}, /* 290: */ {NT_RESULT_BINDING2_TOKEN, {ID_TOKEN, NULL3}, {"position", "", "", ""}}, {NT_RESULT_BINDING2_TOKEN, {ID_TOKEN, NULL3}, {"fogcoord", "", "", ""}}, {NT_RESULT_BINDING2_TOKEN, {ID_TOKEN, NULL3}, {"pointsize", "", "", ""}}, {NT_RESULT_BINDING2_TOKEN, {NT_RESULT_COL_BINDING_TOKEN, NULL3}, NO_KW}, {NT_RESULT_BINDING2_TOKEN, {ID_TOKEN, NT_OPT_TEX_COORD_NUM_TOKEN, NULL2}, {"texcoord", "", "", ""}}, /* 295: */ {NT_RESULT_COL_BINDING_TOKEN, {ID_TOKEN, NT_RESULT_COL_BINDING2_TOKEN, NULL2}, {"color", "", "", ""}}, {NT_RESULT_COL_BINDING2_TOKEN, {NULL4}, NO_KW}, {NT_RESULT_COL_BINDING2_TOKEN, {PERIOD_TOKEN, NT_RESULT_COL_BINDING3_TOKEN, NULL2}, NO_KW}, {NT_RESULT_COL_BINDING3_TOKEN, {ID_TOKEN, NT_RESULT_COL_BINDING4_TOKEN, NULL2}, {"front", "", "", ""}}, {NT_RESULT_COL_BINDING3_TOKEN, {ID_TOKEN, NT_RESULT_COL_BINDING4_TOKEN, NULL2}, {"back", "", "", ""}}, /* 300: */ {NT_RESULT_COL_BINDING4_TOKEN, {NULL4}, NO_KW}, {NT_RESULT_COL_BINDING4_TOKEN, {PERIOD_TOKEN, NT_RESULT_COL_BINDING5_TOKEN, NULL2}, NO_KW}, {NT_RESULT_COL_BINDING5_TOKEN, {ID_TOKEN, NULL3}, {"primary", "", "", ""}}, {NT_RESULT_COL_BINDING5_TOKEN, {ID_TOKEN, NULL3}, {"secondary", "", "", ""}}, {NT_OPT_FACE_TYPE2_TOKEN, {ID_TOKEN, NULL3}, {"front", "", "", ""}}, /* 305: */ {NT_OPT_FACE_TYPE2_TOKEN, {ID_TOKEN, NULL3}, {"back", "", "", ""}}, {NT_OPT_COLOR_TYPE_TOKEN, {PERIOD_TOKEN, NT_OPT_COLOR_TYPE2_TOKEN, NULL2}, NO_KW}, {NT_OPT_COLOR_TYPE_TOKEN, {NULL4}, NO_KW}, {NT_OPT_COLOR_TYPE2_TOKEN, {ID_TOKEN, NULL3}, {"primary", "", "", ""}}, {NT_OPT_COLOR_TYPE2_TOKEN, {ID_TOKEN, NULL3}, {"secondary", "", "", ""}}, /* 310: */ {NT_OPT_TEX_COORD_NUM_TOKEN, {NULL4}, NO_KW}, {NT_OPT_TEX_COORD_NUM_TOKEN, {LBRACKET_TOKEN, NT_TEX_COORD_NUM_TOKEN, RBRACKET_TOKEN, NULL_TOKEN}, NO_KW}, {NT_TEX_COORD_NUM_TOKEN, {INTEGER_TOKEN, NULL3}, {"-1", "", "", ""}}, {NT_ALIAS_STATEMENT_TOKEN, {ALIAS_TOKEN, NT_ESTABLISH_NAME_TOKEN, EQUAL_TOKEN, NT_ESTABLISHED_NAME_TOKEN}, NO_KW}, {NT_ESTABLISH_NAME_TOKEN, {ID_TOKEN, NULL3}, {"-1", "", "", ""}}, /* 315: */ {NT_ESTABLISHED_NAME_TOKEN, {ID_TOKEN, NULL3}, {"-1", "", "", ""}}, {NT_FOO_TOKEN, {NULL4}, NO_KW}, {NT_SWIZZLE_SUFFIX_TOKEN, {PERIOD_TOKEN, NT_SWIZZLE_SUFFIX2_TOKEN, NULL2}, NO_KW}, {NT_SWIZZLE_SUFFIX2_TOKEN, {NT_COMPONENT_TOKEN, NULL3}, NO_KW}, {NT_SWIZZLE_SUFFIX2_TOKEN, {NT_COMPONENT4_TOKEN, NULL3}, NO_KW}, }; /* This is the look ahead table. See the look_ahead_table struct def for a description */ look_ahead_table latab[] = { {NT_PROGRAM_TOKEN, ABS_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, ADD_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, ADDRESS_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, ALIAS_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, ARL_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, ATTRIB_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, DP3_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, DP4_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, DPH_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, DST_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, END_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, EOF_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, EX2_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, EXP_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, FLR_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, FRC_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, LIT_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, LG2_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, LOG_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, MAD_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, MAX_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, MIN_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, MOV_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, MUL_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, OPTION_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, OUTPUT_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, PARAM_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, POW_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, RCP_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, RSQ_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, SGE_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, SLT_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, SUB_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, SWZ_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, XPD_TOKEN, "", 0}, {NT_PROGRAM_TOKEN, TEMP_TOKEN, "", 0}, {NT_OPTION_SEQUENCE_TOKEN, ABS_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, ADD_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, ADDRESS_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, ALIAS_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, ARL_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, ATTRIB_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, DP3_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, DP4_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, DPH_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, DST_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, END_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, EX2_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, EXP_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, FLR_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, FRC_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, LIT_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, LG2_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, LOG_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, MAD_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, MAX_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, MIN_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, MOV_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, MUL_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, OPTION_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, OUTPUT_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, PARAM_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, POW_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, RCP_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, RSQ_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, SGE_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, SLT_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, SUB_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, SWZ_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, XPD_TOKEN, "", 1}, {NT_OPTION_SEQUENCE_TOKEN, TEMP_TOKEN, "", 1}, {NT_OPTION_SEQUENCE2_TOKEN, OPTION_TOKEN, "", 2}, {NT_OPTION_SEQUENCE2_TOKEN, ABS_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, ADD_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, ADDRESS_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, ALIAS_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, ARL_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, ATTRIB_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, DP3_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, DP4_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, DPH_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, DST_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, END_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, EX2_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, EXP_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, FLR_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, FRC_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, LIT_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, LG2_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, LOG_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, MAD_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, MAX_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, MIN_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, MOV_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, MUL_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, OUTPUT_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, PARAM_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, POW_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, RCP_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, RSQ_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, SGE_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, SLT_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, SUB_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, SWZ_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, XPD_TOKEN, "", 3}, {NT_OPTION_SEQUENCE2_TOKEN, TEMP_TOKEN, "", 3}, {NT_OPTION_TOKEN, OPTION_TOKEN, "", 4}, {NT_STATEMENT_SEQUENCE_TOKEN, ABS_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, ADD_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, ADDRESS_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, ALIAS_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, ARL_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, ATTRIB_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, DP3_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, DP4_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, DPH_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, DST_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, END_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, EX2_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, EXP_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, FLR_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, FRC_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, LIT_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, LG2_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, LOG_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, MAD_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, MAX_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, MIN_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, MOV_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, MUL_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, OUTPUT_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, PARAM_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, POW_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, RCP_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, RSQ_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, SGE_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, SLT_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, SUB_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, SWZ_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, XPD_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE_TOKEN, TEMP_TOKEN, "", 5}, {NT_STATEMENT_SEQUENCE2_TOKEN, ABS_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, ADD_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, ADDRESS_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, ALIAS_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, ARL_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, ATTRIB_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, DP3_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, DP4_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, DPH_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, DST_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, EX2_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, EXP_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, FLR_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, FRC_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, LIT_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, LG2_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, LOG_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, MAD_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, MAX_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, MIN_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, MOV_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, MUL_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, OUTPUT_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, PARAM_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, POW_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, RCP_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, RSQ_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, SGE_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, SLT_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, SUB_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, SWZ_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, XPD_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, TEMP_TOKEN, "", 6}, {NT_STATEMENT_SEQUENCE2_TOKEN, END_TOKEN, "", 7}, {NT_STATEMENT_TOKEN, ABS_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, ADD_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, ARL_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, DP3_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, DP4_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, DPH_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, DST_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, EX2_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, EXP_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, FLR_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, FRC_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, LIT_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, LG2_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, LOG_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, MAD_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, MAX_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, MIN_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, MOV_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, MUL_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, POW_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, RCP_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, RSQ_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, SGE_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, SLT_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, SUB_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, SWZ_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, XPD_TOKEN, "", 8}, {NT_STATEMENT_TOKEN, ADDRESS_TOKEN, "", 9}, {NT_STATEMENT_TOKEN, ALIAS_TOKEN, "", 9}, {NT_STATEMENT_TOKEN, ATTRIB_TOKEN, "", 9}, {NT_STATEMENT_TOKEN, OUTPUT_TOKEN, "", 9}, {NT_STATEMENT_TOKEN, PARAM_TOKEN, "", 9}, {NT_STATEMENT_TOKEN, TEMP_TOKEN, "", 9}, {NT_INSTRUCTION_TOKEN, ARL_TOKEN, "", 10}, {NT_INSTRUCTION_TOKEN, ABS_TOKEN, "", 11}, {NT_INSTRUCTION_TOKEN, FLR_TOKEN, "", 11}, {NT_INSTRUCTION_TOKEN, FRC_TOKEN, "", 11}, {NT_INSTRUCTION_TOKEN, LIT_TOKEN, "", 11}, {NT_INSTRUCTION_TOKEN, MOV_TOKEN, "", 11}, {NT_INSTRUCTION_TOKEN, EX2_TOKEN, "", 12}, {NT_INSTRUCTION_TOKEN, EXP_TOKEN, "", 12}, {NT_INSTRUCTION_TOKEN, LG2_TOKEN, "", 12}, {NT_INSTRUCTION_TOKEN, LOG_TOKEN, "", 12}, {NT_INSTRUCTION_TOKEN, RCP_TOKEN, "", 12}, {NT_INSTRUCTION_TOKEN, RSQ_TOKEN, "", 12}, {NT_INSTRUCTION_TOKEN, POW_TOKEN, "", 13}, {NT_INSTRUCTION_TOKEN, ADD_TOKEN, "", 14}, {NT_INSTRUCTION_TOKEN, DP3_TOKEN, "", 14}, {NT_INSTRUCTION_TOKEN, DP4_TOKEN, "", 14}, {NT_INSTRUCTION_TOKEN, DPH_TOKEN, "", 14}, {NT_INSTRUCTION_TOKEN, DST_TOKEN, "", 14}, {NT_INSTRUCTION_TOKEN, MAX_TOKEN, "", 14}, {NT_INSTRUCTION_TOKEN, MIN_TOKEN, "", 14}, {NT_INSTRUCTION_TOKEN, MUL_TOKEN, "", 14}, {NT_INSTRUCTION_TOKEN, SGE_TOKEN, "", 14}, {NT_INSTRUCTION_TOKEN, SLT_TOKEN, "", 14}, {NT_INSTRUCTION_TOKEN, SUB_TOKEN, "", 14}, {NT_INSTRUCTION_TOKEN, XPD_TOKEN, "", 14}, {NT_INSTRUCTION_TOKEN, MAD_TOKEN, "", 15}, {NT_INSTRUCTION_TOKEN, SWZ_TOKEN, "", 16}, {NT_ARL_INSTRUCTION_TOKEN, ARL_TOKEN, "", 17}, {NT_VECTOROP_INSTRUCTION_TOKEN, ABS_TOKEN, "", 18}, {NT_VECTOROP_INSTRUCTION_TOKEN, FLR_TOKEN, "", 18}, {NT_VECTOROP_INSTRUCTION_TOKEN, FRC_TOKEN, "", 18}, {NT_VECTOROP_INSTRUCTION_TOKEN, LIT_TOKEN, "", 18}, {NT_VECTOROP_INSTRUCTION_TOKEN, MOV_TOKEN, "", 18}, {NT_VECTOROP_TOKEN, ABS_TOKEN, "", 19}, {NT_VECTOROP_TOKEN, FLR_TOKEN, "", 20}, {NT_VECTOROP_TOKEN, FRC_TOKEN, "", 21}, {NT_VECTOROP_TOKEN, LIT_TOKEN, "", 22}, {NT_VECTOROP_TOKEN, MOV_TOKEN, "", 23}, {NT_SCALAROP_INSTRUCTION_TOKEN, EX2_TOKEN, "", 24}, {NT_SCALAROP_INSTRUCTION_TOKEN, EXP_TOKEN, "", 24}, {NT_SCALAROP_INSTRUCTION_TOKEN, LG2_TOKEN, "", 24}, {NT_SCALAROP_INSTRUCTION_TOKEN, LOG_TOKEN, "", 24}, {NT_SCALAROP_INSTRUCTION_TOKEN, RCP_TOKEN, "", 24}, {NT_SCALAROP_INSTRUCTION_TOKEN, RSQ_TOKEN, "", 24}, {NT_SCALAROP_TOKEN, EX2_TOKEN, "", 25}, {NT_SCALAROP_TOKEN, EXP_TOKEN, "", 26}, {NT_SCALAROP_TOKEN, LG2_TOKEN, "", 27}, {NT_SCALAROP_TOKEN, LOG_TOKEN, "", 28}, {NT_SCALAROP_TOKEN, RCP_TOKEN, "", 29}, {NT_SCALAROP_TOKEN, RSQ_TOKEN, "", 30}, {NT_BINSCOP_INSTRUCTION_TOKEN, POW_TOKEN, "", 31}, {NT_BINSCOP_INSTRUCTION2_TOKEN, COMMA_TOKEN, "", 32}, {NT_BINSCOP_TOKEN, POW_TOKEN, "", 33}, {NT_BINOP_INSTRUCTION_TOKEN, ADD_TOKEN, "", 34}, {NT_BINOP_INSTRUCTION_TOKEN, DP3_TOKEN, "", 34}, {NT_BINOP_INSTRUCTION_TOKEN, DP4_TOKEN, "", 34}, {NT_BINOP_INSTRUCTION_TOKEN, DPH_TOKEN, "", 34}, {NT_BINOP_INSTRUCTION_TOKEN, DST_TOKEN, "", 34}, {NT_BINOP_INSTRUCTION_TOKEN, MAX_TOKEN, "", 34}, {NT_BINOP_INSTRUCTION_TOKEN, MIN_TOKEN, "", 34}, {NT_BINOP_INSTRUCTION_TOKEN, MUL_TOKEN, "", 34}, {NT_BINOP_INSTRUCTION_TOKEN, SGE_TOKEN, "", 34}, {NT_BINOP_INSTRUCTION_TOKEN, SLT_TOKEN, "", 34}, {NT_BINOP_INSTRUCTION_TOKEN, SUB_TOKEN, "", 34}, {NT_BINOP_INSTRUCTION_TOKEN, XPD_TOKEN, "", 34}, {NT_BINOP_INSTRUCTION2_TOKEN, COMMA_TOKEN, "", 35}, {NT_BINOP_TOKEN, ADD_TOKEN, "", 36}, {NT_BINOP_TOKEN, DP3_TOKEN, "", 37}, {NT_BINOP_TOKEN, DP4_TOKEN, "", 38}, {NT_BINOP_TOKEN, DPH_TOKEN, "", 39}, {NT_BINOP_TOKEN, DST_TOKEN, "", 40}, {NT_BINOP_TOKEN, MAX_TOKEN, "", 41}, {NT_BINOP_TOKEN, MIN_TOKEN, "", 42}, {NT_BINOP_TOKEN, MUL_TOKEN, "", 43}, {NT_BINOP_TOKEN, SGE_TOKEN, "", 44}, {NT_BINOP_TOKEN, SLT_TOKEN, "", 45}, {NT_BINOP_TOKEN, SUB_TOKEN, "", 46}, {NT_BINOP_TOKEN, XPD_TOKEN, "", 47}, {NT_TRIOP_INSTRUCTION_TOKEN, MAD_TOKEN, "", 48}, {NT_TRIOP_INSTRUCTION2_TOKEN, COMMA_TOKEN, "", 49}, {NT_TRIOP_INSTRUCTION3_TOKEN, COMMA_TOKEN, "", 50}, {NT_TRIOP_TOKEN, MAD_TOKEN, "", 51}, {NT_SWZ_INSTRUCTION_TOKEN, SWZ_TOKEN, "", 52}, {NT_SWZ_INSTRUCTION2_TOKEN, COMMA_TOKEN, "", 53}, {NT_SCALAR_SRC_REG_TOKEN, PLUS_TOKEN, "", 54}, {NT_SCALAR_SRC_REG_TOKEN, MINUS_TOKEN, "", 54}, {NT_SCALAR_SRC_REG_TOKEN, VERTEX_TOKEN, "", 54}, {NT_SCALAR_SRC_REG_TOKEN, STATE_TOKEN, "", 54}, {NT_SCALAR_SRC_REG_TOKEN, PROGRAM_TOKEN, "", 54}, {NT_SCALAR_SRC_REG_TOKEN, LBRACE_TOKEN, "", 54}, {NT_SCALAR_SRC_REG_TOKEN, FLOAT_TOKEN, "-1", 54}, {NT_SCALAR_SRC_REG_TOKEN, INTEGER_TOKEN, "-1", 54}, {NT_SCALAR_SRC_REG_TOKEN, ID_TOKEN, "-1", 54}, {NT_SWIZZLE_SRC_REG_TOKEN, PLUS_TOKEN, "", 55}, {NT_SWIZZLE_SRC_REG_TOKEN, MINUS_TOKEN, "", 55}, {NT_SWIZZLE_SRC_REG_TOKEN, VERTEX_TOKEN, "", 55}, {NT_SWIZZLE_SRC_REG_TOKEN, STATE_TOKEN, "", 55}, {NT_SWIZZLE_SRC_REG_TOKEN, PROGRAM_TOKEN, "", 55}, {NT_SWIZZLE_SRC_REG_TOKEN, LBRACE_TOKEN, "", 55}, {NT_SWIZZLE_SRC_REG_TOKEN, FLOAT_TOKEN, "-1", 55}, {NT_SWIZZLE_SRC_REG_TOKEN, INTEGER_TOKEN, "-1", 55}, {NT_SWIZZLE_SRC_REG_TOKEN, ID_TOKEN, "-1", 55}, {NT_MASKED_DST_REG_TOKEN, ID_TOKEN, "-1", 56}, {NT_MASKED_DST_REG_TOKEN, RESULT_TOKEN, "", 56}, {NT_MASKED_ADDR_REG_TOKEN, ID_TOKEN, "-1", 57}, {NT_EXTENDED_SWIZZLE_TOKEN, PLUS_TOKEN, "", 58}, {NT_EXTENDED_SWIZZLE_TOKEN, MINUS_TOKEN, "", 58}, {NT_EXTENDED_SWIZZLE_TOKEN, INTEGER_TOKEN, "0", 58}, {NT_EXTENDED_SWIZZLE_TOKEN, INTEGER_TOKEN, "1", 58}, {NT_EXTENDED_SWIZZLE_TOKEN, ID_TOKEN, "x", 58}, {NT_EXTENDED_SWIZZLE_TOKEN, ID_TOKEN, "y", 58}, {NT_EXTENDED_SWIZZLE_TOKEN, ID_TOKEN, "z", 58}, {NT_EXTENDED_SWIZZLE_TOKEN, ID_TOKEN, "w", 58}, {NT_EXTENDED_SWIZZLE2_TOKEN, COMMA_TOKEN, "", 59}, {NT_EXT_SWIZ_COMP_TOKEN, PLUS_TOKEN, "", 60}, {NT_EXT_SWIZ_COMP_TOKEN, MINUS_TOKEN, "", 60}, {NT_EXT_SWIZ_COMP_TOKEN, INTEGER_TOKEN, "0", 60}, {NT_EXT_SWIZ_COMP_TOKEN, INTEGER_TOKEN, "1", 60}, {NT_EXT_SWIZ_COMP_TOKEN, ID_TOKEN, "x", 60}, {NT_EXT_SWIZ_COMP_TOKEN, ID_TOKEN, "y", 60}, {NT_EXT_SWIZ_COMP_TOKEN, ID_TOKEN, "z", 60}, {NT_EXT_SWIZ_COMP_TOKEN, ID_TOKEN, "w", 60}, {NT_EXT_SWIZ_SEL_TOKEN, INTEGER_TOKEN, "0", 61}, {NT_EXT_SWIZ_SEL_TOKEN, INTEGER_TOKEN, "1", 62}, {NT_EXT_SWIZ_SEL_TOKEN, ID_TOKEN, "x", 63}, {NT_EXT_SWIZ_SEL_TOKEN, ID_TOKEN, "y", 63}, {NT_EXT_SWIZ_SEL_TOKEN, ID_TOKEN, "z", 63}, {NT_EXT_SWIZ_SEL_TOKEN, ID_TOKEN, "w", 63}, /* Special case for 64 - 68 */ {NT_DST_REG_TOKEN, RESULT_TOKEN, "", 68}, {NT_VERTEX_ATTRIB_REG_TOKEN, ID_TOKEN, "-1", 69}, {NT_VERTEX_ATTRIB_REG_TOKEN, VERTEX_TOKEN, "", 70}, {NT_TEMPORARY_REG_TOKEN, ID_TOKEN, "-1", 71}, /* Special case for 72 - 73 */ {NT_PROG_PARAM_REG_TOKEN, STATE_TOKEN, "", 74}, {NT_PROG_PARAM_REG_TOKEN, PROGRAM_TOKEN, "", 74}, {NT_PROG_PARAM_REG_TOKEN, LBRACE_TOKEN, "", 74}, {NT_PROG_PARAM_REG_TOKEN, FLOAT_TOKEN, "-1", 74}, {NT_PROG_PARAM_SINGLE_TOKEN, ID_TOKEN, "-1", 75}, {NT_PROG_PARAM_ARRAY_TOKEN, ID_TOKEN, "-1", 76}, {NT_PROG_PARAM_ARRAY_MEM_TOKEN, INTEGER_TOKEN, "-1", 77}, {NT_PROG_PARAM_ARRAY_MEM_TOKEN, ID_TOKEN, "-1", 78}, {NT_PROG_PARAM_ARRAY_ABS_TOKEN, INTEGER_TOKEN, "-1", 79}, {NT_PROG_PARAM_ARRAY_REL_TOKEN, ID_TOKEN, "-1", 80}, {NT_ADDR_REG_REL_OFFSET_TOKEN, RBRACKET_TOKEN, "", 81}, {NT_ADDR_REG_REL_OFFSET_TOKEN, PLUS_TOKEN, "", 82}, {NT_ADDR_REG_REL_OFFSET_TOKEN, MINUS_TOKEN, "", 83}, {NT_ADDR_REG_POS_OFFSET_TOKEN, INTEGER_TOKEN, "-1", 84}, {NT_ADDR_REG_NEG_OFFSET_TOKEN, INTEGER_TOKEN, "-1", 85}, {NT_VERTEX_RESULT_REG_TOKEN, ID_TOKEN, "-1", 86}, {NT_VERTEX_RESULT_REG_TOKEN, RESULT_TOKEN, "", 87}, {NT_ADDR_REG_TOKEN, ID_TOKEN, "-1", 88}, {NT_ADDR_COMPONENT_TOKEN, PERIOD_TOKEN, "", 89}, {NT_ADDR_WRITE_MASK_TOKEN, PERIOD_TOKEN, "", 90}, {NT_SCALAR_SUFFIX_TOKEN, PERIOD_TOKEN, "", 91}, {NT_SWIZZLE_SUFFIX_TOKEN, COMMA_TOKEN, "", 92}, {NT_SWIZZLE_SUFFIX_TOKEN, SEMICOLON_TOKEN, "", 92}, {NT_SWIZZLE_SUFFIX_TOKEN, PERIOD_TOKEN, "", 317}, {NT_COMPONENT_TOKEN, ID_TOKEN, "x", 93}, {NT_COMPONENT_TOKEN, ID_TOKEN, "y", 94}, {NT_COMPONENT_TOKEN, ID_TOKEN, "z", 95}, {NT_COMPONENT_TOKEN, ID_TOKEN, "w", 96}, {NT_OPTIONAL_MASK_TOKEN, PERIOD_TOKEN, "", 97}, {NT_OPTIONAL_MASK_TOKEN, COMMA_TOKEN, "", 98}, {NT_OPTIONAL_MASK2_TOKEN, ID_TOKEN, "x", 99}, {NT_OPTIONAL_MASK2_TOKEN, ID_TOKEN, "y", 100}, {NT_OPTIONAL_MASK2_TOKEN, ID_TOKEN, "xy", 101}, {NT_OPTIONAL_MASK2_TOKEN, ID_TOKEN, "z", 102}, {NT_OPTIONAL_MASK2_TOKEN, ID_TOKEN, "xz", 103}, {NT_OPTIONAL_MASK2_TOKEN, ID_TOKEN, "yz", 104}, {NT_OPTIONAL_MASK2_TOKEN, ID_TOKEN, "xyz", 105}, {NT_OPTIONAL_MASK2_TOKEN, ID_TOKEN, "w", 106}, {NT_OPTIONAL_MASK2_TOKEN, ID_TOKEN, "xw", 107}, {NT_OPTIONAL_MASK2_TOKEN, ID_TOKEN, "yw", 108}, {NT_OPTIONAL_MASK2_TOKEN, ID_TOKEN, "xyw", 109}, {NT_OPTIONAL_MASK2_TOKEN, ID_TOKEN, "zw", 110}, {NT_OPTIONAL_MASK2_TOKEN, ID_TOKEN, "xzw", 111}, {NT_OPTIONAL_MASK2_TOKEN, ID_TOKEN, "yzw", 112}, {NT_OPTIONAL_MASK2_TOKEN, ID_TOKEN, "xyzw", 113}, {NT_NAMING_STATEMENT_TOKEN, ATTRIB_TOKEN, "", 114}, {NT_NAMING_STATEMENT_TOKEN, PARAM_TOKEN, "", 115}, {NT_NAMING_STATEMENT_TOKEN, TEMP_TOKEN, "", 116}, {NT_NAMING_STATEMENT_TOKEN, ADDRESS_TOKEN, "", 117}, {NT_NAMING_STATEMENT_TOKEN, OUTPUT_TOKEN, "", 118}, {NT_NAMING_STATEMENT_TOKEN, ALIAS_TOKEN, "", 119}, {NT_ATTRIB_STATEMENT_TOKEN, ATTRIB_TOKEN, "", 120}, {NT_VTX_ATTRIB_BINDING_TOKEN, VERTEX_TOKEN, "", 121}, {NT_VTX_ATTRIB_ITEM_TOKEN, ID_TOKEN, "position", 122}, {NT_VTX_ATTRIB_ITEM_TOKEN, ID_TOKEN, "weight", 123}, {NT_VTX_ATTRIB_ITEM_TOKEN, ID_TOKEN, "normal", 124}, {NT_VTX_ATTRIB_ITEM_TOKEN, ID_TOKEN, "color", 125}, {NT_VTX_ATTRIB_ITEM_TOKEN, ID_TOKEN, "fogcoord", 126}, {NT_VTX_ATTRIB_ITEM_TOKEN, ID_TOKEN, "texcoord", 127}, {NT_VTX_ATTRIB_ITEM_TOKEN, ID_TOKEN, "matrixindex", 128}, {NT_VTX_ATTRIB_ITEM_TOKEN, ID_TOKEN, "attrib", 129}, {NT_VTX_ATTRIB_NUM_TOKEN, INTEGER_TOKEN, "-1", 130}, {NT_VTX_OPT_WEIGHT_NUM_TOKEN, SEMICOLON_TOKEN, "", 131}, {NT_VTX_OPT_WEIGHT_NUM_TOKEN, COMMA_TOKEN, "", 131}, {NT_VTX_OPT_WEIGHT_NUM_TOKEN, PERIOD_TOKEN, "", 131}, {NT_VTX_OPT_WEIGHT_NUM_TOKEN, LBRACKET_TOKEN, "", 132}, {NT_VTX_WEIGHT_NUM_TOKEN, INTEGER_TOKEN, "-1", 133}, {NT_PARAM_STATEMENT_TOKEN, PARAM_TOKEN, "", 134}, {NT_PARAM_STATEMENT2_TOKEN, EQUAL_TOKEN, "", 135}, {NT_PARAM_STATEMENT2_TOKEN, LBRACKET_TOKEN, "", 136}, {NT_OPT_ARRAY_SIZE_TOKEN, RBRACKET_TOKEN, "", 137}, {NT_OPT_ARRAY_SIZE_TOKEN, INTEGER_TOKEN, "-1", 138}, {NT_PARAM_SINGLE_INIT_TOKEN, EQUAL_TOKEN, "", 139}, {NT_PARAM_MULTIPLE_INIT_TOKEN, EQUAL_TOKEN, "", 140}, {NT_PARAM_MULT_INIT_LIST_TOKEN, STATE_TOKEN, "", 141}, {NT_PARAM_MULT_INIT_LIST_TOKEN, PROGRAM_TOKEN, "", 141}, {NT_PARAM_MULT_INIT_LIST_TOKEN, PLUS_TOKEN, "", 141}, {NT_PARAM_MULT_INIT_LIST_TOKEN, MINUS_TOKEN, "", 141}, {NT_PARAM_MULT_INIT_LIST_TOKEN, FLOAT_TOKEN, "-1", 141}, {NT_PARAM_MULT_INIT_LIST_TOKEN, INTEGER_TOKEN, "-1", 141}, {NT_PARAM_MULT_INIT_LIST_TOKEN, LBRACE_TOKEN, "", 141}, {NT_PARAM_MULT_INIT_LIST2_TOKEN, COMMA_TOKEN, "", 142}, {NT_PARAM_MULT_INIT_LIST2_TOKEN, RBRACE_TOKEN, "", 143}, {NT_PARAM_SINGLE_ITEM_DECL_TOKEN, STATE_TOKEN, "", 144}, {NT_PARAM_SINGLE_ITEM_DECL_TOKEN, PROGRAM_TOKEN, "", 145}, {NT_PARAM_SINGLE_ITEM_DECL_TOKEN, PLUS_TOKEN, "", 146}, {NT_PARAM_SINGLE_ITEM_DECL_TOKEN, MINUS_TOKEN, "", 146}, {NT_PARAM_SINGLE_ITEM_DECL_TOKEN, FLOAT_TOKEN, "-1", 146}, {NT_PARAM_SINGLE_ITEM_DECL_TOKEN, INTEGER_TOKEN, "-1", 146}, {NT_PARAM_SINGLE_ITEM_DECL_TOKEN, LBRACE_TOKEN, "", 146}, {NT_PARAM_SINGLE_ITEM_USE_TOKEN, STATE_TOKEN, "", 147}, {NT_PARAM_SINGLE_ITEM_USE_TOKEN, PROGRAM_TOKEN, "", 148}, {NT_PARAM_SINGLE_ITEM_USE_TOKEN, LBRACE_TOKEN, "", 149}, {NT_PARAM_SINGLE_ITEM_USE_TOKEN, FLOAT_TOKEN, "-1", 149}, {NT_PARAM_SINGLE_ITEM_USE_TOKEN, INTEGER_TOKEN, "-1", 149}, {NT_PARAM_MULTIPLE_ITEM_TOKEN, STATE_TOKEN, "", 150}, {NT_PARAM_MULTIPLE_ITEM_TOKEN, PROGRAM_TOKEN, "", 151}, {NT_PARAM_MULTIPLE_ITEM_TOKEN, PLUS_TOKEN, "", 152}, {NT_PARAM_MULTIPLE_ITEM_TOKEN, MINUS_TOKEN, "", 152}, {NT_PARAM_MULTIPLE_ITEM_TOKEN, FLOAT_TOKEN, "-1", 152}, {NT_PARAM_MULTIPLE_ITEM_TOKEN, INTEGER_TOKEN, "-1", 152}, {NT_PARAM_MULTIPLE_ITEM_TOKEN, LBRACE_TOKEN, "", 152}, {NT_STATE_MULTIPLE_ITEM_TOKEN, STATE_TOKEN, "", 153}, {NT_STATE_MULTIPLE_ITEM2_TOKEN, ID_TOKEN, "material", 154}, {NT_STATE_MULTIPLE_ITEM2_TOKEN, ID_TOKEN, "light", 155}, {NT_STATE_MULTIPLE_ITEM2_TOKEN, ID_TOKEN, "lightmodel", 156}, {NT_STATE_MULTIPLE_ITEM2_TOKEN, ID_TOKEN, "lightprod", 157}, {NT_STATE_MULTIPLE_ITEM2_TOKEN, ID_TOKEN, "texgen", 158}, {NT_STATE_MULTIPLE_ITEM2_TOKEN, ID_TOKEN, "fog", 159}, {NT_STATE_MULTIPLE_ITEM2_TOKEN, ID_TOKEN, "clip", 160}, {NT_STATE_MULTIPLE_ITEM2_TOKEN, ID_TOKEN, "point", 161}, {NT_STATE_MULTIPLE_ITEM2_TOKEN, ID_TOKEN, "matrix", 162}, {NT_FOO_TOKEN, PERIOD_TOKEN, "", 163}, {NT_FOO_TOKEN, COMMA_TOKEN, "", 316}, {NT_FOO_TOKEN, RBRACE_TOKEN, "", 316}, {NT_FOO2_TOKEN, ID_TOKEN, "inverse", 164}, {NT_FOO2_TOKEN, ID_TOKEN, "transpose", 164}, {NT_FOO2_TOKEN, ID_TOKEN, "invtrans", 164}, {NT_FOO2_TOKEN, ID_TOKEN, "row", 165}, {NT_FOO3_TOKEN, COMMA_TOKEN, "", 166}, {NT_FOO3_TOKEN, RBRACE_TOKEN, "", 166}, {NT_FOO3_TOKEN, PERIOD_TOKEN, "", 167}, {NT_FOO35_TOKEN, INTEGER_TOKEN, "-1", 168}, {NT_FOO4_TOKEN, RBRACKET_TOKEN, "", 169}, {NT_FOO4_TOKEN, DOTDOT_TOKEN, "", 170}, {NT_STATE_SINGLE_ITEM_TOKEN, STATE_TOKEN, "", 171}, {NT_STATE_SINGLE_ITEM2_TOKEN, ID_TOKEN, "material", 172}, {NT_STATE_SINGLE_ITEM2_TOKEN, ID_TOKEN, "light", 173}, {NT_STATE_SINGLE_ITEM2_TOKEN, ID_TOKEN, "lightmodel", 174}, {NT_STATE_SINGLE_ITEM2_TOKEN, ID_TOKEN, "lightprod", 175}, {NT_STATE_SINGLE_ITEM2_TOKEN, ID_TOKEN, "texgen", 176}, {NT_STATE_SINGLE_ITEM2_TOKEN, ID_TOKEN, "fog", 177}, {NT_STATE_SINGLE_ITEM2_TOKEN, ID_TOKEN, "clip", 178}, {NT_STATE_SINGLE_ITEM2_TOKEN, ID_TOKEN, "point", 179}, {NT_STATE_SINGLE_ITEM2_TOKEN, ID_TOKEN, "matrix", 180}, {NT_STATE_MATERIAL_ITEM_TOKEN, ID_TOKEN, "material", 181}, {NT_STATE_MATERIAL_ITEM2_TOKEN, ID_TOKEN, "ambient", 182}, {NT_STATE_MATERIAL_ITEM2_TOKEN, ID_TOKEN, "diffuse", 182}, {NT_STATE_MATERIAL_ITEM2_TOKEN, ID_TOKEN, "specular", 182}, {NT_STATE_MATERIAL_ITEM2_TOKEN, ID_TOKEN, "emission", 182}, {NT_STATE_MATERIAL_ITEM2_TOKEN, ID_TOKEN, "shininess", 182}, {NT_STATE_MATERIAL_ITEM2_TOKEN, PERIOD_TOKEN, "", 183}, {NT_STATE_MAT_PROPERTY_TOKEN, ID_TOKEN, "ambient", 184}, {NT_STATE_MAT_PROPERTY_TOKEN, ID_TOKEN, "diffuse", 185}, {NT_STATE_MAT_PROPERTY_TOKEN, ID_TOKEN, "specular", 186}, {NT_STATE_MAT_PROPERTY_TOKEN, ID_TOKEN, "emission", 187}, {NT_STATE_MAT_PROPERTY_TOKEN, ID_TOKEN, "shininess", 188}, {NT_STATE_LIGHT_ITEM_TOKEN, ID_TOKEN, "light", 189}, {NT_STATE_LIGHT_ITEM2_TOKEN, RBRACKET_TOKEN, "", 190}, {NT_STATE_LIGHT_PROPERTY_TOKEN, ID_TOKEN, "ambient", 191}, {NT_STATE_LIGHT_PROPERTY_TOKEN, ID_TOKEN, "diffuse", 192}, {NT_STATE_LIGHT_PROPERTY_TOKEN, ID_TOKEN, "specular", 193}, {NT_STATE_LIGHT_PROPERTY_TOKEN, ID_TOKEN, "position", 194}, {NT_STATE_LIGHT_PROPERTY_TOKEN, ID_TOKEN, "attenuation", 195}, {NT_STATE_LIGHT_PROPERTY_TOKEN, ID_TOKEN, "spot", 196}, {NT_STATE_LIGHT_PROPERTY_TOKEN, ID_TOKEN, "half", 197}, {NT_STATE_SPOT_PROPERTY_TOKEN, ID_TOKEN, "direction", 198}, {NT_STATE_LIGHT_MODEL_ITEM_TOKEN, ID_TOKEN, "lightmodel", 199}, {NT_STATE_LMOD_PROPERTY_TOKEN, PERIOD_TOKEN, "", 200}, {NT_STATE_LMOD_PROPERTY2_TOKEN, ID_TOKEN, "ambient", 201}, {NT_STATE_LMOD_PROPERTY2_TOKEN, ID_TOKEN, "scenecolor", 202}, {NT_STATE_LMOD_PROPERTY2_TOKEN, ID_TOKEN, "front", 203}, {NT_STATE_LMOD_PROPERTY2_TOKEN, ID_TOKEN, "back", 203}, {NT_STATE_LIGHT_PROD_ITEM_TOKEN, ID_TOKEN, "lightprod", 204}, {NT_STATE_LIGHT_PROD_ITEM15_TOKEN, RBRACKET_TOKEN, "", 205}, {NT_STATE_LIGHT_PROD_ITEM2_TOKEN, ID_TOKEN, "ambient", 206}, {NT_STATE_LIGHT_PROD_ITEM2_TOKEN, ID_TOKEN, "diffuse", 206}, {NT_STATE_LIGHT_PROD_ITEM2_TOKEN, ID_TOKEN, "specular", 206}, {NT_STATE_LIGHT_PROD_ITEM2_TOKEN, ID_TOKEN, "front", 207}, {NT_STATE_LIGHT_PROD_ITEM2_TOKEN, ID_TOKEN, "back", 207}, {NT_STATE_LPROD_PROPERTY_TOKEN, ID_TOKEN, "ambient", 208}, {NT_STATE_LPROD_PROPERTY_TOKEN, ID_TOKEN, "diffuse", 209}, {NT_STATE_LPROD_PROPERTY_TOKEN, ID_TOKEN, "specular", 210}, {NT_STATE_LIGHT_NUMBER_TOKEN, INTEGER_TOKEN, "-1", 211}, {NT_STATE_TEX_GEN_ITEM_TOKEN, ID_TOKEN, "texgen", 212}, {NT_STATE_TEX_GEN_ITEM2_TOKEN, PERIOD_TOKEN, "", 213}, {NT_STATE_TEX_GEN_TYPE_TOKEN, ID_TOKEN, "eye", 214}, {NT_STATE_TEX_GEN_TYPE_TOKEN, ID_TOKEN, "object", 215}, {NT_STATE_TEX_GEN_COORD_TOKEN, ID_TOKEN, "s", 216}, {NT_STATE_TEX_GEN_COORD_TOKEN, ID_TOKEN, "t", 217}, {NT_STATE_TEX_GEN_COORD_TOKEN, ID_TOKEN, "r", 218}, {NT_STATE_TEX_GEN_COORD_TOKEN, ID_TOKEN, "q", 219}, {NT_STATE_FOG_ITEM_TOKEN, ID_TOKEN, "fog", 220}, {NT_STATE_FOG_PROPERTY_TOKEN, ID_TOKEN, "color", 221}, {NT_STATE_FOG_PROPERTY_TOKEN, ID_TOKEN, "params", 222}, {NT_STATE_CLIP_PLANE_ITEM_TOKEN, ID_TOKEN, "clip", 223}, {NT_STATE_CLIP_PLANE_ITEM2_TOKEN, RBRACKET_TOKEN, "", 224}, {NT_STATE_CLIP_PLANE_NUM_TOKEN, INTEGER_TOKEN, "-1", 225}, {NT_STATE_POINT_ITEM_TOKEN, ID_TOKEN, "point", 226}, {NT_STATE_POINT_PROPERTY_TOKEN, ID_TOKEN, "size", 227}, {NT_STATE_POINT_PROPERTY_TOKEN, ID_TOKEN, "attenuation", 228}, {NT_STATE_MATRIX_ROW_TOKEN, ID_TOKEN, "matrix", 229}, {NT_STATE_MATRIX_ROW15_TOKEN, PERIOD_TOKEN, "", 230}, {NT_STATE_MATRIX_ROW2_TOKEN, ID_TOKEN, "row", 231}, {NT_STATE_MATRIX_ROW2_TOKEN, ID_TOKEN, "inverse", 232}, {NT_STATE_MATRIX_ROW2_TOKEN, ID_TOKEN, "transpose", 232}, {NT_STATE_MATRIX_ROW2_TOKEN, ID_TOKEN, "invtrans", 232}, {NT_STATE_MATRIX_ROW3_TOKEN, LBRACKET_TOKEN, "", 233}, {NT_STATE_MAT_MODIFIER_TOKEN, ID_TOKEN, "inverse", 234}, {NT_STATE_MAT_MODIFIER_TOKEN, ID_TOKEN, "transpose", 235}, {NT_STATE_MAT_MODIFIER_TOKEN, ID_TOKEN, "invtrans", 236}, {NT_STATE_MATRIX_ROW_NUM_TOKEN, INTEGER_TOKEN, "-1", 237}, {NT_STATE_MATRIX_NAME_TOKEN, ID_TOKEN, "modelview", 238}, {NT_STATE_MATRIX_NAME_TOKEN, ID_TOKEN, "projection", 239}, {NT_STATE_MATRIX_NAME_TOKEN, ID_TOKEN, "mvp", 240}, {NT_STATE_MATRIX_NAME_TOKEN, ID_TOKEN, "texture", 241}, {NT_STATE_MATRIX_NAME_TOKEN, ID_TOKEN, "palette", 242}, {NT_STATE_MATRIX_NAME_TOKEN, PROGRAM_TOKEN, "", 243}, {NT_STATE_OPT_MOD_MAT_NUM_TOKEN, PERIOD_TOKEN, "", 244}, {NT_STATE_OPT_MOD_MAT_NUM_TOKEN, COMMA_TOKEN, "", 244}, {NT_STATE_OPT_MOD_MAT_NUM_TOKEN, RBRACE_TOKEN, "", 244}, {NT_STATE_OPT_MOD_MAT_NUM_TOKEN, LBRACKET_TOKEN, "", 245}, {NT_STATE_MOD_MAT_NUM_TOKEN, INTEGER_TOKEN, "-1", 246}, {NT_STATE_PALETTE_MAT_NUM_TOKEN, INTEGER_TOKEN, "-1", 247}, {NT_STATE_PROGRAM_MAT_NUM_TOKEN, INTEGER_TOKEN, "-1", 248}, {NT_PROGRAM_SINGLE_ITEM_TOKEN, PROGRAM_TOKEN, "", 249}, {NT_PROGRAM_SINGLE_ITEM2_TOKEN, ID_TOKEN, "env", 250}, {NT_PROGRAM_SINGLE_ITEM2_TOKEN, ID_TOKEN, "local", 251}, {NT_PROGRAM_MULTIPLE_ITEM_TOKEN, PROGRAM_TOKEN, "", 252}, {NT_PROGRAM_MULTIPLE_ITEM2_TOKEN, ID_TOKEN, "env", 253}, {NT_PROGRAM_MULTIPLE_ITEM2_TOKEN, ID_TOKEN, "local", 254}, {NT_PROG_ENV_PARAMS_TOKEN, ID_TOKEN, "env", 255}, {NT_PROG_ENV_PARAM_NUMS_TOKEN, INTEGER_TOKEN, "-1", 256}, {NT_PROG_ENV_PARAM_NUMS2_TOKEN, DOTDOT_TOKEN, "", 257}, {NT_PROG_ENV_PARAM_NUMS2_TOKEN, RBRACKET_TOKEN, "", 258}, {NT_PROG_ENV_PARAM_TOKEN, ID_TOKEN, "env", 259}, {NT_PROG_LOCAL_PARAMS_TOKEN, ID_TOKEN, "local", 260}, {NT_PROG_LOCAL_PARAM_NUMS_TOKEN, INTEGER_TOKEN, "-1", 261}, {NT_PROG_LOCAL_PARAM_NUMS2_TOKEN, DOTDOT_TOKEN, "", 262}, {NT_PROG_LOCAL_PARAM_NUMS2_TOKEN, RBRACKET_TOKEN, "", 263}, {NT_PROG_LOCAL_PARAM_TOKEN, ID_TOKEN, "local", 264}, {NT_PROG_ENV_PARAM_NUM_TOKEN, INTEGER_TOKEN, "-1", 265}, {NT_PROG_LOCAL_PARAM_NUM_TOKEN, INTEGER_TOKEN, "-1", 266}, {NT_PARAM_CONST_DECL_TOKEN, PLUS_TOKEN, "", 267}, {NT_PARAM_CONST_DECL_TOKEN, MINUS_TOKEN, "", 267}, {NT_PARAM_CONST_DECL_TOKEN, FLOAT_TOKEN, "-1", 267}, {NT_PARAM_CONST_DECL_TOKEN, INTEGER_TOKEN, "-1", 267}, {NT_PARAM_CONST_DECL_TOKEN, LBRACE_TOKEN, "", 268}, {NT_PARAM_CONST_USE_TOKEN, FLOAT_TOKEN, "-1", 269}, {NT_PARAM_CONST_USE_TOKEN, INTEGER_TOKEN, "-1", 269}, {NT_PARAM_CONST_USE_TOKEN, LBRACE_TOKEN, "", 270}, {NT_PARAM_CONST_SCALAR_DECL_TOKEN, PLUS_TOKEN, "", 271}, {NT_PARAM_CONST_SCALAR_DECL_TOKEN, MINUS_TOKEN, "", 271}, {NT_PARAM_CONST_SCALAR_DECL_TOKEN, FLOAT_TOKEN, "-1", 271}, {NT_PARAM_CONST_SCALAR_DECL_TOKEN, INTEGER_TOKEN, "-1", 271}, {NT_PARAM_CONST_SCALAR_USE_TOKEN, FLOAT_TOKEN, "-1", 272}, {NT_PARAM_CONST_SCALAR_USE_TOKEN, INTEGER_TOKEN, "-1", 272}, {NT_PARAM_CONST_VECTOR_TOKEN, LBRACE_TOKEN, "", 273}, {NT_PARAM_CONST_VECTOR2_TOKEN, RBRACE_TOKEN, "", 274}, {NT_PARAM_CONST_VECTOR2_TOKEN, COMMA_TOKEN, "", 275}, {NT_PARAM_CONST_VECTOR3_TOKEN, RBRACE_TOKEN, "", 276}, {NT_PARAM_CONST_VECTOR3_TOKEN, COMMA_TOKEN, "", 277}, {NT_PARAM_CONST_VECTOR4_TOKEN, RBRACE_TOKEN, "", 278}, {NT_PARAM_CONST_VECTOR4_TOKEN, COMMA_TOKEN, "", 279}, {NT_SIGNED_FLOAT_CONSTANT_TOKEN, PLUS_TOKEN, "", 280}, {NT_SIGNED_FLOAT_CONSTANT_TOKEN, MINUS_TOKEN, "", 280}, {NT_SIGNED_FLOAT_CONSTANT_TOKEN, FLOAT_TOKEN, "-1", 280}, {NT_SIGNED_FLOAT_CONSTANT_TOKEN, INTEGER_TOKEN, "-1", 280}, {NT_OPTIONAL_SIGN_TOKEN, FLOAT_TOKEN, "-1", 281}, {NT_OPTIONAL_SIGN_TOKEN, INTEGER_TOKEN, "0", 281}, {NT_OPTIONAL_SIGN_TOKEN, INTEGER_TOKEN, "1", 281}, {NT_OPTIONAL_SIGN_TOKEN, INTEGER_TOKEN, "-1", 281}, {NT_OPTIONAL_SIGN_TOKEN, ID_TOKEN, "-1", 281}, {NT_OPTIONAL_SIGN_TOKEN, STATE_TOKEN, "", 281}, {NT_OPTIONAL_SIGN_TOKEN, PROGRAM_TOKEN, "", 281}, {NT_OPTIONAL_SIGN_TOKEN, VERTEX_TOKEN, "", 281}, {NT_OPTIONAL_SIGN_TOKEN, LBRACE_TOKEN, "", 281}, {NT_OPTIONAL_SIGN_TOKEN, MINUS_TOKEN, "", 282}, {NT_OPTIONAL_SIGN_TOKEN, PLUS_TOKEN, "", 283}, {NT_TEMP_STATEMENT_TOKEN, TEMP_TOKEN, "", 284}, {NT_ADDRESS_STATEMENT_TOKEN, ADDRESS_TOKEN, "", 285}, /* Special case 286-7 */ {NT_OUTPUT_STATEMENT_TOKEN, OUTPUT_TOKEN, "", 288}, {NT_RESULT_BINDING_TOKEN, RESULT_TOKEN, "", 289}, {NT_RESULT_BINDING2_TOKEN, ID_TOKEN, "position", 290}, {NT_RESULT_BINDING2_TOKEN, ID_TOKEN, "fogcoord", 291}, {NT_RESULT_BINDING2_TOKEN, ID_TOKEN, "pointsize", 292}, {NT_RESULT_BINDING2_TOKEN, ID_TOKEN, "color", 293}, {NT_RESULT_BINDING2_TOKEN, ID_TOKEN, "texcoord", 294}, {NT_RESULT_COL_BINDING_TOKEN, ID_TOKEN, "color", 295}, /* Special case 296-7 */ {NT_RESULT_COL_BINDING3_TOKEN, ID_TOKEN, "front", 298}, {NT_RESULT_COL_BINDING3_TOKEN, ID_TOKEN, "back", 299}, /* Special case 300-301 */ {NT_RESULT_COL_BINDING5_TOKEN, ID_TOKEN, "primary", 302}, {NT_RESULT_COL_BINDING5_TOKEN, ID_TOKEN, "secondary", 303}, {NT_OPT_FACE_TYPE2_TOKEN, ID_TOKEN, "front", 304}, {NT_OPT_FACE_TYPE2_TOKEN, ID_TOKEN, "back", 305}, /* Special case 306-7 */ {NT_OPT_COLOR_TYPE2_TOKEN, ID_TOKEN, "primary", 308}, {NT_OPT_COLOR_TYPE2_TOKEN, ID_TOKEN, "secondary", 309}, {NT_OPT_TEX_COORD_NUM_TOKEN, PERIOD_TOKEN, "", 310}, {NT_OPT_TEX_COORD_NUM_TOKEN, SEMICOLON_TOKEN, "", 310}, {NT_OPT_TEX_COORD_NUM_TOKEN, COMMA_TOKEN, "", 310}, {NT_OPT_TEX_COORD_NUM_TOKEN, RBRACE_TOKEN, "", 310}, {NT_OPT_TEX_COORD_NUM_TOKEN, LBRACKET_TOKEN, "", 311}, {NT_TEX_COORD_NUM_TOKEN, INTEGER_TOKEN, "-1", 312}, /* Special case for 313 to get aliasing correct */ {NT_ESTABLISH_NAME_TOKEN, ID_TOKEN, "-1", 314}, {NT_ESTABLISHED_NAME_TOKEN, ID_TOKEN, "-1", 315}, /* Special case for 318-9 */ }; static GLint nprods = sizeof(ptab) / sizeof(prod_table); static GLint nlas = sizeof(latab) / sizeof(look_ahead_table); /** * This is a gigantic FSA to recognize the keywords put forth in the * GL_ARB_vertex_program spec. * * All other tokens are deemed 'identifiers', and shoved into the * identifier symbol table (as opposed to the GLint and GLfloat symbol tables) * * \param s The parse state * \param token The next token seen is returned in this value * \param token_attr The token attribute for the next token is returned here. This * is the index into the approprate symbol table if token is INTEGER_TOKEN, * FLOAT_TOKEN, or ID_TOKEN * * \return ARB_VP_ERROR on lex error, ARB_VP_SUCESS on sucess */ static GLint get_next_token(parse_state * s, GLint * token, GLint * token_attr) { GLubyte curr; while (s->start_pos < s->len) { curr = s->str[s->curr_pos]; switch (s->curr_state) { /* Default state */ case STATE_BASE: if (IS_WHITESPACE(curr)) { s->start_pos++; s->curr_pos++; } else { if (IS_IDCHAR(curr)) { switch (curr) { case 'A': ADV_TO_STATE(STATE_A); break; case 'D': ADV_TO_STATE(STATE_D); break; case 'E': ADV_TO_STATE(STATE_E); break; case 'F': ADV_TO_STATE(STATE_F); break; case 'L': ADV_TO_STATE(STATE_L); break; case 'M': ADV_TO_STATE(STATE_M); break; case 'O': ADV_TO_STATE(STATE_O); break; case 'P': ADV_TO_STATE(STATE_P); break; case 'R': ADV_TO_STATE(STATE_R); break; case 'S': ADV_TO_STATE(STATE_S); break; case 'T': ADV_TO_STATE(STATE_T); break; case 'X': ADV_TO_STATE(STATE_X); break; case 'p': ADV_TO_STATE(STATE_LC_P); break; case 'r': ADV_TO_STATE(STATE_LC_R); break; case 's': ADV_TO_STATE(STATE_LC_S); break; case 'v': ADV_TO_STATE(STATE_LC_V); break; default: s->curr_state = 1; s->start_pos = s->curr_pos; s->curr_pos++; } } else if (IS_DIGIT(curr)) { ADV_TO_STATE(STATE_N4); } else { switch (curr) { case '#': ADV_TO_STATE(STATE_COMMENT); break; case ';': ADV_AND_FINISH(SEMICOLON_TOKEN); break; case ',': ADV_AND_FINISH(COMMA_TOKEN); break; case '+': ADV_AND_FINISH(PLUS_TOKEN); break; case '-': ADV_AND_FINISH(MINUS_TOKEN); break; case '[': ADV_AND_FINISH(LBRACKET_TOKEN); break; case ']': ADV_AND_FINISH(RBRACKET_TOKEN); break; case '{': ADV_AND_FINISH(LBRACE_TOKEN); break; case '}': ADV_AND_FINISH(RBRACE_TOKEN); break; case '=': ADV_AND_FINISH(EQUAL_TOKEN); break; case '.': ADV_TO_STATE(STATE_N1); break; default: return ARB_VP_ERROR; break; } } } break; /* Main identifier state */ case STATE_IDENT: if (IS_CD(curr)) { s->curr_pos++; } else { *token = ID_TOKEN; *token_attr = id_table_add(&s->idents, s->str, s->start_pos, s->curr_pos); s->curr_state = 0; s->start_pos = s->curr_pos; return ARB_VP_SUCESS; } break; /* ----------------------------------------------------- * Beginning of the A* keywords */ case STATE_A: if (IS_CD(curr)) { switch (curr) { case 'B': ADV_TO_STATE(STATE_AB); break; case 'D': ADV_TO_STATE(STATE_AD); break; case 'L': ADV_TO_STATE(STATE_AL); break; case 'R': ADV_TO_STATE(STATE_AR); break; case 'T': ADV_TO_STATE(STATE_AT); break; default: ADV_TO_STATE(STATE_IDENT); break; } } else { s->curr_state = 1; } break; case STATE_AB: ADV_OR_FALLBACK('S', STATE_ABS); break; case STATE_ABS: FINISH_OR_FALLBACK(ABS_TOKEN); break; case STATE_AD: ADV_OR_FALLBACK('D', STATE_ADD); break; case STATE_ADD: if (curr == 'R') { ADV_TO_STATE(STATE_ADDR); } else if (IS_CD(curr)) { ADV_TO_STATE(STATE_IDENT); } else { FINISH(ADD_TOKEN); } break; case STATE_ADDR: ADV_OR_FALLBACK('E', STATE_ADDRE); break; case STATE_ADDRE: ADV_OR_FALLBACK('S', STATE_ADDRES); break; case STATE_ADDRES: ADV_OR_FALLBACK('S', STATE_ADDRESS); break; case STATE_ADDRESS: FINISH_OR_FALLBACK(ADDRESS_TOKEN); break; case STATE_AL: ADV_OR_FALLBACK('I', STATE_ALI); break; case STATE_ALI: ADV_OR_FALLBACK('A', STATE_ALIA); break; case STATE_ALIA: ADV_OR_FALLBACK('S', STATE_ALIAS); break; case STATE_ALIAS: FINISH_OR_FALLBACK(ALIAS_TOKEN); break; case STATE_AR: ADV_OR_FALLBACK('L', STATE_ARL); break; case STATE_ARL: FINISH_OR_FALLBACK(ARL_TOKEN); break; case STATE_AT: ADV_OR_FALLBACK('T', STATE_ATT); break; case STATE_ATT: ADV_OR_FALLBACK('R', STATE_ATTR); break; case STATE_ATTR: ADV_OR_FALLBACK('I', STATE_ATTRI); break; case STATE_ATTRI: ADV_OR_FALLBACK('B', STATE_ATTRIB); break; case STATE_ATTRIB: FINISH_OR_FALLBACK(ATTRIB_TOKEN); break; /* ----------------------------------------------------- * Beginning of the D* keywords */ case STATE_D: if (IS_CD(curr)) { switch (curr) { case 'P': ADV_TO_STATE(STATE_DP); break; case 'S': ADV_TO_STATE(STATE_DS); break; default: ADV_TO_STATE(STATE_IDENT); break; } } else { s->curr_state = 1; } break; case STATE_DP: if (IS_CD(curr)) { switch (curr) { case '3': ADV_TO_STATE(STATE_DP3); break; case '4': ADV_TO_STATE(STATE_DP4); break; case 'H': ADV_TO_STATE(STATE_DPH); break; default: ADV_TO_STATE(STATE_IDENT); break; } } else { s->curr_state = 1; } break; case STATE_DP3: FINISH_OR_FALLBACK(DP3_TOKEN); break; case STATE_DP4: FINISH_OR_FALLBACK(DP4_TOKEN); break; case STATE_DPH: FINISH_OR_FALLBACK(DPH_TOKEN); break; case STATE_DS: ADV_OR_FALLBACK('T', STATE_DST); break; case STATE_DST: FINISH_OR_FALLBACK(DST_TOKEN); break; /* ----------------------------------------------------- * Beginning of the E* keywords */ case STATE_E: if (IS_CD(curr)) { switch (curr) { case 'N': ADV_TO_STATE(STATE_EN); break; case 'X': ADV_TO_STATE(STATE_EX); break; default: ADV_TO_STATE(STATE_IDENT); break; } } else { s->curr_state = 1; } break; case STATE_EN: ADV_OR_FALLBACK('D', STATE_END); break; case STATE_END: FINISH_OR_FALLBACK(END_TOKEN); break; case STATE_EX: if (IS_CD(curr)) { switch (curr) { case '2': ADV_TO_STATE(STATE_EX2); break; case 'P': ADV_TO_STATE(STATE_EXP); break; default: ADV_TO_STATE(STATE_IDENT); break; } } else { s->curr_state = 1; } break; case STATE_EX2: FINISH_OR_FALLBACK(EX2_TOKEN); break; case STATE_EXP: FINISH_OR_FALLBACK(EXP_TOKEN); break; /* ----------------------------------------------------- * Beginning of the F* keywords */ case STATE_F: if (IS_CD(curr)) { switch (curr) { case 'L': ADV_TO_STATE(STATE_FL); break; case 'R': ADV_TO_STATE(STATE_FR); break; default: ADV_TO_STATE(STATE_IDENT); break; } } else { s->curr_state = 1; } break; case STATE_FL: ADV_OR_FALLBACK('R', STATE_FLR); break; case STATE_FLR: FINISH_OR_FALLBACK(FLR_TOKEN); break; case STATE_FR: ADV_OR_FALLBACK('C', STATE_FRC); break; case STATE_FRC: FINISH_OR_FALLBACK(FRC_TOKEN); break; /* ----------------------------------------------------- * Beginning of the L* keywords */ case STATE_L: if (IS_CD(curr)) { switch (curr) { case 'G': ADV_TO_STATE(STATE_LG); break; case 'I': ADV_TO_STATE(STATE_LI); break; case 'O': ADV_TO_STATE(STATE_LO); break; default: ADV_TO_STATE(STATE_IDENT); break; } } else { s->curr_state = 1; } break; case STATE_LG: ADV_OR_FALLBACK('2', STATE_LG2); break; case STATE_LG2: FINISH_OR_FALLBACK(LG2_TOKEN); break; case STATE_LI: ADV_OR_FALLBACK('T', STATE_LIT); break; case STATE_LIT: FINISH_OR_FALLBACK(LIT_TOKEN); break; case STATE_LO: ADV_OR_FALLBACK('G', STATE_LOG); break; case STATE_LOG: FINISH_OR_FALLBACK(LOG_TOKEN); break; /* ----------------------------------------------------- * Beginning of the M* keywords */ case STATE_M: if (IS_CD(curr)) { switch (curr) { case 'A': ADV_TO_STATE(STATE_MA); break; case 'I': ADV_TO_STATE(STATE_MI); break; case 'O': ADV_TO_STATE(STATE_MO); break; case 'U': ADV_TO_STATE(STATE_MU); break; default: ADV_TO_STATE(STATE_IDENT); break; } } else { s->curr_state = 1; } break; case STATE_MA: if (IS_CD(curr)) { switch (curr) { case 'D': ADV_TO_STATE(STATE_MAD); break; case 'X': ADV_TO_STATE(STATE_MAX); break; default: ADV_TO_STATE(STATE_IDENT); break; } } else { s->curr_state = 1; } break; case STATE_MAD: FINISH_OR_FALLBACK(MAD_TOKEN); break; case STATE_MAX: FINISH_OR_FALLBACK(MAX_TOKEN); break; case STATE_MI: ADV_OR_FALLBACK('N', STATE_MIN); break; case STATE_MIN: FINISH_OR_FALLBACK(MIN_TOKEN); break; case STATE_MO: ADV_OR_FALLBACK('V', STATE_MOV); break; case STATE_MOV: FINISH_OR_FALLBACK(MOV_TOKEN); break; case STATE_MU: ADV_OR_FALLBACK('L', STATE_MUL); break; case STATE_MUL: FINISH_OR_FALLBACK(MUL_TOKEN); break; /* ----------------------------------------------------- * Beginning of the O* keywords */ case STATE_O: if (IS_CD(curr)) { switch (curr) { case 'P': ADV_TO_STATE(STATE_OP); break; case 'U': ADV_TO_STATE(STATE_OU); break; default: ADV_TO_STATE(STATE_IDENT); break; } } else { s->curr_state = 1; } break; case STATE_OP: ADV_OR_FALLBACK('T', STATE_OPT); break; case STATE_OPT: ADV_OR_FALLBACK('I', STATE_OPTI); break; case STATE_OPTI: ADV_OR_FALLBACK('O', STATE_OPTIO); break; case STATE_OPTIO: ADV_OR_FALLBACK('N', STATE_OPTION); break; case STATE_OPTION: FINISH_OR_FALLBACK(OPTION_TOKEN); break; case STATE_OU: ADV_OR_FALLBACK('T', STATE_OUT); break; case STATE_OUT: ADV_OR_FALLBACK('P', STATE_OUTP); break; case STATE_OUTP: ADV_OR_FALLBACK('U', STATE_OUTPU); break; case STATE_OUTPU: ADV_OR_FALLBACK('T', STATE_OUTPUT); break; case STATE_OUTPUT: FINISH_OR_FALLBACK(OUTPUT_TOKEN); break; /* ----------------------------------------------------- * Beginning of the P* keywords */ case STATE_P: if (IS_CD(curr)) { switch (curr) { case 'A': ADV_TO_STATE(STATE_PA); break; case 'O': ADV_TO_STATE(STATE_PO); break; default: ADV_TO_STATE(STATE_IDENT); break; } } else { s->curr_state = 1; } break; case STATE_PA: ADV_OR_FALLBACK('R', STATE_PAR); break; case STATE_PAR: ADV_OR_FALLBACK('A', STATE_PARA); break; case STATE_PARA: ADV_OR_FALLBACK('M', STATE_PARAM); break; case STATE_PARAM: FINISH_OR_FALLBACK(PARAM_TOKEN); break; case STATE_PO: ADV_OR_FALLBACK('W', STATE_POW); break; case STATE_POW: FINISH_OR_FALLBACK(POW_TOKEN); break; /* ----------------------------------------------------- * Beginning of the R* keywords */ case STATE_R: if (IS_CD(curr)) { switch (curr) { case 'C': ADV_TO_STATE(STATE_RC); break; case 'S': ADV_TO_STATE(STATE_RS); break; default: ADV_TO_STATE(STATE_IDENT); break; } } else { s->curr_state = 1; } break; case STATE_RC: ADV_OR_FALLBACK('P', STATE_RCP); break; case STATE_RCP: FINISH_OR_FALLBACK(RCP_TOKEN); break; case STATE_RS: ADV_OR_FALLBACK('Q', STATE_RSQ); break; case STATE_RSQ: FINISH_OR_FALLBACK(RSQ_TOKEN); break; /* ----------------------------------------------------- * Beginning of the S* keywords */ case STATE_S: if (IS_CD(curr)) { switch (curr) { case 'G': ADV_TO_STATE(STATE_SG); break; case 'L': ADV_TO_STATE(STATE_SL); break; case 'U': ADV_TO_STATE(STATE_SU); break; case 'W': ADV_TO_STATE(STATE_SW); break; default: ADV_TO_STATE(STATE_IDENT); break; } } else { s->curr_state = 1; } break; case STATE_SG: ADV_OR_FALLBACK('E', STATE_SGE); break; case STATE_SGE: FINISH_OR_FALLBACK(SGE_TOKEN); break; case STATE_SL: ADV_OR_FALLBACK('T', STATE_SLT); break; case STATE_SLT: FINISH_OR_FALLBACK(SLT_TOKEN); break; case STATE_SU: ADV_OR_FALLBACK('B', STATE_SUB); break; case STATE_SUB: FINISH_OR_FALLBACK(SUB_TOKEN); break; case STATE_SW: ADV_OR_FALLBACK('Z', STATE_SWZ); break; case STATE_SWZ: FINISH_OR_FALLBACK(SWZ_TOKEN); break; /* ----------------------------------------------------- * Beginning of the T* keywords */ case STATE_T: ADV_OR_FALLBACK('E', STATE_TE); break; case STATE_TE: ADV_OR_FALLBACK('M', STATE_TEM); break; case STATE_TEM: ADV_OR_FALLBACK('P', STATE_TEMP); break; case STATE_TEMP: FINISH_OR_FALLBACK(TEMP_TOKEN); break; /* ----------------------------------------------------- * Beginning of the X* keywords */ case STATE_X: ADV_OR_FALLBACK('P', STATE_XP); break; case STATE_XP: ADV_OR_FALLBACK('D', STATE_XPD); break; case STATE_XPD: FINISH_OR_FALLBACK(XPD_TOKEN); break; /* ----------------------------------------------------- * Beginning of the p* keywords */ case STATE_LC_P: ADV_OR_FALLBACK('r', STATE_LC_PR); break; case STATE_LC_PR: ADV_OR_FALLBACK('o', STATE_LC_PRO); break; case STATE_LC_PRO: ADV_OR_FALLBACK('g', STATE_LC_PROG); break; case STATE_LC_PROG: ADV_OR_FALLBACK('r', STATE_LC_PROGR); break; case STATE_LC_PROGR: ADV_OR_FALLBACK('a', STATE_LC_PROGRA); break; case STATE_LC_PROGRA: ADV_OR_FALLBACK('m', STATE_LC_PROGRAM); break; case STATE_LC_PROGRAM: FINISH_OR_FALLBACK(PROGRAM_TOKEN); break; /* ----------------------------------------------------- * Beginning of the r* keywords */ case STATE_LC_R: ADV_OR_FALLBACK('e', STATE_LC_RE); break; case STATE_LC_RE: ADV_OR_FALLBACK('s', STATE_LC_RES); break; case STATE_LC_RES: ADV_OR_FALLBACK('u', STATE_LC_RESU); break; case STATE_LC_RESU: ADV_OR_FALLBACK('l', STATE_LC_RESUL); break; case STATE_LC_RESUL: ADV_OR_FALLBACK('t', STATE_LC_RESULT); break; case STATE_LC_RESULT: FINISH_OR_FALLBACK(RESULT_TOKEN); break; /* ----------------------------------------------------- * Beginning of the s* keywords */ case STATE_LC_S: ADV_OR_FALLBACK('t', STATE_LC_ST); break; case STATE_LC_ST: ADV_OR_FALLBACK('a', STATE_LC_STA); break; case STATE_LC_STA: ADV_OR_FALLBACK('t', STATE_LC_STAT); break; case STATE_LC_STAT: ADV_OR_FALLBACK('e', STATE_LC_STATE); break; case STATE_LC_STATE: FINISH_OR_FALLBACK(STATE_TOKEN); break; /* ----------------------------------------------------- * Beginning of the v* keywords */ case STATE_LC_V: ADV_OR_FALLBACK('e', STATE_LC_VE); break; case STATE_LC_VE: ADV_OR_FALLBACK('r', STATE_LC_VER); break; case STATE_LC_VER: ADV_OR_FALLBACK('t', STATE_LC_VERT); break; case STATE_LC_VERT: ADV_OR_FALLBACK('e', STATE_LC_VERTE); break; case STATE_LC_VERTE: ADV_OR_FALLBACK('x', STATE_LC_VERTEX); break; case STATE_LC_VERTEX: FINISH_OR_FALLBACK(VERTEX_TOKEN); break; /* ----------------------------------------------------- * Beginning of the number & comment FSAs */ case STATE_N1: if (curr == '.') { ADV_TO_STATE(STATE_N2); } else if (IS_DIGIT(curr)) { ADV_TO_STATE(STATE_N3); } else { /*ADV_AND_FINISH(PERIOD_TOKEN); */ FINISH(PERIOD_TOKEN); } break; case STATE_N2: #if 1 /*ADV_AND_FINISH(DOTDOT_TOKEN);*/ FINISH(DOTDOT_TOKEN); #else FINISH(PERIOD_TOKEN); #endif break; case STATE_N3: if (IS_DIGIT(curr)) { ADV_TO_STATE(STATE_N3); } else if ((curr == 'E') || (curr == 'e')) { ADV_TO_STATE(STATE_N5); } else if (curr == '.') { /* Blech! we have something like 1.. -> have to backup */ s->curr_pos -= 1; *token_attr = int_table_add(&s->ints, s->str, s->start_pos, s->curr_pos); FINISH(INTEGER_TOKEN); } else { *token_attr = float_table_add(&s->floats, s->str, s->start_pos, s->curr_pos); /*ADV_AND_FINISH(FLOAT_TOKEN);*/ FINISH(FLOAT_TOKEN); } break; case STATE_N4: if (IS_DIGIT(curr)) { ADV_TO_STATE(STATE_N4); } else if ((curr == 'E') || (curr == 'e')) { ADV_TO_STATE(STATE_N5); } else if (curr == '.') { ADV_TO_STATE(STATE_N3); } else { *token_attr = int_table_add(&s->ints, s->str, s->start_pos, s->curr_pos); /*ADV_AND_FINISH(INTEGER_TOKEN);*/ FINISH(INTEGER_TOKEN); } break; case STATE_N5: if (IS_DIGIT(curr)) { ADV_TO_STATE(STATE_N6); } else if ((curr == '+') || (curr == '-')) { ADV_TO_STATE(STATE_N7) } else { return ARB_VP_ERROR; } break; case STATE_N6: if (IS_DIGIT(curr)) { ADV_TO_STATE(STATE_N6); } else { *token_attr = float_table_add(&s->floats, s->str, s->start_pos, s->curr_pos); /*ADV_AND_FINISH(FLOAT_TOKEN);*/ FINISH(FLOAT_TOKEN); } break; case STATE_N7: if (IS_DIGIT(curr)) { ADV_TO_STATE(STATE_N6); } else { return ARB_VP_ERROR; } break; case STATE_COMMENT: if ((curr == '\n') || (curr == '\r')) { s->start_pos = s->curr_pos + 1; s->curr_pos++; s->curr_state = 0; } else { ADV_TO_STATE(STATE_COMMENT); } } } *token = EOF_TOKEN; return ARB_VP_SUCESS; } /** * This does the same as get_next_token(), but it does not advance the * position pointers (Err, rather it does, but then it resets them) * * \param s The parse state * \param token The next token seen is returned in this value * \param token_attr The token attribute for the next token is returned here. This * is the index into the approprate symbol table if token is INTEGER_TOKEN, * FLOAT_TOKEN, or ID_TOKEN * \param how_many How many tokens to peek ahead * * \return ARB_VP_ERROR on lex error, ARB_VP_SUCESS on sucess */ static GLint peek_next_token(parse_state * s, GLint * token, GLint * token_attr, GLint how_many) { GLint tmp_state = s->curr_state; GLint tmp_sp = s->start_pos; GLint tmp_cp = s->curr_pos; GLint a, retval; for (a = 0; a < how_many; a++) { retval = get_next_token(s, token, token_attr); if (retval == ARB_VP_ERROR) return retval; } s->curr_state = tmp_state; s->start_pos = tmp_sp; s->curr_pos = tmp_cp; return retval; } /** * Print out the value of a token */ static void debug_token(parse_state * state, GLint t, GLint ta) { switch (t) { case EOF_TOKEN: printf("EOF\n"); break; case ID_TOKEN: printf("|%s| ", state->idents.data[ta]); break; case INTEGER_TOKEN: printf("|%d| ", state->ints.data[ta]); break; case FLOAT_TOKEN: printf("|%f| ", state->floats.data[ta]); break; case ABS_TOKEN: printf("ABS "); break; case ADD_TOKEN: printf("ADD "); break; case ADDRESS_TOKEN: printf("ADDRESS "); break; case ALIAS_TOKEN: printf("ALIAS "); break; case ARL_TOKEN: printf("ARL "); break; case ATTRIB_TOKEN: printf("ATTRIB "); break; case DP3_TOKEN: printf("DP3 "); break; case DP4_TOKEN: printf("DP4 "); break; case DPH_TOKEN: printf("DPH "); break; case DST_TOKEN: printf("DST "); break; case END_TOKEN: printf("END "); break; case EX2_TOKEN: printf("EX2 "); break; case EXP_TOKEN: printf("EXP "); break; case FLR_TOKEN: printf("FLR "); break; case FRC_TOKEN: printf("FRC "); break; case LG2_TOKEN: printf("LG2 "); break; case LIT_TOKEN: printf("LIT "); break; case LOG_TOKEN: printf("LOG "); break; case MAD_TOKEN: printf("MAD "); break; case MAX_TOKEN: printf("MAX "); break; case MIN_TOKEN: printf("MIN "); break; case MOV_TOKEN: printf("MOV "); break; case MUL_TOKEN: printf("MUL "); break; case OPTION_TOKEN: printf("OPTION "); break; case OUTPUT_TOKEN: printf("OUTPUT "); break; case PARAM_TOKEN: printf("PARAM "); break; case POW_TOKEN: printf("POW "); break; case RCP_TOKEN: printf("RCP "); break; case RSQ_TOKEN: printf("RSQ "); break; case SGE_TOKEN: printf("SGE "); break; case SLT_TOKEN: printf("SLT "); break; case SUB_TOKEN: printf("SUB "); break; case SWZ_TOKEN: printf("SWZ "); break; case TEMP_TOKEN: printf("TEMP "); break; case XPD_TOKEN: printf("XPD "); break; case SEMICOLON_TOKEN: printf("; "); break; case COMMA_TOKEN: printf(", "); break; case PLUS_TOKEN: printf("+ "); break; case MINUS_TOKEN: printf("- "); break; case PERIOD_TOKEN: printf(". "); break; case DOTDOT_TOKEN: printf(".. "); break; case LBRACKET_TOKEN: printf("[ "); break; case RBRACKET_TOKEN: printf("] "); break; case LBRACE_TOKEN: printf("{ "); break; case RBRACE_TOKEN: printf("} "); break; case EQUAL_TOKEN: printf("= "); break; case PROGRAM_TOKEN: printf("program "); break; case RESULT_TOKEN: printf("result "); break; case STATE_TOKEN: printf("state "); break; case VERTEX_TOKEN: printf("vertex "); break; default: printf("Unknown token type %d\n", t); } } /** * Setup the state used by the parser / lex * * \param str The program string, with the !!ARBvp1.0 token stripped off * \param len The lenght of the given string * * \return A parse_state struct to keep track of all the things we need while parsing */ static parse_state * parse_state_init(GLubyte * str, GLint len) { parse_state *s = (parse_state *) _mesa_malloc(sizeof(parse_state)); s->str = _mesa_strdup((char *) str); s->len = len; s->curr_pos = 0; s->start_pos = 0; s->curr_state = 0; s->idents.len = 0; s->idents.data = NULL; s->ints.len = 0; s->ints.data = NULL; s->floats.len = 0; s->floats.data = NULL; printf("%s\n", s->str); s->binds.len = 0; s->binds.type = NULL; s->binds.offset = NULL; s->binds.row = NULL; s->binds.consts = NULL; s->arrays.len = 0; s->arrays.num_elements = NULL; s->arrays.data = NULL; s->stack_head = NULL; s->stack_free_list = NULL; s->pt_head = NULL; return s; } /** * This frees all the things we hold while parsing. * * \param s The struct created by parse_state_init() */ static void parse_state_cleanup(parse_state * s) { GLint a; token_list *tl, *next; /* Free our copy of the string [Mesa has its own] */ _mesa_free(s->str); /* Free all the tables ident, int, float, bind, mat */ _mesa_free(s->idents.type); _mesa_free(s->idents.attr); for (a = 0; a < s->idents.len; a++) _mesa_free(s->idents.data[a]); _mesa_free(s->ints.data); _mesa_free(s->floats.data); _mesa_free(s->arrays.num_elements); for (a = 0; a < s->arrays.len; a++) _mesa_free(s->arrays.data[a]); _mesa_free(s->binds.type); _mesa_free(s->binds.offset); _mesa_free(s->binds.row); _mesa_free(s->binds.num_rows); _mesa_free(s->binds.reg_num); #if 0 for (a = 0; a < s->binds.len; a++) { printf("6: %d/%d\n", a, s->binds.len - 1); _mesa_free(s->binds.consts[a]); } #endif /* Free the stack */ tl = s->stack_head; while (tl) { next = tl->next; free(tl); tl = next; } tl = s->stack_free_list; while (tl) { next = tl->next; free(tl); tl = next; } printf("freed stack free list\n"); #if 0 /* Free the parse tree */ parse_tree_free_children(s->pt_head); printf("freed parse_tree\n"); #endif free(s); printf("freed state\n"); } /** * Alloc a new node for a parse tree. * * \return An empty node to fill and stick into the parse tree */ static parse_tree_node * parse_tree_node_init(void) { GLint a; parse_tree_node *pt; pt = (parse_tree_node *) _mesa_malloc(sizeof(parse_tree_node)); pt->tok = -1; pt->tok_attr = -1; pt->is_terminal = 0; pt->prod_applied = -1; for (a = 0; a < 4; a++) pt->children[a] = NULL; return pt; } /** * We maintain a stack of nonterminals used for predictive parsing. To keep * from thrashing malloc/free, we keep a free list of token_list structs * to be used for this stack. This function is called to refill the free * list, when we try to grab a new token_list struct, and find that there are none * available * * \param s The parse state */ static void _fill_free_list(parse_state * s) { GLint a; token_list *tl; if (s->stack_free_list) return; for (a = 0; a < 20; a++) { tl = (token_list *) _mesa_malloc(sizeof(token_list)); tl->next = s->stack_free_list; s->stack_free_list = tl; } } /** * Peek at the head of the nonterminal stack, * * \param s The parse state * \param token Return for the nonterminal token on the top of the stack * \param token_attr Return for the the token attribute on the top of the stack * * \return ARB_VP_ERROR on an empty stack [not necessarily a bad thing], else ARB_VP_SUCESS */ static GLint _stack_peek(parse_state * s, GLint * token, GLint * token_attr) { if (!s->stack_head) { fprintf(stderr, "ACK! Empty stack on peek!\n"); return ARB_VP_ERROR; } *token = s->stack_head->tok; *token_attr = s->stack_head->tok_attr; return ARB_VP_SUCESS; } /** * Remove the token at the head of the nonterminal stack * \param s The parse state * \param token Return for the nonterminal token on the top of the stack * \param token_attr Return for the the token attribute on the top of the stack * \param ptn Return for a pointer to the place in the parse tree where * the token lives * * \return ARB_VP_ERROR on an empty stack [not necessarily a bad thing], else ARB_VP_SUCESS */ static GLint _stack_pop(parse_state * s, GLint * token, GLint * token_attr, parse_tree_node ** ptn) { token_list *tl; if (!s->stack_head) { fprintf(stderr, "ACK! Empty stack!\n"); return ARB_VP_ERROR; } *token = s->stack_head->tok; *token_attr = s->stack_head->tok_attr; if (ptn) *ptn = s->stack_head->pt; tl = s->stack_head; s->stack_head = tl->next; tl->next = s->stack_free_list; s->stack_free_list = tl; return ARB_VP_SUCESS; } /** * Put a token, its attribute, and the the parse tree node where the token is stored, onto * the parse stack. * * \param s The parse state * \param token Return for the nonterminal token on the top of the stack * \param token_attr Return for the the token attribute on the top of the stack * \param ptn Return for a pointer to the place in the parse tree where * the token lives * * \return ARB_VP_ERROR on out of memory while allocing more storage for the stack, * else ARB_VP_SUCESS */ static GLint _stack_push(parse_state * s, GLint token, GLint token_attr, parse_tree_node * ptn) { token_list *tl; if (!s->stack_free_list) { _fill_free_list(s); if (!s->stack_free_list) { fprintf(stderr, "ACK! Error filling stack free list\n"); return ARB_VP_ERROR; } } tl = s->stack_free_list; s->stack_free_list = tl->next; tl->tok = token; tl->tok_attr = token_attr; tl->pt = ptn; tl->next = s->stack_head; s->stack_head = tl; return ARB_VP_SUCESS; } /** * Allocate a new entry in the array table * * \param tab The array table to add a new element too * * \return The index into the array table where the new element is. */ static GLint array_table_new(array_table * tab) { GLint idx; if (tab->len == 0) { tab->num_elements = (GLint *) _mesa_malloc(sizeof(GLint)); tab->data = (GLint **) _mesa_malloc(sizeof(GLint *)); idx = 0; } else { tab->num_elements = (GLint *) _mesa_realloc(tab->num_elements, tab->len * sizeof(GLint), (tab->len + 1) * sizeof(GLint)); tab->data = (GLint **) _mesa_realloc(tab->data, tab->len * sizeof(GLint *), (tab->len + 1) * sizeof(GLint *)); idx = tab->len; } tab->len++; tab->num_elements[idx] = 0; tab->data[idx] = NULL; return idx; } /** * Add a new element to a array in a array table * * \param tab The array table * \param idx The index into the array table of the array we want to append an item onto * \param data The program parameter that goes into the idx-th array */ static void array_table_add_data(array_table * tab, GLint idx, GLint data) { if ((idx < 0) || (idx >= tab->len)) { printf("Bad matrix index %d!\n", idx); return; } if (tab->data[idx] == NULL) { tab->data[idx] = (GLint *) _mesa_malloc(sizeof(GLint)); } else { tab->data[idx] = (GLint *) _mesa_realloc(tab->data[idx], tab->num_elements[idx] * sizeof(GLint), (tab->num_elements[idx] + 1) * sizeof(GLint)); } tab->data[idx][tab->num_elements[idx]] = data; tab->num_elements[idx]++; } /** * This adds a new entry into the binding table. * * \param tab The binding table * \param type The type of the state * \param offset For matrix bindings, e.g. MATRIXROWS_MODELVIEW, this gives the matrix number. * For PROGRAM_ENV_* and PROGRAM_LOCAL_* bindings, this gives the number of the first parameter * * \param row For MATRIXROWS bindings, this is the first row in the matrix we're bound to * \param nrows For MATRIXROWS bindings, this is the number of rows of the matrix we have. * For PROGRAM_ENV/LOCAL bindings, this is the number of parameters in the array we're bound to * \param values For CONSTANT bindings, these are the constant values we're bound to * \return The index into the binding table where this state is bound */ static GLint binding_table_add(binding_table * tab, GLint type, GLint offset, GLint row, GLint nrows, GLfloat * values) { GLint key, a; key = tab->len; /* test for existance */ for (a = 0; a < tab->len; a++) { if ((tab->type[a] == type) && (tab->offset[a] == offset) && (tab->row[a] == row) && (tab->num_rows[a] == nrows) && (fabs(tab->consts[a][0] - values[0]) < .0001) && (fabs(tab->consts[a][1] - values[1]) < .0001) && (fabs(tab->consts[a][2] - values[2]) < .0001) && (fabs(tab->consts[a][3] - values[3]) < .0001)) return a; } if (tab->len == 0) { tab->type = (GLint *) _mesa_malloc(sizeof(GLint)); tab->offset = (GLint *) _mesa_malloc(sizeof(GLint)); tab->row = (GLint *) _mesa_malloc(sizeof(GLint)); tab->num_rows = (GLint *) _mesa_malloc(sizeof(GLint)); tab->consts = (GLfloat **) _mesa_malloc(sizeof(GLfloat *)); tab->consts[0] = (GLfloat *) _mesa_malloc(4 * sizeof(GLfloat)); tab->reg_num = (GLint *) _mesa_malloc(sizeof(GLint)); } else { tab->type = (GLint *) _mesa_realloc(tab->type, tab->len * sizeof(GLint), (tab->len + 1) * sizeof(GLint)); tab->offset = (GLint *) _mesa_realloc(tab->offset, tab->len * sizeof(GLint), (tab->len + 1) * sizeof(GLint)); tab->row = (GLint *) _mesa_realloc(tab->row, tab->len * sizeof(GLint), (tab->len + 1) * sizeof(GLint)); tab->num_rows = (GLint *) _mesa_realloc(tab->num_rows, tab->len * sizeof(GLint), (tab->len + 1) * sizeof(GLint)); tab->consts = (GLfloat **) _mesa_realloc(tab->consts, tab->len * sizeof(GLfloat), (tab->len + 1) * sizeof(GLfloat *)); tab->consts[tab->len] = (GLfloat *) _mesa_malloc(4 * sizeof(GLfloat)); tab->reg_num = (GLint *) _mesa_realloc(tab->reg_num, tab->len * sizeof(GLint), (tab->len + 1) * sizeof(GLint)); } tab->type[key] = type; tab->offset[key] = offset; tab->row[key] = row; /*key;*/ tab->num_rows[key] = nrows; tab->reg_num[key] = 0; _mesa_memcpy(tab->consts[key], values, 4 * sizeof(GLfloat)); tab->len++; return key; } /** * Given a string and a start/end point, add a string into the float * symbol table (and convert it into a float) * * If we already have this GLfloat in the table, don't bother * adding another, just return the key to the existing one * * \param tab The float table * \param str The string containing the float * \param start The starting position of the float in str * \param end The ending position of the float in str * * \return The index of the float, after we insert it, in the float table */ static GLint float_table_add(float_table *tab, const char *str, GLint start, GLint end) { GLint key, a; GLubyte *newstr; key = tab->len; newstr = (GLubyte *) _mesa_malloc(end - start + 2); _mesa_memset(newstr, 0, end - start + 2); _mesa_memcpy(newstr, str + start, end - start); /* test for existance */ for (a = 0; a < tab->len; a++) { if (tab->data[a] == atof((char *) newstr)) { _mesa_free(newstr); return a; } } if (tab->len == 0) { tab->data = (GLdouble *) _mesa_malloc(sizeof(GLdouble)); } else { tab->data = (GLdouble *) _mesa_realloc(tab->data, tab->len * sizeof(GLdouble), (tab->len + 1) * sizeof(GLdouble)); } tab->data[key] = atof((char *) newstr); tab->len++; _mesa_free(newstr); return key; } /** * Given a string and a start/end point, add a string into the int * symbol table (and convert it into a int) * * If we already have this int in the table, don't bother * adding another, just return the key to the existing one * * \param tab The int table * \param str The string containing the int * \param start The starting position of the int in str * \param end The ending position of the int in str * * \return The index of the int, after we insert it, in the int table */ static GLint int_table_add(int_table * tab, const char *str, GLint start, GLint end) { GLint key, a; char *newstr; key = tab->len; newstr = (char *) _mesa_malloc(end - start + 2); _mesa_memset(newstr, 0, end - start + 2); _mesa_memcpy(newstr, str + start, end - start); for (a = 0; a < tab->len; a++) { if (tab->data[a] == _mesa_atoi(newstr)) { _mesa_free(newstr); return a; } } if (tab->len == 0) { tab->data = (GLint *) _mesa_malloc(sizeof(GLint)); } else { tab->data = (GLint *) _mesa_realloc(tab->data, tab->len * sizeof(GLint), (tab->len + 1) * sizeof(GLint)); } tab->data[key] = _mesa_atoi(newstr); tab->len++; _mesa_free(newstr); return key; } /** * Insert an identifier into the identifier symbol table * * If we already have this id in the table, don't bother * adding another, just return the key to the existing one * * If we already have this id in the table, and it has been * initialized to an ALIAS, return what the alias points * to, not the alias var * * \param tab The ID table * \param str The string containing the id * \param start The position in str where the id begins * \param end The position in str where the id ends * * \return either: * 1) The index into the id table where the id is * 2) The index into the id table where the alias of id, if we already have id * in the table, and it has been initialized to type ALIAS */ static GLint id_table_add(id_table * tab, const char * str, GLint start, GLint end) { GLint key, a; GLubyte *newstr; key = tab->len; if (tab->len == 0) { tab->data = (GLubyte **) _mesa_malloc(sizeof(GLubyte *)); tab->type = (GLint *) _mesa_malloc(sizeof(GLint)); tab->attr = (GLint *) _mesa_malloc(sizeof(GLint)); } else { tab->data = (GLubyte **) _mesa_realloc(tab->data, tab->len * sizeof(GLubyte *), (tab->len + 1) * sizeof(GLubyte *)); tab->type = (GLint *) _mesa_realloc(tab->type, tab->len * sizeof(GLint), (tab->len + 1) * sizeof(GLint)); tab->attr = (GLint *) _mesa_realloc(tab->attr, tab->len * sizeof(GLint), (tab->len + 1) * sizeof(GLint)); } /*tab->type[key] = TYPE_NONE;*/ newstr = (GLubyte *) _mesa_malloc((end - start + 2) * sizeof(GLubyte)); _mesa_memset(newstr, 0, end - start + 2); _mesa_memcpy(newstr, str + start, end - start); for (a = 0; a < tab->len; a++) { /* aha! we found it in the table */ if (!_mesa_strcmp((char *) tab->data[a], (char *) newstr)) { _mesa_free(newstr); key = a; while ((tab->type[key] == TYPE_ALIAS) && (tab->attr[key] != -1)) { printf("----------- %s is an alias, renaming to %s\n", tab->data[key], tab->data[tab->attr[key]]); key = tab->attr[key]; } return key; } } /* oh, we really have a new id */ tab->data[key] = newstr; tab->type[key] = TYPE_NONE; tab->attr[key] = -1; tab->len++; return key; } /*#define SHOW_STEPS 1*/ /** * Apply the specified production number to the parse state. This handles * looking at the production table and sticking new tokens onto the * parse stack. * * It also handles the construction of the parse tree * * \param s The parse state * \param num The production number to apply [the idx in the production table] * */ static void apply_production(parse_state * s, int num) { GLint a, str_key, stack_tok, stack_tok_attr; GLint tok, nnptr = 0; parse_tree_node *ptn; parse_tree_node *pt_ptr_new[4]; (void) _stack_pop(s, &stack_tok, &stack_tok_attr, &ptn); /*printf("apply prod %d\n", num); */ ptn->prod_applied = num; for (a = 3; a >= 0; a--) { str_key = 0; tok = ptab[num].rhs[a]; if (tok == NULL_TOKEN) continue; /* If we are pushing an identifier or a number, we need to translate the string literal * in the production table into an entry in the approprate symbol table */ if (tok == ID_TOKEN) { str_key = id_table_add(&s->idents, ptab[num].key[a], 0, _mesa_strlen(ptab[num].key[a])); } else if (tok == INTEGER_TOKEN) { str_key = int_table_add(&s->ints, ptab[num].key[a], 0, _mesa_strlen(ptab[num].key[a])); } else if (tok == FLOAT_TOKEN) { str_key = float_table_add(&s->floats, ptab[num].key[a], 0, _mesa_strlen(ptab[num].key[a])); } /* "-1" is a wildcard flag, accept any id/float/int */ if ((!_mesa_strcmp(ptab[num].key[a], "-1")) && ((tok == FLOAT_TOKEN) || (tok == INTEGER_TOKEN) || (tok == ID_TOKEN))) { pt_ptr_new[nnptr] = parse_tree_node_init(); pt_ptr_new[nnptr]->is_terminal = 0; pt_ptr_new[nnptr]->tok = tok; pt_ptr_new[nnptr]->tok_attr = str_key; nnptr++; _stack_push(s, ptab[num].rhs[a], str_key, pt_ptr_new[nnptr - 1]); } else if (tok >= NT_PROGRAM_TOKEN) { pt_ptr_new[nnptr] = parse_tree_node_init(); pt_ptr_new[nnptr]->is_terminal = 0; pt_ptr_new[nnptr]->tok = tok; nnptr++; _stack_push(s, ptab[num].rhs[a], str_key, pt_ptr_new[nnptr - 1]); } else _stack_push(s, ptab[num].rhs[a], str_key, NULL); } tok = 0; if (ptn) { /*printf("%x %d:[%x %x %x %x]\n", ptn, nnptr, pt_ptr_new[0], pt_ptr_new[1], pt_ptr_new[2], pt_ptr_new[3]); */ for (a = nnptr - 1; a >= 0; a--) { ptn->children[tok] = pt_ptr_new[a]; /*printf("%x->children[%d] = %x\n", ptn, tok, pt_ptr_new[a]); */ tok++; } } } /** * Here we initialize a bunch of variables to a given type (e.g. TEMP). * * We stick the variable type into the 0-th element in the var_queue array, followed by var_queue_size * indicies into the identifier table which designate the variables we are to init. * * \param s The parse state * \param var_queue The queue of variables to initialize. The first element in the array is variable * type. It is followed by var_queue_size indicies into the identifier table * who we are supposed to init to type var_queue[0]. * \param var_queue_size The number of variables listed in var_queue[]. * * \return ARB_VP_ERROR if we have already initilized a variable in var_queue, otherwise * ARB_VP_SUCESS */ static GLint init_vars(parse_state * s, GLint * var_queue, GLint var_queue_size) { GLint a; a = 1; while (a < var_queue_size) { /* Make sure we haven't already init'd this var. This will * catch multiple definations of the same symbol */ if (s->idents.type[var_queue[a]] != TYPE_NONE) { printf("%s already init'd! (%d)\n", s->idents.data[var_queue[a]], s->idents.type[var_queue[a]]); return ARB_VP_ERROR; } s->idents.type[var_queue[a]] = var_queue[0]; s->idents.attr[var_queue[a]] = -1; a++; } return ARB_VP_SUCESS; } /** * The main parsing loop. This applies productions and builds the parse tree. * * \param s The parse state * * \return ARB_VP_ERROR on a parse error, else ARB_VP_SUCESS */ static GLint parse(parse_state * s) { GLint input_tok, input_tok_attr; GLint stack_tok, stack_tok_attr; GLint peek_tok, peek_tok_attr, ret; GLint idx, str_key; GLint var_queue_size = 0; GLint *var_queue; parse_tree_node *ptn, *ptn2; /* This should be MAX_VAR + 1 */ var_queue = (GLint *) _mesa_malloc(1000 * sizeof(int)); s->stack_head = NULL; /* init the system by pushing the start symbol onto the stack */ ptn = parse_tree_node_init(); ptn->is_terminal = 0; ptn->tok = NT_PROGRAM_TOKEN; s->pt_head = ptn; _stack_push(s, NT_PROGRAM_TOKEN, 0, ptn); /* and get the first token */ if (get_next_token(s, &input_tok, &input_tok_attr) == ARB_VP_ERROR) { fprintf(stderr, "LEX ERROR!!\n"); return ARB_VP_ERROR; } while (1) { GLint la, is_nonterm; /* If the stack is empty, and we've eaten all the input, we're done */ if ((_stack_peek(s, &stack_tok, &stack_tok_attr) == ARB_VP_ERROR) && (input_tok == EOF_TOKEN)) break; #ifdef SHOW_STEPS printf("stack: %d input: ", stack_tok); debug_token(s, input_tok, input_tok_attr); printf("\n"); #endif /* We [may] have a non-terminal on top of the stack, apply * productions! */ switch (stack_tok) { /* Special case non-terminals */ /* productions 64-66 */ case NT_SRC_REG_TOKEN: if ((input_tok == VERTEX_TOKEN) || ((input_tok == ID_TOKEN) && (s->idents.type[input_tok_attr] == TYPE_ATTRIB))) { apply_production(s, 64); } else if ((input_tok == ID_TOKEN) && (s->idents.type[input_tok_attr] == TYPE_TEMP)) { apply_production(s, 65); } else if ((input_tok == STATE_TOKEN) || (input_tok == PROGRAM_TOKEN) || (input_tok == LBRACE_TOKEN) || (input_tok == FLOAT_TOKEN) || (input_tok == INTEGER_TOKEN) || ((input_tok == ID_TOKEN) && (s->idents.type[input_tok_attr] == TYPE_PARAM_SINGLE)) || ((input_tok == ID_TOKEN) && (s->idents.type[input_tok_attr] == TYPE_PARAM_ARRAY))) { apply_production(s, 66); } else { return ARB_VP_ERROR; } break; /* productions 67-68 */ case NT_DST_REG_TOKEN: /* We can only write to result.*, TEMP vars, or OUTPUT vars */ if (input_tok == RESULT_TOKEN) { apply_production(s, 68); } else if (input_tok == ID_TOKEN) { if (s->idents.type[input_tok_attr] == TYPE_TEMP) { apply_production(s, 67); } else if (s->idents.type[input_tok_attr] == TYPE_OUTPUT) { apply_production(s, 68); } else { return ARB_VP_ERROR; } } else { return ARB_VP_ERROR; } break; /* productions 72-4 */ case NT_PROG_PARAM_REG_TOKEN: if ((input_tok == ID_TOKEN) && (s->idents.type[input_tok_attr] == TYPE_PARAM_SINGLE)) { apply_production(s, 72); } else if ((input_tok == ID_TOKEN) && (s->idents.type[input_tok_attr] == TYPE_PARAM_ARRAY)) { apply_production(s, 73); } else if ((input_tok == STATE_TOKEN) || (input_tok == PROGRAM_TOKEN) || (input_tok == FLOAT_TOKEN) || (input_tok == INTEGER_TOKEN) || (input_tok == LBRACE_TOKEN)) { apply_production(s, 74); } else { return ARB_VP_ERROR; } break; /* productions 286-7 */ case NT_VAR_NAME_LIST_TOKEN: ret = peek_next_token(s, &peek_tok, &peek_tok_attr, 1); var_queue[var_queue_size] = input_tok_attr; var_queue_size++; if ((ret == ARB_VP_ERROR) || (peek_tok != COMMA_TOKEN)) { apply_production(s, 286); /* Dump the var_queue & assign types */ if (init_vars(s, var_queue, var_queue_size) == ARB_VP_ERROR) return ARB_VP_ERROR; } else { apply_production(s, 287); } break; /* productions 296-7 */ case NT_RESULT_COL_BINDING2_TOKEN: if ((input_tok == SEMICOLON_TOKEN) || (input_tok == COMMA_TOKEN)) { apply_production(s, 296); } else if (input_tok == PERIOD_TOKEN) { ret = peek_next_token(s, &peek_tok, &peek_tok_attr, 1); if ((peek_tok == ID_TOKEN) && ((!_mesa_strcmp((char *) s->idents.data[peek_tok_attr], "back")) || (!_mesa_strcmp((char *) s->idents.data[peek_tok_attr], "front")))) { apply_production(s, 297); } else { apply_production(s, 296); } } else { return ARB_VP_ERROR; } break; /* productions 300-1 */ case NT_RESULT_COL_BINDING4_TOKEN: if ((input_tok == SEMICOLON_TOKEN) || (input_tok == COMMA_TOKEN)) { apply_production(s, 300); } else if (input_tok == PERIOD_TOKEN) { ret = peek_next_token(s, &peek_tok, &peek_tok_attr, 1); if ((ret == ARB_VP_SUCESS) && (peek_tok == ID_TOKEN) && ((!_mesa_strcmp((char *) s->idents.data[peek_tok_attr], "primary")) || (!_mesa_strcmp((char *) s->idents.data[peek_tok_attr], "secondary")))) { apply_production(s, 301); } else { apply_production(s, 300); } } else { return ARB_VP_ERROR; } break; /* productions 306-7 */ case NT_OPT_COLOR_TYPE_TOKEN: if ((input_tok == SEMICOLON_TOKEN) || (input_tok == COMMA_TOKEN)) { apply_production(s, 307); } else if (input_tok == PERIOD_TOKEN) { ret = peek_next_token(s, &peek_tok, &peek_tok_attr, 1); if ((ret == ARB_VP_SUCESS) && (peek_tok == ID_TOKEN) && ((!_mesa_strcmp((char *) s->idents.data[peek_tok_attr], "primary")) || (!_mesa_strcmp((char *) s->idents.data[peek_tok_attr], "secondary")))) { apply_production(s, 306); } else { apply_production(s, 307); } } else { return ARB_VP_ERROR; } break; /* production 313 -- Do this so we can mangle IDs as they are * added into the ID table for the lex */ case NT_ALIAS_STATEMENT_TOKEN: if (input_tok == ALIAS_TOKEN) { GLint alias_to; apply_production(s, 313); /* stack ALIAS */ var_queue_size = 1; var_queue[0] = TYPE_ALIAS; ret = peek_next_token(s, &peek_tok, &peek_tok_attr, 1); var_queue[var_queue_size] = peek_tok_attr; var_queue_size++; if (init_vars(s, var_queue, var_queue_size) == ARB_VP_ERROR) return ARB_VP_ERROR; /* Now, peek ahead and see what we are aliasing _to_ */ alias_to = peek_tok_attr; ret = peek_next_token(s, &peek_tok, &peek_tok_attr, 3); if (ret == ARB_VP_SUCESS) { s->idents.attr[alias_to] = peek_tok_attr; } else return ARB_VP_ERROR; } else { return ARB_VP_ERROR; } break; /* productions 314 (ESTABLISH_NAME) duplicates are caught by the ID symbol table */ /* productions 315 */ case NT_ESTABLISHED_NAME_TOKEN: if (input_tok == ID_TOKEN) { if (s->idents.type[input_tok_attr] == TYPE_NONE) { printf("Trying to use variable %s before initializing!\n", s->idents.data[input_tok_attr]); return ARB_VP_ERROR; } else { apply_production(s, 315); } } else { return ARB_VP_ERROR; } break; /* productions 318-9 */ case NT_SWIZZLE_SUFFIX2_TOKEN: if (_mesa_strlen((char *) s->idents.data[input_tok_attr]) == 1) { apply_production(s, 318); } else if (_mesa_strlen((char *) s->idents.data[input_tok_attr]) == 4) { apply_production(s, 319); } else { return ARB_VP_ERROR; } break; /* 4-component swizzle mask -- this is a total hack */ #define IS_SWZ_CMP(foo) ((foo == 'x') || (foo == 'y') || (foo == 'z') || (foo == 'w')) case NT_COMPONENT4_TOKEN: { GLubyte *str = s->idents.data[input_tok_attr]; if (IS_SWZ_CMP(str[0]) && IS_SWZ_CMP(str[1]) && IS_SWZ_CMP(str[2]) && IS_SWZ_CMP(str[3])) { _stack_pop(s, &stack_tok, &stack_tok_attr, &ptn); /* _stack_push(s, input_tok, input_tok_attr, NULL);*/ ptn2 = parse_tree_node_init(); ptn2->tok = input_tok; ptn2->tok_attr = input_tok_attr; ptn2->is_terminal = 1; ptn->children[0] = ptn2; _stack_push(s, input_tok, input_tok_attr, ptn2); } else { return ARB_VP_ERROR; } } break; /* Handle general non-terminals using tables, and terminals */ default: is_nonterm = 0; for (la = 0; la < nlas; la++) { if (latab[la].lhs != stack_tok) continue; if (latab[la].la != input_tok) continue; if (input_tok == ID_TOKEN) { str_key = id_table_add(&s->idents, latab[la].la_kw, 0, _mesa_strlen(latab[la].la_kw)); if ((str_key != input_tok_attr) && (_mesa_strcmp(latab[la].la_kw, "-1"))) continue; } else if (input_tok == INTEGER_TOKEN) { if ((s->ints.data[input_tok_attr] != _mesa_atoi(latab[la].la_kw)) && (_mesa_atoi(latab[la].la_kw) != -1)) { continue; } } else if (input_tok == FLOAT_TOKEN) { if ((s->floats.data[input_tok_attr] != atof(latab[la].la_kw)) && (atof(latab[la].la_kw) != -1)) continue; } idx = latab[la].prod_idx; /* Here we stack identifiers onto the var_queue */ switch (idx) { /* setup ATTRIB */ case 120: var_queue_size = 1; var_queue[0] = TYPE_ATTRIB; ret = peek_next_token(s, &peek_tok, &peek_tok_attr, 1); var_queue[var_queue_size] = peek_tok_attr; var_queue_size++; if (init_vars(s, var_queue, var_queue_size) == ARB_VP_ERROR) return ARB_VP_ERROR; break; /* stack PARAM */ case 134: var_queue_size = 1; var_queue[0] = TYPE_PARAM; ret = peek_next_token(s, &peek_tok, &peek_tok_attr, 1); var_queue[var_queue_size] = peek_tok_attr; var_queue_size++; break; case 135: var_queue[0] = TYPE_PARAM_SINGLE; if (init_vars(s, var_queue, var_queue_size) == ARB_VP_ERROR) return ARB_VP_ERROR; break; case 136: var_queue[0] = TYPE_PARAM_ARRAY; if (init_vars(s, var_queue, var_queue_size) == ARB_VP_ERROR) return ARB_VP_ERROR; break; /* stack TEMP */ case 284: var_queue_size = 1; var_queue[0] = TYPE_TEMP; break; /* stack ADDRESS */ case 285: var_queue_size = 1; var_queue[0] = TYPE_ADDRESS; break; /* stack OUTPUT */ case 288: var_queue_size = 1; var_queue[0] = TYPE_OUTPUT; ret = peek_next_token(s, &peek_tok, &peek_tok_attr, 1); var_queue[var_queue_size] = peek_tok_attr; var_queue_size++; if (init_vars(s, var_queue, var_queue_size) == ARB_VP_ERROR) return ARB_VP_ERROR; break; /* stack opts for varNameList -- see above */ } /* finally.. we match! apply the production */ if ((idx < 0) || (idx >= nprods)) { fprintf(stderr, "Prod IDX of %d in look ahead table [%d] is horked!\n", idx, la); exit(1); } apply_production(s, idx); is_nonterm = 1; break; } if (!is_nonterm) { if ((stack_tok == EOF_TOKEN) && (s->stack_head == NULL)) return ARB_VP_SUCESS; if ((input_tok == stack_tok) || ((stack_tok == FLOAT_TOKEN) && (input_tok == INTEGER_TOKEN))) { /* XXX: Need to check values for int/id/GLfloat tokens here -- yes! */ _stack_pop(s, &stack_tok, &stack_tok_attr, &ptn); if ((ptn) && ((stack_tok == FLOAT_TOKEN) || (stack_tok == INTEGER_TOKEN) || (stack_tok == ID_TOKEN))) { ptn->is_terminal = 1; ptn->tok = input_tok; ptn->tok_attr = input_tok_attr; } if (get_next_token(s, &input_tok, &input_tok_attr) == ARB_VP_ERROR) { fprintf(stderr, "PARSE ERROR!!\n"); return ARB_VP_ERROR; } } else { fprintf(stderr, "PARSE ERROR!\n"); return ARB_VP_ERROR; } } break; } } return ARB_VP_SUCESS; } /** * Print out the parse tree from a given point. Just for debugging. * * \param s The parse state * \param ptn The root to start printing from */ static void print_parse_tree(parse_state * s, parse_tree_node * ptn) { GLint a; /* If we're terminal, prGLint and exit */ if (ptn->is_terminal) { debug_token(s, ptn->tok, ptn->tok_attr); printf("\n"); return; } /* Else, recurse on all our children */ for (a = 0; a < 4; a++) { if (!ptn->children[a]) return; print_parse_tree(s, ptn->children[a]); } } /** * Free all of the children of a given parse tree node. * * \param ptn The root node whose children we recursively free */ static void parse_tree_free_children(parse_tree_node * ptn) { GLint a; if (!ptn) return; if (!ptn->children[0]) return; for (a = 0; a < 4; a++) { if (ptn->children[a]) { parse_tree_free_children(ptn->children[a]); _mesa_free(ptn->children[a]); ptn->children[a] = NULL; } } } /** * Given the name of a matrix, and a modifier, expand into a binding type. * * names: 0 -- modelview * 1 -- projection * 2 -- mvp * 3 -- texture * 4 -- palette * 5 -- program * * mods: 0 -- normal * 1 -- inverse * 2 -- invtrans * 3 -- transpose * * \param name The number of the matrix type * \param mod The number of the matrix modifier * * \return The binding state corresponding to name & mod */ static GLint name_and_mod_to_matrixrows(GLint name, GLint mod) { switch (name) { case 0: /* modelview */ switch (mod) { case 0: return MATRIXROWS_MODELVIEW; case 1: return MATRIXROWS_MODELVIEW_INVERSE; case 2: return MATRIXROWS_MODELVIEW_INVTRANS; case 3: return MATRIXROWS_MODELVIEW_TRANSPOSE; } break; case 1: /* projection */ switch (mod) { case 0: return MATRIXROWS_PROJECTION; case 1: return MATRIXROWS_PROJECTION_INVERSE; case 2: return MATRIXROWS_PROJECTION_INVTRANS; case 3: return MATRIXROWS_PROJECTION_TRANSPOSE; } break; case 2: /* mvp */ switch (mod) { case 0: return MATRIXROWS_MVP; case 1: return MATRIXROWS_MVP_INVERSE; case 2: return MATRIXROWS_MVP_INVTRANS; case 3: return MATRIXROWS_MVP_TRANSPOSE; } break; case 3: /* texture */ switch (mod) { case 0: return MATRIXROWS_TEXTURE; case 1: return MATRIXROWS_TEXTURE_INVERSE; case 2: return MATRIXROWS_TEXTURE_INVTRANS; case 3: return MATRIXROWS_TEXTURE_TRANSPOSE; } break; case 4: /* palette */ switch (mod) { case 0: return MATRIXROWS_PALETTE; case 1: return MATRIXROWS_PALETTE_INVERSE; case 2: return MATRIXROWS_PALETTE_INVTRANS; case 3: return MATRIXROWS_PALETTE_TRANSPOSE; } break; case 5: /* program */ switch (mod) { case 0: return MATRIXROWS_PROGRAM; case 1: return MATRIXROWS_PROGRAM_INVERSE; case 2: return MATRIXROWS_PROGRAM_INVTRANS; case 3: return MATRIXROWS_PROGRAM_TRANSPOSE; } break; } return 0; } /** * This takes a node in the parse tree for an OPTIONAL_MASK token * being derived into a write mask for a register. * * This will expand the production number into a 4-component * write mask. * * \param mask_node The parse tree node for the optional_mask non-termina * \param mask 4-component write mask */ static void get_optional_mask(parse_tree_node * mask_node, GLint * mask) { if (mask_node->prod_applied == 97) { switch (mask_node->children[0]->prod_applied) { case 99: /* x */ mask[0] = 1; mask[1] = 0; mask[2] = 0; mask[3] = 0; break; case 100: /* y */ mask[0] = 0; mask[1] = 1; mask[2] = 0; mask[3] = 0; break; case 101: /* xy */ mask[0] = 1; mask[1] = 1; mask[2] = 0; mask[3] = 0; break; case 102: /* z */ mask[0] = 0; mask[1] = 0; mask[2] = 1; mask[3] = 0; break; case 103: /* xz */ mask[0] = 1; mask[1] = 0; mask[2] = 1; mask[3] = 0; break; case 104: /* yz */ mask[0] = 0; mask[1] = 1; mask[2] = 1; mask[3] = 0; break; case 105: /* xyz */ mask[0] = 1; mask[1] = 1; mask[2] = 1; mask[3] = 0; break; case 106: /* w */ mask[0] = 0; mask[1] = 0; mask[2] = 0; mask[3] = 1; break; case 107: /* xw */ mask[0] = 1; mask[1] = 0; mask[2] = 0; mask[3] = 1; break; case 108: /* yw */ mask[0] = 0; mask[1] = 1; mask[2] = 0; mask[3] = 1; break; case 109: /* xyw */ mask[0] = 1; mask[1] = 1; mask[2] = 0; mask[3] = 1; break; case 110: /* zw */ mask[0] = 0; mask[1] = 0; mask[2] = 1; mask[3] = 1; break; case 111: /* xzw */ mask[0] = 1; mask[1] = 0; mask[2] = 1; mask[3] = 1; break; case 112: /* yzw */ mask[0] = 0; mask[1] = 1; mask[2] = 1; mask[3] = 1; break; case 113: /* xyzw */ mask[0] = 1; mask[1] = 1; mask[2] = 1; mask[3] = 1; break; } } } /** * Given a MASKED_DST_REG token in a parse tree node, figure out what * register number and write mask the production results in. * * \param s The parse state * \param mdr The parse tree node * \param dest The destination register number * \param dest_mask The 4-component write mask */ static void get_masked_dst_reg(parse_state * s, parse_tree_node * mdr, GLint * dest, GLint * dest_mask) { GLint a; /* dest is a TEMP variable */ if (mdr->children[0]->prod_applied == 67) { a = mdr->children[0]->children[0]->children[0]->children[0]->tok_attr; *dest = s->binds.reg_num[s->idents.attr[a]]; printf("dst reg: %d (%s)\n", *dest, s->idents.data[a]); } else { /* dest is a result variable */ if (mdr->children[0]->children[0]->prod_applied == 86) { a = mdr->children[0]->children[0]->children[0]->children[0]-> tok_attr; *dest = s->binds.reg_num[s->idents.attr[a]]; printf("dest reg: %d (%s)\n", *dest, s->idents.data[a]); } /* dest is an implicit binding to result/output state */ else { a = mdr->children[0]->children[0]->children[0]->tok_attr; *dest = s->binds.reg_num[a]; printf("dst: %d\n", *dest); } } /* mdr->children[1] is the write mask */ get_optional_mask(mdr->children[1], dest_mask); } /** * Given a parse tree node with a swizzled src token, figure out the swizzle * mask. * * \param s The parse state * \param ssr The parse tree node * \param swz The 4-component swizzle, 0 - x, 1 - y, 2 - z, 3 - w */ static void get_src_swizzle(parse_state * s, parse_tree_node * ssr, GLint * swz) { GLint a; GLubyte *c; if (ssr->prod_applied == 317) { if (ssr->children[0]->prod_applied == 318) { /* single component */ switch (ssr->children[0]->children[0]->prod_applied) { case 93: /* x */ for (a = 0; a < 4; a++) swz[a] = 0; break; case 94: /* y */ for (a = 0; a < 4; a++) swz[a] = 1; break; case 95: /* z */ for (a = 0; a < 4; a++) swz[a] = 2; break; case 96: /* w */ for (a = 0; a < 4; a++) swz[a] = 3; break; } } else { /* 4-component */ c = s->idents.data[ssr->children[0]->children[0]->children[0]-> tok_attr]; for (a = 0; a < 4; a++) { switch (c[a]) { case 'x': swz[a] = 0; break; case 'y': swz[a] = 1; break; case 'z': swz[a] = 2; break; case 'w': swz[a] = 3; break; } } } } } /** * Given a parse tree node for a src register with an optional sign, figure out * what register the src maps to, and what the sign is * * \param s The parse state * \param ssr The parse tree node to work from * \param sign The sign (1 or -1) * \param ssrc The src register number */ static void get_optional_sign_and_src_reg(parse_state * s, parse_tree_node * ssr, int *sign, int *ssrc) { GLint a; /* ssr->children[0] is the optionalSign */ if (ssr->children[0]->prod_applied == 282) { /* - */ *sign = -1; } /* ssr->children[1] is the srcReg */ /* The src is a vertex attrib */ if (ssr->children[1]->prod_applied == 64) { if (ssr->children[1]->children[0]->prod_applied == 69) { /* variable */ a = ssr->children[1]->children[0]->children[0]->children[0]-> tok_attr; *ssrc = s->binds.reg_num[s->idents.attr[a]]; printf("src reg: %d (%s)\n", *ssrc, s->idents.data[a]); } else { /* implicit binding */ a = ssr->children[1]->children[0]->children[0]->tok_attr; *ssrc = s->binds.reg_num[a]; printf("src reg: %d %d (implicit binding)\n", *ssrc, s->binds.type[a]); } } else /* The src is a temp variable */ if (ssr->children[1]->prod_applied == 65) { a = ssr->children[1]->children[0]->children[0]->children[0]->tok_attr; *ssrc = s->binds.reg_num[s->idents.attr[a]]; printf("src reg: %d (%s)\n", *ssrc, s->idents.data[a]); } /* The src is a param */ else { /* We have a single item */ if (ssr->children[1]->children[0]->prod_applied == 72) { a = ssr->children[1]->children[0]->children[0]->children[0]-> children[0]->tok_attr; *ssrc = s->binds.reg_num[s->idents.attr[a]]; printf("src reg: %d (%s)\n", *ssrc, s->idents.data[a]); } else /* We have an array of items */ if (ssr->children[1]->children[0]->prod_applied == 73) { a = ssr->children[1]->children[0]->children[0]->children[0]-> children[0]->tok_attr; *ssrc = s->binds.reg_num[s->idents.attr[a]]; /* We have an absolute offset into the array */ if (ssr->children[1]->children[0]->children[1]->prod_applied == 77) { /* Ok, are array will be layed out fully in registers, so we can compute the reg */ printf("array base: %s\n", s->idents.data[a]); a = ssr->children[1]->children[0]->children[1]->children[0]-> children[0]->tok_attr; printf("array absolute offset: %d\n", s->ints.data[a]); *ssrc += s->ints.data[a]; } /* Otherwise, we have to grab the offset register */ else { /* progParamArrayRel */ /* XXX: We don't know the offset, so we have to grab the offset register # */ } } /* Otherwise, we have an implicit binding */ else { /* paramSingleItemUse */ if (ssr->children[1]->children[0]->children[0]->prod_applied == 148) { /* programSingleItem */ a = ssr->children[1]->children[0]->children[0]->children[0]-> tok_attr; } else { a = ssr->children[1]->children[0]->children[0]->children[0]-> children[0]->tok_attr; } *ssrc = s->binds.reg_num[a]; printf("src reg: %d %d (implicit binding)\n", *ssrc, s->binds.type[a]); } } } /** * Figure out what register a src reg is in, as well as the swizzle mask and the * sign * * \param s The parse state * \param ssr The swizzeled src reg parse tree node * \param sign The return value for the sign {1, -1} * \param ssrc The return value for the register number * \param swz The 4-component swizzle mask */ static void get_swizzle_src_reg(parse_state * s, parse_tree_node * ssr, GLint * sign, GLint * ssrc, GLint * swz) { get_optional_sign_and_src_reg(s, ssr, sign, ssrc); /* ssr->children[2] is the swizzleSuffix */ get_src_swizzle(s, ssr->children[2], swz); } /** * Just like get_swizzle_src_reg, but find the scalar value to use from the register instead * of the swizzle mask * * \param s The parse state * \param ssr The swizzeled src reg parse tree node * \param sign The return value for the sign {1, -1} * \param ssrc The return value for the register number * \param scalar The 1-component scalar number */ static void get_scalar_src_reg(parse_state * s, parse_tree_node * ssr, GLint * sign, GLint * ssrc, GLint * scalar) { get_optional_sign_and_src_reg(s, ssr, sign, ssrc); /* sn->children[2] is a scalarSuffix */ switch (ssr->children[2]->children[0]->prod_applied) { case 93: *scalar = 0; break; case 94: *scalar = 1; break; case 95: *scalar = 2; break; case 96: *scalar = 3; break; } } /** * Recursivly traverse the parse tree and generate Mesa opcodes * * \param s The parse state * \param ptn The parse tree node to process */ static void parse_tree_generate_opcodes(parse_state * s, parse_tree_node * ptn) { GLint a; GLint opcode, dst, src[3]; GLint dst_mask[4], src_swz[3][4], src_scalar[2], src_sign[3]; parse_tree_node *dn, *sn[3]; src_sign[0] = src_sign[1] = src_sign[2] = 1; for (a = 0; a < 4; a++) { src_swz[0][a] = a; src_swz[1][a] = a; src_swz[2][a] = a; } src_scalar[0] = src_scalar[1] = src_scalar[2] = 0; dst_mask[0] = dst_mask[1] = dst_mask[2] = dst_mask[3] = 1; switch (ptn->prod_applied) { case 17: /* ARL */ opcode = VP_OPCODE_ARL; dn = ptn->children[0]; sn[0] = ptn->children[1]; /* dn is a maskedAddrReg */ /* dn->children[0] is an addrReg */ /* dn->children[1] is an addrWriteMask */ /* XXX: do this.. */ break; case 18: /* VECTORop */ switch (ptn->children[0]->prod_applied) { case 19: /* ABS */ opcode = VP_OPCODE_ABS; break; case 20: /* FLR */ opcode = VP_OPCODE_FLR; break; case 21: /* FRC */ opcode = VP_OPCODE_FRC; break; case 22: /* LIT */ opcode = VP_OPCODE_LIT; break; case 23: /* MOV */ opcode = VP_OPCODE_MOV; break; } printf("opcode: %d\n", opcode); /* dn is a maskedDstReg */ dn = ptn->children[1]; /* sn is a swizzleSrcReg */ sn[0] = ptn->children[2]; get_masked_dst_reg(s, dn, &dst, dst_mask); printf("dst: %d mask: %d %d %d %d\n", dst, dst_mask[0], dst_mask[1], dst_mask[2], dst_mask[3]); get_swizzle_src_reg(s, sn[0], &src_sign[0], &src[0], src_swz[0]); printf("src sign: %d reg: %d swz: %d %d %d %d\n", src_sign[0], src[0], src_swz[0][0], src_swz[0][1], src_swz[0][2], src_swz[0][3]); break; case 24: /* SCALARop */ switch (ptn->children[0]->prod_applied) { case 25: /* EX2 */ opcode = VP_OPCODE_EX2; break; case 26: /* EXP */ opcode = VP_OPCODE_EXP; break; case 27: /* LG2 */ opcode = VP_OPCODE_LG2; break; case 28: /* LOG */ opcode = VP_OPCODE_LOG; break; case 29: /* RCP */ opcode = VP_OPCODE_RCP; break; case 30: /* RSQ */ opcode = VP_OPCODE_RSQ; break; } printf("opcode: %d\n", opcode); /* dn is a maskedDstReg */ dn = ptn->children[1]; get_masked_dst_reg(s, dn, &dst, dst_mask); printf("dst: %d mask: %d %d %d %d\n", dst, dst_mask[0], dst_mask[1], dst_mask[2], dst_mask[3]); /* sn is a scalarSrcReg */ sn[0] = ptn->children[2]; get_scalar_src_reg(s, sn[0], &src_sign[0], &src[0], &src_scalar[0]); printf("src sign: %d reg: %d scalar: %d\n", src_sign[0], src[0], src_scalar[0]); break; case 31: /* BINSC */ opcode = VP_OPCODE_POW; printf("opcode: %d\n", opcode); /* maskedDstReg */ dn = ptn->children[1]; get_masked_dst_reg(s, dn, &dst, dst_mask); printf("dst: %d mask: %d %d %d %d\n", dst, dst_mask[0], dst_mask[1], dst_mask[2], dst_mask[3]); /* sn are scalarSrcReg's */ sn[0] = ptn->children[2]->children[0]; sn[1] = ptn->children[2]->children[1]; get_scalar_src_reg(s, sn[0], &src_sign[0], &src[0], &src_scalar[0]); get_scalar_src_reg(s, sn[1], &src_sign[1], &src[1], &src_scalar[1]); printf("src0 sign: %d reg: %d scalar: %d\n", src_sign[0], src[0], src_scalar[0]); printf("src1 sign: %d reg: %d scalar: %d\n", src_sign[1], src[1], src_scalar[1]); break; case 34: /* BIN */ switch (ptn->children[0]->prod_applied) { case 36: /* ADD */ opcode = VP_OPCODE_ADD; break; case 37: /* DP3 */ opcode = VP_OPCODE_DP3; break; case 38: /* DP4 */ opcode = VP_OPCODE_DP4; break; case 39: /* DPH */ opcode = VP_OPCODE_DPH; break; case 40: /* DST */ opcode = VP_OPCODE_DST; break; case 41: /* MAX */ opcode = VP_OPCODE_MAX; break; case 42: /* MIN */ opcode = VP_OPCODE_MIN; break; case 43: /* MUL */ opcode = VP_OPCODE_MUL; break; case 44: /* SGE */ opcode = VP_OPCODE_SGE; break; case 45: /* SLT */ opcode = VP_OPCODE_SLT; break; case 46: /* SUB */ opcode = VP_OPCODE_SUB; break; case 47: /* XPD */ opcode = VP_OPCODE_XPD; break; } printf("opcode: %d\n", opcode); /* maskedDstReg */ dn = ptn->children[1]; get_masked_dst_reg(s, dn, &dst, dst_mask); printf("dst: %d mask: %d %d %d %d\n", dst, dst_mask[0], dst_mask[1], dst_mask[2], dst_mask[3]); /* sn are scalarSrcReg's */ sn[0] = ptn->children[2]->children[0]; sn[1] = ptn->children[2]->children[1]; get_swizzle_src_reg(s, sn[0], &src_sign[0], &src[0], src_swz[0]); get_swizzle_src_reg(s, sn[1], &src_sign[1], &src[1], src_swz[1]); printf("src0 sign: %d reg: %d swz: %d %d %d %d\n", src_sign[0], src[0], src_swz[0][0], src_swz[0][1], src_swz[0][2], src_swz[0][3]); printf("src1 sign: %d reg: %d swz: %d %d %d %d\n", src_sign[1], src[1], src_swz[1][0], src_swz[1][1], src_swz[1][2], src_swz[1][3]); break; case 48: /* TRI */ opcode = VP_OPCODE_MAD; printf("opcode: %d\n", opcode); /* maskedDstReg */ dn = ptn->children[1]; get_masked_dst_reg(s, dn, &dst, dst_mask); printf("dst: %d mask: %d %d %d %d\n", dst, dst_mask[0], dst_mask[1], dst_mask[2], dst_mask[3]); /* sn are scalarSrcReg's */ sn[0] = ptn->children[2]->children[0]; sn[1] = ptn->children[2]->children[1]->children[0]; sn[2] = ptn->children[2]->children[1]->children[1]; get_swizzle_src_reg(s, sn[0], &src_sign[0], &src[0], src_swz[0]); get_swizzle_src_reg(s, sn[1], &src_sign[1], &src[1], src_swz[1]); get_swizzle_src_reg(s, sn[2], &src_sign[2], &src[2], src_swz[2]); printf("src0 sign: %d reg: %d swz: %d %d %d %d\n", src_sign[0], src[0], src_swz[0][0], src_swz[0][1], src_swz[0][2], src_swz[0][3]); printf("src1 sign: %d reg: %d swz: %d %d %d %d\n", src_sign[1], src[1], src_swz[1][0], src_swz[1][1], src_swz[1][2], src_swz[1][3]); printf("src2 sign: %d reg: %d swz: %d %d %d %d\n", src_sign[2], src[2], src_swz[2][0], src_swz[2][1], src_swz[2][2], src_swz[2][3]); } for (a = 0; a < 4; a++) { if (!ptn->children[a]) return; parse_tree_generate_opcodes(s, ptn->children[a]); } } /** * When we go to examine the parse tree to generate opcodes, things are not exactly pretty to deal with. * Parameters, constants, matricies, attribute bindings, and the like are represented by large numbers * of nodes. * * In order to keep the code generation code cleaner, we make a recursive pass over the parse tree and 'roll up' these deep * derivations of the attribs, and replace them with a single token, BINDING_TOKEN. The token attribute for * BINDING_TOKEN is a index in the 'binding table' where all the relavant info on the chunk of state is stored, * e.g its type. * * For example, the string 'vertex.color.secondary' is represented by 4 productions, and 4 nodes in the parse * tree. The token at the root of this derivation is NT_VTX_ATTRIB_BINDING_TOKEN. After this folding, * the token at the root is BINDING_TOKEN, and s->binds[token_attr_at_the_root].type = ATTRIB_COLOR_SECONDARY. * * \param s The parse state * \param ptn The root parse tree node to start folding bindings */ static void parse_tree_fold_bindings(parse_state * s, parse_tree_node * ptn) { GLint a, b; GLint eat_children, bind_type, bind_idx, bind_row, bind_nrows; GLfloat bind_vals[4]; parse_tree_node *ptmp; eat_children = 0; bind_row = 0; bind_nrows = 1; bind_vals[0] = bind_vals[1] = bind_vals[2] = bind_vals[3] = 0.0f; switch (ptn->prod_applied) { /* vertex */ case 121: eat_children = 1; bind_idx = 0; switch (ptn->children[0]->prod_applied) { case 122: /* position */ bind_type = ATTRIB_POSITION; break; case 123: /* weight */ bind_type = ATTRIB_WEIGHT; if (ptn->children[0]->children[0]->prod_applied == 132) { bind_idx = s->ints.data[ptn->children[0]->children[0]->children[0]-> children[0]->tok_attr]; } break; case 124: /* normal */ bind_type = ATTRIB_NORMAL; break; case 125: /* color */ bind_type = ATTRIB_COLOR_PRIMARY; if (ptn->children[0]->children[0]->prod_applied == 306) { if (ptn->children[0]->children[0]->children[0]->prod_applied == 309) bind_type = ATTRIB_COLOR_SECONDARY; } break; case 126: /* fogcoord */ bind_type = ATTRIB_FOGCOORD; break; case 127: /* texcoord */ bind_type = ATTRIB_TEXCOORD; if (ptn->children[0]->children[0]->prod_applied == 311) { bind_idx = s->ints.data[ptn->children[0]->children[0]->children[0]-> children[0]->tok_attr]; } break; case 128: /* matrixindex */ bind_type = ATTRIB_MATRIXINDEX; bind_idx = s->ints.data[ptn->children[0]->children[0]->children[0]-> tok_attr]; break; case 129: /* attrib */ bind_type = ATTRIB_ATTRIB; bind_idx = s->ints.data[ptn->children[0]->children[0]->children[0]-> tok_attr]; break; } break; /* state */ case 154: case 172: /* material */ eat_children = 2; bind_idx = 0; ptmp = ptn->children[0]->children[0]; a = 0; if (ptmp->prod_applied == 182) { a = 1; b = 0; } else if ((ptmp->prod_applied == 183) && (ptmp->children[0]->prod_applied == 305)) { a = 1; b = 1; } /* no explicit face, or explicit front */ if (a) { switch (ptmp->children[b]->prod_applied) { case 184: /* ambient */ bind_type = MATERIAL_FRONT_AMBIENT; break; case 185: /* diffuse */ bind_type = MATERIAL_FRONT_DIFFUSE; break; case 186: /* specular */ bind_type = MATERIAL_FRONT_SPECULAR; break; case 187: /* emission */ bind_type = MATERIAL_FRONT_EMISSION; break; case 188: /* shininess */ bind_type = MATERIAL_FRONT_SHININESS; break; } } /* has explicit back face */ else { switch (ptmp->children[1]->prod_applied) { case 184: /* ambient */ bind_type = MATERIAL_BACK_AMBIENT; break; case 185: /* diffuse */ bind_type = MATERIAL_BACK_DIFFUSE; break; case 186: /* specular */ bind_type = MATERIAL_BACK_SPECULAR; break; case 187: /* emission */ bind_type = MATERIAL_BACK_EMISSION; break; case 188: /* shininess */ bind_type = MATERIAL_BACK_SHININESS; break; } } break; case 155: case 173: /* light */ eat_children = 2; bind_idx = 0; printf("FOLDING LIGHT!\n"); ptmp = ptn->children[0]; bind_idx = s->ints.data[ptmp->children[0]->children[0]->tok_attr]; switch (ptmp->children[1]->children[0]->prod_applied) { case 191: /* ambient */ bind_type = LIGHT_AMBIENT; break; case 192: /* diffuse */ bind_type = LIGHT_DIFFUSE; break; case 193: /* specular */ bind_type = LIGHT_SPECULAR; break; case 194: /* position */ bind_type = LIGHT_POSITION; break; case 195: /* attenuation */ bind_type = LIGHT_ATTENUATION; break; case 196: /* spot */ bind_type = LIGHT_SPOT_DIRECTION; break; case 197: /* half */ bind_type = LIGHT_HALF; break; } break; case 156: case 174: /* lightmodel */ eat_children = 2; bind_idx = 0; ptmp = ptn->children[0]; switch (ptmp->prod_applied) { case 201: /* ambient */ bind_type = LIGHTMODEL_AMBIENT; break; case 202: /* scenecolor */ bind_type = LIGHTMODEL_FRONT_SCENECOLOR; break; case 203: /* foo.scenecolor */ if (ptmp->children[0]->prod_applied == 304) bind_type = LIGHTMODEL_FRONT_SCENECOLOR; else bind_type = LIGHTMODEL_BACK_SCENECOLOR; } break; case 157: case 175: /* lightprod */ eat_children = 2; bind_idx = 0; ptmp = ptn->children[0]; bind_idx = s->ints.data[ptmp->children[0]->children[0]->tok_attr]; /* No explicit face */ if (ptmp->children[1]->children[0]->prod_applied == 206) { a = 1; /* front */ b = 0; /* 0-th child */ } else if ((ptmp->children[1]->children[0]->prod_applied == 207) && (ptmp->children[1]->children[0]->children[0]->prod_applied == 304)) { a = 1; /* front */ b = 1; /* 1-th child */ } else { a = 0; b = 1; } if (a) { switch (ptmp->children[1]->children[0]->children[b]->prod_applied) { case 208: /* ambient */ bind_type = LIGHTPROD_FRONT_AMBIENT; break; case 209: /* diffuse */ bind_type = LIGHTPROD_FRONT_DIFFUSE; break; case 210: /* specular */ bind_type = LIGHTPROD_FRONT_SPECULAR; break; } } else { switch (ptmp->children[1]->children[0]->children[b]->prod_applied) { case 208: /* ambient */ bind_type = LIGHTPROD_BACK_AMBIENT; break; case 209: /* diffuse */ bind_type = LIGHTPROD_BACK_DIFFUSE; break; case 210: /* specular */ bind_type = LIGHTPROD_BACK_SPECULAR; break; } } break; case 158: case 176: /* texgen */ eat_children = 2; bind_idx = 0; ptmp = ptn->children[0]; if (ptmp->children[0]->prod_applied == 311) bind_idx = s->ints.data[ptmp->children[0]->children[0]->children[0]-> tok_attr]; ptmp = ptn->children[0]->children[1]; if (ptmp->children[0]->prod_applied == 214) a = 1; /* eye */ else a = 0; /* object */ b = ptmp->children[1]->prod_applied - 216; if (a == 1) { switch (b) { case 0: bind_type = TEXGEN_EYE_S; break; case 1: bind_type = TEXGEN_EYE_T; break; case 2: bind_type = TEXGEN_EYE_R; break; case 3: bind_type = TEXGEN_EYE_Q; break; } } else { switch (b) { case 0: bind_type = TEXGEN_OBJECT_S; break; case 1: bind_type = TEXGEN_OBJECT_T; break; case 2: bind_type = TEXGEN_OBJECT_R; break; case 3: bind_type = TEXGEN_OBJECT_Q; break; } } break; case 159: case 177: /* fog */ eat_children = 2; bind_idx = 0; ptmp = ptn->children[0]; if (ptmp->children[0]->prod_applied == 221) bind_type = FOG_COLOR; else bind_type = FOG_PARAMS; break; case 160: case 178: /* clip */ eat_children = 2; bind_idx = 0; ptmp = ptn->children[0]; bind_idx = s->ints.data[ptmp->children[0]->children[0]->tok_attr]; bind_type = CLIP_PLANE; break; case 161: case 179: /* point */ eat_children = 2; bind_idx = 0; ptmp = ptn->children[0]; if (ptmp->children[0]->prod_applied == 227) bind_type = POINT_SIZE; else bind_type = POINT_ATTENUATION; break; case 162: /* matrix rows/whole matrix */ eat_children = 2; bind_idx = 0; { parse_tree_node *mname; GLint mod = 0; GLint name = 0; mname = ptn->children[0]; switch (mname->prod_applied) { case 238: /* modelview */ name = 0; if (mname->children[0]->prod_applied == 245) bind_idx = s->ints.data[mname->children[0]->children[0]->children[0]-> tok_attr]; break; case 239: /* projection */ name = 1; break; case 240: /* mvp */ name = 2; break; case 241: /* texture */ if (mname->children[0]->prod_applied == 311) bind_idx = s->ints.data[mname->children[0]->children[0]->children[0]-> tok_attr]; name = 3; break; case 242: /* palette */ bind_idx = s->ints.data[mname->children[0]->children[0]->tok_attr]; name = 4; break; case 243: /* program */ bind_idx = s->ints.data[mname->children[0]->children[0]->tok_attr]; name = 5; break; } ptmp = ptn->children[1]; if (ptmp->prod_applied == 316) { bind_type = name_and_mod_to_matrixrows(name, mod); bind_row = 0; bind_nrows = 4; } else { if (ptmp->children[0]->prod_applied == 164) { switch (ptmp->children[0]->children[0]->prod_applied) { case 234: /* inverse */ mod = 1; break; case 235: /* transpose */ mod = 3; break; case 236: /* invtrans */ mod = 2; break; } if (ptmp->children[0]->children[1]->prod_applied == 166) { bind_type = name_and_mod_to_matrixrows(name, mod); bind_row = 0; bind_nrows = 4; } else { /* prod 167 */ bind_type = name_and_mod_to_matrixrows(name, mod); bind_row = s->ints.data[ptmp->children[0]->children[1]-> children[0]->children[0]->children[0]-> tok_attr]; if (ptmp->children[0]->children[1]->children[0]-> children[1]->prod_applied == 169) bind_nrows = 1; else { bind_nrows = s->ints.data[ptmp->children[0]->children[1]-> children[0]->children[1]->children[0]-> children[0]->tok_attr] - bind_row + 1; } } } else { /* prod 165 */ bind_type = name_and_mod_to_matrixrows(name, mod); bind_row = s->ints.data[ptmp->children[0]->children[0]->children[0]-> tok_attr]; if (ptmp->children[0]->children[1]->prod_applied == 169) bind_nrows = 1; else bind_nrows = s->ints.data[ptmp->children[0]->children[1]-> children[0]->children[0]->tok_attr] - bind_row + 1; } } } printf("folding matrixrows: %d %d %d %d\n", bind_type, bind_idx, bind_row, bind_nrows); break; case 180: /* matrix row */ eat_children = 2; bind_idx = 0; { GLint mod; parse_tree_node *mname, *mrow; ptmp = ptn->children[0]; mname = ptmp->children[0]; mod = 0; if (ptmp->children[1]->children[0]->prod_applied == 232) { mrow = ptmp->children[1]->children[0]->children[1]->children[0]-> children[0]; switch (ptmp->children[1]->children[0]->children[0]->prod_applied) { case 234: mod = 1; /* inverse */ break; case 235: mod = 2; /* transpose */ break; case 236: mod = 3; /* invtrans */ break; } } else { mrow = ptmp->children[1]->children[0]->children[0]->children[0]; } bind_row = s->ints.data[mrow->tok_attr]; switch (mname->prod_applied) { case 238: /* modelview */ if (mname->children[0]->prod_applied == 245) { bind_idx = s->ints.data[mname->children[0]->children[0]->children[0]-> tok_attr]; } switch (mod) { case 0: bind_type = MATRIXROW_MODELVIEW; break; case 1: bind_type = MATRIXROW_MODELVIEW_INVERSE; break; case 2: bind_type = MATRIXROW_MODELVIEW_TRANSPOSE; break; case 3: bind_type = MATRIXROW_MODELVIEW_INVTRANS; } break; case 239: /* projection */ switch (mod) { case 0: bind_type = MATRIXROW_PROJECTION; break; case 1: bind_type = MATRIXROW_PROJECTION_INVERSE; break; case 2: bind_type = MATRIXROW_PROJECTION_TRANSPOSE; break; case 3: bind_type = MATRIXROW_PROJECTION_INVTRANS; } break; case 240: /* mvp */ switch (mod) { case 0: bind_type = MATRIXROW_MVP; break; case 1: bind_type = MATRIXROW_MVP_INVERSE; break; case 2: bind_type = MATRIXROW_MVP_TRANSPOSE; break; case 3: bind_type = MATRIXROW_MVP_INVTRANS; } break; case 241: /* texture */ if (mname->children[0]->prod_applied == 311) { bind_idx = s->ints.data[mname->children[0]->children[0]->children[0]-> tok_attr]; } switch (mod) { case 0: bind_type = MATRIXROW_TEXTURE; break; case 1: bind_type = MATRIXROW_TEXTURE_INVERSE; break; case 2: bind_type = MATRIXROW_TEXTURE_TRANSPOSE; break; case 3: bind_type = MATRIXROW_TEXTURE_INVTRANS; } break; case 242: /* palette */ bind_idx = s->ints.data[mname->children[0]->children[0]->tok_attr]; switch (mod) { case 0: bind_type = MATRIXROW_PALETTE; break; case 1: bind_type = MATRIXROW_PALETTE_INVERSE; break; case 2: bind_type = MATRIXROW_PALETTE_TRANSPOSE; break; case 3: bind_type = MATRIXROW_PALETTE_INVTRANS; } break; case 243: /* program */ bind_idx = s->ints.data[mname->children[0]->children[0]->tok_attr]; switch (mod) { case 0: bind_type = MATRIXROW_PROGRAM; break; case 1: bind_type = MATRIXROW_PROGRAM_INVERSE; break; case 2: bind_type = MATRIXROW_PROGRAM_TRANSPOSE; break; case 3: bind_type = MATRIXROW_PROGRAM_INVTRANS; } break; } } break; /* program (single) */ case 249: eat_children = 1; bind_idx = 0; switch (ptn->children[0]->prod_applied) { case 250: /* env */ bind_type = PROGRAM_ENV_SINGLE; break; case 251: /* local */ bind_type = PROGRAM_LOCAL_SINGLE; break; } bind_idx = s->ints.data[ptn->children[0]->children[0]->children[0]-> children[0]->tok_attr]; break; /* program (multi) */ case 252: eat_children = 1; bind_idx = 0; switch (ptn->children[0]->prod_applied) { case 253: /* env */ case 254: /* local */ if (ptn->children[0]->prod_applied == 253) bind_type = PROGRAM_ENV_MULTI; else bind_type = PROGRAM_LOCAL_MULTI; ptmp = ptn->children[0]->children[0]->children[0]; bind_idx = bind_row = s->ints.data[ptmp->children[0]->children[0]->tok_attr]; bind_nrows = 1; ptmp = ptn->children[0]->children[0]->children[0]->children[1]; if ((ptmp->prod_applied == 257) || (ptmp->prod_applied == 262)) bind_nrows = s->ints.data[ptmp->children[0]->children[0]->tok_attr] - bind_idx; break; } break; #define FOLD_FLOAT_CONSTANT(float_ptr, bind_vals_idx, sign) \ if (float_ptr->tok == 49) /* GLfloat */ {\ bind_vals[bind_vals_idx] = sign * (GLfloat) s->floats.data[float_ptr->tok_attr];\ }\ else /* GLint */ {\ bind_vals[bind_vals_idx] = sign * s->ints.data[float_ptr->tok_attr];\ } #define FOLD_SIGNED_FLOAT_CONSTANT(sf_ptr, bind_vals_idx) \ {\ GLfloat __mul = 1.0F;\ if (sf_ptr->children[0]->prod_applied == 282) \ __mul = -1.0F;\ FOLD_FLOAT_CONSTANT(sf_ptr->children[1], bind_vals_idx, __mul);\ } /* const scalar decl */ case 271: eat_children = 1; bind_idx = 0; bind_type = CONSTANT; FOLD_SIGNED_FLOAT_CONSTANT(ptn->children[0], 0); #if 0 { GLfloat mul = 1.; if (ptn->children[0]->children[0]->prod_applied == 282) { mul = -1; } FOLD_FLOAT_CONSTANT(ptn->children[0]->children[1], 0, mul); } #endif break; /* const vector */ case 273: eat_children = 1; bind_idx = 0; bind_type = CONSTANT; FOLD_SIGNED_FLOAT_CONSTANT(ptn->children[0], 0); if (ptn->children[1]->prod_applied == 275) { FOLD_SIGNED_FLOAT_CONSTANT(ptn->children[1]->children[0], 1); if (ptn->children[1]->children[1]->prod_applied == 277) { FOLD_SIGNED_FLOAT_CONSTANT(ptn->children[1]->children[1]-> children[0], 2); if (ptn->children[1]->children[1]->children[1]->prod_applied == 279) { FOLD_SIGNED_FLOAT_CONSTANT(ptn->children[1]->children[1]-> children[1]->children[0], 3); } } } break; /* result */ case 289: eat_children = 1; bind_idx = 0; switch (ptn->children[0]->prod_applied) { case 290: /* position */ bind_type = RESULT_POSITION; break; case 291: /* fogcoord */ bind_type = RESULT_FOGCOORD; break; case 292: /* pointsize */ bind_type = RESULT_POINTSIZE; break; case 293: /* color */ bind_type = RESULT_COLOR_FRONT_PRIMARY; ptmp = ptn->children[0]->children[0]->children[0]; if (ptmp->prod_applied == 297) { if (ptmp->children[0]->prod_applied == 298) { /* front */ if (ptmp->children[0]->children[0]->prod_applied == 301) { if (ptmp->children[0]->children[0]->children[0]->prod_applied == 303) /* secondary */ bind_type = RESULT_COLOR_FRONT_SECONDARY; } } else { /* back */ bind_type = RESULT_COLOR_BACK_PRIMARY; if (ptmp->children[0]->children[0]->prod_applied == 301) { if (ptmp->children[0]->children[0]->children[0]->prod_applied == 303) /* secondary */ bind_type = RESULT_COLOR_BACK_SECONDARY; } } } break; case 294: /* texcoord */ bind_type = RESULT_TEXCOORD; if (ptn->children[0]->children[0]->prod_applied == 311) { bind_idx = s->ints.data[ptn->children[0]->children[0]->children[0]-> children[0]->tok_attr]; } break; } break; } /* Mmmmm... baaaaby */ if (eat_children) { if (eat_children == 2) parse_tree_free_children(ptn->children[0]); else parse_tree_free_children(ptn); /* Insert the binding into the binding table */ ptn->tok = BINDING_TOKEN; ptn->tok_attr = binding_table_add(&s->binds, bind_type, bind_idx, bind_row, bind_nrows, bind_vals); printf("Got binding %d %d %d %d at pos %d in bind tab [%f %f %f %f]\n", bind_type, bind_idx, bind_row, bind_nrows, ptn->tok_attr, bind_vals[0], bind_vals[1], bind_vals[2], bind_vals[3]); } for (a = 0; a < 4; a++) { if (!ptn->children[a]) return; parse_tree_fold_bindings(s, ptn->children[a]); } } /** * After we have figured out what mess of parse tree actually represents GL state (or constants, or * whatnot), we have to line up variables with the state. For example, a line something like * * OUTPUT foo = result.position; * * We would have 'foo' in the identifier table at some position foo_idx, and 'result.position' in the * binding table at some position res_pos_idx. To set things up such that 'foo' is associated with * the result position state, we need to set ident[foo_idx].attr = res_pos_idx so we can generate * opcodes without going bonkers. * * This function works on OUTPUT, ATTRIB, and PARAM single bindings. PARAM array bindings are handled in * parse_tree_assign_param_arrays(). * * \param s The parse state * \param ptn The root of the parse tree from which to start lining up state and variables */ static void parse_tree_assign_bindings(parse_state * s, parse_tree_node * ptn) { GLint a; parse_tree_node *var_name, *attr_item; /* OUTPUT, ATTRIB */ if ((ptn->prod_applied == 288) || (ptn->prod_applied == 120)) { var_name = ptn->children[0]->children[0]; attr_item = ptn->children[1]; if (attr_item->tok != BINDING_TOKEN) { fprintf(stderr, "sanity check: trying to bind an output variable to something funky!\n"); return; } s->idents.attr[var_name->tok_attr] = attr_item->tok_attr; printf("result: %s bound to %d\n", s->idents.data[var_name->tok_attr], s->binds.type[s->idents.attr[var_name->tok_attr]]); return; } /* stateSingleItemDecl */ if (ptn->prod_applied == 134) { var_name = ptn->children[0]->children[0]; if (ptn->children[1]->prod_applied == 135) { if (ptn->children[1]->children[0]->prod_applied == 139) { if (ptn->children[1]->children[0]->children[0]->prod_applied == 144) attr_item = ptn->children[1]->children[0]->children[0]->children[0]-> children[0]; else if (ptn->children[1]->children[0]->children[0]-> prod_applied == 145) attr_item = ptn->children[1]->children[0]->children[0]->children[0]; else attr_item = ptn->children[1]->children[0]->children[0]->children[0]-> children[0]; if (attr_item->tok != BINDING_TOKEN) { fprintf(stderr, "sanity check: trying to bind an param variable (%s) to something funky! [%d]\n", s->idents.data[var_name->tok_attr], attr_item->tok); exit(1); } s->idents.attr[var_name->tok_attr] = attr_item->tok_attr; printf("result: %s bound to %d\n", s->idents.data[var_name->tok_attr], s->binds.type[s->idents.attr[var_name->tok_attr]]); return; } } } /* else, recurse on all our children */ for (a = 0; a < 4; a++) { if (!ptn->children[a]) return; parse_tree_assign_bindings(s, ptn->children[a]); } } /** * This handles lining up PARAM arrays with variables, much like parse_tree_assign_bindings(). * * In parse_tree_assign_bindings, we set the identifier attr to the index into the binding table of * the bound state. * * Here, instead, we allocate a slot in the 'array table' to stick the bound state into. Instead * of an index into the binding table, the identifier attr now holds the index into the array table. * * \param s The parse state * \param pnt The root parse tree node to handle arrays from * */ static void parse_tree_assign_param_arrays(parse_state * s, parse_tree_node * ptn) { GLint a, is_mult, array_len; parse_tree_node *var_name, *binding, *arraysize, *ptmp; /* If we're a param */ if (ptn->prod_applied == 134) { /* establish name */ var_name = ptn->children[0]; /* param_statement2 */ binding = ptn->children[1]; if (binding->prod_applied == 136) { /* optarraysize */ arraysize = binding->children[0]; is_mult = 0; /* foo[3] */ if (arraysize->prod_applied == 138) { debug_token(s, var_name->children[0]->tok, var_name->children[0]->tok_attr); debug_token(s, arraysize->children[0]->tok, arraysize->children[0]->tok_attr); printf("\n"); is_mult = 1; } else /* foo[] */ if (arraysize->prod_applied == 137) { arraysize = NULL; printf("How do I init a PARAM array like foo[]?? \n"); is_mult = 1; } if (!is_mult) return; s->idents.attr[var_name->tok_attr] = array_table_new(&s->arrays); binding = binding->children[1]->children[0]; ptmp = binding->children[0]; array_len = 0; if (ptmp->prod_applied == 150) { /* state */ printf("matrix 0 [state]:\n"); printf("%d %d\n", ptmp->children[0]->children[0]->tok, ptmp->children[0]->children[0]->tok_attr); array_table_add_data(&s->arrays, s->idents.attr[var_name->tok_attr], ptmp->children[0]->children[0]->tok_attr); array_len += s->binds.num_rows[ptmp->children[0]->children[0]->tok_attr]; } else if (ptmp->prod_applied == 151) { /* program */ printf("matrix 0 [program]:\n"); printf("%d %d\n", ptmp->children[0]->tok, ptmp->children[0]->tok_attr); array_table_add_data(&s->arrays, s->idents.attr[var_name->tok_attr], ptmp->children[0]->tok_attr); array_len += s->binds.num_rows[ptmp->children[0]->tok_attr]; } else { /* constant */ printf("matrix 0 [constant]:\n"); printf("%d %d\n", ptmp->children[0]->children[0]->tok, ptmp->children[0]->children[0]->tok_attr); array_table_add_data(&s->arrays, s->idents.attr[var_name->tok_attr], ptmp->children[0]->children[0]->tok_attr); array_len += s->binds.num_rows[ptmp->children[0]->children[0]->tok_attr]; } binding = binding->children[1]; while (binding->prod_applied != 143) { ptmp = binding->children[0]->children[0]; printf("mat: %d\n", ptmp->prod_applied); if (ptmp->prod_applied == 150) { /* state */ printf("matrix %d:\n", array_len); printf("%d %d\n", ptmp->children[0]->children[0]->tok, ptmp->children[0]->children[0]->tok_attr); array_table_add_data(&s->arrays, s->idents.attr[var_name->tok_attr], ptmp->children[0]->children[0]->tok_attr); array_len += s->binds.num_rows[ptmp->children[0]->children[0]->tok_attr]; } else if (ptmp->prod_applied == 151) { /* program */ printf("matrix %d [program]:\n", array_len); printf("%d %d\n", ptmp->children[0]->tok, ptmp->children[0]->tok_attr); array_table_add_data(&s->arrays, s->idents.attr[var_name->tok_attr], ptmp->children[0]->tok_attr); array_len += s->binds.num_rows[ptmp->children[0]->tok_attr]; } else { /* constant */ printf("matrix %d [constant]:\n", array_len); printf("%d %d\n", ptmp->children[0]->children[0]->tok, ptmp->children[0]->children[0]->tok_attr); array_table_add_data(&s->arrays, s->idents.attr[var_name->tok_attr], ptmp->children[0]->children[0]->tok_attr); array_len += s->binds.num_rows[ptmp->children[0]->children[0]->tok_attr]; } binding = binding->children[0]->children[1]; } /* XXX: have to compare the requested size, and the actual * size, and fix up any inconsistancies */ if (arraysize) { printf("matrix wants to get %d rows\n", s->ints.data[arraysize->children[0]->tok_attr]); } printf("matrix num rows: %d\n", array_len); } return; } /* Else, recurse on all our children */ for (a = 0; a < 4; a++) { if (!ptn->children[a]) return; parse_tree_assign_param_arrays(s, ptn->children[a]); } } /* XXX: This needs to be written properly. */ /** * Here we allocate 'registers' for all of the various variables and bound state. * * The 'register' number is given by the reg_num field in the binding table. Note that this field * is not stored in the identifier table. If it were, we would need a different mechanism for handling * implicit bindings. * * However, after some discussion with Brian, implicit bindings may be handled by grabbing state * directly from Mesa's state structs. This might be a little hairy here, maybe not.. Implicit * bindings are those in the binding table that are not pointed to by any ident.attr or array.data * * This should also do various error checking, like the multiple vertex attrib error, or 'too many bindings' * error. * * \param s The parse state */ static void assign_regs(parse_state * s) { GLint a; GLfloat foo[4]; for (a = 0; a < s->idents.len; a++) { if (s->idents.type[a] == TYPE_TEMP) { s->idents.attr[a] = binding_table_add(&s->binds, TYPE_TEMP, 0, 0, 0, foo); } } } /** * Parse/compile the 'str' returning the compiled 'program'. * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos * indicates the position of the error in 'str'. */ void _mesa_parse_arb_vertex_program(GLcontext * ctx, GLenum target, const GLubyte * string, GLsizei len, struct vertex_program *program) { GLubyte *our_string; parse_state *state; /* XXX: How do I handle these errors? */ if (len < 10 || _mesa_strncmp((const char *) string, "!!ARBvp1.0", 10)) { ctx->Program.ErrorPos = 0; _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramStringARB(bad header)"); return; } /* Make a null-terminated copy of the program string */ our_string = (GLubyte *) MALLOC(len + 1); if (!our_string) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glProgramStringARB"); return; } MEMCPY(our_string, string, len); our_string[len] = 0; state = parse_state_init(our_string + 10, _mesa_strlen((char *) our_string) - 10); if (parse(state) == ARB_VP_SUCESS) { printf("parse sucess!\n"); } else { printf("*** error\n"); parse_state_cleanup(state); return; } /* First, we 'fold' bindings from a big mess of productions and * tokens into one BINDING_TOKEN, which points to an entry * in the binding sym table that holds all of the relevant * info for the binding destination. */ parse_tree_fold_bindings(state, state->pt_head); /* Now, for each type of binding, walk the parse tree and stick * the index into the binding sym table */ parse_tree_assign_bindings(state, state->pt_head); /* XXX: this still needs a' fixin to get folded bindings * -- it does? wtf do I mean? */ parse_tree_assign_param_arrays(state, state->pt_head); /* XXX: Now, assign registers. For this, we'll need to create * bindings for all temps (and what else?? ) */ assign_regs(state); /* Ok, now generate code */ parse_tree_generate_opcodes(state, state->pt_head); /* Just for testing.. */ program->Base.Target = target; if (program->Base.String) { FREE(program->Base.String); } program->Base.String = our_string; program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB; if (program->Instructions) { FREE(program->Instructions); } program->Instructions = (struct vp_instruction *) _mesa_malloc(sizeof(struct vp_instruction)); program->Instructions[0].Opcode = VP_OPCODE_END; program->InputsRead = 0; program->OutputsWritten = 0; program->IsPositionInvariant = 0; parse_state_cleanup(state); /* TODO: * - handle implicit state grabbing & register allocation like discussed * - implicit param declarations -- see above * * - variable bindings -- ADDRESS * - deal with explicit array sizes & size mismatches * - shuddup all my debugging crap * - grep for XXX * - multiple vtx attrib binding error * - What do I do on look ahead for prod 54 & 55? (see arbvp_grammar.txt) * - misc errors * - check integer ranges * - check array index ranges * - check variable counts * - param register allocation * - exercise swizzles and masks * - error handling * - generate opcodes * + Get addres registers for relative offsets in PARAM arrays * + Properly encode implicit PARAMs and ATTRIBs. * + ARL * + SWZ * + actually emit Mesa opcodes * - segfaults while freeing stuff * - OPTION */ }