Initial changes after moving from src/mesa/main/.
authorMichal Krol <mjkrol@gmail.org>
Thu, 4 Mar 2004 13:15:32 +0000 (13:15 +0000)
committerMichal Krol <mjkrol@gmail.org>
Thu, 4 Mar 2004 13:15:32 +0000 (13:15 +0000)
Needs testing - it havent been even compiled yet.

src/mesa/shader/arbfragparse.c [new file with mode: 0644]
src/mesa/shader/arbfragparse.h [new file with mode: 0644]
src/mesa/shader/arbprogparse.c [new file with mode: 0644]
src/mesa/shader/arbprogparse.h [new file with mode: 0644]
src/mesa/shader/arbvertparse.c [new file with mode: 0644]
src/mesa/shader/arbvertparse.h [new file with mode: 0644]

diff --git a/src/mesa/shader/arbfragparse.c b/src/mesa/shader/arbfragparse.c
new file mode 100644 (file)
index 0000000..46d80dd
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  6.1
+ *
+ * Copyright (C) 1999-2004  Brian Paul   All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#define DEBUG_FP 0
+
+/**
+ * \file arbfragparse.c
+ * ARB_fragment_program parser.
+ * \author Karl Rasche
+ */
+
+#include "glheader.h"
+#include "context.h"
+#include "imports.h"
+#include "macros.h"
+#include "mtypes.h"
+#include "arbprogparse.h"
+#include "arbfragparse.h"
+
+void
+_mesa_debug_fp_inst(GLint num, struct fp_instruction *fp)
+{
+   GLint a;
+   fprintf(stderr, "PROGRAM_OUTPUT: 0x%x\n",    PROGRAM_OUTPUT);
+   fprintf(stderr, "PROGRAM_INPUT: 0x%x\n",     PROGRAM_INPUT);
+   fprintf(stderr, "PROGRAM_TEMPORARY: 0x%x\n", PROGRAM_TEMPORARY);
+
+   for (a=0; a<num; a++) {
+      switch (fp[a].Opcode) {
+         case FP_OPCODE_END:
+            fprintf(stderr, "FP_OPCODE_END"); break;
+
+         case  FP_OPCODE_ABS:
+            fprintf(stderr, "FP_OPCODE_ABS"); break;
+
+         case  FP_OPCODE_ADD:
+            fprintf(stderr, "FP_OPCODE_ADD"); break;
+
+         case  FP_OPCODE_CMP:
+            fprintf(stderr, "FP_OPCODE_CMP"); break;
+
+         case  FP_OPCODE_COS:
+            fprintf(stderr, "FP_OPCODE_COS"); break;
+
+         case  FP_OPCODE_DP3:
+            fprintf(stderr, "FP_OPCODE_DP3"); break;
+
+         case  FP_OPCODE_DP4:
+            fprintf(stderr, "FP_OPCODE_DP4"); break;
+
+         case  FP_OPCODE_DPH:
+            fprintf(stderr, "FP_OPCODE_DPH"); break;
+
+         case  FP_OPCODE_DST:
+            fprintf(stderr, "FP_OPCODE_DST"); break;
+
+         case  FP_OPCODE_EX2:
+            fprintf(stderr, "FP_OPCODE_EX2"); break;
+
+         case  FP_OPCODE_FLR:
+            fprintf(stderr, "FP_OPCODE_FLR"); break;
+
+         case  FP_OPCODE_FRC:
+            fprintf(stderr, "FP_OPCODE_FRC"); break;
+
+         case  FP_OPCODE_KIL:
+            fprintf(stderr, "FP_OPCODE_KIL"); break;
+
+         case  FP_OPCODE_LG2:
+            fprintf(stderr, "FP_OPCODE_LG2"); break;
+
+         case  FP_OPCODE_LIT:
+            fprintf(stderr, "FP_OPCODE_LIT"); break;
+
+         case  FP_OPCODE_LRP:
+            fprintf(stderr, "FP_OPCODE_LRP"); break;
+
+         case  FP_OPCODE_MAD:
+            fprintf(stderr, "FP_OPCODE_MAD"); break;
+
+         case  FP_OPCODE_MAX:
+            fprintf(stderr, "FP_OPCODE_MAX"); break;
+
+         case  FP_OPCODE_MIN:
+            fprintf(stderr, "FP_OPCODE_MIN"); break;
+
+         case  FP_OPCODE_MOV:
+            fprintf(stderr, "FP_OPCODE_MOV"); break;
+
+         case  FP_OPCODE_MUL:
+            fprintf(stderr, "FP_OPCODE_MUL"); break;
+
+         case  FP_OPCODE_POW:
+            fprintf(stderr, "FP_OPCODE_POW"); break;
+
+         case  FP_OPCODE_RCP:
+            fprintf(stderr, "FP_OPCODE_RCP"); break;
+
+         case  FP_OPCODE_RSQ:
+            fprintf(stderr, "FP_OPCODE_RSQ"); break;
+
+         case  FP_OPCODE_SCS:
+            fprintf(stderr, "FP_OPCODE_SCS"); break;
+
+         case  FP_OPCODE_SIN:
+            fprintf(stderr, "FP_OPCODE_SIN"); break;
+
+         case  FP_OPCODE_SLT:
+            fprintf(stderr, "FP_OPCODE_SLT"); break;
+
+         case  FP_OPCODE_SUB:
+            fprintf(stderr, "FP_OPCODE_SUB"); break;
+
+         case  FP_OPCODE_SWZ:
+            fprintf(stderr, "FP_OPCODE_SWZ"); break;
+
+         case  FP_OPCODE_TEX:
+            fprintf(stderr, "FP_OPCODE_TEX"); break;
+
+         case  FP_OPCODE_TXB:
+            fprintf(stderr, "FP_OPCODE_TXB"); break;
+
+         case  FP_OPCODE_TXP:
+            fprintf(stderr, "FP_OPCODE_TXP"); break;
+
+         case  FP_OPCODE_X2D:
+            fprintf(stderr, "FP_OPCODE_XPD"); break;
+
+         default:
+            _mesa_warning(NULL, "Bad opcode in debug_fg_inst()");
+      }
+
+      fprintf(stderr, " D(0x%x:%d:%d%d%d%d) ", 
+         fp[a].DstReg.File, fp[a].DstReg.Index,
+         fp[a].DstReg.WriteMask[0], fp[a].DstReg.WriteMask[1], 
+         fp[a].DstReg.WriteMask[2], fp[a].DstReg.WriteMask[3]); 
+                                                
+      fprintf(stderr, "S1(0x%x:%d:%d%d%d%d) ", fp[a].SrcReg[0].File, fp[a].SrcReg[0].Index,
+         fp[a].SrcReg[0].Swizzle[0],
+         fp[a].SrcReg[0].Swizzle[1],
+         fp[a].SrcReg[0].Swizzle[2],
+         fp[a].SrcReg[0].Swizzle[3]);
+
+      fprintf(stderr, "S2(0x%x:%d:%d%d%d%d) ", fp[a].SrcReg[1].File, fp[a].SrcReg[1].Index,
+        fp[a].SrcReg[1].Swizzle[0],
+        fp[a].SrcReg[1].Swizzle[1],
+        fp[a].SrcReg[1].Swizzle[2],
+        fp[a].SrcReg[1].Swizzle[3]);
+
+      fprintf(stderr, "S3(0x%x:%d:%d%d%d%d)",  fp[a].SrcReg[2].File, fp[a].SrcReg[2].Index,
+        fp[a].SrcReg[2].Swizzle[0],
+        fp[a].SrcReg[2].Swizzle[1],
+        fp[a].SrcReg[2].Swizzle[2],
+        fp[a].SrcReg[2].Swizzle[3]);
+
+      fprintf(stderr, "\n");
+   }
+}
+
+void
+_mesa_parse_arb_fragment_program(GLcontext * ctx, GLenum target,
+                                 const GLubyte * str, GLsizei len,
+                                 struct fragment_program *program)
+{
+   GLuint a, retval;
+   struct arb_program ap;
+
+   /* set the program target before parsing */
+   ap.Base.Target = GL_FRAGMENT_PROGRAM_ARB;
+
+   retval = _mesa_parse_arb_program(ctx, str, len, &ap);
+
+   /* copy the relvant contents of the arb_program struct into the
+    * fragment_program struct
+    */
+   program->Base.NumInstructions = ap.Base.NumInstructions;
+   program->Base.NumTemporaries  = ap.Base.NumTemporaries;
+   program->Base.NumParameters   = ap.Base.NumParameters;
+   program->Base.NumAttributes   = ap.Base.NumAttributes;
+   program->Base.NumAddressRegs  = ap.Base.NumAddressRegs;
+
+   program->InputsRead     = ap.InputsRead;
+   program->OutputsWritten = ap.OutputsWritten;
+   for (a=0; a<MAX_TEXTURE_IMAGE_UNITS; a++)
+      program->TexturesUsed[a] = ap.TexturesUsed[a];
+   program->NumAluInstructions = ap.NumAluInstructions;
+   program->NumTexInstructions = ap.NumTexInstructions;
+   program->NumTexIndirections = ap.NumTexIndirections;
+   program->Parameters         = ap.Parameters;
+   program->FogOption          = ap.FogOption;
+
+   /* XXX: Parse error. Cleanup things and return */
+   if (retval)
+   {
+      program->Instructions = (struct fp_instruction *) _mesa_malloc (
+                                     sizeof(struct fp_instruction) );
+      program->Instructions[0].Opcode = FP_OPCODE_END;
+      return;
+   }
+
+   /* XXX: Eh.. we parsed something that wasn't a fragment program. doh! */
+   /* this wont happen any more */
+/*
+   if (ap.Base.Target != GL_FRAGMENT_PROGRAM_ARB)
+   {
+      program->Instructions = (struct fp_instruction *) _mesa_malloc (
+                                     sizeof(struct fp_instruction) );
+      program->Instructions[0].Opcode = FP_OPCODE_END;
+
+      _mesa_error (ctx, GL_INVALID_OPERATION, "Parsed a non-fragment program as a fragment program");
+      return;
+   }
+*/
+
+#if DEBUG_FP
+   _mesa_debug_fp_inst(ap.Base.NumInstructions, ap.FPInstructions);
+#endif
+
+   program->Instructions   = ap.FPInstructions;
+}
diff --git a/src/mesa/shader/arbfragparse.h b/src/mesa/shader/arbfragparse.h
new file mode 100644 (file)
index 0000000..0d3e69f
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#ifndef ARBFRAGPARSE_H
+#define ARBFRAGPARSE_H
+
+#include "mtypes.h"
+
+extern void
+_mesa_parse_arb_fragment_program(GLcontext * ctx, GLenum target,
+                                 const GLubyte * str, GLsizei len,
+                                 struct fragment_program *program);
+
+extern void
+_mesa_debug_fp_inst(GLint num, struct fp_instruction *fp);
+
+
+#endif
diff --git a/src/mesa/shader/arbprogparse.c b/src/mesa/shader/arbprogparse.c
new file mode 100644 (file)
index 0000000..78c7177
--- /dev/null
@@ -0,0 +1,3954 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  6.1
+ *
+ * Copyright (C) 1999-2004  Brian Paul   All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#define DEBUG_PARSING 0
+
+/**
+ * \file arbprogparse.c
+ * ARB_*_program parser core
+ * \author Karl Rasche
+ */
+
+#include "mtypes.h"
+#include "glheader.h"
+#include "context.h"
+#include "hash.h"
+#include "imports.h"
+#include "macros.h"
+#include "program.h"
+#include "nvvertprog.h"
+#include "nvfragprog.h"
+#include "arbprogparse.h"
+#include "grammar_mesa.h"
+
+/* TODO:
+ *    Fragment Program Stuff:
+ *    -----------------------------------------------------
+ *
+ *    - things from Michal's email
+ *       + overflow on atoi
+ *       + not-overflowing floats (don't use parse_integer..)
+ *       + can remove range checking in arbparse.c
+ *
+ *    - check all limits of number of various variables
+ *      + parameters
+ *
+ *    - test! test! test!
+ *
+ *    Vertex Program Stuff:
+ *    -----------------------------------------------------
+ *    - Optimize param array usage and count limits correctly, see spec,
+ *         section 2.14.3.7
+ *       + Record if an array is reference absolutly or relatively (or both)
+ *       + For absolute arrays, store a bitmap of accesses
+ *       + For single parameters, store an access flag
+ *       + After parsing, make a parameter cleanup and merging pass, where
+ *           relative arrays are layed out first, followed by abs arrays, and
+ *           finally single state.
+ *       + Remap offsets for param src and dst registers
+ *       + Now we can properly count parameter usage
+ *
+ *    - Multiple state binding errors in param arrays (see spec, just before
+ *         section 2.14.3.3)
+ *    - grep for XXX
+ *
+ *    Mesa Stuff
+ *    -----------------------------------------------------
+ *    - User clipping planes vs. PositionInvariant
+ *    - Is it sufficient to just multiply by the mvp to transform in the
+ *        PositionInvariant case? Or do we need something more involved?
+ *
+ *    - vp_src swizzle is GLubyte, fp_src swizzle is GLuint
+ *    - fetch state listed in program_parameters list
+ *       + WTF should this go???
+ *       + currently in nvvertexec.c and s_nvfragprog.c
+ *
+ *    - allow for multiple address registers (and fetch address regs properly)
+ *
+ *    Cosmetic Stuff
+ *    -----------------------------------------------------
+ *     - remove any leftover unused grammer.c stuff (dict_ ?)
+ *     - fix grammer.c error handling so its not static
+ *     - #ifdef around stuff pertaining to extentions
+ *
+ *    Outstanding Questions:
+ *    -----------------------------------------------------
+ *    - ARB_matrix_palette / ARB_vertex_blend -- not supported
+ *      what gets hacked off because of this:
+ *       + VERTEX_ATTRIB_MATRIXINDEX
+ *       + VERTEX_ATTRIB_WEIGHT
+ *       + MATRIX_MODELVIEW
+ *       + MATRIX_PALETTE
+ *
+ *    - When can we fetch env/local params from their own register files, and
+ *      when to we have to fetch them into the main state register file?
+ *      (think arrays)
+ *
+ *    Grammar Changes:
+ *    -----------------------------------------------------
+ */
+
+/* Changes since moving the file to shader directory
+
+2004-III-4 ------------------------------------------------------------
+- added #include "grammar_mesa.h"
+- removed grammar specific code part (it resides now in grammar.c)
+- added GL_ARB_fragment_program_shadow tokens
+- modified #include "arbparse_syn.h"
+- major changes inside _mesa_parse_arb_program()
+- check the program string for '\0' characters
+- copy the program string to a one-byte-longer location to have
+  it null-terminated
+- position invariance test (not writing to result.position) moved
+  to syntax part
+*/
+
+typedef GLubyte *production;
+
+/**
+ * This is the text describing the rules to parse the grammar
+ */
+static char arb_grammar_text[] =
+#include "arbprogram_syn.h"
+;
+
+/**
+ * These should match up with the values defined in arbprogram.syn
+ */
+
+/*
+    Changes:
+    - changed and merged V_* and F_* opcode values to OP_*.
+    - added GL_ARB_fragment_program_shadow specific tokens (michal)
+*/
+#define  REVISION                                   0x07
+
+/* program type */
+#define  FRAGMENT_PROGRAM                           0x01
+#define  VERTEX_PROGRAM                             0x02
+
+/* program section */
+#define  OPTION                                     0x01
+#define  INSTRUCTION                                0x02
+#define  DECLARATION                                0x03
+#define  END                                        0x04
+
+/* GL_ARB_fragment_program option flags */
+#define  ARB_PRECISION_HINT_FASTEST                 0x01
+#define  ARB_PRECISION_HINT_NICEST                  0x02
+#define  ARB_FOG_EXP                                0x04
+#define  ARB_FOG_EXP2                               0x08
+#define  ARB_FOG_LINEAR                             0x10
+
+/* GL_ARB_vertex_program option flags */
+#define  ARB_POSITION_INVARIANT                     0x20
+
+/* GL_ARB_fragment_program_shadow option flags */
+#define  ARB_FRAGMENT_PROGRAM_SHADOW                0x40
+
+/* GL_ARB_fragment_program instruction class */
+#define  OP_ALU_INST                                0x00
+#define  OP_TEX_INST                                0x01
+
+/* GL_ARB_vertex_program instruction class */
+/*       OP_ALU_INST */
+
+/* GL_ARB_fragment_program instruction type */
+#define  OP_ALU_VECTOR                               0x00
+#define  OP_ALU_SCALAR                               0x01
+#define  OP_ALU_BINSC                                0x02
+#define  OP_ALU_BIN                                  0x03
+#define  OP_ALU_TRI                                  0x04
+#define  OP_ALU_SWZ                                  0x05
+#define  OP_TEX_SAMPLE                               0x06
+#define  OP_TEX_KIL                                  0x07
+
+/* GL_ARB_vertex_program instruction type */
+#define  OP_ALU_ARL                                  0x08
+/*       OP_ALU_VECTOR */
+/*       OP_ALU_SCALAR */
+/*       OP_ALU_BINSC */
+/*       OP_ALU_BIN */
+/*       OP_ALU_TRI */
+/*       OP_ALU_SWZ */
+
+/* GL_ARB_fragment_program instruction code */
+#define  OP_ABS                                     0x00
+#define  OP_ABS_SAT                                 0x1B
+#define  OP_FLR                                     0x09
+#define  OP_FLR_SAT                                 0x26
+#define  OP_FRC                                     0x0A
+#define  OP_FRC_SAT                                 0x27
+#define  OP_LIT                                     0x0C
+#define  OP_LIT_SAT                                 0x2A
+#define  OP_MOV                                     0x11
+#define  OP_MOV_SAT                                 0x30
+#define  OP_COS                                     0x1F
+#define  OP_COS_SAT                                 0x20
+#define  OP_EX2                                     0x07
+#define  OP_EX2_SAT                                 0x25
+#define  OP_LG2                                     0x0B
+#define  OP_LG2_SAT                                 0x29
+#define  OP_RCP                                     0x14
+#define  OP_RCP_SAT                                 0x33
+#define  OP_RSQ                                     0x15
+#define  OP_RSQ_SAT                                 0x34
+#define  OP_SIN                                     0x38
+#define  OP_SIN_SAT                                 0x39
+#define  OP_SCS                                     0x35
+#define  OP_SCS_SAT                                 0x36
+#define  OP_POW                                     0x13
+#define  OP_POW_SAT                                 0x32
+#define  OP_ADD                                     0x01
+#define  OP_ADD_SAT                                 0x1C
+#define  OP_DP3                                     0x03
+#define  OP_DP3_SAT                                 0x21
+#define  OP_DP4                                     0x04
+#define  OP_DP4_SAT                                 0x22
+#define  OP_DPH                                     0x05
+#define  OP_DPH_SAT                                 0x23
+#define  OP_DST                                     0x06
+#define  OP_DST_SAT                                 0x24
+#define  OP_MAX                                     0x0F
+#define  OP_MAX_SAT                                 0x2E
+#define  OP_MIN                                     0x10
+#define  OP_MIN_SAT                                 0x2F
+#define  OP_MUL                                     0x12
+#define  OP_MUL_SAT                                 0x31
+#define  OP_SGE                                     0x16
+#define  OP_SGE_SAT                                 0x37
+#define  OP_SLT                                     0x17
+#define  OP_SLT_SAT                                 0x3A
+#define  OP_SUB                                     0x18
+#define  OP_SUB_SAT                                 0x3B
+#define  OP_XPD                                     0x1A
+#define  OP_XPD_SAT                                 0x43
+#define  OP_CMP                                     0x1D
+#define  OP_CMP_SAT                                 0x1E
+#define  OP_LRP                                     0x2B
+#define  OP_LRP_SAT                                 0x2C
+#define  OP_MAD                                     0x0E
+#define  OP_MAD_SAT                                 0x2D
+#define  OP_SWZ                                     0x19
+#define  OP_SWZ_SAT                                 0x3C
+#define  OP_TEX                                     0x3D
+#define  OP_TEX_SAT                                 0x3E
+#define  OP_TXB                                     0x3F
+#define  OP_TXB_SAT                                 0x40
+#define  OP_TXP                                     0x41
+#define  OP_TXP_SAT                                 0x42
+#define  OP_KIL                                     0x28
+
+/* GL_ARB_vertex_program instruction code */
+#define  OP_ARL                                     0x02
+/*       OP_ABS */
+/*       OP_FLR */
+/*       OP_FRC */
+/*       OP_LIT */
+/*       OP_MOV */
+/*       OP_EX2 */
+#define  OP_EXP                                     0x08
+/*       OP_LG2 */
+#define  OP_LOG                                     0x0D
+/*       OP_RCP */
+/*       OP_RSQ */
+/*       OP_POW */
+/*       OP_ADD */
+/*       OP_DP3 */
+/*       OP_DP4 */
+/*       OP_DPH */
+/*       OP_DST */
+/*       OP_MAX */
+/*       OP_MIN */
+/*       OP_MUL */
+/*       OP_SGE */
+/*       OP_SLT */
+/*       OP_SUB */
+/*       OP_XPD */
+/*       OP_MAD */
+/*       OP_SWZ */
+
+/* fragment attribute binding */
+#define  FRAGMENT_ATTRIB_COLOR                      0x01
+#define  FRAGMENT_ATTRIB_TEXCOORD                   0x02
+#define  FRAGMENT_ATTRIB_FOGCOORD                   0x03
+#define  FRAGMENT_ATTRIB_POSITION                   0x04
+
+/* vertex attribute binding */
+#define  VERTEX_ATTRIB_POSITION                     0x01
+#define  VERTEX_ATTRIB_WEIGHT                       0x02
+#define  VERTEX_ATTRIB_NORMAL                       0x03
+#define  VERTEX_ATTRIB_COLOR                        0x04
+#define  VERTEX_ATTRIB_FOGCOORD                     0x05
+#define  VERTEX_ATTRIB_TEXCOORD                     0x06
+#define  VERTEX_ATTRIB_MATRIXINDEX                  0x07
+#define  VERTEX_ATTRIB_GENERIC                      0x08
+
+/* fragment result binding */
+#define  FRAGMENT_RESULT_COLOR                      0x01
+#define  FRAGMENT_RESULT_DEPTH                      0x02
+
+/* vertex result binding */
+#define  VERTEX_RESULT_POSITION                     0x01
+#define  VERTEX_RESULT_COLOR                        0x02
+#define  VERTEX_RESULT_FOGCOORD                     0x03
+#define  VERTEX_RESULT_POINTSIZE                    0x04
+#define  VERTEX_RESULT_TEXCOORD                     0x05
+
+/* texture target */
+#define  TEXTARGET_1D                               0x01
+#define  TEXTARGET_2D                               0x02
+#define  TEXTARGET_3D                               0x03
+#define  TEXTARGET_RECT                             0x04
+#define  TEXTARGET_CUBE                             0x05
+/* GL_ARB_fragment_program_shadow */
+#define  TEXTARGET_SHADOW1D                         0x06
+#define  TEXTARGET_SHADOW2D                         0x07
+#define  TEXTARGET_SHADOWRECT                       0x08
+
+/* face type */
+#define  FACE_FRONT                                 0x00
+#define  FACE_BACK                                  0x01
+
+/* color type */
+#define  COLOR_PRIMARY                              0x00
+#define  COLOR_SECONDARY                            0x01
+
+/* component */
+#define  COMPONENT_X                                0x00
+#define  COMPONENT_Y                                0x01
+#define  COMPONENT_Z                                0x02
+#define  COMPONENT_W                                0x03
+#define  COMPONENT_0                                0x04
+#define  COMPONENT_1                                0x05
+
+/* array index type */
+#define  ARRAY_INDEX_ABSOLUTE                       0x00
+#define  ARRAY_INDEX_RELATIVE                       0x01
+
+/* matrix name */
+#define  MATRIX_MODELVIEW                           0x01
+#define  MATRIX_PROJECTION                          0x02
+#define  MATRIX_MVP                                 0x03
+#define  MATRIX_TEXTURE                             0x04
+#define  MATRIX_PALETTE                             0x05
+#define  MATRIX_PROGRAM                             0x06
+
+/* matrix modifier */
+#define  MATRIX_MODIFIER_IDENTITY                   0x00
+#define  MATRIX_MODIFIER_INVERSE                    0x01
+#define  MATRIX_MODIFIER_TRANSPOSE                  0x02
+#define  MATRIX_MODIFIER_INVTRANS                   0x03
+
+/* constant type */
+#define  CONSTANT_SCALAR                            0x01
+#define  CONSTANT_VECTOR                            0x02
+
+/* program param type */
+#define  PROGRAM_PARAM_ENV                          0x01
+#define  PROGRAM_PARAM_LOCAL                        0x02
+
+/* register type */
+#define  REGISTER_ATTRIB                            0x01
+#define  REGISTER_PARAM                             0x02
+#define  REGISTER_RESULT                            0x03
+#define  REGISTER_ESTABLISHED_NAME                  0x04
+
+/* param binding */
+#define  PARAM_NULL                                 0x00
+#define  PARAM_ARRAY_ELEMENT                        0x01
+#define  PARAM_STATE_ELEMENT                        0x02
+#define  PARAM_PROGRAM_ELEMENT                      0x03
+#define  PARAM_PROGRAM_ELEMENTS                     0x04
+#define  PARAM_CONSTANT                             0x05
+
+/* param state property */
+#define  STATE_MATERIAL                             0x01
+#define  STATE_LIGHT                                0x02
+#define  STATE_LIGHT_MODEL                          0x03
+#define  STATE_LIGHT_PROD                           0x04
+#define  STATE_FOG                                  0x05
+#define  STATE_MATRIX_ROWS                          0x06
+/* GL_ARB_fragment_program */
+#define  STATE_TEX_ENV                              0x07
+#define  STATE_DEPTH                                0x08
+/* GL_ARB_vertex_program */
+#define  STATE_TEX_GEN                              0x09
+#define  STATE_CLIP_PLANE                           0x0A
+#define  STATE_POINT                                0x0B
+
+/* state material property */
+#define  MATERIAL_AMBIENT                           0x01
+#define  MATERIAL_DIFFUSE                           0x02
+#define  MATERIAL_SPECULAR                          0x03
+#define  MATERIAL_EMISSION                          0x04
+#define  MATERIAL_SHININESS                         0x05
+
+/* state light property */
+#define  LIGHT_AMBIENT                              0x01
+#define  LIGHT_DIFFUSE                              0x02
+#define  LIGHT_SPECULAR                             0x03
+#define  LIGHT_POSITION                             0x04
+#define  LIGHT_ATTENUATION                          0x05
+#define  LIGHT_HALF                                 0x06
+#define  LIGHT_SPOT_DIRECTION                       0x07
+
+/* state light model property */
+#define  LIGHT_MODEL_AMBIENT                        0x01
+#define  LIGHT_MODEL_SCENECOLOR                     0x02
+
+/* state light product property */
+#define  LIGHT_PROD_AMBIENT                         0x01
+#define  LIGHT_PROD_DIFFUSE                         0x02
+#define  LIGHT_PROD_SPECULAR                        0x03
+
+/* state texture environment property */
+#define  TEX_ENV_COLOR                              0x01
+
+/* state texture generation coord property */
+#define  TEX_GEN_EYE                                0x01
+#define  TEX_GEN_OBJECT                             0x02
+
+/* state fog property */
+#define  FOG_COLOR                                  0x01
+#define  FOG_PARAMS                                 0x02
+
+/* state depth property */
+#define  DEPTH_RANGE                                0x01
+
+/* state point parameters property */
+#define  POINT_SIZE                                 0x01
+#define  POINT_ATTENUATION                          0x02
+
+/* declaration */
+#define  ATTRIB                                     0x01
+#define  PARAM                                      0x02
+#define  TEMP                                       0x03
+#define  OUTPUT                                     0x04
+#define  ALIAS                                      0x05
+/* GL_ARB_vertex_program */
+#define  ADDRESS                                    0x06
+
+/*-----------------------------------------------------------------------
+ * From here on down is the semantic checking portion
+ *
+ */
+
+/**
+ * Variable Table Handling functions
+ */
+typedef enum
+{
+   vt_none,
+   vt_address,
+   vt_attrib,
+   vt_param,
+   vt_temp,
+   vt_output,
+   vt_alias
+} var_type;
+
+
+/*
+ * Setting an explicit field for each of the binding properties is a bit wasteful
+ * of space, but it should be much more clear when reading later on..
+ */
+struct var_cache
+{
+   GLubyte *name;
+   var_type type;
+   GLuint address_binding;      /* The index of the address register we should
+                                 * be using                                        */
+   GLuint attrib_binding;       /* For type vt_attrib, see nvfragprog.h for values */
+   GLuint attrib_binding_idx;   /* The index into the attrib register file corresponding
+                                 * to the state in attrib_binding                  */
+   GLuint attrib_is_generic;    /* If the attrib was specified through a generic
+                                 * vertex attrib                                   */
+   GLuint temp_binding;         /* The index of the temp register we are to use    */
+   GLuint output_binding;       /* For type vt_output, see nvfragprog.h for values */
+   GLuint output_binding_idx;   /* This is the index into the result register file
+                                 * corresponding to the bound result state         */
+   struct var_cache *alias_binding;     /* For type vt_alias, points to the var_cache entry
+                                         * that this is aliased to                         */
+   GLuint param_binding_type;   /* {PROGRAM_STATE_VAR, PROGRAM_LOCAL_PARAM,
+                                 *    PROGRAM_ENV_PARAM}                           */
+   GLuint param_binding_begin;  /* This is the offset into the program_parameter_list where
+                                 * the tokens representing our bound state (or constants)
+                                 * start */
+   GLuint param_binding_length; /* This is how many entries in the the program_parameter_list
+                                 * we take up with our state tokens or constants. Note that
+                                 * this is _not_ the same as the number of param registers
+                                 * we eventually use */
+   struct var_cache *next;
+};
+
+static GLvoid
+var_cache_create (struct var_cache **va)
+{
+   *va = (struct var_cache *) _mesa_malloc (sizeof (struct var_cache));
+   if (*va) {
+      (**va).name = NULL;
+      (**va).type = vt_none;
+      (**va).attrib_binding = ~0;
+      (**va).attrib_is_generic = 0;
+      (**va).temp_binding = ~0;
+      (**va).output_binding = ~0;
+      (**va).output_binding_idx = ~0;
+      (**va).param_binding_type = ~0;
+      (**va).param_binding_begin = ~0;
+      (**va).param_binding_length = ~0;
+      (**va).alias_binding = NULL;
+      (**va).next = NULL;
+   }
+}
+
+static GLvoid
+var_cache_destroy (struct var_cache **va)
+{
+   if (*va) {
+      var_cache_destroy (&(**va).next);
+      _mesa_free (*va);
+      *va = NULL;
+   }
+}
+
+static GLvoid
+var_cache_append (struct var_cache **va, struct var_cache *nv)
+{
+   if (*va)
+      var_cache_append (&(**va).next, nv);
+   else
+      *va = nv;
+}
+
+static struct var_cache *
+var_cache_find (struct var_cache *va, GLubyte * name)
+{
+   struct var_cache *first = va;
+
+   while (va) {
+      if (!strcmp ( (const char*) name, (const char*) va->name)) {
+         if (va->type == vt_alias)
+            return var_cache_find (first, va->name);
+         return va;
+      }
+
+      va = va->next;
+   }
+
+   return NULL;
+}
+
+/**
+ * constructs an integer from 4 GLubytes in LE format
+ */
+static GLuint
+parse_position (GLubyte ** inst)
+{
+   GLuint value;
+
+   value =  (GLuint) (*(*inst)++);
+   value += (GLuint) (*(*inst)++) * 0x100;
+   value += (GLuint) (*(*inst)++) * 0x10000;
+   value += (GLuint) (*(*inst)++) * 0x1000000;
+
+   return value;
+}
+
+/**
+ * This will, given a string, lookup the string as a variable name in the
+ * var cache. If the name is found, the var cache node corresponding to the
+ * var name is returned. If it is not found, a new entry is allocated
+ *
+ * \param  I     Points into the binary array where the string identifier begins
+ * \param  found 1 if the string was found in the var_cache, 0 if it was allocated
+ * \return       The location on the var_cache corresponding the the string starting at I
+ */
+static struct var_cache *
+parse_string (GLubyte ** inst, struct var_cache **vc_head,
+              struct arb_program *Program, GLuint * found)
+{
+   GLubyte *i = *inst;
+   struct var_cache *va = NULL;
+
+   *inst += _mesa_strlen ((char *) i) + 1;
+
+   va = var_cache_find (*vc_head, i);
+
+   if (va) {
+      *found = 1;
+      return va;
+   }
+
+   *found = 0;
+   var_cache_create (&va);
+   va->name = i;
+
+   var_cache_append (vc_head, va);
+
+   return va;
+}
+
+static char *
+parse_string_without_adding (GLubyte ** inst, struct arb_program *Program)
+{
+   GLubyte *i = *inst;
+
+   *inst += _mesa_strlen ((char *) i) + 1;
+
+   return (char *) i;
+}
+
+/**
+ * \return 0 if sign is plus, 1 if sign is minus
+ */
+static GLuint
+parse_sign (GLubyte ** inst)
+{
+   /*return *(*inst)++ != '+'; */
+
+   if (**inst == '-') {
+      (*inst)++;
+      return 1;
+   }
+   else if (**inst == '+') {
+      (*inst)++;
+      return 0;
+   }
+
+   return 0;
+}
+
+/**
+ * parses and returns signed integer
+ */
+static GLint
+parse_integer (GLubyte ** inst, struct arb_program *Program)
+{
+   GLint sign;
+   GLint value;
+
+   /* check if *inst points to '+' or '-'
+    * if yes, grab the sign and increment *inst
+    */
+   sign = parse_sign (inst);
+
+   /* now check if *inst points to 0
+    * if yes, increment the *inst and return the default value
+    */
+   if (**inst == 0) {
+      (*inst)++;
+      return 0;
+   }
+
+   /* parse the integer as you normally would do it */
+   value = _mesa_atoi (parse_string_without_adding (inst, Program));
+
+   /* now, after terminating 0 there is a position
+    * to parse it - parse_position()
+    */
+   Program->Position = parse_position (inst);
+
+   if (sign)
+      value *= -1;
+
+   return value;
+}
+
+/**
+ */
+static GLfloat
+parse_float (GLubyte ** inst, struct arb_program *Program)
+{
+   GLint tmp[5], denom;
+   GLuint leading_zeros =0;
+   GLfloat value = 0;
+
+#if 0
+   tmp[0] = parse_sign (inst);  /* This is the sign of the number + - >0, - -> 1 */
+#endif
+   tmp[1] = parse_integer (inst, Program);   /* This is the integer portion of the number */
+
+   /* Now we grab the fractional portion of the number (the digits after
+       * the .). We can have leading 0's here, which parse_integer will ignore,
+       * so we'll check for those first
+       */
+   while ((**inst == '0') && ( *(*inst+1) != 0))
+   {
+         leading_zeros++;
+         (*inst)++;
+   }
+   tmp[2] = parse_integer (inst, Program);   /* This is the fractional portion of the number */
+   tmp[3] = parse_sign (inst);               /* This is the sign of the exponent */
+   tmp[4] = parse_integer (inst, Program);   /* This is the exponent */
+
+   value = (GLfloat) tmp[1];
+   denom = 1;
+   while (denom < tmp[2])
+      denom *= 10;
+   denom *= (GLint) _mesa_pow( 10, leading_zeros );
+   value += (GLfloat) tmp[2] / (GLfloat) denom;
+#if 0
+   if (tmp[0])
+      value *= -1;
+#endif
+   value *= (GLfloat) _mesa_pow (10, (GLfloat) tmp[3] * (GLfloat) tmp[4]);
+
+   return value;
+}
+
+
+/**
+ */
+static GLfloat
+parse_signed_float (GLubyte ** inst, struct arb_program *Program)
+{
+   GLint negate;
+   GLfloat value;
+
+   negate = parse_sign (inst);
+
+   value = parse_float (inst, Program);
+
+   if (negate)
+      value *= -1;
+
+   return value;
+}
+
+/**
+ * This picks out a constant value from the parsed array. The constant vector is r
+ * returned in the *values array, which should be of length 4.
+ *
+ * \param values - The 4 component vector with the constant value in it
+ */
+static GLvoid
+parse_constant (GLubyte ** inst, GLfloat *values, struct arb_program *Program,
+                GLboolean use)
+{
+   GLuint components, i;
+
+
+   switch (*(*inst)++) {
+      case CONSTANT_SCALAR:
+         if (use == GL_TRUE) {
+            values[0] =
+               values[1] =
+               values[2] = values[3] = parse_float (inst, Program);
+         }
+         else {
+            values[0] =
+               values[1] =
+               values[2] = values[3] = parse_signed_float (inst, Program);
+         }
+
+         break;
+      case CONSTANT_VECTOR:
+         values[0] = values[1] = values[2] = 0;
+         values[3] = 1;
+         components = *(*inst)++;
+         for (i = 0; i < components; i++) {
+            values[i] = parse_signed_float (inst, Program);
+         }
+         break;
+   }
+}
+
+/**
+ * \param offset The offset from the address register that we should
+ *                address
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_relative_offset (GLcontext *ctx, GLubyte **inst, struct arb_program *Program,
+                        GLint *offset)
+{
+   *offset = parse_integer(inst, Program);
+   if ((*offset > 63) || (*offset < -64)) {
+      _mesa_set_program_error (ctx, Program->Position,
+                               "Relative offset out of range");
+      _mesa_error (ctx, GL_INVALID_OPERATION, "Relative offset %d out of range",
+                                                *offset);
+      return 1;
+   }
+
+   return 0;
+}
+
+/**
+ * \param  color 0 if color type is primary, 1 if color type is secondary
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_color_type (GLcontext * ctx, GLubyte ** inst, struct arb_program *Program,
+                  GLint * color)
+{
+   *color = *(*inst)++ != COLOR_PRIMARY;
+   return 0;
+}
+
+/**
+ * Get an integer corresponding to a generic vertex attribute.
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_generic_attrib_num(GLcontext *ctx, GLubyte ** inst,
+                       struct arb_program *Program, GLuint *attrib)
+{
+   *attrib = parse_integer(inst, Program);
+
+   if ((*attrib < 0) || (*attrib > MAX_VERTEX_PROGRAM_ATTRIBS))
+   {
+      _mesa_set_program_error (ctx, Program->Position,
+                               "Invalid generic vertex attribute index");
+      _mesa_error (ctx, GL_INVALID_OPERATION, "Invalid generic vertex attribute index");
+
+      return 1;
+   }
+
+   return 0;
+}
+
+
+/**
+ * \param coord The texture unit index
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_texcoord_num (GLcontext * ctx, GLubyte ** inst,
+                    struct arb_program *Program, GLuint * coord)
+{
+   *coord = parse_integer (inst, Program);
+
+   if ((*coord < 0) || (*coord >= ctx->Const.MaxTextureUnits)) {
+      _mesa_set_program_error (ctx, Program->Position,
+                               "Invalid texture unit index");
+      _mesa_error (ctx, GL_INVALID_OPERATION, "Invalid texture unit index");
+      return 1;
+   }
+
+   return 0;
+}
+
+/**
+ * \param coord The weight index
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_weight_num (GLcontext * ctx, GLubyte ** inst, struct arb_program *Program,
+                  GLint * coord)
+{
+   *coord = parse_integer (inst, Program);
+
+   if ((*coord < 0) || (*coord >= 1)) {
+      _mesa_set_program_error (ctx, Program->Position,
+                               "Invalid weight index");
+      _mesa_error (ctx, GL_INVALID_OPERATION, "Invalid weight index");
+      return 1;
+   }
+
+   return 0;
+}
+
+/**
+ * \param coord The clip plane index
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_clipplane_num (GLcontext * ctx, GLubyte ** inst,
+                     struct arb_program *Program, GLint * coord)
+{
+   *coord = parse_integer (inst, Program);
+
+   if ((*coord < 0) || (*coord >= (GLint) ctx->Const.MaxClipPlanes)) {
+      _mesa_set_program_error (ctx, Program->Position,
+                               "Invalid clip plane index");
+      _mesa_error (ctx, GL_INVALID_OPERATION, "Invalid clip plane index");
+      return 1;
+   }
+
+   return 0;
+}
+
+
+/**
+ * \return 0 on front face, 1 on back face
+ */
+static GLuint
+parse_face_type (GLubyte ** inst)
+{
+   switch (*(*inst)++) {
+      case FACE_FRONT:
+         return 0;
+
+      case FACE_BACK:
+         return 1;
+   }
+   return 0;
+}
+
+
+/**
+ * Given a matrix and a modifier token on the binary array, return tokens
+ * that _mesa_fetch_state() [program.c] can understand.
+ *
+ * \param matrix - the matrix we are talking about
+ * \param matrix_idx - the index of the matrix we have (for texture & program matricies)
+ * \param matrix_modifier - the matrix modifier (trans, inv, etc)
+ * \return 0 on sucess, 1 on failure
+ */
+static GLuint
+parse_matrix (GLcontext * ctx, GLubyte ** inst, struct arb_program *Program,
+              GLint * matrix, GLint * matrix_idx, GLint * matrix_modifier)
+{
+   GLubyte mat = *(*inst)++;
+
+   *matrix_idx = 0;
+
+   switch (mat) {
+      case MATRIX_MODELVIEW:
+         *matrix = STATE_MODELVIEW;
+         *matrix_idx = parse_integer (inst, Program);
+         if (*matrix_idx > 0) {
+            _mesa_set_program_error (ctx, Program->Position,
+               "ARB_vertex_blend not supported\n");
+            _mesa_error (ctx, GL_INVALID_OPERATION,
+               "ARB_vertex_blend not supported\n");
+            return 1;
+         }
+         break;
+
+      case MATRIX_PROJECTION:
+         *matrix = STATE_PROJECTION;
+         break;
+
+      case MATRIX_MVP:
+         *matrix = STATE_MVP;
+         break;
+
+      case MATRIX_TEXTURE:
+         *matrix = STATE_TEXTURE;
+         *matrix_idx = parse_integer (inst, Program);
+         if (*matrix_idx >= (GLint) ctx->Const.MaxTextureUnits) {
+            _mesa_set_program_error (ctx, Program->Position,
+                                     "Invalid Texture Unit");
+            _mesa_error (ctx, GL_INVALID_OPERATION,
+                         "Invalid Texture Unit: %d", *matrix_idx);
+            return 1;
+         }
+         break;
+
+         /* This is not currently supported (ARB_matrix_palette) */
+      case MATRIX_PALETTE:
+         *matrix_idx = parse_integer (inst, Program);
+         _mesa_set_program_error (ctx, Program->Position,
+              "ARB_matrix_palette not supported\n");
+         _mesa_error (ctx, GL_INVALID_OPERATION,
+              "ARB_matrix_palette not supported\n");
+         return 1;
+         break;
+
+      case MATRIX_PROGRAM:
+         *matrix = STATE_PROGRAM;
+         *matrix_idx = parse_integer (inst, Program);
+         if (*matrix_idx >= (GLint) ctx->Const.MaxProgramMatrices) {
+            _mesa_set_program_error (ctx, Program->Position,
+                                     "Invalid Program Matrix");
+            _mesa_error (ctx, GL_INVALID_OPERATION,
+                         "Invalid Program Matrix: %d", *matrix_idx);
+            return 1;
+         }
+         break;
+   }
+
+   switch (*(*inst)++) {
+      case MATRIX_MODIFIER_IDENTITY:
+         *matrix_modifier = 0;
+         break;
+      case MATRIX_MODIFIER_INVERSE:
+         *matrix_modifier = STATE_MATRIX_INVERSE;
+         break;
+      case MATRIX_MODIFIER_TRANSPOSE:
+         *matrix_modifier = STATE_MATRIX_TRANSPOSE;
+         break;
+      case MATRIX_MODIFIER_INVTRANS:
+         *matrix_modifier = STATE_MATRIX_INVTRANS;
+         break;
+   }
+
+   return 0;
+}
+
+
+/**
+ * This parses a state string (rather, the binary version of it) into
+ * a 6-token sequence as described in _mesa_fetch_state() [program.c]
+ *
+ * \param inst         - the start in the binary arry to start working from
+ * \param state_tokens - the storage for the 6-token state description
+ * \return             - 0 on sucess, 1 on error
+ */
+static GLuint
+parse_state_single_item (GLcontext * ctx, GLubyte ** inst,
+                         struct arb_program *Program, GLint * state_tokens)
+{
+   switch (*(*inst)++) {
+      case STATE_MATERIAL_PARSER:
+         state_tokens[0] = STATE_MATERIAL;
+         state_tokens[1] = parse_face_type (inst);
+         switch (*(*inst)++) {
+            case MATERIAL_AMBIENT:
+               state_tokens[2] = STATE_AMBIENT;
+               break;
+            case MATERIAL_DIFFUSE:
+               state_tokens[2] = STATE_DIFFUSE;
+               break;
+            case MATERIAL_SPECULAR:
+               state_tokens[2] = STATE_SPECULAR;
+               break;
+            case MATERIAL_EMISSION:
+               state_tokens[2] = STATE_EMISSION;
+              break;
+            case MATERIAL_SHININESS:
+               state_tokens[2] = STATE_SHININESS;
+               break;
+         }
+         break;
+
+      case STATE_LIGHT_PARSER:
+         state_tokens[0] = STATE_LIGHT;
+         state_tokens[1] = parse_integer (inst, Program);
+
+         /* Check the value of state_tokens[1] against the # of lights */
+         if (state_tokens[1] >= (GLint) ctx->Const.MaxLights) {
+            _mesa_set_program_error (ctx, Program->Position,
+                                     "Invalid Light Number");
+            _mesa_error (ctx, GL_INVALID_OPERATION,
+                         "Invalid Light Number: %d", state_tokens[1]);
+            return 1;
+         }
+
+         switch (*(*inst)++) {
+            case LIGHT_AMBIENT:
+               state_tokens[2] = STATE_AMBIENT;
+               break;
+            case LIGHT_DIFFUSE:
+               state_tokens[2] = STATE_DIFFUSE;
+               break;
+            case LIGHT_SPECULAR:
+               state_tokens[2] = STATE_SPECULAR;
+               break;
+            case LIGHT_POSITION:
+               state_tokens[2] = STATE_POSITION;
+               break;
+            case LIGHT_ATTENUATION:
+               state_tokens[2] = STATE_ATTENUATION;
+               break;
+            case LIGHT_HALF:
+               state_tokens[2] = STATE_HALF;
+               break;
+            case LIGHT_SPOT_DIRECTION:
+               state_tokens[2] = STATE_SPOT_DIRECTION;
+               break;
+         }
+         break;
+
+      case STATE_LIGHT_MODEL:
+         switch (*(*inst)++) {
+            case LIGHT_MODEL_AMBIENT:
+               state_tokens[0] = STATE_LIGHTMODEL_AMBIENT;
+               break;
+            case LIGHT_MODEL_SCENECOLOR:
+               state_tokens[0] = STATE_LIGHTMODEL_SCENECOLOR;
+               state_tokens[1] = parse_face_type (inst);
+               break;
+         }
+         break;
+
+      case STATE_LIGHT_PROD:
+         state_tokens[0] = STATE_LIGHTPROD;
+         state_tokens[1] = parse_integer (inst, Program);
+
+         /* Check the value of state_tokens[1] against the # of lights */
+         if (state_tokens[1] >= (GLint) ctx->Const.MaxLights) {
+            _mesa_set_program_error (ctx, Program->Position,
+                                     "Invalid Light Number");
+            _mesa_error (ctx, GL_INVALID_OPERATION,
+                         "Invalid Light Number: %d", state_tokens[1]);
+            return 1;
+         }
+
+         state_tokens[2] = parse_face_type (inst);
+         switch (*(*inst)++) {
+            case LIGHT_PROD_AMBIENT:
+               state_tokens[3] = STATE_AMBIENT;
+               break;
+            case LIGHT_PROD_DIFFUSE:
+               state_tokens[3] = STATE_DIFFUSE;
+               break;
+            case LIGHT_PROD_SPECULAR:
+               state_tokens[3] = STATE_SPECULAR;
+               break;
+         }
+         break;
+
+
+      case STATE_FOG:
+         switch (*(*inst)++) {
+            case FOG_COLOR:
+               state_tokens[0] = STATE_FOG_COLOR;
+               break;
+            case FOG_PARAMS:
+               state_tokens[0] = STATE_FOG_PARAMS;
+               break;
+         }
+         break;
+
+      case STATE_TEX_ENV:
+         state_tokens[1] = parse_integer (inst, Program);
+         switch (*(*inst)++) {
+            case TEX_ENV_COLOR:
+               state_tokens[0] = STATE_TEXENV_COLOR;
+               break;
+         }
+         break;
+
+      case STATE_TEX_GEN:
+         {
+            GLuint type, coord;
+
+            state_tokens[0] = STATE_TEXGEN;
+            /*state_tokens[1] = parse_integer (inst, Program);*/    /* Texture Unit */
+
+            if (parse_texcoord_num (ctx, inst, Program, &coord))
+               return 1;
+           state_tokens[1] = coord;
+
+            /* EYE or OBJECT */
+            type = *(*inst++);
+
+            /* 0 - s, 1 - t, 2 - r, 3 - q */
+            coord = *(*inst++);
+
+            if (type == TEX_GEN_EYE) {
+               switch (coord) {
+                  case COMPONENT_X:
+                     state_tokens[2] = STATE_TEXGEN_EYE_S;
+                     break;
+                  case COMPONENT_Y:
+                     state_tokens[2] = STATE_TEXGEN_EYE_T;
+                     break;
+                  case COMPONENT_Z:
+                     state_tokens[2] = STATE_TEXGEN_EYE_R;
+                     break;
+                  case COMPONENT_W:
+                     state_tokens[2] = STATE_TEXGEN_EYE_Q;
+                     break;
+               }
+            }
+            else {
+               switch (coord) {
+                  case COMPONENT_X:
+                     state_tokens[2] = STATE_TEXGEN_OBJECT_S;
+                     break;
+                  case COMPONENT_Y:
+                     state_tokens[2] = STATE_TEXGEN_OBJECT_T;
+                     break;
+                  case COMPONENT_Z:
+                     state_tokens[2] = STATE_TEXGEN_OBJECT_R;
+                     break;
+                  case COMPONENT_W:
+                     state_tokens[2] = STATE_TEXGEN_OBJECT_Q;
+                     break;
+               }
+            }
+         }
+         break;
+
+      case STATE_DEPTH:
+         switch (*(*inst)++) {
+            case DEPTH_RANGE:
+               state_tokens[0] = STATE_DEPTH_RANGE;
+               break;
+         }
+         break;
+
+      case STATE_CLIP_PLANE:
+         state_tokens[0] = STATE_CLIPPLANE;
+         state_tokens[1] = parse_integer (inst, Program);
+         if (parse_clipplane_num (ctx, inst, Program, &state_tokens[1]))
+            return 1;
+         break;
+
+      case STATE_POINT:
+         switch (*(*inst++)) {
+            case POINT_SIZE:
+               state_tokens[0] = STATE_POINT_SIZE;
+               break;
+
+            case POINT_ATTENUATION:
+               state_tokens[0] = STATE_POINT_ATTENUATION;
+               break;
+         }
+         break;
+
+         /* XXX: I think this is the correct format for a matrix row */
+      case STATE_MATRIX_ROWS:
+         state_tokens[0] = STATE_MATRIX;
+         if (parse_matrix
+             (ctx, inst, Program, &state_tokens[1], &state_tokens[2],
+              &state_tokens[5]))
+            return 1;
+
+         state_tokens[3] = parse_integer (inst, Program);       /* The first row to grab */
+
+         if ((**inst) != 0) {                                   /* Either the last row, 0 */
+            state_tokens[4] = parse_integer (inst, Program);
+            if (state_tokens[4] < state_tokens[3]) {
+               _mesa_set_program_error (ctx, Program->Position,
+                     "Second matrix index less than the first");
+               _mesa_error (ctx, GL_INVALID_OPERATION,
+                     "Second matrix index (%d) less than the first (%d)",
+                     state_tokens[4], state_tokens[3]);
+               return 1;
+            }
+         }
+         else {
+            state_tokens[4] = state_tokens[3];
+            (*inst)++;
+         }
+         break;
+   }
+
+   return 0;
+}
+
+/**
+ * This parses a state string (rather, the binary version of it) into
+ * a 6-token similar for the state fetching code in program.c
+ *
+ * One might ask, why fetch these parameters into just like  you fetch
+ * state when they are already stored in other places?
+ *
+ * Because of array offsets -> We can stick env/local parameters in the
+ * middle of a parameter array and then index someplace into the array
+ * when we execute.
+ *
+ * One optimization might be to only do this for the cases where the
+ * env/local parameters end up inside of an array, and leave the
+ * single parameters (or arrays of pure env/local pareameters) in their
+ * respective register files.
+ *
+ * For ENV parameters, the format is:
+ *    state_tokens[0] = STATE_FRAGMENT_PROGRAM / STATE_VERTEX_PROGRAM
+ *    state_tokens[1] = STATE_ENV
+ *    state_tokens[2] = the parameter index
+ *
+ * for LOCAL parameters, the format is:
+ *    state_tokens[0] = STATE_FRAGMENT_PROGRAM / STATE_VERTEX_PROGRAM
+ *    state_tokens[1] = STATE_LOCAL
+ *    state_tokens[2] = the parameter index
+ *
+ * \param inst         - the start in the binary arry to start working from
+ * \param state_tokens - the storage for the 6-token state description
+ * \return             - 0 on sucess, 1 on failure
+ */
+static GLuint
+parse_program_single_item (GLcontext * ctx, GLubyte ** inst,
+                           struct arb_program *Program, GLint * state_tokens)
+{
+   if (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB)
+      state_tokens[0] = STATE_FRAGMENT_PROGRAM;
+   else
+      state_tokens[0] = STATE_VERTEX_PROGRAM;
+
+
+   switch (*(*inst)++) {
+      case PROGRAM_PARAM_ENV:
+         state_tokens[1] = STATE_ENV;
+         state_tokens[2] = parse_integer (inst, Program);
+
+         /* Check state_tokens[2] against the number of ENV parameters available */
+         if (((Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) &&
+              (state_tokens[2] >= (GLint) ctx->Const.MaxFragmentProgramEnvParams))
+             ||
+             ((Program->Base.Target == GL_VERTEX_PROGRAM_ARB) &&
+              (state_tokens[2] >= (GLint) ctx->Const.MaxVertexProgramEnvParams))) {
+            _mesa_set_program_error (ctx, Program->Position,
+                                     "Invalid Program Env Parameter");
+            _mesa_error (ctx, GL_INVALID_OPERATION,
+                         "Invalid Program Env Parameter: %d",
+                         state_tokens[2]);
+            return 1;
+         }
+
+         break;
+
+      case PROGRAM_PARAM_LOCAL:
+         state_tokens[1] = STATE_LOCAL;
+         state_tokens[2] = parse_integer (inst, Program);
+
+         /* Check state_tokens[2] against the number of LOCAL parameters available */
+         if (((Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) &&
+              (state_tokens[2] >= (GLint) ctx->Const.MaxFragmentProgramLocalParams))
+             ||
+             ((Program->Base.Target == GL_VERTEX_PROGRAM_ARB) &&
+              (state_tokens[2] >= (GLint) ctx->Const.MaxVertexProgramLocalParams))) {
+            _mesa_set_program_error (ctx, Program->Position,
+                                     "Invalid Program Local Parameter");
+            _mesa_error (ctx, GL_INVALID_OPERATION,
+                         "Invalid Program Local Parameter: %d",
+                         state_tokens[2]);
+            return 1;
+         }
+         break;
+   }
+
+   return 0;
+}
+
+/**
+ * For ARB_vertex_program, programs are not allowed to use both an explicit
+ * vertex attribute and a generic vertex attribute corresponding to the same
+ * state. See section 2.14.3.1 of the GL_ARB_vertex_program spec.
+ *
+ * This will walk our var_cache and make sure that nobody does anything fishy.
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+generic_attrib_check(struct var_cache *vc_head)
+{
+   int a;
+   struct var_cache *curr;
+   GLboolean explicitAttrib[MAX_VERTEX_PROGRAM_ATTRIBS],
+      genericAttrib[MAX_VERTEX_PROGRAM_ATTRIBS];
+
+   for (a=0; a<MAX_VERTEX_PROGRAM_ATTRIBS; a++) {
+      explicitAttrib[a] = GL_FALSE;
+      genericAttrib[a] = GL_FALSE;
+   }
+
+   curr = vc_head;
+   while (curr) {
+      if (curr->type == vt_attrib) {
+         if (curr->attrib_is_generic)
+            genericAttrib[ curr->attrib_binding_idx ] = GL_TRUE;
+         else
+            explicitAttrib[ curr->attrib_binding_idx ] = GL_TRUE;
+      }
+
+      curr = curr->next;
+   }
+
+   for (a=0; a<MAX_VERTEX_PROGRAM_ATTRIBS; a++) {
+      if ((explicitAttrib[a]) && (genericAttrib[a]))
+         return 1;
+   }
+
+   return 0;
+}
+
+/**
+ * This will handle the binding side of an ATTRIB var declaration
+ *
+ * \param binding     - the fragment input register state, defined in nvfragprog.h
+ * \param binding_idx - the index in the attrib register file that binding is associated with
+ * \return returns 0 on sucess, 1 on error
+ *
+ * See nvfragparse.c for attrib register file layout
+ */
+static GLuint
+parse_attrib_binding (GLcontext * ctx, GLubyte ** inst,
+                      struct arb_program *Program, GLuint * binding,
+                      GLuint * binding_idx, GLuint *is_generic)
+{
+   GLuint texcoord;
+   GLint coord;
+   GLint err = 0;
+
+   *is_generic = 0;
+   if (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) {
+      switch (*(*inst)++) {
+         case FRAGMENT_ATTRIB_COLOR:
+            err = parse_color_type (ctx, inst, Program, &coord);
+            *binding = FRAG_ATTRIB_COL0 + coord;
+            *binding_idx = 1 + coord;
+            break;
+
+         case FRAGMENT_ATTRIB_TEXCOORD:
+            err = parse_texcoord_num (ctx, inst, Program, &texcoord);
+            *binding = FRAG_ATTRIB_TEX0 + texcoord;
+            *binding_idx = 4 + texcoord;
+            break;
+
+         case FRAGMENT_ATTRIB_FOGCOORD:
+            *binding = FRAG_ATTRIB_FOGC;
+            *binding_idx = 3;
+            break;
+
+         case FRAGMENT_ATTRIB_POSITION:
+            *binding = FRAG_ATTRIB_WPOS;
+            *binding_idx = 0;
+            break;
+
+         default:
+            err = 1;
+            break;
+      }
+   }
+   else {
+      switch (*(*inst)++) {
+         case VERTEX_ATTRIB_POSITION:
+            *binding = VERT_ATTRIB_POS;
+            *binding_idx = 0;
+            break;
+
+         case VERTEX_ATTRIB_WEIGHT:
+            {
+               GLint weight;
+
+               err = parse_weight_num (ctx, inst, Program, &weight);
+               *binding = VERT_ATTRIB_WEIGHT;
+               *binding_idx = 1;
+            }
+            _mesa_set_program_error (ctx, Program->Position,
+                 "ARB_vertex_blend not supported\n");
+            _mesa_error (ctx, GL_INVALID_OPERATION,
+                 "ARB_vertex_blend not supported\n");
+            return 1;
+            break;
+
+         case VERTEX_ATTRIB_NORMAL:
+            *binding = VERT_ATTRIB_NORMAL;
+            *binding_idx = 2;
+            break;
+
+         case VERTEX_ATTRIB_COLOR:
+            {
+               GLint color;
+
+               err = parse_color_type (ctx, inst, Program, &color);
+               if (color) {
+                  *binding = VERT_ATTRIB_COLOR1;
+                  *binding_idx = 4;
+               }
+               else {
+                  *binding = VERT_ATTRIB_COLOR0;
+                  *binding_idx = 3;
+               }
+            }
+            break;
+
+         case VERTEX_ATTRIB_FOGCOORD:
+            *binding = VERT_ATTRIB_FOG;
+            *binding_idx = 5;
+            break;
+
+         case VERTEX_ATTRIB_TEXCOORD:
+            {
+               GLuint unit;
+
+               err = parse_texcoord_num (ctx, inst, Program, &unit);
+               *binding = VERT_ATTRIB_TEX0 + unit;
+               *binding_idx = 8 + unit;
+            }
+            break;
+
+            /* It looks like we don't support this at all, atm */
+         case VERTEX_ATTRIB_MATRIXINDEX:
+            parse_integer (inst, Program);
+            _mesa_set_program_error (ctx, Program->Position,
+                  "ARB_palette_matrix not supported");
+            _mesa_error (ctx, GL_INVALID_OPERATION,
+                  "ARB_palette_matrix not supported");
+            return 1;
+            break;
+
+         case VERTEX_ATTRIB_GENERIC:
+            {
+               GLuint attrib;
+
+               if (!parse_generic_attrib_num(ctx, inst, Program, &attrib)) {
+                  *is_generic = 1;
+                  switch (attrib) {
+                     case 0:
+                        *binding = VERT_ATTRIB_POS;
+                        break;
+                     case 1:
+                        *binding = VERT_ATTRIB_WEIGHT;
+                        break;
+                     case 2:
+                        *binding = VERT_ATTRIB_NORMAL;
+                        break;
+                     case 3:
+                        *binding = VERT_ATTRIB_COLOR0;
+                        break;
+                     case 4:
+                        *binding = VERT_ATTRIB_COLOR1;
+                        break;
+                     case 5:
+                        *binding = VERT_ATTRIB_FOG;
+                        break;
+                     case 6:
+                        break;
+                     case 7:
+                        break;
+                     default:
+                        *binding = VERT_ATTRIB_TEX0 + (attrib-8);
+                        break;
+                  }
+                  *binding_idx = attrib;
+               }
+            }
+            break;
+
+         default:
+            err = 1;
+            break;
+      }
+   }
+
+   /* Can this even happen? */
+   if (err) {
+      _mesa_set_program_error (ctx, Program->Position,
+                               "Bad attribute binding");
+      _mesa_error (ctx, GL_INVALID_OPERATION, "Bad attribute binding");
+   }
+
+   Program->InputsRead |= (1 << *binding_idx);
+
+   return err;
+}
+
+/**
+ * This translates between a binary token for an output variable type
+ * and the mesa token for the same thing.
+ *
+ *
+ * XXX: What is the 'name' for vertex program state? -> do we need it?
+ *         I don't think we do;
+ *
+ * See nvfragprog.h for definitions
+ *
+ * \param inst        - The parsed tokens
+ * \param binding     - The name of the state we are binding too
+ * \param binding_idx - The index into the result register file that this is bound too
+ *
+ * See nvfragparse.c for the register file layout for fragment programs
+ * See nvvertparse.c for the register file layout for vertex programs
+ */
+static GLuint
+parse_result_binding (GLcontext * ctx, GLubyte ** inst, GLuint * binding,
+                      GLuint * binding_idx, struct arb_program *Program)
+{
+   GLuint b;
+
+   switch (*(*inst)++) {
+      case FRAGMENT_RESULT_COLOR:
+         /* for frag programs, this is FRAGMENT_RESULT_COLOR */
+         if (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) {
+            *binding = FRAG_OUTPUT_COLR;
+            *binding_idx = 0;
+         }
+         /* for vtx programs, this is VERTEX_RESULT_POSITION */
+         else {
+            *binding_idx = 0;
+         }
+         break;
+
+      case FRAGMENT_RESULT_DEPTH:
+         /* for frag programs, this is FRAGMENT_RESULT_DEPTH */
+         if (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) {
+            *binding = FRAG_OUTPUT_DEPR;
+            *binding_idx = 2;
+         }
+         /* for vtx programs, this is VERTEX_RESULT_COLOR */
+         else {
+            GLint color_type;
+            GLuint face_type = parse_face_type(inst);
+           GLint color_type_ret = parse_color_type(ctx, inst, Program, &color_type);
+
+            /* back face */
+            if (face_type) {
+               if (color_type_ret) return 1;
+
+               /* secondary color */
+               if (color_type) {
+                  *binding_idx = 4;
+               }
+               /*  primary color */
+               else {
+                  *binding_idx = 3;
+               }
+            }
+            /* front face */
+            else {
+               /* secondary color */
+               if (color_type) {
+                  *binding_idx = 2;
+               }
+               /* primary color */
+               else {
+                  *binding_idx = 1;
+               }
+            }
+         }
+         break;
+
+      case VERTEX_RESULT_FOGCOORD:
+         *binding_idx = 5;
+         break;
+
+      case VERTEX_RESULT_POINTSIZE:
+         *binding_idx = 6;
+         break;
+
+      case VERTEX_RESULT_TEXCOORD:
+         if (parse_texcoord_num (ctx, inst, Program, &b))
+            return 1;
+         *binding_idx = 7 + b;
+         break;
+   }
+
+   Program->OutputsWritten |= (1 << *binding_idx);
+
+   return 0;
+}
+
+/**
+ * This handles the declaration of ATTRIB variables
+ *
+ * XXX: Still needs
+ *      parse_vert_attrib_binding(), or something like that
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLint
+parse_attrib (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
+              struct arb_program *Program)
+{
+   GLuint found;
+   char *error_msg;
+   struct var_cache *attrib_var;
+
+   attrib_var = parse_string (inst, vc_head, Program, &found);
+   Program->Position = parse_position (inst);
+   if (found) {
+      error_msg = (char *)
+         _mesa_malloc (_mesa_strlen ((char *) attrib_var->name) + 40);
+      _mesa_sprintf (error_msg, "Duplicate Varible Declaration: %s",
+                     attrib_var->name);
+
+      _mesa_set_program_error (ctx, Program->Position, error_msg);
+      _mesa_error (ctx, GL_INVALID_OPERATION, error_msg);
+
+      _mesa_free (error_msg);
+      return 1;
+   }
+
+   attrib_var->type = vt_attrib;
+
+   /* I think this is ok now - karl */
+   /* XXX: */
+   /*if (Program->type == GL_FRAGMENT_PROGRAM_ARB) */
+   {
+      if (parse_attrib_binding
+          (ctx, inst, Program, &attrib_var->attrib_binding,
+           &attrib_var->attrib_binding_idx, &attrib_var->attrib_is_generic))
+         return 1;
+      if (generic_attrib_check(*vc_head)) {
+         _mesa_set_program_error (ctx, Program->Position,
+   "Cannot use both a generic vertex attribute and a specific attribute of the same type");
+         _mesa_error (ctx, GL_INVALID_OPERATION,
+   "Cannot use both a generic vertex attribute and a specific attribute of the same type");
+         return 1;
+      }
+
+   }
+
+   Program->Base.NumAttributes++;
+   return 0;
+}
+
+/**
+ * \param use -- TRUE if we're called when declaring implicit parameters,
+ *               FALSE if we're declaraing variables. This has to do with
+ *               if we get a signed or unsigned float for scalar constants
+ */
+static GLuint
+parse_param_elements (GLcontext * ctx, GLubyte ** inst,
+                      struct var_cache *param_var,
+                      struct arb_program *Program, GLboolean use)
+{
+   GLint idx;
+   GLuint err;
+   GLint state_tokens[6];
+   GLfloat const_values[4];
+
+   err = 0;
+
+   switch (*(*inst)++) {
+      case PARAM_STATE_ELEMENT:
+
+         if (parse_state_single_item (ctx, inst, Program, state_tokens))
+            return 1;
+
+         /* If we adding STATE_MATRIX that has multiple rows, we need to
+          * unroll it and call _mesa_add_state_reference() for each row
+          */
+         if ((state_tokens[0] == STATE_MATRIX)
+             && (state_tokens[3] != state_tokens[4])) {
+            GLint row;
+            GLint first_row = state_tokens[3];
+            GLint last_row = state_tokens[4];
+
+            for (row = first_row; row <= last_row; row++) {
+               state_tokens[3] = state_tokens[4] = row;
+
+               idx =
+                  _mesa_add_state_reference (Program->Parameters,
+                                             state_tokens);
+               if (param_var->param_binding_begin == ~0U)
+                  param_var->param_binding_begin = idx;
+               param_var->param_binding_length++;
+               Program->Base.NumParameters++;
+            }
+         }
+         else {
+            idx =
+               _mesa_add_state_reference (Program->Parameters, state_tokens);
+            if (param_var->param_binding_begin == ~0U)
+               param_var->param_binding_begin = idx;
+            param_var->param_binding_length++;
+            Program->Base.NumParameters++;
+         }
+         break;
+
+      case PARAM_PROGRAM_ELEMENT:
+
+         if (parse_program_single_item (ctx, inst, Program, state_tokens))
+            return 1;
+         idx = _mesa_add_state_reference (Program->Parameters, state_tokens);
+         if (param_var->param_binding_begin == ~0U)
+            param_var->param_binding_begin = idx;
+         param_var->param_binding_length++;
+         Program->Base.NumParameters++;
+
+         /* Check if there is more: 0 -> we're done, else its an integer */
+         if (**inst) {
+            GLuint out_of_range, new_idx;
+            GLuint start_idx = state_tokens[2] + 1;
+            GLuint end_idx = parse_integer (inst, Program);
+
+            out_of_range = 0;
+            if (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) {
+               if (((state_tokens[1] == STATE_ENV)
+                    && (end_idx >= ctx->Const.MaxFragmentProgramEnvParams))
+                   || ((state_tokens[1] == STATE_LOCAL)
+                       && (end_idx >=
+                           ctx->Const.MaxFragmentProgramLocalParams)))
+                  out_of_range = 1;
+            }
+            else {
+               if (((state_tokens[1] == STATE_ENV)
+                    && (end_idx >= ctx->Const.MaxVertexProgramEnvParams))
+                   || ((state_tokens[1] == STATE_LOCAL)
+                       && (end_idx >=
+                           ctx->Const.MaxVertexProgramLocalParams)))
+                  out_of_range = 1;
+            }
+            if (out_of_range) {
+               _mesa_set_program_error (ctx, Program->Position,
+                                        "Invalid Program Parameter");
+               _mesa_error (ctx, GL_INVALID_OPERATION,
+                            "Invalid Program Parameter: %d", end_idx);
+               return 1;
+            }
+
+            for (new_idx = start_idx; new_idx <= end_idx; new_idx++) {
+               state_tokens[2] = new_idx;
+               idx =
+                  _mesa_add_state_reference (Program->Parameters,
+                                             state_tokens);
+               param_var->param_binding_length++;
+               Program->Base.NumParameters++;
+            }
+         }
+                       else
+                       {
+                               (*inst)++;
+                       }
+         break;
+
+      case PARAM_CONSTANT:
+         parse_constant (inst, const_values, Program, use);
+         idx =
+            _mesa_add_named_constant (Program->Parameters,
+                                      (char *) param_var->name, const_values);
+         if (param_var->param_binding_begin == ~0U)
+            param_var->param_binding_begin = idx;
+         param_var->param_binding_length++;
+         Program->Base.NumParameters++;
+         break;
+
+      default:
+         _mesa_set_program_error (ctx, Program->Position,
+                                  "Unexpected token in parse_param_elements()");
+         _mesa_error (ctx, GL_INVALID_OPERATION,
+                      "Unexpected token in parse_param_elements()");
+         return 1;
+   }
+
+   /* Make sure we haven't blown past our parameter limits */
+   if (((Program->Base.Target == GL_VERTEX_PROGRAM_ARB) &&
+        (Program->Base.NumParameters >=
+         ctx->Const.MaxVertexProgramLocalParams))
+       || ((Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB)
+           && (Program->Base.NumParameters >=
+               ctx->Const.MaxFragmentProgramLocalParams))) {
+      _mesa_set_program_error (ctx, Program->Position,
+                               "Too many parameter variables");
+      _mesa_error (ctx, GL_INVALID_OPERATION, "Too many parameter variables");
+      return 1;
+   }
+
+   return err;
+}
+
+/**
+ * This picks out PARAM program parameter bindings.
+ *
+ * XXX: This needs to be stressed & tested
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_param (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
+             struct arb_program *Program)
+{
+   GLuint found, specified_length, err;
+   char *error_msg;
+   struct var_cache *param_var;
+
+   err = 0;
+   param_var = parse_string (inst, vc_head, Program, &found);
+   Program->Position = parse_position (inst);
+
+   if (found) {
+      error_msg = (char *) _mesa_malloc (_mesa_strlen ((char *) param_var->name) + 40);
+      _mesa_sprintf (error_msg, "Duplicate Varible Declaration: %s",
+                     param_var->name);
+
+      _mesa_set_program_error (ctx, Program->Position, error_msg);
+      _mesa_error (ctx, GL_INVALID_OPERATION, error_msg);
+
+      _mesa_free (error_msg);
+      return 1;
+   }
+
+   specified_length = parse_integer (inst, Program);
+
+   if (specified_length < 0) {
+      _mesa_set_program_error (ctx, Program->Position,
+                               "Negative parameter array length");
+      _mesa_error (ctx, GL_INVALID_OPERATION,
+                   "Negative parameter array length: %d", specified_length);
+      return 1;
+   }
+
+   param_var->type = vt_param;
+   param_var->param_binding_length = 0;
+
+   /* Right now, everything is shoved into the main state register file.
+    *
+    * In the future, it would be nice to leave things ENV/LOCAL params
+    * in their respective register files, if possible
+    */
+   param_var->param_binding_type = PROGRAM_STATE_VAR;
+
+   /* Remember to:
+    * *   - add each guy to the parameter list
+    * *   - increment the param_var->param_binding_len
+    * *   - store the param_var->param_binding_begin for the first one
+    * *   - compare the actual len to the specified len at the end
+    */
+   while (**inst != PARAM_NULL) {
+      if (parse_param_elements (ctx, inst, param_var, Program, GL_FALSE))
+         return 1;
+   }
+
+   /* Test array length here! */
+   if (specified_length) {
+      if (specified_length != param_var->param_binding_length) {
+         _mesa_set_program_error (ctx, Program->Position,
+                                  "Declared parameter array lenght does not match parameter list");
+         _mesa_error (ctx, GL_INVALID_OPERATION,
+                      "Declared parameter array lenght does not match parameter list");
+      }
+   }
+
+   (*inst)++;
+
+   return 0;
+}
+
+/**
+ *
+ */
+static GLuint
+parse_param_use (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
+                 struct arb_program *Program, struct var_cache **new_var)
+{
+   struct var_cache *param_var;
+
+   /* First, insert a dummy entry into the var_cache */
+   var_cache_create (&param_var);
+   param_var->name = (GLubyte *) _mesa_strdup (" ");
+   param_var->type = vt_param;
+
+   param_var->param_binding_length = 0;
+   /* Don't fill in binding_begin; We use the default value of -1
+    * to tell if its already initialized, elsewhere.
+    *
+    * param_var->param_binding_begin  = 0;
+    */
+   param_var->param_binding_type = PROGRAM_STATE_VAR;
+
+   var_cache_append (vc_head, param_var);
+
+   /* Then fill it with juicy parameter goodness */
+   if (parse_param_elements (ctx, inst, param_var, Program, GL_TRUE))
+      return 1;
+
+   *new_var = param_var;
+
+   return 0;
+}
+
+
+/**
+ * This handles the declaration of TEMP variables
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_temp (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
+            struct arb_program *Program)
+{
+   GLuint found;
+   struct var_cache *temp_var;
+   char *error_msg;
+
+   while (**inst != 0) {
+      temp_var = parse_string (inst, vc_head, Program, &found);
+      Program->Position = parse_position (inst);
+      if (found) {
+         error_msg = (char *)
+            _mesa_malloc (_mesa_strlen ((char *) temp_var->name) + 40);
+         _mesa_sprintf (error_msg, "Duplicate Varible Declaration: %s",
+                        temp_var->name);
+
+         _mesa_set_program_error (ctx, Program->Position, error_msg);
+         _mesa_error (ctx, GL_INVALID_OPERATION, error_msg);
+
+         _mesa_free (error_msg);
+         return 1;
+      }
+
+      temp_var->type = vt_temp;
+
+      if (((Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) &&
+           (Program->Base.NumTemporaries >=
+            ctx->Const.MaxFragmentProgramTemps))
+          || ((Program->Base.Target == GL_VERTEX_PROGRAM_ARB)
+              && (Program->Base.NumTemporaries >=
+                  ctx->Const.MaxVertexProgramTemps))) {
+         _mesa_set_program_error (ctx, Program->Position,
+                                  "Too many TEMP variables declared");
+         _mesa_error (ctx, GL_INVALID_OPERATION,
+                      "Too many TEMP variables declared");
+         return 1;
+      }
+
+      temp_var->temp_binding = Program->Base.NumTemporaries;
+      Program->Base.NumTemporaries++;
+   }
+   (*inst)++;
+
+   return 0;
+}
+
+/**
+ * This handles variables of the OUTPUT variety
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_output (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
+              struct arb_program *Program)
+{
+   GLuint found;
+   struct var_cache *output_var;
+
+   output_var = parse_string (inst, vc_head, Program, &found);
+   Program->Position = parse_position (inst);
+   if (found) {
+      char *error_msg;
+      error_msg = (char *)
+         _mesa_malloc (_mesa_strlen ((char *) output_var->name) + 40);
+      _mesa_sprintf (error_msg, "Duplicate Varible Declaration: %s",
+                     output_var->name);
+
+      _mesa_set_program_error (ctx, Program->Position, error_msg);
+      _mesa_error (ctx, GL_INVALID_OPERATION, error_msg);
+
+      _mesa_free (error_msg);
+      return 1;
+   }
+
+   output_var->type = vt_output;
+   return parse_result_binding (ctx, inst, &output_var->output_binding,
+                                &output_var->output_binding_idx, Program);
+}
+
+/**
+ * This handles variables of the ALIAS kind
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_alias (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
+             struct arb_program *Program)
+{
+   GLuint found;
+   struct var_cache *temp_var;
+   char *error_msg;
+
+
+   temp_var = parse_string (inst, vc_head, Program, &found);
+   Program->Position = parse_position (inst);
+
+   if (found) {
+      error_msg = (char *)
+         _mesa_malloc (_mesa_strlen ((char *) temp_var->name) + 40);
+      _mesa_sprintf (error_msg, "Duplicate Varible Declaration: %s",
+                     temp_var->name);
+
+      _mesa_set_program_error (ctx, Program->Position, error_msg);
+      _mesa_error (ctx, GL_INVALID_OPERATION, error_msg);
+
+      _mesa_free (error_msg);
+      return 1;
+   }
+
+   temp_var->type = vt_alias;
+   temp_var->alias_binding =  parse_string (inst, vc_head, Program, &found);
+   Program->Position = parse_position (inst);
+
+   if (!found)
+   {
+      error_msg = (char *)
+         _mesa_malloc (_mesa_strlen ((char *) temp_var->name) + 40);
+      _mesa_sprintf (error_msg, "Alias value %s is not defined",
+                     temp_var->alias_binding->name);
+
+      _mesa_set_program_error (ctx, Program->Position, error_msg);
+      _mesa_error (ctx, GL_INVALID_OPERATION, error_msg);
+
+      _mesa_free (error_msg);
+      return 1;
+   }
+
+   return 0;
+}
+
+/**
+ * This handles variables of the ADDRESS kind
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_address (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
+               struct arb_program *Program)
+{
+   GLuint found;
+   struct var_cache *temp_var;
+   char *error_msg;
+
+   while (**inst != 0) {
+      temp_var = parse_string (inst, vc_head, Program, &found);
+      Program->Position = parse_position (inst);
+      if (found) {
+         error_msg = (char *)
+            _mesa_malloc (_mesa_strlen ((char *) temp_var->name) + 40);
+         _mesa_sprintf (error_msg, "Duplicate Varible Declaration: %s",
+                        temp_var->name);
+
+         _mesa_set_program_error (ctx, Program->Position, error_msg);
+         _mesa_error (ctx, GL_INVALID_OPERATION, error_msg);
+
+         _mesa_free (error_msg);
+         return 1;
+      }
+
+      temp_var->type = vt_address;
+
+      if (Program->Base.NumAddressRegs >=
+          ctx->Const.MaxVertexProgramAddressRegs) {
+         _mesa_set_program_error (ctx, Program->Position,
+                                  "Too many ADDRESS variables declared");
+         _mesa_error (ctx, GL_INVALID_OPERATION,
+                      "Too many ADDRESS variables declared");
+         return 1;
+      }
+
+      temp_var->address_binding = Program->Base.NumAddressRegs;
+      Program->Base.NumAddressRegs++;
+   }
+   (*inst)++;
+
+   return 0;
+}
+
+/**
+ * Parse a program declaration
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLint
+parse_declaration (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
+                   struct arb_program *Program)
+{
+   GLint err = 0;
+
+   switch (*(*inst)++) {
+      case ADDRESS:
+         err = parse_address (ctx, inst, vc_head, Program);
+         break;
+
+      case ALIAS:
+         err = parse_alias (ctx, inst, vc_head, Program);
+         break;
+
+      case ATTRIB:
+         err = parse_attrib (ctx, inst, vc_head, Program);
+         break;
+
+      case OUTPUT:
+         err = parse_output (ctx, inst, vc_head, Program);
+         break;
+
+      case PARAM:
+         err = parse_param (ctx, inst, vc_head, Program);
+         break;
+
+      case TEMP:
+         err = parse_temp (ctx, inst, vc_head, Program);
+         break;
+   }
+
+   return err;
+}
+
+/**
+ * Handle the parsing out of a masked destination register
+ *
+ * If we are a vertex program, make sure we don't write to
+ * result.position of we have specified that the program is
+ * position invariant
+ *
+ * \param File      - The register file we write to
+ * \param Index     - The register index we write to
+ * \param WriteMask - The mask controlling which components we write (1->write)
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_masked_dst_reg (GLcontext * ctx, GLubyte ** inst,
+                      struct var_cache **vc_head, struct arb_program *Program,
+                      GLint * File, GLint * Index, GLboolean * WriteMask)
+{
+   GLuint result;
+   GLubyte mask;
+   struct var_cache *dst;
+
+   /* We either have a result register specified, or a
+    * variable that may or may not be writable
+    */
+   switch (*(*inst)++) {
+      case REGISTER_RESULT:
+         if (parse_result_binding
+             (ctx, inst, &result, (GLuint *) Index, Program))
+            return 1;
+         *File = PROGRAM_OUTPUT;
+         break;
+
+      case REGISTER_ESTABLISHED_NAME:
+         dst = parse_string (inst, vc_head, Program, &result);
+         Program->Position = parse_position (inst);
+
+         /* If the name has never been added to our symbol table, we're hosed */
+         if (!result) {
+            _mesa_set_program_error (ctx, Program->Position,
+                                     "0: Undefined variable");
+            _mesa_error (ctx, GL_INVALID_OPERATION, "0: Undefined variable: %s",
+                         dst->name);
+            return 1;
+         }
+
+         switch (dst->type) {
+            case vt_output:
+               *File = PROGRAM_OUTPUT;
+               *Index = dst->output_binding_idx;
+               break;
+
+            case vt_temp:
+               *File = PROGRAM_TEMPORARY;
+               *Index = dst->temp_binding;
+               break;
+
+               /* If the var type is not vt_output or vt_temp, no go */
+            default:
+               _mesa_set_program_error (ctx, Program->Position,
+                                        "Destination register is read only");
+               _mesa_error (ctx, GL_INVALID_OPERATION,
+                            "Destination register is read only: %s",
+                            dst->name);
+               return 1;
+         }
+         break;
+
+      default:
+         _mesa_set_program_error (ctx, Program->Position,
+                                  "Unexpected opcode in parse_masked_dst_reg()");
+         _mesa_error (ctx, GL_INVALID_OPERATION,
+                      "Unexpected opcode in parse_masked_dst_reg()");
+         return 1;
+   }
+
+
+   /* Position invariance test */
+   /* This test is done now in syntax portion - when position invariance OPTION
+      is specified, "result.position" rule is disabled so there is no way
+      to write the position
+   */
+   /*if ((Program->HintPositionInvariant) && (*File == PROGRAM_OUTPUT) &&
+      (*Index == 0))   {
+      _mesa_set_program_error (ctx, Program->Position,
+                  "Vertex program specified position invariance and wrote vertex position");
+      _mesa_error (ctx, GL_INVALID_OPERATION,
+                  "Vertex program specified position invariance and wrote vertex position");
+   }*/
+
+   /* And then the mask.
+    *  w,a -> bit 0
+    *  z,b -> bit 1
+    *  y,g -> bit 2
+    *  x,r -> bit 3
+    */
+   mask = *(*inst)++;
+
+   WriteMask[0] = (GLboolean) (mask & (1 << 3)) >> 3;
+   WriteMask[1] = (GLboolean) (mask & (1 << 2)) >> 2;
+   WriteMask[2] = (GLboolean) (mask & (1 << 1)) >> 1;
+   WriteMask[3] = (GLboolean) (mask & (1));
+
+   return 0;
+}
+
+
+/**
+ * Handle the parsing of a address register
+ *
+ * \param Index     - The register index we write to
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_address_reg (GLcontext * ctx, GLubyte ** inst,
+                          struct var_cache **vc_head,
+                          struct arb_program *Program, GLint * Index)
+{
+   struct var_cache *dst;
+   GLuint result;
+
+   dst = parse_string (inst, vc_head, Program, &result);
+   Program->Position = parse_position (inst);
+
+   /* If the name has never been added to our symbol table, we're hosed */
+   if (!result) {
+      _mesa_set_program_error (ctx, Program->Position, "Undefined variable");
+      _mesa_error (ctx, GL_INVALID_OPERATION, "Undefined variable: %s",
+                   dst->name);
+      return 1;
+   }
+
+   if (dst->type != vt_address) {
+      _mesa_set_program_error (ctx, Program->Position,
+                               "Variable is not of type ADDRESS");
+      _mesa_error (ctx, GL_INVALID_OPERATION,
+                   "Variable: %s is not of type ADDRESS", dst->name);
+      return 1;
+   }
+
+   return 0;
+}
+
+/**
+ * Handle the parsing out of a masked address register
+ *
+ * \param Index     - The register index we write to
+ * \param WriteMask - The mask controlling which components we write (1->write)
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_masked_address_reg (GLcontext * ctx, GLubyte ** inst,
+                          struct var_cache **vc_head,
+                          struct arb_program *Program, GLint * Index,
+                          GLboolean * WriteMask)
+{
+   if (parse_address_reg (ctx, inst, vc_head, Program, Index))
+      return 1;
+
+   /* This should be 0x8 */
+   (*inst)++;
+
+   /* Writemask of .x is implied */
+   WriteMask[0] = 1;
+   WriteMask[1] = WriteMask[2] = WriteMask[3] = 0;
+
+   return 0;
+}
+
+
+/**
+ * Parse out a swizzle mask.
+ *
+ * The values in the input stream are:
+ *   COMPONENT_X -> x/r
+ *   COMPONENT_Y -> y/g
+ *   COMPONENT_Z-> z/b
+ *   COMPONENT_W-> w/a
+ *
+ * The values in the output mask are:
+ *   0 -> x/r
+ *   1 -> y/g
+ *   2 -> z/b
+ *   3 -> w/a
+ *
+ * The len parameter allows us to grab 4 components for a vector
+ * swizzle, or just 1 component for a scalar src register selection
+ */
+static GLuint
+parse_swizzle_mask (GLubyte ** inst, GLubyte * mask, GLint len)
+{
+   GLint a;
+
+   for (a = 0; a < 4; a++)
+      mask[a] = a;
+
+   for (a = 0; a < len; a++) {
+      switch (*(*inst)++) {
+         case COMPONENT_X:
+            mask[a] = 0;
+            break;
+
+         case COMPONENT_Y:
+            mask[a] = 1;
+            break;
+
+         case COMPONENT_Z:
+            mask[a] = 2;
+            break;
+
+         case COMPONENT_W:
+            mask[a] = 3;
+            break;
+      }
+   }
+
+   return 0;
+}
+
+/**
+ */
+static GLuint
+parse_extended_swizzle_mask (GLubyte ** inst, GLubyte * mask, GLboolean * Negate)
+{
+   GLint a;
+   GLubyte swz;
+
+   *Negate = GL_FALSE;
+   for (a = 0; a < 4; a++) {
+      if (parse_sign (inst))
+         *Negate = GL_TRUE;
+
+      swz = *(*inst)++;
+
+      switch (swz) {
+         case COMPONENT_0:
+            mask[a] = SWIZZLE_ZERO;
+            break;
+         case COMPONENT_1:
+            mask[a] = SWIZZLE_ONE;
+            break;
+         case COMPONENT_X:
+            mask[a] = SWIZZLE_X;
+            break;
+         case COMPONENT_Y:
+            mask[a] = SWIZZLE_Y;
+            break;
+         case COMPONENT_Z:
+            mask[a] = SWIZZLE_Z;
+            break;
+         case COMPONENT_W:
+            mask[a] = SWIZZLE_W;
+            break;
+
+      }
+#if 0
+      if (swz == 0)
+         mask[a] = SWIZZLE_ZERO;
+      else if (swz == 1)
+         mask[a] = SWIZZLE_ONE;
+      else
+         mask[a] = swz - 2;
+#endif
+
+   }
+
+   return 0;
+}
+
+
+static GLuint
+parse_src_reg (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
+               struct arb_program *Program, GLint * File, GLint * Index,
+               GLboolean *IsRelOffset )
+{
+   struct var_cache *src;
+   GLuint binding_state, binding_idx, is_generic, found, offset;
+
+   /* And the binding for the src */
+   switch (*(*inst)++) {
+      case REGISTER_ATTRIB:
+         if (parse_attrib_binding
+             (ctx, inst, Program, &binding_state, &binding_idx, &is_generic))
+            return 1;
+         *File = PROGRAM_INPUT;
+         *Index = binding_idx;
+
+         /* We need to insert a dummy variable into the var_cache so we can
+          * catch generic vertex attrib aliasing errors
+          */
+         var_cache_create(&src);
+         src->type = vt_attrib;
+         src->name = (GLubyte *)_mesa_strdup("Dummy Attrib Variable");
+         src->attrib_binding     = binding_state;
+         src->attrib_binding_idx = binding_idx;
+         src->attrib_is_generic  = is_generic;
+         var_cache_append(vc_head, src);
+         if (generic_attrib_check(*vc_head)) {
+            _mesa_set_program_error (ctx, Program->Position,
+   "Cannot use both a generic vertex attribute and a specific attribute of the same type");
+            _mesa_error (ctx, GL_INVALID_OPERATION,
+   "Cannot use both a generic vertex attribute and a specific attribute of the same type");
+            return 1;
+         }
+         break;
+
+      case REGISTER_PARAM:
+         switch (**inst) {
+            case PARAM_ARRAY_ELEMENT:
+               (*inst)++;
+               src = parse_string (inst, vc_head, Program, &found);
+               Program->Position = parse_position (inst);
+
+               if (!found) {
+                  _mesa_set_program_error (ctx, Program->Position,
+                                           "2: Undefined variable");
+                  _mesa_error (ctx, GL_INVALID_OPERATION,
+                               "2: Undefined variable: %s", src->name);
+                  return 1;
+               }
+
+               *File = src->param_binding_type;
+
+               switch (*(*inst)++) {
+                  case ARRAY_INDEX_ABSOLUTE:
+                     offset = parse_integer (inst, Program);
+
+                     if ((offset < 0)
+                         || (offset >= src->param_binding_length)) {
+                        _mesa_set_program_error (ctx, Program->Position,
+                                                 "Index out of range");
+                        _mesa_error (ctx, GL_INVALID_OPERATION,
+                                     "Index %d out of range for %s", offset,
+                                     src->name);
+                        return 1;
+                     }
+
+                     *Index = src->param_binding_begin + offset;
+                     break;
+
+                  case ARRAY_INDEX_RELATIVE:
+                     {
+                        GLint addr_reg_idx, rel_off;
+
+                        /* First, grab the address regiseter */
+                        if (parse_address_reg (ctx, inst, vc_head, Program, &addr_reg_idx))
+                           return 1;
+
+                        /* And the .x */
+                        ((*inst)++);
+                        ((*inst)++);
+                        ((*inst)++);
+                        ((*inst)++);
+
+                        /* Then the relative offset */
+                        if (parse_relative_offset(ctx, inst, Program, &rel_off)) return 1;
+
+                        /* And store it properly */
+                        *Index = src->param_binding_begin + rel_off;
+                        *IsRelOffset = 1;
+                     }
+                     break;
+               }
+               break;
+
+            default:
+
+               if (parse_param_use (ctx, inst, vc_head, Program, &src))
+                  return 1;
+
+               *File = src->param_binding_type;
+               *Index = src->param_binding_begin;
+               break;
+         }
+         break;
+
+      case REGISTER_ESTABLISHED_NAME:
+
+         src = parse_string (inst, vc_head, Program, &found);
+         Program->Position = parse_position (inst);
+
+         /* If the name has never been added to our symbol table, we're hosed */
+         if (!found) {
+            _mesa_set_program_error (ctx, Program->Position,
+                                     "3: Undefined variable");
+            _mesa_error (ctx, GL_INVALID_OPERATION, "3: Undefined variable: %s",
+                         src->name);
+            return 1;
+         }
+
+         switch (src->type) {
+            case vt_attrib:
+               *File = PROGRAM_INPUT;
+               *Index = src->attrib_binding_idx;
+               break;
+
+               /* XXX: We have to handle offsets someplace in here!  -- or are those above? */
+            case vt_param:
+               *File = src->param_binding_type;
+               *Index = src->param_binding_begin;
+               break;
+
+            case vt_temp:
+               *File = PROGRAM_TEMPORARY;
+               *Index = src->temp_binding;
+               break;
+
+               /* If the var type is vt_output no go */
+            default:
+               _mesa_set_program_error (ctx, Program->Position,
+                                        "destination register is read only");
+               _mesa_error (ctx, GL_INVALID_OPERATION,
+                            "destination register is read only: %s",
+                            src->name);
+               return 1;
+         }
+         break;
+
+      default:
+         _mesa_set_program_error (ctx, Program->Position,
+                                  "Unknown token in parse_src_reg");
+         _mesa_error (ctx, GL_INVALID_OPERATION,
+                      "Unknown token in parse_src_reg");
+         return 1;
+   }
+
+   return 0;
+}
+
+/**
+ */
+static GLuint
+parse_vector_src_reg (GLcontext * ctx, GLubyte ** inst,
+                      struct var_cache **vc_head, struct arb_program *Program,
+                      GLint * File, GLint * Index, GLboolean * Negate,
+                      GLubyte * Swizzle, GLboolean *IsRelOffset)
+{
+   /* Grab the sign */
+   *Negate = parse_sign (inst);
+
+   /* And the src reg */
+   if (parse_src_reg (ctx, inst, vc_head, Program, File, Index, IsRelOffset))
+      return 1;
+
+   /* finally, the swizzle */
+   parse_swizzle_mask (inst, Swizzle, 4);
+
+   return 0;
+}
+
+/**
+ */
+static GLuint
+parse_scalar_src_reg (GLcontext * ctx, GLubyte ** inst,
+                      struct var_cache **vc_head, struct arb_program *Program,
+                      GLint * File, GLint * Index, GLboolean * Negate,
+                      GLubyte * Swizzle, GLboolean *IsRelOffset)
+{
+   /* Grab the sign */
+   *Negate = parse_sign (inst);
+
+   /* And the src reg */
+   if (parse_src_reg (ctx, inst, vc_head, Program, File, Index, IsRelOffset))
+      return 1;
+
+   /* Now, get the component and shove it into all the swizzle slots  */
+   parse_swizzle_mask (inst, Swizzle, 1);
+
+   return 0;
+}
+
+/**
+ * This is a big mother that handles getting opcodes into the instruction
+ * and handling the src & dst registers for fragment program instructions
+ */
+static GLuint
+parse_fp_instruction (GLcontext * ctx, GLubyte ** inst,
+                      struct var_cache **vc_head, struct arb_program *Program,
+                      struct fp_instruction *fp)
+{
+   GLint a, b;
+   GLubyte swz[4]; /* FP's swizzle mask is a GLubyte, while VP's is GLuint */
+   GLuint texcoord;
+   GLubyte instClass, type, code;
+   GLboolean rel;
+
+   /* No condition codes in ARB_fp */
+   fp->UpdateCondRegister = 0;
+
+   /* Record the position in the program string for debugging */
+   fp->StringPos = Program->Position;
+
+   /* OP_ALU_INST or OP_TEX_INST */
+   instClass = *(*inst)++;
+
+   /* OP_ALU_{VECTOR, SCALAR, BINSC, BIN, TRI, SWZ},
+    * OP_TEX_{SAMPLE, KIL}
+    */
+   type = *(*inst)++;
+
+   /* The actual opcode name */
+   code = *(*inst)++;
+
+   /* Increment the correct count */
+   switch (instClass) {
+      case OP_ALU_INST:
+         Program->NumAluInstructions++;
+         break;
+      case OP_TEX_INST:
+         Program->NumTexInstructions++;
+         break;
+   }
+
+   fp->Saturate = 0;
+   fp->Precision = FLOAT32;
+
+   fp->DstReg.CondMask = COND_TR;
+
+   switch (type) {
+      case OP_ALU_VECTOR:
+         switch (code) {
+            case OP_ABS_SAT:
+               fp->Saturate = 1;
+            case OP_ABS:
+               fp->Opcode = FP_OPCODE_ABS;
+               break;
+
+            case OP_FLR_SAT:
+               fp->Saturate = 1;
+            case OP_FLR:
+               fp->Opcode = FP_OPCODE_FLR;
+               break;
+
+            case OP_FRC_SAT:
+               fp->Saturate = 1;
+            case OP_FRC:
+               fp->Opcode = FP_OPCODE_FRC;
+               break;
+
+            case OP_LIT_SAT:
+               fp->Saturate = 1;
+            case OP_LIT:
+               fp->Opcode = FP_OPCODE_LIT;
+               break;
+
+            case OP_MOV_SAT:
+               fp->Saturate = 1;
+            case OP_MOV:
+               fp->Opcode = FP_OPCODE_MOV;
+               break;
+         }
+
+         if (parse_masked_dst_reg
+             (ctx, inst, vc_head, Program, (GLint *) & fp->DstReg.File,
+              &fp->DstReg.Index, fp->DstReg.WriteMask))
+            return 1;
+
+         fp->SrcReg[0].Abs = GL_FALSE;
+         fp->SrcReg[0].NegateAbs = GL_FALSE;
+         if (parse_vector_src_reg
+             (ctx, inst, vc_head, Program, (GLint *) & fp->SrcReg[0].File,
+              &fp->SrcReg[0].Index, &fp->SrcReg[0].NegateBase,
+              swz, &rel))
+            return 1;
+         for (b=0; b<4; b++)
+            fp->SrcReg[0].Swizzle[b] = swz[b];
+         break;
+
+      case OP_ALU_SCALAR:
+         switch (code) {
+            case OP_COS_SAT:
+               fp->Saturate = 1;
+            case OP_COS:
+               fp->Opcode = FP_OPCODE_COS;
+               break;
+
+            case OP_EX2_SAT:
+               fp->Saturate = 1;
+            case OP_EX2:
+               fp->Opcode = FP_OPCODE_EX2;
+               break;
+
+            case OP_LG2_SAT:
+               fp->Saturate = 1;
+            case OP_LG2:
+               fp->Opcode = FP_OPCODE_LG2;
+               break;
+
+            case OP_RCP_SAT:
+               fp->Saturate = 1;
+            case OP_RCP:
+               fp->Opcode = FP_OPCODE_RCP;
+               break;
+
+            case OP_RSQ_SAT:
+               fp->Saturate = 1;
+            case OP_RSQ:
+               fp->Opcode = FP_OPCODE_RSQ;
+               break;
+
+            case OP_SIN_SAT:
+               fp->Saturate = 1;
+            case OP_SIN:
+               fp->Opcode = FP_OPCODE_SIN;
+               break;
+
+            case OP_SCS_SAT:
+               fp->Saturate = 1;
+            case OP_SCS:
+
+               fp->Opcode = FP_OPCODE_SCS;
+               break;
+         }
+
+         if (parse_masked_dst_reg
+             (ctx, inst, vc_head, Program, (GLint *) & fp->DstReg.File,
+              &fp->DstReg.Index, fp->DstReg.WriteMask))
+            return 1;
+         fp->SrcReg[0].Abs = GL_FALSE;
+         fp->SrcReg[0].NegateAbs = GL_FALSE;
+         if (parse_scalar_src_reg
+             (ctx, inst, vc_head, Program, (GLint *) & fp->SrcReg[0].File,
+              &fp->SrcReg[0].Index, &fp->SrcReg[0].NegateBase,
+              swz, &rel))
+            return 1;
+         for (b=0; b<4; b++)
+            fp->SrcReg[0].Swizzle[b] = swz[b];
+         break;
+
+      case OP_ALU_BINSC:
+         switch (code) {
+            case OP_POW_SAT:
+               fp->Saturate = 1;
+            case OP_POW:
+               fp->Opcode = FP_OPCODE_POW;
+               break;
+         }
+
+         if (parse_masked_dst_reg
+             (ctx, inst, vc_head, Program, (GLint *) & fp->DstReg.File,
+              &fp->DstReg.Index, fp->DstReg.WriteMask))
+            return 1;
+         for (a = 0; a < 2; a++) {
+            fp->SrcReg[a].Abs = GL_FALSE;
+            fp->SrcReg[a].NegateAbs = GL_FALSE;
+            if (parse_scalar_src_reg
+                (ctx, inst, vc_head, Program, (GLint *) & fp->SrcReg[a].File,
+                 &fp->SrcReg[a].Index, &fp->SrcReg[a].NegateBase,
+                 swz, &rel))
+               return 1;
+            for (b=0; b<4; b++)
+               fp->SrcReg[a].Swizzle[b] = swz[b];
+         }
+         break;
+
+
+      case OP_ALU_BIN:
+         switch (code) {
+            case OP_ADD_SAT:
+               fp->Saturate = 1;
+            case OP_ADD:
+               fp->Opcode = FP_OPCODE_ADD;
+               break;
+
+            case OP_DP3_SAT:
+               fp->Saturate = 1;
+            case OP_DP3:
+               fp->Opcode = FP_OPCODE_DP3;
+               break;
+
+            case OP_DP4_SAT:
+               fp->Saturate = 1;
+            case OP_DP4:
+               fp->Opcode = FP_OPCODE_DP4;
+               break;
+
+            case OP_DPH_SAT:
+               fp->Saturate = 1;
+            case OP_DPH:
+               fp->Opcode = FP_OPCODE_DPH;
+               break;
+
+            case OP_DST_SAT:
+               fp->Saturate = 1;
+            case OP_DST:
+               fp->Opcode = FP_OPCODE_DST;
+               break;
+
+            case OP_MAX_SAT:
+               fp->Saturate = 1;
+            case OP_MAX:
+               fp->Opcode = FP_OPCODE_MAX;
+               break;
+
+            case OP_MIN_SAT:
+               fp->Saturate = 1;
+            case OP_MIN:
+               fp->Opcode = FP_OPCODE_MIN;
+               break;
+
+            case OP_MUL_SAT:
+               fp->Saturate = 1;
+            case OP_MUL:
+               fp->Opcode = FP_OPCODE_MUL;
+               break;
+
+            case OP_SGE_SAT:
+               fp->Saturate = 1;
+            case OP_SGE:
+               fp->Opcode = FP_OPCODE_SGE;
+               break;
+
+            case OP_SLT_SAT:
+               fp->Saturate = 1;
+            case OP_SLT:
+               fp->Opcode = FP_OPCODE_SLT;
+               break;
+
+            case OP_SUB_SAT:
+               fp->Saturate = 1;
+            case OP_SUB:
+               fp->Opcode = FP_OPCODE_SUB;
+               break;
+
+            case OP_XPD_SAT:
+               fp->Saturate = 1;
+            case OP_XPD:
+               fp->Opcode = FP_OPCODE_X2D;
+               break;
+         }
+
+         if (parse_masked_dst_reg
+             (ctx, inst, vc_head, Program, (GLint *) & fp->DstReg.File,
+              &fp->DstReg.Index, fp->DstReg.WriteMask))
+            return 1;
+         for (a = 0; a < 2; a++) {
+            fp->SrcReg[a].Abs = GL_FALSE;
+            fp->SrcReg[a].NegateAbs = GL_FALSE;
+            if (parse_vector_src_reg
+                (ctx, inst, vc_head, Program, (GLint *) & fp->SrcReg[a].File,
+                 &fp->SrcReg[a].Index, &fp->SrcReg[a].NegateBase,
+                 swz, &rel))
+               return 1;
+            for (b=0; b<4; b++)
+               fp->SrcReg[a].Swizzle[b] = swz[b];
+         }
+         break;
+
+      case OP_ALU_TRI:
+         switch (code) {
+            case OP_CMP_SAT:
+               fp->Saturate = 1;
+            case OP_CMP:
+               fp->Opcode = FP_OPCODE_CMP;
+               break;
+
+            case OP_LRP_SAT:
+               fp->Saturate = 1;
+            case OP_LRP:
+               fp->Opcode = FP_OPCODE_LRP;
+               break;
+
+            case OP_MAD_SAT:
+               fp->Saturate = 1;
+            case OP_MAD:
+               fp->Opcode = FP_OPCODE_MAD;
+               break;
+         }
+
+         if (parse_masked_dst_reg
+             (ctx, inst, vc_head, Program, (GLint *) & fp->DstReg.File,
+              &fp->DstReg.Index, fp->DstReg.WriteMask))
+            return 1;
+         for (a = 0; a < 3; a++) {
+            fp->SrcReg[a].Abs = GL_FALSE;
+            fp->SrcReg[a].NegateAbs = GL_FALSE;
+            if (parse_vector_src_reg
+                (ctx, inst, vc_head, Program, (GLint *) & fp->SrcReg[a].File,
+                 &fp->SrcReg[a].Index, &fp->SrcReg[a].NegateBase,
+                 swz, &rel))
+               return 1;
+            for (b=0; b<4; b++)
+               fp->SrcReg[a].Swizzle[b] = swz[b];
+         }
+         break;
+
+      case OP_ALU_SWZ:
+         switch (code) {
+            case OP_SWZ_SAT:
+               fp->Saturate = 1;
+            case OP_SWZ:
+               fp->Opcode = FP_OPCODE_SWZ;
+               break;
+         }
+         if (parse_masked_dst_reg
+             (ctx, inst, vc_head, Program, (GLint *) & fp->DstReg.File,
+              &fp->DstReg.Index, fp->DstReg.WriteMask))
+            return 1;
+
+         if (parse_src_reg
+             (ctx, inst, vc_head, Program, (GLint *) & fp->SrcReg[0].File,
+              &fp->SrcReg[0].Index, &rel))
+            return 1;
+         parse_extended_swizzle_mask (inst, swz,
+                                      &fp->SrcReg[0].NegateBase);
+         for (b=0; b<4; b++)
+            fp->SrcReg[0].Swizzle[b] = swz[b];
+         break;
+
+      case OP_TEX_SAMPLE:
+         switch (code) {
+            case OP_TEX_SAT:
+               fp->Saturate = 1;
+            case OP_TEX:
+               fp->Opcode = FP_OPCODE_TEX;
+               break;
+
+            case OP_TXP_SAT:
+               fp->Saturate = 1;
+            case OP_TXP:
+               fp->Opcode = FP_OPCODE_TXP;
+               break;
+
+            case OP_TXB_SAT:
+
+               fp->Saturate = 1;
+            case OP_TXB:
+               fp->Opcode = FP_OPCODE_TXB;
+               break;
+         }
+
+         if (parse_masked_dst_reg
+             (ctx, inst, vc_head, Program, (GLint *) & fp->DstReg.File,
+              &fp->DstReg.Index, fp->DstReg.WriteMask))
+            return 1;
+         fp->SrcReg[0].Abs = GL_FALSE;
+         fp->SrcReg[0].NegateAbs = GL_FALSE;
+         if (parse_vector_src_reg
+             (ctx, inst, vc_head, Program, (GLint *) & fp->SrcReg[0].File,
+              &fp->SrcReg[0].Index, &fp->SrcReg[0].NegateBase,
+              swz, &rel))
+            return 1;
+         for (b=0; b<4; b++)
+            fp->SrcReg[0].Swizzle[b] = swz[b];
+
+         /* texImageUnit */
+         if (parse_texcoord_num (ctx, inst, Program, &texcoord))
+            return 1;
+         fp->TexSrcUnit = texcoord;
+
+         /* texTarget */
+         switch (*(*inst)++) {
+            case TEXTARGET_1D:
+               fp->TexSrcBit = TEXTURE_1D_BIT;
+               break;
+            case TEXTARGET_2D:
+               fp->TexSrcBit = TEXTURE_2D_BIT;
+               break;
+            case TEXTARGET_3D:
+               fp->TexSrcBit = TEXTURE_3D_BIT;
+               break;
+            case TEXTARGET_RECT:
+               fp->TexSrcBit = TEXTURE_RECT_BIT;
+               break;
+            case TEXTARGET_CUBE:
+               fp->TexSrcBit = TEXTURE_CUBE_BIT;
+               break;
+           case TEXTARGET_SHADOW1D:
+           case TEXTARGET_SHADOW2D:
+           case TEXTARGET_SHADOWRECT:
+              /* TODO ARB_fragment_program_shadow code */
+              break;
+         }
+         Program->TexturesUsed[texcoord] |= fp->TexSrcBit;
+         break;
+
+      case OP_TEX_KIL:
+         fp->Opcode = FP_OPCODE_KIL;
+         fp->SrcReg[0].Abs = GL_FALSE;
+         fp->SrcReg[0].NegateAbs = GL_FALSE;
+         if (parse_vector_src_reg
+             (ctx, inst, vc_head, Program, (GLint *) & fp->SrcReg[0].File,
+              &fp->SrcReg[0].Index, &fp->SrcReg[0].NegateBase,
+              swz, &rel))
+            return 1;
+         for (b=0; b<4; b++)
+            fp->SrcReg[0].Swizzle[b] = swz[b];
+         break;
+   }
+
+   return 0;
+}
+
+/**
+ * This is a big mother that handles getting opcodes into the instruction
+ * and handling the src & dst registers for vertex program instructions
+ */
+static GLuint
+parse_vp_instruction (GLcontext * ctx, GLubyte ** inst,
+                      struct var_cache **vc_head, struct arb_program *Program,
+                      struct vp_instruction *vp)
+{
+   GLint a;
+   GLubyte type, code;
+
+   /* OP_ALU_{ARL, VECTOR, SCALAR, BINSC, BIN, TRI, SWZ} */
+   type = *(*inst)++;
+
+   /* The actual opcode name */
+   code = *(*inst)++;
+
+   /* Record the position in the program string for debugging */
+   vp->StringPos = Program->Position;
+
+   vp->SrcReg[0].RelAddr = vp->SrcReg[1].RelAddr = vp->SrcReg[2].RelAddr = 0;
+
+   for (a = 0; a < 4; a++) {
+      vp->SrcReg[0].Swizzle[a] = a;
+      vp->SrcReg[1].Swizzle[a] = a;
+      vp->SrcReg[2].Swizzle[a] = a;
+      vp->DstReg.WriteMask[a] = 1;
+   }
+
+   switch (type) {
+         /* XXX: */
+      case OP_ALU_ARL:
+         vp->Opcode = VP_OPCODE_ARL;
+
+         /* Remember to set SrcReg.RelAddr; */
+
+         /* Get the masked address register [dst] */
+         if (parse_masked_address_reg
+             (ctx, inst, vc_head, Program, &vp->DstReg.Index,
+              vp->DstReg.WriteMask))
+            return 1;
+         vp->DstReg.File = PROGRAM_ADDRESS;
+
+         /* Get a scalar src register */
+         if (parse_scalar_src_reg
+             (ctx, inst, vc_head, Program, (GLint *) & vp->SrcReg[0].File,
+              &vp->SrcReg[0].Index, &vp->SrcReg[0].Negate,
+              vp->SrcReg[0].Swizzle, &vp->SrcReg[0].RelAddr))
+            return 1;
+
+         break;
+
+      case OP_ALU_VECTOR:
+         switch (code) {
+            case OP_ABS:
+               vp->Opcode = VP_OPCODE_ABS;
+               break;
+            case OP_FLR:
+               vp->Opcode = VP_OPCODE_FLR;
+               break;
+            case OP_FRC:
+               vp->Opcode = VP_OPCODE_FRC;
+               break;
+            case OP_LIT:
+               vp->Opcode = VP_OPCODE_LIT;
+               break;
+            case OP_MOV:
+               vp->Opcode = VP_OPCODE_MOV;
+               break;
+         }
+         if (parse_masked_dst_reg
+             (ctx, inst, vc_head, Program, (GLint *) & vp->DstReg.File,
+              &vp->DstReg.Index, vp->DstReg.WriteMask))
+            return 1;
+         if (parse_vector_src_reg
+             (ctx, inst, vc_head, Program, (GLint *) & vp->SrcReg[0].File,
+              &vp->SrcReg[0].Index, &vp->SrcReg[0].Negate,
+              vp->SrcReg[0].Swizzle, &vp->SrcReg[0].RelAddr))
+            return 1;
+         break;
+
+      case OP_ALU_SCALAR:
+         switch (code) {
+            case OP_EX2:
+               vp->Opcode = VP_OPCODE_EX2;
+               break;
+            case OP_EXP:
+               vp->Opcode = VP_OPCODE_EXP;
+               break;
+            case OP_LG2:
+               vp->Opcode = VP_OPCODE_LG2;
+               break;
+            case OP_LOG:
+               vp->Opcode = VP_OPCODE_LOG;
+               break;
+            case OP_RCP:
+               vp->Opcode = VP_OPCODE_RCP;
+               break;
+            case OP_RSQ:
+               vp->Opcode = VP_OPCODE_RSQ;
+               break;
+         }
+         if (parse_masked_dst_reg
+             (ctx, inst, vc_head, Program, (GLint *) & vp->DstReg.File,
+              &vp->DstReg.Index, vp->DstReg.WriteMask))
+            return 1;
+         if (parse_scalar_src_reg
+             (ctx, inst, vc_head, Program, (GLint *) & vp->SrcReg[0].File,
+              &vp->SrcReg[0].Index, &vp->SrcReg[0].Negate,
+              vp->SrcReg[0].Swizzle, &vp->SrcReg[0].RelAddr))
+            return 1;
+         break;
+
+      case OP_ALU_BINSC:
+         switch (code) {
+            case OP_POW:
+               vp->Opcode = VP_OPCODE_POW;
+               break;
+         }
+         if (parse_masked_dst_reg
+             (ctx, inst, vc_head, Program, (GLint *) & vp->DstReg.File,
+              &vp->DstReg.Index, vp->DstReg.WriteMask))
+            return 1;
+         for (a = 0; a < 2; a++) {
+            if (parse_scalar_src_reg
+                (ctx, inst, vc_head, Program, (GLint *) & vp->SrcReg[a].File,
+                 &vp->SrcReg[a].Index, &vp->SrcReg[a].Negate,
+                 vp->SrcReg[a].Swizzle, &vp->SrcReg[a].RelAddr))
+               return 1;
+         }
+         break;
+
+      case OP_ALU_BIN:
+         switch (code) {
+            case OP_ADD:
+               vp->Opcode = VP_OPCODE_ADD;
+               break;
+            case OP_DP3:
+               vp->Opcode = VP_OPCODE_DP3;
+               break;
+            case OP_DP4:
+               vp->Opcode = VP_OPCODE_DP4;
+               break;
+            case OP_DPH:
+               vp->Opcode = VP_OPCODE_DPH;
+               break;
+            case OP_DST:
+               vp->Opcode = VP_OPCODE_DST;
+               break;
+            case OP_MAX:
+               vp->Opcode = VP_OPCODE_MAX;
+               break;
+            case OP_MIN:
+               vp->Opcode = VP_OPCODE_MIN;
+               break;
+            case OP_MUL:
+               vp->Opcode = VP_OPCODE_MUL;
+               break;
+            case OP_SGE:
+               vp->Opcode = VP_OPCODE_SGE;
+               break;
+            case OP_SLT:
+               vp->Opcode = VP_OPCODE_SLT;
+               break;
+            case OP_SUB:
+               vp->Opcode = VP_OPCODE_SUB;
+               break;
+            case OP_XPD:
+               vp->Opcode = VP_OPCODE_XPD;
+               break;
+         }
+         if (parse_masked_dst_reg
+             (ctx, inst, vc_head, Program, (GLint *) & vp->DstReg.File,
+              &vp->DstReg.Index, vp->DstReg.WriteMask))
+            return 1;
+         for (a = 0; a < 2; a++) {
+            if (parse_vector_src_reg
+                (ctx, inst, vc_head, Program, (GLint *) & vp->SrcReg[a].File,
+                 &vp->SrcReg[a].Index, &vp->SrcReg[a].Negate,
+                 vp->SrcReg[a].Swizzle, &vp->SrcReg[a].RelAddr))
+               return 1;
+         }
+         break;
+
+      case OP_ALU_TRI:
+         switch (code) {
+            case OP_MAD:
+               vp->Opcode = VP_OPCODE_MAD;
+               break;
+         }
+
+         if (parse_masked_dst_reg
+             (ctx, inst, vc_head, Program, (GLint *) & vp->DstReg.File,
+              &vp->DstReg.Index, vp->DstReg.WriteMask))
+            return 1;
+         for (a = 0; a < 3; a++) {
+            if (parse_vector_src_reg
+                (ctx, inst, vc_head, Program, (GLint *) & vp->SrcReg[a].File,
+                 &vp->SrcReg[a].Index, &vp->SrcReg[a].Negate,
+                 vp->SrcReg[a].Swizzle, &vp->SrcReg[a].RelAddr))
+               return 1;
+         }
+         break;
+
+      case OP_ALU_SWZ:
+         switch (code) {
+            case OP_SWZ:
+               vp->Opcode = VP_OPCODE_SWZ;
+               break;
+         }
+         if (parse_masked_dst_reg
+             (ctx, inst, vc_head, Program, (GLint *) & vp->DstReg.File,
+              &vp->DstReg.Index, vp->DstReg.WriteMask))
+            return 1;
+
+         if (parse_src_reg
+             (ctx, inst, vc_head, Program, (GLint *) & vp->SrcReg[0].File,
+              &vp->SrcReg[0].Index, &vp->SrcReg[0].RelAddr))
+            return 1;
+         parse_extended_swizzle_mask (inst, vp->SrcReg[0].Swizzle,
+                                      &vp->SrcReg[0].Negate);
+         break;
+   }
+   return 0;
+}
+
+#if DEBUG_PARSING
+
+static GLvoid
+print_state_token (GLint token)
+{
+   switch (token) {
+      case STATE_MATERIAL:
+         fprintf (stderr, "STATE_MATERIAL ");
+         break;
+      case STATE_LIGHT:
+         fprintf (stderr, "STATE_LIGHT ");
+         break;
+
+      case STATE_LIGHTMODEL_AMBIENT:
+         fprintf (stderr, "STATE_AMBIENT ");
+         break;
+
+      case STATE_LIGHTMODEL_SCENECOLOR:
+         fprintf (stderr, "STATE_SCENECOLOR ");
+         break;
+
+      case STATE_LIGHTPROD:
+         fprintf (stderr, "STATE_LIGHTPROD ");
+         break;
+
+      case STATE_TEXGEN:
+         fprintf (stderr, "STATE_TEXGEN ");
+         break;
+
+      case STATE_FOG_COLOR:
+         fprintf (stderr, "STATE_FOG_COLOR ");
+         break;
+
+      case STATE_FOG_PARAMS:
+         fprintf (stderr, "STATE_FOG_PARAMS ");
+         break;
+
+      case STATE_CLIPPLANE:
+         fprintf (stderr, "STATE_CLIPPLANE ");
+         break;
+
+      case STATE_POINT_SIZE:
+         fprintf (stderr, "STATE_POINT_SIZE ");
+         break;
+
+      case STATE_POINT_ATTENUATION:
+         fprintf (stderr, "STATE_ATTENUATION ");
+         break;
+
+      case STATE_MATRIX:
+         fprintf (stderr, "STATE_MATRIX ");
+         break;
+
+      case STATE_MODELVIEW:
+         fprintf (stderr, "STATE_MODELVIEW ");
+         break;
+
+      case STATE_PROJECTION:
+         fprintf (stderr, "STATE_PROJECTION ");
+         break;
+
+      case STATE_MVP:
+         fprintf (stderr, "STATE_MVP ");
+         break;
+
+      case STATE_TEXTURE:
+         fprintf (stderr, "STATE_TEXTURE ");
+         break;
+
+      case STATE_PROGRAM:
+         fprintf (stderr, "STATE_PROGRAM ");
+         break;
+
+      case STATE_MATRIX_INVERSE:
+         fprintf (stderr, "STATE_INVERSE ");
+         break;
+
+      case STATE_MATRIX_TRANSPOSE:
+         fprintf (stderr, "STATE_TRANSPOSE ");
+         break;
+
+      case STATE_MATRIX_INVTRANS:
+         fprintf (stderr, "STATE_INVTRANS ");
+         break;
+
+      case STATE_AMBIENT:
+         fprintf (stderr, "STATE_AMBIENT ");
+         break;
+
+      case STATE_DIFFUSE:
+         fprintf (stderr, "STATE_DIFFUSE ");
+         break;
+
+      case STATE_SPECULAR:
+         fprintf (stderr, "STATE_SPECULAR ");
+         break;
+
+      case STATE_EMISSION:
+         fprintf (stderr, "STATE_EMISSION ");
+         break;
+
+      case STATE_SHININESS:
+         fprintf (stderr, "STATE_SHININESS ");
+         break;
+
+      case STATE_HALF:
+         fprintf (stderr, "STATE_HALF ");
+         break;
+
+      case STATE_POSITION:
+         fprintf (stderr, "STATE_POSITION ");
+         break;
+
+      case STATE_ATTENUATION:
+         fprintf (stderr, "STATE_ATTENUATION ");
+         break;
+
+      case STATE_SPOT_DIRECTION:
+         fprintf (stderr, "STATE_DIRECTION ");
+         break;
+
+      case STATE_TEXGEN_EYE_S:
+         fprintf (stderr, "STATE_TEXGEN_EYE_S ");
+         break;
+
+      case STATE_TEXGEN_EYE_T:
+         fprintf (stderr, "STATE_TEXGEN_EYE_T ");
+         break;
+
+      case STATE_TEXGEN_EYE_R:
+         fprintf (stderr, "STATE_TEXGEN_EYE_R ");
+         break;
+
+      case STATE_TEXGEN_EYE_Q:
+         fprintf (stderr, "STATE_TEXGEN_EYE_Q ");
+         break;
+
+      case STATE_TEXGEN_OBJECT_S:
+         fprintf (stderr, "STATE_TEXGEN_EYE_S ");
+         break;
+
+      case STATE_TEXGEN_OBJECT_T:
+         fprintf (stderr, "STATE_TEXGEN_OBJECT_T ");
+         break;
+
+      case STATE_TEXGEN_OBJECT_R:
+         fprintf (stderr, "STATE_TEXGEN_OBJECT_R ");
+         break;
+
+      case STATE_TEXGEN_OBJECT_Q:
+         fprintf (stderr, "STATE_TEXGEN_OBJECT_Q ");
+         break;
+
+      case STATE_TEXENV_COLOR:
+         fprintf (stderr, "STATE_TEXENV_COLOR ");
+         break;
+
+      case STATE_DEPTH_RANGE:
+         fprintf (stderr, "STATE_DEPTH_RANGE ");
+         break;
+
+      case STATE_VERTEX_PROGRAM:
+         fprintf (stderr, "STATE_VERTEX_PROGRAM ");
+         break;
+
+      case STATE_FRAGMENT_PROGRAM:
+         fprintf (stderr, "STATE_FRAGMENT_PROGRAM ");
+         break;
+
+      case STATE_ENV:
+         fprintf (stderr, "STATE_ENV ");
+         break;
+
+      case STATE_LOCAL:
+         fprintf (stderr, "STATE_LOCAL ");
+         break;
+
+   }
+   fprintf (stderr, "[%d] ", token);
+}
+
+
+static GLvoid
+debug_variables (GLcontext * ctx, struct var_cache *vc_head,
+                 struct arb_program *Program)
+{
+   struct var_cache *vc;
+   GLint a, b;
+
+   fprintf (stderr, "debug_variables, vc_head: %x\n", vc_head);
+
+   /* First of all, print out the contents of the var_cache */
+   vc = vc_head;
+   while (vc) {
+      fprintf (stderr, "[%x]\n", vc);
+      switch (vc->type) {
+         case vt_none:
+            fprintf (stderr, "UNDEFINED %s\n", vc->name);
+            break;
+         case vt_attrib:
+            fprintf (stderr, "ATTRIB    %s\n", vc->name);
+            fprintf (stderr, "          binding: 0x%x\n", vc->attrib_binding);
+            break;
+         case vt_param:
+            fprintf (stderr, "PARAM     %s  begin: %d len: %d\n", vc->name,
+                     vc->param_binding_begin, vc->param_binding_length);
+            b = vc->param_binding_begin;
+            for (a = 0; a < vc->param_binding_length; a++) {
+               fprintf (stderr, "%s\n",
+                        Program->Parameters->Parameters[a + b].Name);
+               if (Program->Parameters->Parameters[a + b].Type == STATE) {
+                  print_state_token (Program->Parameters->Parameters[a + b].
+                                     StateIndexes[0]);
+                  print_state_token (Program->Parameters->Parameters[a + b].
+                                     StateIndexes[1]);
+                  print_state_token (Program->Parameters->Parameters[a + b].
+                                     StateIndexes[2]);
+                  print_state_token (Program->Parameters->Parameters[a + b].
+                                     StateIndexes[3]);
+                  print_state_token (Program->Parameters->Parameters[a + b].
+                                     StateIndexes[4]);
+                  print_state_token (Program->Parameters->Parameters[a + b].
+                                     StateIndexes[5]);
+               }
+               else
+                  fprintf (stderr, "%f %f %f %f\n",
+                           Program->Parameters->Parameters[a + b].Values[0],
+                           Program->Parameters->Parameters[a + b].Values[1],
+                           Program->Parameters->Parameters[a + b].Values[2],
+                           Program->Parameters->Parameters[a + b].Values[3]);
+            }
+            break;
+         case vt_temp:
+            fprintf (stderr, "TEMP      %s\n", vc->name);
+            fprintf (stderr, "          binding: 0x%x\n", vc->temp_binding);
+            break;
+         case vt_output:
+            fprintf (stderr, "OUTPUT    %s\n", vc->name);
+            fprintf (stderr, "          binding: 0x%x\n", vc->output_binding);
+            break;
+         case vt_alias:
+            fprintf (stderr, "ALIAS     %s\n", vc->name);
+            fprintf (stderr, "          binding: 0x%x (%s)\n",
+                     vc->alias_binding, vc->alias_binding->name);
+            break;
+      }
+      vc = vc->next;
+   }
+}
+
+#endif
+
+
+/**
+ * The main loop for parsing a fragment or vertex program
+ *
+ * \return 0 on sucess, 1 on error
+ */
+static GLint
+parse_arb_program (GLcontext * ctx, GLubyte * inst, struct var_cache **vc_head,
+                   struct arb_program *Program)
+{
+   GLint err = 0;
+
+   Program->MajorVersion = (GLuint) * inst++;
+   Program->MinorVersion = (GLuint) * inst++;
+
+   while (*inst != END) {
+      switch (*inst++) {
+
+         case OPTION:
+            switch (*inst++) {
+               case ARB_PRECISION_HINT_FASTEST:
+                  Program->PrecisionOption = GL_FASTEST;
+                  break;
+
+               case ARB_PRECISION_HINT_NICEST:
+                  Program->PrecisionOption = GL_NICEST;
+                  break;
+
+               case ARB_FOG_EXP:
+                  Program->FogOption = GL_EXP;
+                  break;
+
+               case ARB_FOG_EXP2:
+                  Program->FogOption = GL_EXP2;
+                  break;
+
+               case ARB_FOG_LINEAR:
+                  Program->FogOption = GL_LINEAR;
+                  break;
+
+               case ARB_POSITION_INVARIANT:
+                  if (Program->Base.Target == GL_VERTEX_PROGRAM_ARB)
+                     Program->HintPositionInvariant = 1;
+                  break;
+
+               case ARB_FRAGMENT_PROGRAM_SHADOW:
+                 if (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) {
+                    /* TODO ARB_fragment_program_shadow code */
+                 }
+                 break;
+            }
+            break;
+
+         case INSTRUCTION:
+            Program->Position = parse_position (&inst);
+
+            if (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) {
+
+               /* Check the instruction count
+                * XXX: Does END count as an instruction?
+                */
+               if (Program->Base.NumInstructions+1 == MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS) {
+                  _mesa_set_program_error (ctx, Program->Position,
+                      "Max instruction count exceeded!");
+                  _mesa_error (ctx, GL_INVALID_OPERATION,
+                      "Max instruction count exceeded!");
+               }
+
+               /* Realloc Program->FPInstructions */
+               Program->FPInstructions =
+                  (struct fp_instruction *) _mesa_realloc (Program->FPInstructions,
+                                                           Program->Base.NumInstructions*sizeof(struct fp_instruction),
+                                                           (Program->Base.NumInstructions+1)*sizeof (struct fp_instruction));
+
+               /* parse the current instruction   */
+               err = parse_fp_instruction (ctx, &inst, vc_head, Program,
+                                           &Program->FPInstructions[Program->Base.NumInstructions]);
+
+            }
+            else {
+               /* Check the instruction count
+                * XXX: Does END count as an instruction?
+                */
+               if (Program->Base.NumInstructions+1 == MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS) {
+                  _mesa_set_program_error (ctx, Program->Position,
+                      "Max instruction count exceeded!");
+                  _mesa_error (ctx, GL_INVALID_OPERATION,
+                      "Max instruction count exceeded!");
+               }
+
+               /* Realloc Program->VPInstructions */
+               Program->VPInstructions =
+                  (struct vp_instruction *) _mesa_realloc (Program->VPInstructions,
+                                                           Program->Base.NumInstructions*sizeof(struct vp_instruction),
+                                                           (Program->Base.NumInstructions +1)*sizeof(struct vp_instruction));
+
+               /* parse the current instruction   */
+               err = parse_vp_instruction (ctx, &inst, vc_head, Program,
+                                           &Program->VPInstructions[Program->Base.NumInstructions]);
+            }
+
+            /* increment Program->Base.NumInstructions */
+            Program->Base.NumInstructions++;
+            break;
+
+         case DECLARATION:
+            err = parse_declaration (ctx, &inst, vc_head, Program);
+            break;
+
+         default:
+            break;
+      }
+
+      if (err)
+         break;
+   }
+
+   /* Finally, tag on an OPCODE_END instruction */
+   if (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) {
+      Program->FPInstructions =
+         (struct fp_instruction *) _mesa_realloc (Program->FPInstructions,
+                                                 Program->Base.NumInstructions*sizeof(struct fp_instruction),
+                                                  (Program->Base.NumInstructions+1)*sizeof(struct fp_instruction));
+
+      Program->FPInstructions[Program->Base.NumInstructions].Opcode = FP_OPCODE_END;
+      /* YYY Wrong Position in program, whatever, at least not random -> crash
+        Program->Position = parse_position (&inst);
+      */
+      Program->FPInstructions[Program->Base.NumInstructions].StringPos = Program->Position;
+   }
+   else {
+      Program->VPInstructions =
+         (struct vp_instruction *) _mesa_realloc (Program->VPInstructions,
+                                                  Program->Base.NumInstructions*sizeof(struct vp_instruction),
+                                                  (Program->Base.NumInstructions+1)*sizeof(struct vp_instruction));
+
+      Program->VPInstructions[Program->Base.NumInstructions].Opcode = VP_OPCODE_END;
+      /* YYY Wrong Position in program, whatever, at least not random -> crash
+        Program->Position = parse_position (&inst);
+      */
+      Program->VPInstructions[Program->Base.NumInstructions].StringPos = Program->Position;
+   }
+
+   /* increment Program->Base.NumInstructions */
+   Program->Base.NumInstructions++;
+
+   return err;
+}
+
+/* XXX temporary */
+static char core_grammar_text[] =
+#include "grammar_syn.h"
+;
+
+static int set_reg8 (GLcontext *ctx, grammar id, const byte *name, byte value)
+{
+   char error_msg;
+   GLint error_pos;
+
+   if (grammar_set_reg8 (id, name, value))
+      return 0;
+
+   grammar_get_last_error ((byte *) error_msg, 300, &error_pos);
+   _mesa_set_program_error (ctx, error_pos, error_msg);
+   _mesa_error (ctx, GL_INVALID_OPERATION, "Grammar Register Error");
+   return 1;
+}
+
+/*
+       Taken from SGI sample code
+*/
+static int extension_is_supported (const byte *ext)
+{
+   const byte *extensions = glGetString (GL_EXTENSIONS);
+   const byte *end = extensions + _mesa_strlen ((const char *) extensions);
+   const int ext_len = _mesa_strlen ((const char *) ext);
+
+   while (extensions < end) {
+      const int n = _mesa_strcspn ((const char *) extensions, " ");
+      if ((ext_len == n) && (_mesa_strncmp ((const char *) ext,
+                             (const char *) extensions, n) == 0))
+         return 1;
+      extensions += (n + 1);
+    }
+
+   return 0;
+}
+
+static int enable_ext (GLcontext *ctx, grammar id, const byte *name, const byte *extname)
+{
+   if (extension_is_supported (extname)) {
+      if (set_reg8 (ctx, id, name, 0x01))
+         return 1;
+   return 0;
+}
+
+/**
+ * This kicks everything off.
+ *
+ * \param ctx - The GL Context
+ * \param str - The program string
+ * \param len - The program string length
+ * \param Program - The arb_program struct to return all the parsed info in
+ * \return 0 on sucess, 1 on error
+ */
+GLuint
+_mesa_parse_arb_program (GLcontext * ctx, const GLubyte * str, GLsizei len,
+                         struct arb_program * program)
+{
+   GLint a, err, error_pos;
+   char error_msg[300];
+   GLuint parsed_len;
+   struct var_cache *vc_head;
+   grammar arbprogram_syn_id;
+   GLubyte *parsed, *inst;
+   GLubyte *strz = NULL;
+   static int arbprogram_syn_is_ok = 0;                /* XXX temporary */
+
+#if DEBUG_PARSING
+   fprintf (stderr, "Loading grammar text!\n");
+#endif
+
+   /* check if the arb_grammar_text (arbprogram.syn) is syntactically correct */
+   if (!arbprogram_syn_is_ok) {
+      grammar grammar_syn_id;
+      GLint err;
+      GLuint parsed_len;
+      byte *parsed;
+
+      grammar_syn_id = grammar_load_from_text ((byte *) core_grammar_text);
+      if (grammar_syn_id == 0) {
+         grammar_get_last_error ((byte *) error_msg, 300, &error_pos);
+         _mesa_set_program_error (ctx, error_pos, error_msg);
+         _mesa_error (ctx, GL_INVALID_OPERATION,
+                      "Error loading grammar rule set");
+         return 1;
+      }
+
+      err = grammar_check (grammar_syn_id, (byte *) arb_grammar_text, &parsed, &parsed_len);
+
+      /* NOTE: we cant destroy grammar_syn_id right here because grammar_destroy() can
+         reset the last error
+      */
+
+      if (err == 0) {
+         grammar_get_last_error ((byte *) error_msg, 300, &error_pos);
+         _mesa_set_program_error (ctx, error_pos, error_msg);
+         _mesa_error (ctx, GL_INVALID_OPERATION, "Error loading grammar rule set");
+
+         grammar_destroy (grammar_syn_id);
+         return 1;
+      }
+
+      grammar_destroy (grammar_syn_id);
+
+      arbprogram_syn_is_ok = 1;
+   }
+
+   /* create the grammar object */
+   arbprogram_syn_id = grammar_load_from_text ((byte *) arb_grammar_text);
+   if (arbprogram_syn_id == 0) {
+      grammar_get_last_error ((GLubyte *) error_msg, 300, &error_pos);
+      _mesa_set_program_error (ctx, error_pos, error_msg);
+      _mesa_error (ctx, GL_INVALID_OPERATION,
+                   "Error loading grammer rule set");
+      return 1;
+   }
+
+   /* Set program_target register value */
+   if (set_reg8 (ctx, arbprogram_syn_id, (byte *) "program_target",
+      program->Base.Target == GL_FRAGMENT_PROGRAM_ARB ? 0x10 : 0x20)) {
+      grammar_destroy (arbprogram_syn_id);
+      return 1;
+   }
+
+   /* Enable all active extensions */
+   if (enable_ext (ctx, arbprogram_syn_id,
+          (byte *) "vertex_blend", (byte *) "GL_ARB_vertex_blend") ||
+       enable_ext (ctx, arbprogram_syn_id,
+          (byte *) "vertex_blend", (byte *) "GL_EXT_vertex_weighting") ||
+       enable_ext (ctx, arbprogram_syn_id,
+          (byte *) "matrix_palette", (byte *) "GL_ARB_matrix_palette") ||
+       enable_ext (ctx, arbprogram_syn_id,
+          (byte *) "point_parameters", (byte *) "GL_ARB_point_parameters") ||
+       enable_ext (ctx, arbprogram_syn_id,
+          (byte *) "point_parameters", (byte *) "GL_EXT_point_parameters") ||
+       enable_ext (ctx, arbprogram_syn_id,
+          (byte *) "secondary_color", (byte *) "GL_EXT_secondary_color") ||
+       enable_ext (ctx, arbprogram_syn_id,
+          (byte *) "fog_coord", (byte *) "GL_EXT_fog_coord") ||
+       enable_ext (ctx, arbprogram_syn_id,
+          (byte *) "texture_rectangle", (byte *) "GL_EXT_texture_rectangle") ||
+       enable_ext (ctx, arbprogram_syn_id,
+          (byte *) "texture_rectangle", (byte *) "GL_NV_texture_rectangle") ||
+       enable_ext (ctx, arbprogram_syn_id,
+          (byte *) "fragment_program_shadow", (byte *) "GL_ARB_fragment_program_shadow")) {
+      grammar_destroy (arbprogram_syn_id);
+      return 1;
+   }
+
+   /* check for NULL character occurences */
+   {
+      int i;
+      for (i = 0; i < len; i++)
+         if (str[i] == '\0') {
+            _mesa_set_program_error (ctx, i, "invalid character");
+            _mesa_error (ctx, GL_INVALID_OPERATION, "Lexical Error");
+
+            grammar_destroy (arbprogram_syn_id);
+            return 1;
+         }
+   }
+
+   /* copy the program string to a null-terminated string */
+   /* XXX should I check for NULL from malloc()? */
+   strz = _mesa_malloc (len + 1);
+   _mesa_memcpy (strz, str, len);
+   strz[len] = '\0';
+
+#if DEBUG_PARSING
+   printf ("Checking Grammar!\n");
+#endif
+   err = grammar_check (arbprogram_syn_id, strz, &parsed, &parsed_len);
+
+   _mesa_free (strz);
+   strz = NULL;
+
+   /* Syntax parse error */
+   if (err == 0) {
+      grammar_get_last_error ((GLubyte *) error_msg, 300, &error_pos);
+      _mesa_set_program_error (ctx, error_pos, error_msg);
+      _mesa_error (ctx, GL_INVALID_OPERATION, "Parse Error");
+
+      grammar_destroy (arbprogram_syn_id);
+      return 1;
+   }
+
+#if DEBUG_PARSING
+   printf ("Destroying grammer dict [parse retval: %d]\n", err);
+#endif
+   grammar_destroy (arbprogram_syn_id);
+
+   /* Initialize the arb_program struct */
+   program->Base.NumInstructions =
+   program->Base.NumTemporaries =
+   program->Base.NumParameters =
+   program->Base.NumAttributes = program->Base.NumAddressRegs = 0;
+   program->Parameters = _mesa_new_parameter_list ();
+   program->InputsRead = 0;
+   program->OutputsWritten = 0;
+   program->Position = 0;
+   program->MajorVersion = program->MinorVersion = 0;
+   program->PrecisionOption = GL_DONT_CARE;
+   program->FogOption = GL_NONE;
+   program->HintPositionInvariant = GL_FALSE;
+   for (a = 0; a < MAX_TEXTURE_IMAGE_UNITS; a++)
+      program->TexturesUsed[a] = 0;
+   program->NumAluInstructions =
+   program->NumTexInstructions =
+   program->NumTexIndirections = 0;
+
+   program->FPInstructions = NULL;
+   program->VPInstructions = NULL;
+
+   vc_head = NULL;
+   err = 0;
+
+   /* Start examining the tokens in the array */
+   inst = parsed;
+
+   /* Check the grammer rev */
+   if (*inst++ != REVISION) {
+      _mesa_set_program_error (ctx, 0, "Grammar version mismatch");
+      _mesa_error (ctx, GL_INVALID_OPERATION, "Grammar verison mismatch");
+      err = 1;
+   }
+   else {
+      switch (*inst++) {
+         case FRAGMENT_PROGRAM:
+            program->Base.Target = GL_FRAGMENT_PROGRAM_ARB;
+            break;
+
+         case VERTEX_PROGRAM:
+            program->Base.Target = GL_VERTEX_PROGRAM_ARB;
+            break;
+      }
+
+      err = parse_arb_program (ctx, inst, &vc_head, program);
+#if DEBUG_PARSING
+      fprintf (stderr, "Symantic analysis returns %d [1 is bad!]\n", err);
+#endif
+   }
+
+   /*debug_variables(ctx, vc_head, program); */
+
+   /* We're done with the parsed binary array */
+   var_cache_destroy (&vc_head);
+
+   _mesa_free (parsed);
+#if DEBUG_PARSING
+   printf ("_mesa_parse_arb_program() done\n");
+#endif
+   return err;
+}
diff --git a/src/mesa/shader/arbprogparse.h b/src/mesa/shader/arbprogparse.h
new file mode 100644 (file)
index 0000000..a7b97e9
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  6.1
+ *
+ * Copyright (C) 1999-2004  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.
+ */
+
+
+#ifndef ARBPROGPARSE_H
+#define ARBPROGPARSE_H
+
+#include "context.h"
+#include "mtypes.h"
+#include "nvvertprog.h"
+#include "nvfragprog.h"
+
+/**
+ * This is basically a union of the vertex_program and fragment_program
+ * structs that we can use to parse the program into
+ *
+ * XXX: this should go into mtypes.h?
+ */
+struct arb_program
+{
+   struct program Base;
+   struct program_parameter_list *Parameters; 
+   GLuint InputsRead;
+   GLuint OutputsWritten;
+
+   GLuint Position;       /* Just used for error reporting while parsing */
+   GLuint MajorVersion;
+   GLuint MinorVersion;
+
+   /* ARB_vertex_program specifics */ 
+   struct vp_instruction *VPInstructions;
+
+   /* Options currently recognized by the parser */
+   /* ARB_fp */
+   GLenum PrecisionOption; /* GL_DONT_CARE, GL_NICEST or GL_FASTEST */
+   GLenum FogOption;       /* GL_NONE, GL_LINEAR, GL_EXP or GL_EXP2 */
+
+   /* ARB_fp & _vp */
+   GLboolean HintPositionInvariant;
+
+   /* ARB_fragment_program sepecifics */
+   struct fp_instruction *FPInstructions;
+   GLuint TexturesUsed[MAX_TEXTURE_IMAGE_UNITS]; 
+   GLuint NumAluInstructions; 
+   GLuint NumTexInstructions;
+   GLuint NumTexIndirections;
+};
+
+extern GLuint 
+_mesa_parse_arb_program( GLcontext *ctx, const GLubyte *str, GLsizei len, 
+                         struct arb_program *Program );
+                          
+#endif
diff --git a/src/mesa/shader/arbvertparse.c b/src/mesa/shader/arbvertparse.c
new file mode 100644 (file)
index 0000000..5f01110
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  6.1
+ *
+ * Copyright (C) 1999-2004  Brian Paul   All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#define DEBUG_VP 0
+
+/**
+ * \file arbvertparse.c
+ * ARB_vertex_program parser.
+ * \author Karl Rasche
+ */
+
+#include "glheader.h"
+#include "context.h"
+#include "arbvertparse.h"
+#include "hash.h"
+#include "imports.h"
+#include "macros.h"
+#include "mtypes.h"
+#include "nvprogram.h"
+#include "nvvertparse.h"
+#include "nvvertprog.h"
+
+#include "arbprogparse.h"
+
+
+static GLvoid
+debug_vp_inst(GLint num, struct vp_instruction *vp)
+{
+   GLint a;
+
+   for (a=0; a<num; a++) {
+      switch (vp[a].Opcode) {
+         case VP_OPCODE_MOV:
+            fprintf(stderr, "VP_OPCODE_MOV"); break;
+
+         case VP_OPCODE_LIT:
+            fprintf(stderr, "VP_OPCODE_LIT"); break;
+
+         case VP_OPCODE_RCP:
+            fprintf(stderr, "VP_OPCODE_RCP"); break;
+
+         case VP_OPCODE_RSQ:
+            fprintf(stderr, "VP_OPCODE_RSQ"); break;
+
+         case VP_OPCODE_EXP:
+            fprintf(stderr, "VP_OPCODE_EXP"); break;
+
+         case VP_OPCODE_LOG:
+            fprintf(stderr, "VP_OPCODE_LOG"); break;
+
+         case VP_OPCODE_MUL:
+            fprintf(stderr, "VP_OPCODE_MUL"); break;
+
+         case VP_OPCODE_ADD:
+            fprintf(stderr, "VP_OPCODE_ADD"); break;
+                               
+         case VP_OPCODE_DP3:
+            fprintf(stderr, "VP_OPCODE_DP3"); break;
+
+         case VP_OPCODE_DP4:
+            fprintf(stderr, "VP_OPCODE_DP4"); break;
+
+         case VP_OPCODE_DST:
+            fprintf(stderr, "VP_OPCODE_DST"); break;
+
+         case VP_OPCODE_MIN:
+            fprintf(stderr, "VP_OPCODE_MIN"); break;
+
+         case VP_OPCODE_MAX:
+            fprintf(stderr, "VP_OPCODE_MAX"); break;
+
+         case VP_OPCODE_SLT:
+            fprintf(stderr, "VP_OPCODE_SLT"); break;
+
+         case VP_OPCODE_SGE:
+            fprintf(stderr, "VP_OPCODE_SGE"); break;
+
+         case VP_OPCODE_MAD:
+            fprintf(stderr, "VP_OPCODE_MAD"); break;
+
+         case VP_OPCODE_ARL:
+            fprintf(stderr, "VP_OPCODE_ARL"); break;
+
+         case VP_OPCODE_DPH:
+            fprintf(stderr, "VP_OPCODE_DPH"); break;
+
+         case VP_OPCODE_RCC:
+            fprintf(stderr, "VP_OPCODE_RCC"); break;
+
+         case VP_OPCODE_SUB:
+            fprintf(stderr, "VP_OPCODE_SUB"); break;
+
+         case VP_OPCODE_ABS:
+            fprintf(stderr, "VP_OPCODE_ABS"); break;
+
+         case VP_OPCODE_FLR:
+            fprintf(stderr, "VP_OPCODE_FLR"); break;
+
+         case VP_OPCODE_FRC:
+            fprintf(stderr, "VP_OPCODE_FRC"); break;
+
+         case VP_OPCODE_EX2:
+            fprintf(stderr, "VP_OPCODE_EX2"); break;
+
+         case VP_OPCODE_LG2:
+            fprintf(stderr, "VP_OPCODE_LG2"); break;
+
+         case VP_OPCODE_POW:
+            fprintf(stderr, "VP_OPCODE_POW"); break;
+
+         case VP_OPCODE_XPD:
+            fprintf(stderr, "VP_OPCODE_XPD"); break;
+
+         case VP_OPCODE_SWZ:
+            fprintf(stderr, "VP_OPCODE_SWZ"); break;
+                               
+         case VP_OPCODE_END:
+            fprintf(stderr, "VP_OPCODE_END"); break;
+      }
+
+      fprintf(stderr, " D(0x%x:%d:%d%d%d%d) ", vp[a].DstReg.File, vp[a].DstReg.Index,
+          vp[a].DstReg.WriteMask[0],
+          vp[a].DstReg.WriteMask[1],
+          vp[a].DstReg.WriteMask[2],
+          vp[a].DstReg.WriteMask[3]);
+               
+      fprintf(stderr, "S1(0x%x:%d:%d%d%d%d) ", vp[a].SrcReg[0].File, vp[a].SrcReg[0].Index,
+          vp[a].SrcReg[0].Swizzle[0],
+          vp[a].SrcReg[0].Swizzle[1],
+          vp[a].SrcReg[0].Swizzle[2],
+          vp[a].SrcReg[0].Swizzle[3]);
+
+      fprintf(stderr, "S2(0x%x:%d:%d%d%d%d) ", vp[a].SrcReg[1].File, vp[a].SrcReg[1].Index,
+          vp[a].SrcReg[1].Swizzle[0],
+          vp[a].SrcReg[1].Swizzle[1],
+          vp[a].SrcReg[1].Swizzle[2],
+          vp[a].SrcReg[1].Swizzle[3]);
+
+      fprintf(stderr, "S3(0x%x:%d:%d%d%d%d)",  vp[a].SrcReg[2].File, vp[a].SrcReg[2].Index,    
+          vp[a].SrcReg[2].Swizzle[0],
+          vp[a].SrcReg[2].Swizzle[1],
+          vp[a].SrcReg[2].Swizzle[2],
+          vp[a].SrcReg[2].Swizzle[3]);
+
+      fprintf(stderr, "\n");
+   }
+}
+
+
+void
+_mesa_parse_arb_vertex_program(GLcontext * ctx, GLenum target,
+                              const GLubyte * str, GLsizei len,
+                              struct vertex_program *program)
+{
+   GLuint retval;
+   struct arb_program ap;
+
+   /* set the program target before parsing */
+   ap.Base.Target = GL_VERTEX_PROGRAM_ARB;
+
+   retval = _mesa_parse_arb_program(ctx, str, len, &ap);
+
+   /* copy the relvant contents of the arb_program struct into the 
+    * fragment_program struct
+    */
+   program->Base.NumInstructions = ap.Base.NumInstructions;
+   program->Base.NumTemporaries  = ap.Base.NumTemporaries;
+   program->Base.NumParameters   = ap.Base.NumParameters;
+   program->Base.NumAttributes   = ap.Base.NumAttributes;
+   program->Base.NumAddressRegs  = ap.Base.NumAddressRegs;
+
+   program->IsPositionInvariant = ap.HintPositionInvariant;
+   program->InputsRead     = ap.InputsRead;
+   program->OutputsWritten = ap.OutputsWritten;
+   program->Parameters     = ap.Parameters; 
+
+   /*  Parse error. Allocate a dummy program and return */     
+   if (retval)
+   {
+      program->Instructions = (struct vp_instruction *) _mesa_malloc (
+                                     sizeof(struct vp_instruction) );                    
+      program->Instructions[0].Opcode = VP_OPCODE_END;
+      return;
+   }
+
+   /* Eh.. we parsed something that wasn't a vertex program. doh! */
+   /* this wont happen any more */
+/*
+   if (ap.Base.Target != GL_VERTEX_PROGRAM_ARB)
+   {
+      program->Instructions = (struct vp_instruction *) _mesa_malloc (
+                                     sizeof(struct vp_instruction) );
+      program->Instructions[0].Opcode = VP_OPCODE_END;
+
+      _mesa_error (ctx, GL_INVALID_OPERATION, "Parsed a non-vertex program as a vertex program");
+      return;
+   }
+*/
+
+   program->Instructions   = ap.VPInstructions;
+
+#if DEBUG_VP
+   debug_vp_inst(ap.Base.NumInstructions, ap.VPInstructions);
+#else
+   (void) debug_vp_inst;
+#endif
+
+}
diff --git a/src/mesa/shader/arbvertparse.h b/src/mesa/shader/arbvertparse.h
new file mode 100644 (file)
index 0000000..3e4490b
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#ifndef ARBVERTPARSE_H
+#define ARBVERTPARSE_H
+
+extern void
+_mesa_parse_arb_vertex_program(GLcontext * ctx, GLenum target,
+                              const GLubyte * str, GLsizei len,
+                              struct vertex_program *program);
+
+#endif