Fix Windows newlines.
[mesa.git] / src / mesa / shader / arbprogparse.c
index e1a42e2dd9d35390d3c78bf51c20761b28990f50..b8e5e4bd8aef67d56b6dfeb34c329fc04d9bb6a8 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Mesa 3-D graphics library
- * Version:  6.5
+ * Version:  6.5.1
  *
- * Copyright (C) 1999-2005  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2006  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"),
 #include "arbprogparse.h"
 #include "grammar_mesa.h"
 #include "program.h"
-#include "get.h"
+#include "context.h"
+#include "macros.h"
+#include "mtypes.h"
+#include "program_instruction.h"
+
+
+/* For ARB programs, use the NV instruction limits */
+#define MAX_INSTRUCTIONS MAX2(MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS, \
+                              MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS)
+
+
+/**
+ * This is basically a union of the vertex_program and fragment_program
+ * structs that we can use to parse the program into
+ *
+ * XXX we can probably get rid of this entirely someday.
+ */
+struct arb_program
+{
+   struct gl_program Base;
+
+   GLuint Position;       /* Just used for error reporting while parsing */
+   GLuint MajorVersion;
+   GLuint MinorVersion;
+
+   /* ARB_vertex_progmra options */
+   GLboolean HintPositionInvariant;
+
+   /* ARB_fragment_progmra options */
+   GLenum PrecisionOption; /* GL_DONT_CARE, GL_NICEST or GL_FASTEST */
+   GLenum FogOption;       /* GL_NONE, GL_LINEAR, GL_EXP or GL_EXP2 */
+
+   /* ARB_fragment_program specifics */
+   GLbitfield TexturesUsed[MAX_TEXTURE_IMAGE_UNITS]; 
+   GLuint NumAluInstructions; 
+   GLuint NumTexInstructions;
+   GLuint NumTexIndirections;
+
+   GLboolean UsesKill;
+};
+
 
 #ifndef __extension__
 #if !defined(__GNUC__) || (__GNUC__ < 2) || \
@@ -481,7 +521,7 @@ typedef enum
  */
 struct var_cache
 {
-   GLubyte *name;
+   const GLubyte *name;         /* don't free() - no need */
    var_type type;
    GLuint address_binding;      /* The index of the address register we should
                                  * be using                                        */
@@ -543,7 +583,7 @@ var_cache_append (struct var_cache **va, struct var_cache *nv)
 }
 
 static struct var_cache *
-var_cache_find (struct var_cache *va, GLubyte * name)
+var_cache_find (struct var_cache *va, const GLubyte * name)
 {
    /*struct var_cache *first = va;*/
 
@@ -560,11 +600,39 @@ var_cache_find (struct var_cache *va, GLubyte * name)
    return NULL;
 }
 
+
+
+/**
+ * Called when an error is detected while parsing/compiling a program.
+ * Sets the ctx->Program.ErrorString field to descript and records a
+ * GL_INVALID_OPERATION error.
+ * \param position  position of error in program string
+ * \param descrip  verbose error description
+ */
+static void
+program_error(GLcontext *ctx, GLint position, const char *descrip)
+{
+   if (descrip) {
+      const char *prefix = "glProgramString(", *suffix = ")";
+      char *str = (char *) _mesa_malloc(_mesa_strlen(descrip) +
+                                        _mesa_strlen(prefix) +
+                                        _mesa_strlen(suffix) + 1);
+      if (str) {
+         _mesa_sprintf(str, "%s%s%s", prefix, descrip, suffix);
+         _mesa_error(ctx, GL_INVALID_OPERATION, str);
+         _mesa_free(str);
+      }
+   }
+   _mesa_set_program_error(ctx, position, descrip);
+}
+
+
+
 /**
  * constructs an integer from 4 GLubytes in LE format
  */
 static GLuint
-parse_position (GLubyte ** inst)
+parse_position (const GLubyte ** inst)
 {
    GLuint value;
 
@@ -586,10 +654,10 @@ parse_position (GLubyte ** inst)
  * \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,
+parse_string (const GLubyte ** inst, struct var_cache **vc_head,
               struct arb_program *Program, GLuint * found)
 {
-   GLubyte *i = *inst;
+   const GLubyte *i = *inst;
    struct var_cache *va = NULL;
    (void) Program;
 
@@ -604,7 +672,7 @@ parse_string (GLubyte ** inst, struct var_cache **vc_head,
 
    *found = 0;
    var_cache_create (&va);
-   va->name = i;
+   va->name = (const GLubyte *) i;
 
    var_cache_append (vc_head, va);
 
@@ -612,9 +680,9 @@ parse_string (GLubyte ** inst, struct var_cache **vc_head,
 }
 
 static char *
-parse_string_without_adding (GLubyte ** inst, struct arb_program *Program)
+parse_string_without_adding (const GLubyte ** inst, struct arb_program *Program)
 {
-   GLubyte *i = *inst;
+   const GLubyte *i = *inst;
    (void) Program;
    
    *inst += _mesa_strlen ((char *) i) + 1;
@@ -626,7 +694,7 @@ parse_string_without_adding (GLubyte ** inst, struct arb_program *Program)
  * \return -1 if we parse '-', return 1 otherwise
  */
 static GLint
-parse_sign (GLubyte ** inst)
+parse_sign (const GLubyte ** inst)
 {
    /*return *(*inst)++ != '+'; */
 
@@ -646,7 +714,7 @@ parse_sign (GLubyte ** inst)
  * parses and returns signed integer
  */
 static GLint
-parse_integer (GLubyte ** inst, struct arb_program *Program)
+parse_integer (const GLubyte ** inst, struct arb_program *Program)
 {
    GLint sign;
    GLint value;
@@ -683,7 +751,7 @@ parse_integer (GLubyte ** inst, struct arb_program *Program)
   in the string.
 */
 static GLdouble
-parse_float_string(GLubyte ** inst, struct arb_program *Program, GLdouble *scale)
+parse_float_string(const GLubyte ** inst, struct arb_program *Program, GLdouble *scale)
 {
    GLdouble value = 0.0;
    GLdouble oscale = 1.0;
@@ -716,7 +784,7 @@ parse_float_string(GLubyte ** inst, struct arb_program *Program, GLdouble *scale
      12.34e-4
  */
 static GLfloat
-parse_float (GLubyte ** inst, struct arb_program *Program)
+parse_float (const GLubyte ** inst, struct arb_program *Program)
 {
    GLint exponent;
    GLdouble whole, fraction, fracScale = 1.0;
@@ -736,7 +804,7 @@ parse_float (GLubyte ** inst, struct arb_program *Program)
 /**
  */
 static GLfloat
-parse_signed_float (GLubyte ** inst, struct arb_program *Program)
+parse_signed_float (const GLubyte ** inst, struct arb_program *Program)
 {
    GLint sign = parse_sign (inst);
    GLfloat value = parse_float (inst, Program);
@@ -750,7 +818,7 @@ parse_signed_float (GLubyte ** inst, struct arb_program *Program)
  * \param values - The 4 component vector with the constant value in it
  */
 static GLvoid
-parse_constant (GLubyte ** inst, GLfloat *values, struct arb_program *Program,
+parse_constant (const GLubyte ** inst, GLfloat *values, struct arb_program *Program,
                 GLboolean use)
 {
    GLuint components, i;
@@ -788,9 +856,10 @@ parse_constant (GLubyte ** inst, GLfloat *values, struct arb_program *Program,
  * \return 0 on sucess, 1 on error
  */
 static GLuint
-parse_relative_offset (GLcontext *ctx, GLubyte **inst, struct arb_program *Program,
-                        GLint *offset)
+parse_relative_offset(GLcontext *ctx, const GLubyte **inst,
+                      struct arb_program *Program, GLint *offset)
 {
+   (void) ctx;
    *offset = parse_integer(inst, Program);
    return 0;
 }
@@ -800,7 +869,7 @@ parse_relative_offset (GLcontext *ctx, GLubyte **inst, struct arb_program *Progr
  * \return 0 on sucess, 1 on error
  */
 static GLuint
-parse_color_type (GLcontext * ctx, GLubyte ** inst, struct arb_program *Program,
+parse_color_type (GLcontext * ctx, const GLubyte ** inst, struct arb_program *Program,
                   GLint * color)
 {
    (void) ctx; (void) Program;
@@ -814,17 +883,15 @@ parse_color_type (GLcontext * ctx, GLubyte ** inst, struct arb_program *Program,
  * \return 0 on sucess, 1 on error
  */
 static GLuint
-parse_generic_attrib_num(GLcontext *ctx, GLubyte ** inst,
+parse_generic_attrib_num(GLcontext *ctx, const GLubyte ** inst,
                        struct arb_program *Program, GLuint *attrib)
 {
    GLint i = parse_integer(inst, Program);
 
-   if ((i < 0) || (i > MAX_VERTEX_PROGRAM_ATTRIBS))
+   if ((i < 0) || (i >= 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");
-
+      program_error(ctx, Program->Position,
+                    "Invalid generic vertex attribute index");
       return 1;
    }
 
@@ -839,15 +906,13 @@ parse_generic_attrib_num(GLcontext *ctx, GLubyte ** inst,
  * \return 0 on sucess, 1 on error
  */
 static GLuint
-parse_output_color_num (GLcontext * ctx, GLubyte ** inst,
+parse_output_color_num (GLcontext * ctx, const GLubyte ** inst,
                     struct arb_program *Program, GLuint * color)
 {
    GLint i = parse_integer (inst, Program);
 
    if ((i < 0) || (i >= (int)ctx->Const.MaxDrawBuffers)) {
-      _mesa_set_program_error (ctx, Program->Position,
-                               "Invalid draw buffer index");
-      _mesa_error (ctx, GL_INVALID_OPERATION, "Invalid draw buffer index");
+      program_error(ctx, Program->Position, "Invalid draw buffer index");
       return 1;
    }
 
@@ -861,15 +926,13 @@ parse_output_color_num (GLcontext * ctx, GLubyte ** inst,
  * \return 0 on sucess, 1 on error
  */
 static GLuint
-parse_texcoord_num (GLcontext * ctx, GLubyte ** inst,
+parse_texcoord_num (GLcontext * ctx, const GLubyte ** inst,
                     struct arb_program *Program, GLuint * coord)
 {
    GLint i = parse_integer (inst, Program);
 
    if ((i < 0) || (i >= (int)ctx->Const.MaxTextureUnits)) {
-      _mesa_set_program_error (ctx, Program->Position,
-                               "Invalid texture unit index");
-      _mesa_error (ctx, GL_INVALID_OPERATION, "Invalid texture unit index");
+      program_error(ctx, Program->Position, "Invalid texture unit index");
       return 1;
    }
 
@@ -882,15 +945,13 @@ parse_texcoord_num (GLcontext * ctx, GLubyte ** inst,
  * \return 0 on sucess, 1 on error
  */
 static GLuint
-parse_weight_num (GLcontext * ctx, GLubyte ** inst, struct arb_program *Program,
+parse_weight_num (GLcontext * ctx, const 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");
+      program_error(ctx, Program->Position, "Invalid weight index");
       return 1;
    }
 
@@ -902,15 +963,13 @@ parse_weight_num (GLcontext * ctx, GLubyte ** inst, struct arb_program *Program,
  * \return 0 on sucess, 1 on error
  */
 static GLuint
-parse_clipplane_num (GLcontext * ctx, GLubyte ** inst,
+parse_clipplane_num (GLcontext * ctx, const 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");
+      program_error(ctx, Program->Position, "Invalid clip plane index");
       return 1;
    }
 
@@ -922,7 +981,7 @@ parse_clipplane_num (GLcontext * ctx, GLubyte ** inst,
  * \return 0 on front face, 1 on back face
  */
 static GLuint
-parse_face_type (GLubyte ** inst)
+parse_face_type (const GLubyte ** inst)
 {
    switch (*(*inst)++) {
       case FACE_FRONT:
@@ -945,7 +1004,7 @@ parse_face_type (GLubyte ** inst)
  * \return 0 on sucess, 1 on failure
  */
 static GLuint
-parse_matrix (GLcontext * ctx, GLubyte ** inst, struct arb_program *Program,
+parse_matrix (GLcontext * ctx, const GLubyte ** inst, struct arb_program *Program,
               GLint * matrix, GLint * matrix_idx, GLint * matrix_modifier)
 {
    GLubyte mat = *(*inst)++;
@@ -957,10 +1016,8 @@ parse_matrix (GLcontext * ctx, GLubyte ** inst, struct arb_program *Program,
          *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");
+            program_error(ctx, Program->Position,
+                          "ARB_vertex_blend not supported");
             return 1;
          }
          break;
@@ -977,10 +1034,8 @@ parse_matrix (GLcontext * ctx, GLubyte ** inst, struct arb_program *Program,
          *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);
+            program_error(ctx, Program->Position, "Invalid Texture Unit");
+            /* bad *matrix_id */
             return 1;
          }
          break;
@@ -988,10 +1043,8 @@ parse_matrix (GLcontext * ctx, GLubyte ** inst, struct arb_program *Program,
          /* 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");
+         program_error(ctx, Program->Position,
+                       "ARB_matrix_palette not supported");
          return 1;
          break;
 
@@ -999,10 +1052,8 @@ parse_matrix (GLcontext * ctx, GLubyte ** inst, struct arb_program *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);
+            program_error(ctx, Program->Position, "Invalid Program Matrix");
+            /* bad *matrix_idx */
             return 1;
          }
          break;
@@ -1036,7 +1087,7 @@ parse_matrix (GLcontext * ctx, GLubyte ** inst, struct arb_program *Program,
  * \return             - 0 on sucess, 1 on error
  */
 static GLuint
-parse_state_single_item (GLcontext * ctx, GLubyte ** inst,
+parse_state_single_item (GLcontext * ctx, const GLubyte ** inst,
                          struct arb_program *Program, GLint * state_tokens)
 {
    switch (*(*inst)++) {
@@ -1068,10 +1119,8 @@ parse_state_single_item (GLcontext * ctx, GLubyte ** inst,
 
          /* 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]);
+            program_error(ctx, Program->Position, "Invalid Light Number");
+            /* bad state_tokens[1] */
             return 1;
          }
 
@@ -1118,10 +1167,8 @@ parse_state_single_item (GLcontext * ctx, GLubyte ** inst,
 
          /* 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]);
+            program_error(ctx, Program->Position, "Invalid Light Number");
+            /* bad state_tokens[1] */
             return 1;
          }
 
@@ -1252,11 +1299,9 @@ parse_state_single_item (GLcontext * ctx, GLubyte ** inst,
          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]);
+               program_error(ctx, Program->Position,
+                             "Second matrix index less than the first");
+               /* state_tokens[4] vs. state_tokens[3] */
                return 1;
             }
          }
@@ -1301,7 +1346,7 @@ parse_state_single_item (GLcontext * ctx, GLubyte ** inst,
  * \return             - 0 on sucess, 1 on failure
  */
 static GLuint
-parse_program_single_item (GLcontext * ctx, GLubyte ** inst,
+parse_program_single_item (GLcontext * ctx, const GLubyte ** inst,
                            struct arb_program *Program, GLint * state_tokens)
 {
    if (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB)
@@ -1321,11 +1366,9 @@ parse_program_single_item (GLcontext * ctx, GLubyte ** inst,
              ||
              ((Program->Base.Target == GL_VERTEX_PROGRAM_ARB) &&
               (state_tokens[2] >= (GLint) ctx->Const.VertexProgram.MaxEnvParams))) {
-            _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]);
+            program_error(ctx, Program->Position,
+                          "Invalid Program Env Parameter");
+            /* bad state_tokens[2] */
             return 1;
          }
 
@@ -1341,11 +1384,9 @@ parse_program_single_item (GLcontext * ctx, GLubyte ** inst,
              ||
              ((Program->Base.Target == GL_VERTEX_PROGRAM_ARB) &&
               (state_tokens[2] >= (GLint) ctx->Const.VertexProgram.MaxLocalParams))) {
-            _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]);
+            program_error(ctx, Program->Position,
+                          "Invalid Program Local Parameter");
+            /* bad state_tokens[2] */
             return 1;
          }
          break;
@@ -1401,10 +1442,10 @@ generic_attrib_check(struct var_cache *vc_head)
  *
  * \param inputReg  returns the input register index, one of the
  *                  VERT_ATTRIB_* or FRAG_ATTRIB_* values.
- * \return returns 0 on sucess, 1 on error
+ * \return returns 0 on success, 1 on error
  */
 static GLuint
-parse_attrib_binding(GLcontext * ctx, GLubyte ** inst,
+parse_attrib_binding(GLcontext * ctx, const GLubyte ** inst,
                      struct arb_program *Program,
                      GLuint *inputReg, GLuint *is_generic)
 {
@@ -1447,14 +1488,19 @@ parse_attrib_binding(GLcontext * ctx, GLubyte ** inst,
 
          case VERTEX_ATTRIB_WEIGHT:
             {
-               const char *msg = "ARB_vertex_blend not supported";
                GLint weight;
                err = parse_weight_num (ctx, inst, Program, &weight);
                *inputReg = VERT_ATTRIB_WEIGHT;
-               _mesa_set_program_error(ctx, Program->Position, msg);
-               _mesa_error(ctx, GL_INVALID_OPERATION, msg);
+#if 1
+               /* hack for Warcraft (see bug 8060) */
+               _mesa_warning(ctx, "Application error: vertex program uses 'vertex.weight' but GL_ARB_vertex_blend not supported.");
+               break;
+#else
+               program_error(ctx, Program->Position,
+                             "ARB_vertex_blend not supported");
+               return 1;
+#endif
             }
-            return 1;
 
          case VERTEX_ATTRIB_NORMAL:
             *inputReg = VERT_ATTRIB_NORMAL;
@@ -1490,17 +1536,24 @@ parse_attrib_binding(GLcontext * ctx, GLubyte ** inst,
             {
                const char *msg = "ARB_palette_matrix not supported";
                parse_integer (inst, Program);
-               _mesa_set_program_error (ctx, Program->Position, msg);
-               _mesa_error (ctx, GL_INVALID_OPERATION, msg);
+               program_error(ctx, Program->Position, msg);
             }
             return 1;
 
          case VERTEX_ATTRIB_GENERIC:
             {
                GLuint attrib;
-               if (!parse_generic_attrib_num(ctx, inst, Program, &attrib)) {
+               err = parse_generic_attrib_num(ctx, inst, Program, &attrib);
+               if (!err) {
                   *is_generic = 1;
-                  *inputReg = attrib;
+                  /* Add VERT_ATTRIB_GENERIC0 here because ARB_vertex_program's
+                   * attributes do not alias the conventional vertex
+                   * attributes.
+                   */
+                  if (attrib > 0)
+                     *inputReg = attrib + VERT_ATTRIB_GENERIC0;
+                  else
+                     *inputReg = 0;
                }
             }
             break;
@@ -1511,11 +1564,8 @@ parse_attrib_binding(GLcontext * ctx, GLubyte ** inst,
       }
    }
 
-   /* Can this even happen? */
    if (err) {
-      const char *msg = "Bad attribute binding";
-      _mesa_set_program_error(ctx, Program->Position, msg);
-      _mesa_error(ctx, GL_INVALID_OPERATION, msg);
+      program_error(ctx, Program->Position, "Bad attribute binding");
    }
 
    Program->Base.InputsRead |= (1 << *inputReg);
@@ -1533,7 +1583,7 @@ parse_attrib_binding(GLcontext * ctx, GLubyte ** inst,
  *                   one of the VERT_RESULT_* or FRAG_RESULT_* values.
  */
 static GLuint
-parse_result_binding(GLcontext *ctx, GLubyte **inst,
+parse_result_binding(GLcontext *ctx, const GLubyte **inst,
                      GLuint *outputReg, struct arb_program *Program)
 {
    const GLubyte token = *(*inst)++;
@@ -1624,7 +1674,7 @@ parse_result_binding(GLcontext *ctx, GLubyte **inst,
  * \return 0 on sucess, 1 on error
  */
 static GLint
-parse_attrib (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
+parse_attrib (GLcontext * ctx, const GLubyte ** inst, struct var_cache **vc_head,
               struct arb_program *Program)
 {
    GLuint found;
@@ -1638,10 +1688,7 @@ parse_attrib (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
          _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);
-
+      program_error(ctx, Program->Position, error_msg);
       _mesa_free (error_msg);
       return 1;
    }
@@ -1653,12 +1700,9 @@ parse_attrib (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
       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");
+      program_error(ctx, Program->Position,
+                    "Cannot use both a generic vertex attribute "
+                    "and a specific attribute of the same type");
       return 1;
    }
 
@@ -1672,7 +1716,7 @@ parse_attrib (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
  *               if we get a signed or unsigned float for scalar constants
  */
 static GLuint
-parse_param_elements (GLcontext * ctx, GLubyte ** inst,
+parse_param_elements (GLcontext * ctx, const GLubyte ** inst,
                       struct var_cache *param_var,
                       struct arb_program *Program, GLboolean use)
 {
@@ -1749,10 +1793,8 @@ parse_param_elements (GLcontext * ctx, GLubyte ** inst,
                   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);
+               program_error(ctx, Program->Position,
+                             "Invalid Program Parameter"); /*end_idx*/
                return 1;
             }
 
@@ -1781,10 +1823,8 @@ parse_param_elements (GLcontext * ctx, GLubyte ** inst,
          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()");
+         program_error(ctx, Program->Position,
+                       "Unexpected token (in parse_param_elements())");
          return 1;
    }
 
@@ -1795,9 +1835,7 @@ parse_param_elements (GLcontext * ctx, GLubyte ** inst,
        || ((Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB)
            && (Program->Base.NumParameters >=
                ctx->Const.FragmentProgram.MaxLocalParams))) {
-      _mesa_set_program_error (ctx, Program->Position,
-                               "Too many parameter variables");
-      _mesa_error (ctx, GL_INVALID_OPERATION, "Too many parameter variables");
+      program_error(ctx, Program->Position, "Too many parameter variables");
       return 1;
    }
 
@@ -1813,7 +1851,7 @@ parse_param_elements (GLcontext * ctx, GLubyte ** inst,
  * \return 0 on sucess, 1 on error
  */
 static GLuint
-parse_param (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
+parse_param (GLcontext * ctx, const GLubyte ** inst, struct var_cache **vc_head,
              struct arb_program *Program)
 {
    GLuint found, err;
@@ -1829,10 +1867,7 @@ parse_param (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
          _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);
-
+      program_error (ctx, Program->Position, error_msg);
       _mesa_free (error_msg);
       return 1;
    }
@@ -1840,10 +1875,7 @@ parse_param (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
    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);
+      program_error(ctx, Program->Position, "Negative parameter array length");
       return 1;
    }
 
@@ -1871,10 +1903,8 @@ parse_param (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
    /* Test array length here! */
    if (specified_length) {
       if (specified_length != (int)param_var->param_binding_length) {
-         const char *msg
-            = "Declared parameter array length does not match parameter list";
-         _mesa_set_program_error(ctx, Program->Position, msg);
-         _mesa_error(ctx, GL_INVALID_OPERATION, msg);
+         program_error(ctx, Program->Position,
+              "Declared parameter array length does not match parameter list");
       }
    }
 
@@ -1887,14 +1917,14 @@ parse_param (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
  *
  */
 static GLuint
-parse_param_use (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
+parse_param_use (GLcontext * ctx, const 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->name = (const GLubyte *) " ";
    param_var->type = vt_param;
 
    param_var->param_binding_length = 0;
@@ -1923,7 +1953,7 @@ parse_param_use (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
  * \return 0 on sucess, 1 on error
  */
 static GLuint
-parse_temp (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
+parse_temp (GLcontext * ctx, const GLubyte ** inst, struct var_cache **vc_head,
             struct arb_program *Program)
 {
    GLuint found;
@@ -1937,10 +1967,7 @@ parse_temp (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
             _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);
-
+         program_error(ctx, Program->Position, error_msg);
          _mesa_free (error_msg);
          return 1;
       }
@@ -1953,10 +1980,8 @@ parse_temp (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
           || ((Program->Base.Target == GL_VERTEX_PROGRAM_ARB)
               && (Program->Base.NumTemporaries >=
                   ctx->Const.VertexProgram.MaxTemps))) {
-         _mesa_set_program_error (ctx, Program->Position,
-                                  "Too many TEMP variables declared");
-         _mesa_error (ctx, GL_INVALID_OPERATION,
-                      "Too many TEMP variables declared");
+         program_error(ctx, Program->Position,
+                       "Too many TEMP variables declared");
          return 1;
       }
 
@@ -1974,7 +1999,7 @@ parse_temp (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
  * \return 0 on sucess, 1 on error
  */
 static GLuint
-parse_output (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
+parse_output (GLcontext * ctx, const GLubyte ** inst, struct var_cache **vc_head,
               struct arb_program *Program)
 {
    GLuint found;
@@ -1988,10 +2013,7 @@ parse_output (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
          _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);
-
+      program_error (ctx, Program->Position, error_msg);
       _mesa_free (error_msg);
       return 1;
    }
@@ -2008,7 +2030,7 @@ parse_output (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
  * \return 0 on sucess, 1 on error
  */
 static GLuint
-parse_alias (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
+parse_alias (GLcontext * ctx, const GLubyte ** inst, struct var_cache **vc_head,
              struct arb_program *Program)
 {
    GLuint found;
@@ -2022,10 +2044,7 @@ parse_alias (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
          _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);
-
+      program_error(ctx, Program->Position, error_msg);
       _mesa_free (error_msg);
       return 1;
    }
@@ -2040,10 +2059,7 @@ parse_alias (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
          _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);
-
+      program_error (ctx, Program->Position, error_msg);
       _mesa_free (error_msg);
       return 1;
    }
@@ -2057,7 +2073,7 @@ parse_alias (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
  * \return 0 on sucess, 1 on error
  */
 static GLuint
-parse_address (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
+parse_address (GLcontext * ctx, const GLubyte ** inst, struct var_cache **vc_head,
                struct arb_program *Program)
 {
    GLuint found;
@@ -2071,10 +2087,7 @@ parse_address (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
             _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);
-
+         program_error (ctx, Program->Position, error_msg);
          _mesa_free (error_msg);
          return 1;
       }
@@ -2084,9 +2097,7 @@ parse_address (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
       if (Program->Base.NumAddressRegs >=
           ctx->Const.VertexProgram.MaxAddressRegs) {
          const char *msg = "Too many ADDRESS variables declared";
-         _mesa_set_program_error(ctx, Program->Position, msg);
-                                  
-         _mesa_error(ctx, GL_INVALID_OPERATION, msg);
+         program_error(ctx, Program->Position, msg);
          return 1;
       }
 
@@ -2104,7 +2115,7 @@ parse_address (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
  * \return 0 on sucess, 1 on error
  */
 static GLint
-parse_declaration (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
+parse_declaration (GLcontext * ctx, const GLubyte ** inst, struct var_cache **vc_head,
                    struct arb_program *Program)
 {
    GLint err = 0;
@@ -2153,7 +2164,7 @@ parse_declaration (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
  * \return 0 on sucess, 1 on error
  */
 static GLuint
-parse_masked_dst_reg (GLcontext * ctx, GLubyte ** inst,
+parse_masked_dst_reg (GLcontext * ctx, const GLubyte ** inst,
                       struct var_cache **vc_head, struct arb_program *Program,
                       enum register_file *File, GLuint *Index, GLint *WriteMask)
 {
@@ -2176,10 +2187,7 @@ parse_masked_dst_reg (GLcontext * ctx, GLubyte ** 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);
+            program_error(ctx, Program->Position, "0: Undefined variable");
             return 1;
          }
 
@@ -2196,20 +2204,15 @@ parse_masked_dst_reg (GLcontext * ctx, GLubyte ** inst,
 
                /* 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);
+               program_error(ctx, Program->Position,
+                             "Destination register is read only");
                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()");
+         program_error(ctx, Program->Position,
+                       "Unexpected opcode in parse_masked_dst_reg()");
          return 1;
    }
 
@@ -2221,9 +2224,7 @@ parse_masked_dst_reg (GLcontext * ctx, GLubyte ** inst,
    */
    /*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,
+      program_error(ctx, Program->Position,
                   "Vertex program specified position invariance and wrote vertex position");
    }*/
 
@@ -2253,30 +2254,26 @@ parse_masked_dst_reg (GLcontext * ctx, GLubyte ** inst,
  * \return 0 on sucess, 1 on error
  */
 static GLuint
-parse_address_reg (GLcontext * ctx, GLubyte ** inst,
+parse_address_reg (GLcontext * ctx, const GLubyte ** inst,
                           struct var_cache **vc_head,
                           struct arb_program *Program, GLint * Index)
 {
    struct var_cache *dst;
    GLuint result;
-   (void) Index;
+
+   *Index = 0; /* XXX */
 
    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);
+      program_error(ctx, Program->Position, "Undefined variable");
       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);
+      program_error(ctx, Program->Position, "Variable is not of type ADDRESS");
       return 1;
    }
 
@@ -2293,7 +2290,7 @@ parse_address_reg (GLcontext * ctx, GLubyte ** inst,
  * \return 0 on sucess, 1 on error
  */
 static GLuint
-parse_masked_address_reg (GLcontext * ctx, GLubyte ** inst,
+parse_masked_address_reg (GLcontext * ctx, const GLubyte ** inst,
                           struct var_cache **vc_head,
                           struct arb_program *Program, GLint * Index,
                           GLboolean * WriteMask)
@@ -2321,7 +2318,7 @@ parse_masked_address_reg (GLcontext * ctx, GLubyte ** inst,
  * swizzle, or just 1 component for a scalar src register selection
  */
 static void
-parse_swizzle_mask(GLubyte ** inst, GLubyte *swizzle, GLint len)
+parse_swizzle_mask(const GLubyte ** inst, GLubyte *swizzle, GLint len)
 {
    GLint i;
 
@@ -2357,7 +2354,7 @@ parse_swizzle_mask(GLubyte ** inst, GLubyte *swizzle, GLint len)
  * \return negateMask  four element bitfield
  */
 static void
-parse_extended_swizzle_mask(GLubyte **inst, GLubyte swizzle[4],
+parse_extended_swizzle_mask(const GLubyte **inst, GLubyte swizzle[4],
                             GLubyte *negateMask)
 {
    GLint i;
@@ -2398,7 +2395,8 @@ parse_extended_swizzle_mask(GLubyte **inst, GLubyte swizzle[4],
 
 
 static GLuint
-parse_src_reg (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
+parse_src_reg (GLcontext * ctx, const GLubyte ** inst,
+               struct var_cache **vc_head,
                struct arb_program *Program,
                enum register_file * File, GLint * Index,
                GLboolean *IsRelOffset )
@@ -2423,15 +2421,14 @@ parse_src_reg (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
           */
          var_cache_create(&src);
          src->type = vt_attrib;
-         src->name = (GLubyte *)_mesa_strdup("Dummy Attrib Variable");
+         src->name = (const GLubyte *) "Dummy Attrib Variable";
          src->attrib_binding = binding;
          src->attrib_is_generic = is_generic;
          var_cache_append(vc_head, src);
          if (generic_attrib_check(*vc_head)) {
-            const char *msg = "Cannot use both a generic vertex attribute "
-               "and a specific attribute of the same type";
-            _mesa_set_program_error (ctx, Program->Position, msg);
-            _mesa_error (ctx, GL_INVALID_OPERATION, msg);
+            program_error(ctx, Program->Position,
+                          "Cannot use both a generic vertex attribute "
+                          "and a specific attribute of the same type");
             return 1;
          }
          break;
@@ -2444,14 +2441,12 @@ parse_src_reg (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
                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);
+                  program_error(ctx, Program->Position,
+                                "2: Undefined variable"); /* src->name */
                   return 1;
                }
 
-               *File = src->param_binding_type;
+               *File = (enum register_file) src->param_binding_type;
 
                switch (*(*inst)++) {
                   case ARRAY_INDEX_ABSOLUTE:
@@ -2459,11 +2454,9 @@ parse_src_reg (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
 
                      if ((offset < 0)
                          || (offset >= (int)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);
+                        program_error(ctx, Program->Position,
+                                      "Index out of range");
+                        /* offset, src->name */
                         return 1;
                      }
 
@@ -2499,7 +2492,7 @@ parse_src_reg (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
                if (parse_param_use (ctx, inst, vc_head, Program, &src))
                   return 1;
 
-               *File = src->param_binding_type;
+               *File = (enum register_file) src->param_binding_type;
                *Index = src->param_binding_begin;
                break;
          }
@@ -2511,10 +2504,8 @@ parse_src_reg (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
 
          /* 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);
+            program_error(ctx, Program->Position,
+                          "3: Undefined variable"); /* src->name */
             return 1;
          }
 
@@ -2526,7 +2517,7 @@ parse_src_reg (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
 
                /* XXX: We have to handle offsets someplace in here!  -- or are those above? */
             case vt_param:
-               *File = src->param_binding_type;
+               *File = (enum register_file) src->param_binding_type;
                *Index = src->param_binding_begin;
                break;
 
@@ -2537,20 +2528,16 @@ parse_src_reg (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
 
                /* 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);
+               program_error(ctx, Program->Position,
+                             "destination register is read only");
+               /* bad 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");
+         program_error(ctx, Program->Position,
+                       "Unknown token in parse_src_reg");
          return 1;
    }
 
@@ -2561,7 +2548,7 @@ parse_src_reg (GLcontext * ctx, GLubyte ** inst, struct var_cache **vc_head,
  * Parse fragment program vector source register.
  */
 static GLuint
-parse_fp_vector_src_reg(GLcontext * ctx, GLubyte ** inst,
+parse_fp_vector_src_reg(GLcontext * ctx, const GLubyte ** inst,
                         struct var_cache **vc_head,
                         struct arb_program *program,
                         struct prog_src_register *reg)
@@ -2592,8 +2579,12 @@ parse_fp_vector_src_reg(GLcontext * ctx, GLubyte ** inst,
 }
 
 
+/**
+ * Parse fragment program destination register.
+ * \return 1 if error, 0 if no error.
+ */
 static GLuint 
-parse_fp_dst_reg(GLcontext * ctx, GLubyte ** inst,
+parse_fp_dst_reg(GLcontext * ctx, const GLubyte ** inst,
                 struct var_cache **vc_head, struct arb_program *Program,
                 struct prog_dst_register *reg )
 {
@@ -2615,9 +2606,10 @@ parse_fp_dst_reg(GLcontext * ctx, GLubyte ** inst,
 
 /**
  * Parse fragment program scalar src register.
+ * \return 1 if error, 0 if no error.
  */
 static GLuint
-parse_fp_scalar_src_reg (GLcontext * ctx, GLubyte ** inst,
+parse_fp_scalar_src_reg (GLcontext * ctx, const GLubyte ** inst,
                         struct var_cache **vc_head,
                          struct arb_program *Program,
                         struct prog_src_register *reg )
@@ -2652,9 +2644,10 @@ parse_fp_scalar_src_reg (GLcontext * ctx, GLubyte ** inst,
 /**
  * This is a big mother that handles getting opcodes into the instruction
  * and handling the src & dst registers for fragment program instructions
+ * \return 1 if error, 0 if no error
  */
 static GLuint
-parse_fp_instruction (GLcontext * ctx, GLubyte ** inst,
+parse_fp_instruction (GLcontext * ctx, const GLubyte ** inst,
                       struct var_cache **vc_head, struct arb_program *Program,
                       struct prog_instruction *fp)
 {
@@ -2693,31 +2686,31 @@ parse_fp_instruction (GLcontext * ctx, GLubyte ** inst,
       case OP_ALU_VECTOR:
          switch (code) {
             case OP_ABS_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_ABS:
                fp->Opcode = OPCODE_ABS;
                break;
 
             case OP_FLR_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_FLR:
                fp->Opcode = OPCODE_FLR;
                break;
 
             case OP_FRC_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_FRC:
                fp->Opcode = OPCODE_FRC;
                break;
 
             case OP_LIT_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_LIT:
                fp->Opcode = OPCODE_LIT;
                break;
 
             case OP_MOV_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_MOV:
                fp->Opcode = OPCODE_MOV;
                break;
@@ -2733,43 +2726,43 @@ parse_fp_instruction (GLcontext * ctx, GLubyte ** inst,
       case OP_ALU_SCALAR:
          switch (code) {
             case OP_COS_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_COS:
                fp->Opcode = OPCODE_COS;
                break;
 
             case OP_EX2_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_EX2:
                fp->Opcode = OPCODE_EX2;
                break;
 
             case OP_LG2_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_LG2:
                fp->Opcode = OPCODE_LG2;
                break;
 
             case OP_RCP_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_RCP:
                fp->Opcode = OPCODE_RCP;
                break;
 
             case OP_RSQ_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_RSQ:
                fp->Opcode = OPCODE_RSQ;
                break;
 
             case OP_SIN_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_SIN:
                fp->Opcode = OPCODE_SIN;
                break;
 
             case OP_SCS_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_SCS:
 
                fp->Opcode = OPCODE_SCS;
@@ -2786,7 +2779,7 @@ parse_fp_instruction (GLcontext * ctx, GLubyte ** inst,
       case OP_ALU_BINSC:
          switch (code) {
             case OP_POW_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_POW:
                fp->Opcode = OPCODE_POW;
                break;
@@ -2805,73 +2798,73 @@ parse_fp_instruction (GLcontext * ctx, GLubyte ** inst,
       case OP_ALU_BIN:
          switch (code) {
             case OP_ADD_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_ADD:
                fp->Opcode = OPCODE_ADD;
                break;
 
             case OP_DP3_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_DP3:
                fp->Opcode = OPCODE_DP3;
                break;
 
             case OP_DP4_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_DP4:
                fp->Opcode = OPCODE_DP4;
                break;
 
             case OP_DPH_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_DPH:
                fp->Opcode = OPCODE_DPH;
                break;
 
             case OP_DST_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_DST:
                fp->Opcode = OPCODE_DST;
                break;
 
             case OP_MAX_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_MAX:
                fp->Opcode = OPCODE_MAX;
                break;
 
             case OP_MIN_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_MIN:
                fp->Opcode = OPCODE_MIN;
                break;
 
             case OP_MUL_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_MUL:
                fp->Opcode = OPCODE_MUL;
                break;
 
             case OP_SGE_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_SGE:
                fp->Opcode = OPCODE_SGE;
                break;
 
             case OP_SLT_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_SLT:
                fp->Opcode = OPCODE_SLT;
                break;
 
             case OP_SUB_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_SUB:
                fp->Opcode = OPCODE_SUB;
                break;
 
             case OP_XPD_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_XPD:
                fp->Opcode = OPCODE_XPD;
                break;
@@ -2888,19 +2881,19 @@ parse_fp_instruction (GLcontext * ctx, GLubyte ** inst,
       case OP_ALU_TRI:
          switch (code) {
             case OP_CMP_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_CMP:
                fp->Opcode = OPCODE_CMP;
                break;
 
             case OP_LRP_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_LRP:
                fp->Opcode = OPCODE_LRP;
                break;
 
             case OP_MAD_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_MAD:
                fp->Opcode = OPCODE_MAD;
                break;
@@ -2918,7 +2911,7 @@ parse_fp_instruction (GLcontext * ctx, GLubyte ** inst,
       case OP_ALU_SWZ:
          switch (code) {
             case OP_SWZ_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_SWZ:
                fp->Opcode = OPCODE_SWZ;
                break;
@@ -2948,19 +2941,19 @@ parse_fp_instruction (GLcontext * ctx, GLubyte ** inst,
       case OP_TEX_SAMPLE:
          switch (code) {
             case OP_TEX_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_TEX:
                fp->Opcode = OPCODE_TEX;
                break;
 
             case OP_TXP_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_TXP:
                fp->Opcode = OPCODE_TXP;
                break;
 
             case OP_TXB_SAT:
-               fp->Saturate = 1;
+               fp->SaturateMode = SATURATE_ZERO_ONE;
             case OP_TXB:
                fp->Opcode = OPCODE_TXB;
                break;
@@ -3000,7 +2993,13 @@ parse_fp_instruction (GLcontext * ctx, GLubyte ** inst,
               /* TODO ARB_fragment_program_shadow code */
               break;
          }
-         Program->TexturesUsed[texcoord] |= (1<<fp->TexSrcTarget);
+         Program->TexturesUsed[texcoord] |= (1 << fp->TexSrcTarget);
+         /* Check that both "2D" and "CUBE" (for example) aren't both used */
+         if (_mesa_bitcount(Program->TexturesUsed[texcoord]) > 1) {
+            program_error(ctx, Program->Position,
+                          "multiple targets used on one texture image unit");
+            return 1;
+         }
          break;
 
       case OP_TEX_KIL:
@@ -3009,13 +3008,16 @@ parse_fp_instruction (GLcontext * ctx, GLubyte ** inst,
             return 1;
          fp->Opcode = OPCODE_KIL;
          break;
+      default:
+         _mesa_problem(ctx, "bad type 0x%x in parse_fp_instruction()", type);
+         return 1;
    }
 
    return 0;
 }
 
 static GLuint 
-parse_vp_dst_reg(GLcontext * ctx, GLubyte ** inst,
+parse_vp_dst_reg(GLcontext * ctx, const GLubyte ** inst,
                 struct var_cache **vc_head, struct arb_program *Program,
                 struct prog_dst_register *reg )
 {
@@ -3041,7 +3043,7 @@ parse_vp_dst_reg(GLcontext * ctx, GLubyte ** inst,
  * \return 0 on sucess, 1 on error
  */
 static GLuint
-parse_vp_address_reg (GLcontext * ctx, GLubyte ** inst,
+parse_vp_address_reg (GLcontext * ctx, const GLubyte ** inst,
                      struct var_cache **vc_head,
                      struct arb_program *Program,
                      struct prog_dst_register *reg)
@@ -3066,7 +3068,7 @@ parse_vp_address_reg (GLcontext * ctx, GLubyte ** inst,
  * Parse vertex program vector source register.
  */
 static GLuint
-parse_vp_vector_src_reg(GLcontext * ctx, GLubyte ** inst,
+parse_vp_vector_src_reg(GLcontext * ctx, const GLubyte ** inst,
                         struct var_cache **vc_head,
                         struct arb_program *program,
                         struct prog_src_register *reg )
@@ -3098,7 +3100,7 @@ parse_vp_vector_src_reg(GLcontext * ctx, GLubyte ** inst,
 
 
 static GLuint
-parse_vp_scalar_src_reg (GLcontext * ctx, GLubyte ** inst,
+parse_vp_scalar_src_reg (GLcontext * ctx, const GLubyte ** inst,
                         struct var_cache **vc_head,
                          struct arb_program *Program,
                         struct prog_src_register *reg )
@@ -3133,7 +3135,7 @@ parse_vp_scalar_src_reg (GLcontext * ctx, GLubyte ** inst,
  * and handling the src & dst registers for vertex program instructions
  */
 static GLuint
-parse_vp_instruction (GLcontext * ctx, GLubyte ** inst,
+parse_vp_instruction (GLcontext * ctx, const GLubyte ** inst,
                       struct var_cache **vc_head, struct arb_program *Program,
                       struct prog_instruction *vp)
 {
@@ -3594,8 +3596,8 @@ debug_variables (GLcontext * ctx, struct var_cache *vc_head,
  * \return 1 on error, 0 on success
  */
 static GLint
-parse_arb_program(GLcontext * ctx, GLubyte * inst, struct var_cache **vc_head,
-                  struct arb_program *Program)
+parse_instructions(GLcontext * ctx, const GLubyte * inst,
+                   struct var_cache **vc_head, struct arb_program *Program)
 {
    const GLuint maxInst = (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB)
       ? ctx->Const.FragmentProgram.MaxInstructions
@@ -3654,20 +3656,19 @@ parse_arb_program(GLcontext * ctx, GLubyte * inst, struct var_cache **vc_head,
          case INSTRUCTION:
             /* check length */
             if (Program->Base.NumInstructions + 1 >= maxInst) {
-               const char *msg = "Max instruction count exceeded";
-               _mesa_set_program_error(ctx, Program->Position, msg);
-               _mesa_error(ctx, GL_INVALID_OPERATION, msg);
+               program_error(ctx, Program->Position,
+                             "Max instruction count exceeded");
                return 1;
             }
             Program->Position = parse_position (&inst);
             /* parse the current instruction */
             if (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) {
                err = parse_fp_instruction (ctx, &inst, vc_head, Program,
-                      &Program->FPInstructions[Program->Base.NumInstructions]);
+                      &Program->Base.Instructions[Program->Base.NumInstructions]);
             }
             else {
                err = parse_vp_instruction (ctx, &inst, vc_head, Program,
-                      &Program->VPInstructions[Program->Base.NumInstructions]);
+                      &Program->Base.Instructions[Program->Base.NumInstructions]);
             }
 
             /* increment instuction count */
@@ -3687,23 +3688,14 @@ parse_arb_program(GLcontext * ctx, GLubyte * inst, struct var_cache **vc_head,
    }
 
    /* Finally, tag on an OPCODE_END instruction */
-   if (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) {
-      const GLuint numInst = Program->Base.NumInstructions;
-      _mesa_init_instruction(Program->FPInstructions + numInst);
-      Program->FPInstructions[numInst].Opcode = OPCODE_END;
-      /* YYY Wrong Position in program, whatever, at least not random -> crash
-        Program->Position = parse_position (&inst);
-      */
-      Program->FPInstructions[numInst].StringPos = Program->Position;
-   }
-   else {
+   {
       const GLuint numInst = Program->Base.NumInstructions;
-      _mesa_init_instruction(Program->VPInstructions + numInst);
-      Program->VPInstructions[numInst].Opcode = OPCODE_END;
+      _mesa_init_instruction(Program->Base.Instructions + numInst);
+      Program->Base.Instructions[numInst].Opcode = OPCODE_END;
       /* YYY Wrong Position in program, whatever, at least not random -> crash
         Program->Position = parse_position (&inst);
       */
-      Program->VPInstructions[numInst].StringPos = Program->Position;
+      Program->Base.Instructions[numInst].StringPos = Program->Position;
    }
    Program->Base.NumInstructions++;
 
@@ -3716,12 +3708,6 @@ parse_arb_program(GLcontext * ctx, GLubyte * inst, struct var_cache **vc_head,
    Program->Base.NumNativeParameters = Program->Base.NumParameters;
    Program->Base.NumNativeAttributes = Program->Base.NumAttributes;
    Program->Base.NumNativeAddressRegs = Program->Base.NumAddressRegs;
-   if (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) {
-      struct fragment_program *fp = (struct fragment_program *) Program;
-      fp->NumNativeAluInstructions = fp->NumAluInstructions;
-      fp->NumNativeTexInstructions = fp->NumTexInstructions;
-      fp->NumNativeTexIndirections = fp->NumTexIndirections;
-   }
 
    return err;
 }
@@ -3733,12 +3719,19 @@ __extension__ static char core_grammar_text[] =
 ;
 
 
-static int set_reg8 (GLcontext *ctx, grammar id, const byte *name, byte value)
+/**
+ * Set a grammar parameter.
+ * \param name the grammar parameter
+ * \param value the new parameter value
+ * \return 0 if OK, 1 if error
+ */
+static int
+set_reg8 (GLcontext *ctx, grammar id, const char *name, GLubyte value)
 {
    char error_msg[300];
    GLint error_pos;
 
-   if (grammar_set_reg8 (id, name, value))
+   if (grammar_set_reg8 (id, (const byte *) name, value))
       return 0;
 
    grammar_get_last_error ((byte *) error_msg, 300, &error_pos);
@@ -3747,34 +3740,65 @@ static int set_reg8 (GLcontext *ctx, grammar id, const byte *name, byte value)
    return 1;
 }
 
-static int extension_is_supported (const GLubyte *ext)
-{
-   const GLubyte *extensions = _mesa_GetString(GL_EXTENSIONS);
-   const GLubyte *end = extensions + _mesa_strlen ((const char *) extensions);
-   const GLint ext_len = (GLint)_mesa_strlen ((const char *) ext);
-
-   while (extensions < end)
-   {
-      const GLubyte *name_end = (const GLubyte *) _mesa_strstr ((const char *) extensions, " ");
-      if (name_end == NULL)
-         name_end = end;
-      if (name_end - extensions == ext_len && _mesa_strncmp ((const char *) ext,
-         (const char *) extensions, ext_len) == 0)
-         return 1;
-      extensions = name_end + 1;
-   }
 
-   return 0;
+/**
+ * Enable support for the given language option in the parser.
+ * \return 1 if OK, 0 if error
+ */
+static int
+enable_ext(GLcontext *ctx, grammar id, const char *name)
+{
+   return !set_reg8(ctx, id, name, 1);
 }
 
-static int enable_ext (GLcontext *ctx, grammar id, const byte *name, const byte *extname)
+
+/**
+ * Enable parser extensions based on which OpenGL extensions are supported
+ * by this rendering context.
+ *
+ * \return GL_TRUE if OK, GL_FALSE if error.
+ */
+static GLboolean
+enable_parser_extensions(GLcontext *ctx, grammar id)
 {
-   if (extension_is_supported (extname))
-      if (set_reg8 (ctx, id, name, 0x01))
-         return 1;
-   return 0;
+#if 0
+   /* These are not supported at this time */
+   if ((ctx->Extensions.ARB_vertex_blend ||
+        ctx->Extensions.EXT_vertex_weighting)
+       && !enable_ext(ctx, id, "vertex_blend"))
+      return GL_FALSE;
+   if (ctx->Extensions.ARB_matrix_palette
+       && !enable_ext(ctx, id, "matrix_palette"))
+      return GL_FALSE;
+   if (ctx->Extensions.ARB_fragment_program_shadow
+       && !enable_ext(ctx, id, "fragment_program_shadow"))
+      return GL_FALSE;
+#endif
+   if (ctx->Extensions.EXT_point_parameters
+       && !enable_ext(ctx, id, "point_parameters"))
+      return GL_FALSE;
+   if (ctx->Extensions.EXT_secondary_color
+       && !enable_ext(ctx, id, "secondary_color"))
+      return GL_FALSE;
+   if (ctx->Extensions.EXT_fog_coord
+       && !enable_ext(ctx, id, "fog_coord"))
+      return GL_FALSE;
+   if (ctx->Extensions.NV_texture_rectangle
+       && !enable_ext(ctx, id, "texture_rectangle"))
+      return GL_FALSE;
+   if (ctx->Extensions.ARB_draw_buffers
+       && !enable_ext(ctx, id, "draw_buffers"))
+      return GL_FALSE;
+
+#if 1
+   /* hack for Warcraft (see bug 8060) */
+   enable_ext(ctx, id, "vertex_blend");
+#endif
+
+   return GL_TRUE;
 }
 
+
 /**
  * This kicks everything off.
  *
@@ -3784,9 +3808,10 @@ static int enable_ext (GLcontext *ctx, grammar id, const byte *name, const byte
  * \param program - The arb_program struct to return all the parsed info in
  * \return GL_TRUE on sucess, GL_FALSE on error
  */
-GLboolean
-_mesa_parse_arb_program (GLcontext * ctx, const GLubyte * str, GLsizei len,
-                         struct arb_program * program)
+static GLboolean
+_mesa_parse_arb_program(GLcontext *ctx, GLenum target,
+                        const GLubyte *str, GLsizei len,
+                        struct arb_program *program)
 {
    GLint a, err, error_pos;
    char error_msg[300];
@@ -3797,39 +3822,44 @@ _mesa_parse_arb_program (GLcontext * ctx, const GLubyte * str, GLsizei len,
    GLubyte *strz = NULL;
    static int arbprogram_syn_is_ok = 0;                /* XXX temporary */
 
+   /* set the program target before parsing */
+   program->Base.Target = target;
+
    /* Reset error state */
    _mesa_set_program_error(ctx, -1, NULL);
 
-#if DEBUG_PARSING
-   fprintf (stderr, "Loading grammar text!\n");
-#endif
-
-   /* check if the arb_grammar_text (arbprogram.syn) is syntactically correct */
+   /* check if arb_grammar_text (arbprogram.syn) is syntactically correct */
    if (!arbprogram_syn_is_ok) {
+      /* One-time initialization of parsing system */
       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);
+         /* XXX this is not a GL error - it's an implementation bug! - FIX */
          _mesa_set_program_error (ctx, error_pos, error_msg);
          _mesa_error (ctx, GL_INVALID_OPERATION,
-                      "Error loading grammar rule set");
+                      "glProgramStringARB(Error loading grammar rule set)");
          return GL_FALSE;
       }
 
-      err = grammar_check (grammar_syn_id, (byte *) arb_grammar_text, &parsed, &parsed_len);
+      err = !grammar_check(grammar_syn_id, (byte *) arb_grammar_text,
+                           &parsed, &parsed_len);
+
+      /* 'parsed' is unused here */
+      _mesa_free (parsed);
+      parsed = NULL;
 
       /* NOTE: we can't destroy grammar_syn_id right here because
        * grammar_destroy() can reset the last error
        */
-      if (err == 0) {
+      if (err) {
+         /* XXX this is not a GL error - it's an implementation bug! - FIX */
          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");
-
+         _mesa_error (ctx, GL_INVALID_OPERATION,
+                      "glProgramString(Error loading grammar rule set");
          grammar_destroy (grammar_syn_id);
          return GL_FALSE;
       }
@@ -3842,107 +3872,88 @@ _mesa_parse_arb_program (GLcontext * ctx, const GLubyte * str, GLsizei len,
    /* create the grammar object */
    arbprogram_syn_id = grammar_load_from_text ((byte *) arb_grammar_text);
    if (arbprogram_syn_id == 0) {
+      /* XXX this is not a GL error - it's an implementation bug! - FIX */
       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");
+                   "glProgramString(Error loading grammer rule set)");
       return GL_FALSE;
    }
 
    /* Set program_target register value */
-   if (set_reg8 (ctx, arbprogram_syn_id, (byte *) "program_target",
+   if (set_reg8 (ctx, arbprogram_syn_id, "program_target",
       program->Base.Target == GL_FRAGMENT_PROGRAM_ARB ? 0x10 : 0x20)) {
       grammar_destroy (arbprogram_syn_id);
       return GL_FALSE;
    }
 
-   /* 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_ARB_texture_rectangle") ||
-       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") ||
-       enable_ext (ctx, arbprogram_syn_id,
-          (byte *) "draw_buffers", (byte *) "GL_ARB_draw_buffers")) {
-      grammar_destroy (arbprogram_syn_id);
+   if (!enable_parser_extensions(ctx, arbprogram_syn_id)) {
+      grammar_destroy(arbprogram_syn_id);
       return GL_FALSE;
    }
 
    /* check for NULL character occurences */
    {
-      int i;
-      for (i = 0; i < len; i++)
+      GLint 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");
-
+            program_error(ctx, i, "illegal character");
             grammar_destroy (arbprogram_syn_id);
             return GL_FALSE;
          }
+      }
    }
 
    /* copy the program string to a null-terminated string */
    strz = (GLubyte *) _mesa_malloc (len + 1);
    if (!strz) {
-      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glprogramStringARB");
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glProgramStringARB");
+      grammar_destroy (arbprogram_syn_id);
       return GL_FALSE;
    }
    _mesa_memcpy (strz, str, len);
    strz[len] = '\0';
 
-#if DEBUG_PARSING
-   fprintf (stderr, "Checking Grammar!\n");
-#endif
    /* do a fast check on program string - initial production buffer is 4K */
-   err = grammar_fast_check (arbprogram_syn_id, strz, &parsed, &parsed_len, 0x1000);
+   err = !grammar_fast_check(arbprogram_syn_id, strz,
+                             &parsed, &parsed_len, 0x1000);
 
    /* Syntax parse error */
-   if (err == 0) {
-      _mesa_free (strz);
-      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, "glprogramStringARB(syntax error)");
+   if (err) {
+      grammar_get_last_error((GLubyte *) error_msg, 300, &error_pos);
+      program_error(ctx, error_pos, error_msg);
 
-      /* useful for debugging */
 #if DEBUG_PARSING
+      /* useful for debugging */
       do {
          int line, col;
          char *s;
          fprintf(stderr, "program: %s\n", (char *) strz);
          fprintf(stderr, "Error Pos: %d\n", ctx->program.ErrorPos);
-         s = (char *) _mesa_find_line_column(strz, strz+ctx->program.ErrorPos, &line, &col);
+         s = (char *) _mesa_find_line_column(strz, strz+ctx->program.ErrorPos,
+                                             &line, &col);
          fprintf(stderr, "line %d col %d: %s\n", line, col, s);
       } while (0)
 #endif
 
+      _mesa_free(strz);
+      _mesa_free(parsed);
+
       grammar_destroy (arbprogram_syn_id);
       return GL_FALSE;
    }
 
-#if DEBUG_PARSING
-   fprintf (stderr, "Destroying grammer dict [parse retval: %d]\n", err);
-#endif
    grammar_destroy (arbprogram_syn_id);
 
+   /*
+    * Program string is syntactically correct at this point
+    * Parse the tokenized version of the program now, generating
+    * vertex/fragment program instructions.
+    */
+
    /* Initialize the arb_program struct */
    program->Base.String = strz;
+   program->Base.Instructions = _mesa_alloc_instructions(MAX_INSTRUCTIONS);
    program->Base.NumInstructions =
    program->Base.NumTemporaries =
    program->Base.NumParameters =
@@ -3960,7 +3971,6 @@ _mesa_parse_arb_program (GLcontext * ctx, const GLubyte * str, GLsizei len,
    program->NumAluInstructions =
    program->NumTexInstructions =
    program->NumTexIndirections = 0;
-
    program->UsesKill = 0;
 
    vc_head = NULL;
@@ -3971,19 +3981,13 @@ _mesa_parse_arb_program (GLcontext * ctx, const GLubyte * str, GLsizei len,
 
    /* Check the grammer rev */
    if (*inst++ != REVISION) {
-      _mesa_set_program_error (ctx, 0, "Grammar version mismatch");
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "glProgramStringARB(Grammar version mismatch)");
+      program_error (ctx, 0, "Grammar version mismatch");
       err = GL_TRUE;
    }
    else {
       /* ignore program target */
       inst++;
-
-      err = parse_arb_program (ctx, inst, &vc_head, program);
-#if DEBUG_PARSING
-      fprintf (stderr, "Symantic analysis returns %d [1 is bad!]\n", err);
-#endif
+      err = parse_instructions(ctx, inst, &vc_head, program);
    }
 
    /*debug_variables(ctx, vc_head, program); */
@@ -3992,9 +3996,121 @@ _mesa_parse_arb_program (GLcontext * ctx, const GLubyte * str, GLsizei len,
    var_cache_destroy (&vc_head);
 
    _mesa_free (parsed);
-#if DEBUG_PARSING
-   fprintf (stderr, "_mesa_parse_arb_program() done\n");
-#endif
+
+   /* Reallocate the instruction array from size [MAX_INSTRUCTIONS]
+    * to size [ap.Base.NumInstructions].
+    */
+   program->Base.Instructions
+      = _mesa_realloc_instructions(program->Base.Instructions,
+                                   MAX_INSTRUCTIONS,
+                                   program->Base.NumInstructions);
 
    return !err;
 }
+
+
+
+void
+_mesa_parse_arb_fragment_program(GLcontext* ctx, GLenum target,
+                                 const GLvoid *str, GLsizei len,
+                                 struct gl_fragment_program *program)
+{
+   struct arb_program ap;
+   GLuint i;
+
+   ASSERT(target == GL_FRAGMENT_PROGRAM_ARB);
+   if (!_mesa_parse_arb_program(ctx, target, (const GLubyte*) str, len, &ap)) {
+      /* Error in the program. Just return. */
+      return;
+   }
+
+   /* Copy the relevant contents of the arb_program struct into the
+    * fragment_program struct.
+    */
+   program->Base.String          = ap.Base.String;
+   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->Base.NumNativeInstructions = ap.Base.NumNativeInstructions;
+   program->Base.NumNativeTemporaries = ap.Base.NumNativeTemporaries;
+   program->Base.NumNativeParameters = ap.Base.NumNativeParameters;
+   program->Base.NumNativeAttributes = ap.Base.NumNativeAttributes;
+   program->Base.NumNativeAddressRegs = ap.Base.NumNativeAddressRegs;
+   program->NumAluInstructions   = ap.NumAluInstructions;
+   program->NumTexInstructions   = ap.NumTexInstructions;
+   program->NumTexIndirections   = ap.NumTexIndirections;
+   program->NumNativeAluInstructions = ap.NumAluInstructions;
+   program->NumNativeTexInstructions = ap.NumTexInstructions;
+   program->NumNativeTexIndirections = ap.NumTexIndirections;
+   program->Base.InputsRead      = ap.Base.InputsRead;
+   program->Base.OutputsWritten  = ap.Base.OutputsWritten;
+   for (i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)
+      program->TexturesUsed[i] = ap.TexturesUsed[i];
+   program->FogOption          = ap.FogOption;
+
+   if (program->Base.Instructions)
+      _mesa_free(program->Base.Instructions);
+   program->Base.Instructions = ap.Base.Instructions;
+
+   if (program->Base.Parameters)
+      _mesa_free_parameter_list(program->Base.Parameters);
+   program->Base.Parameters    = ap.Base.Parameters;
+
+#if DEBUG_FP
+   _mesa_print_program(&program.Base);
+#endif
+}
+
+
+
+/**
+ * Parse the vertex program string.  If success, update the given
+ * vertex_program object with the new program.  Else, leave the vertex_program
+ * object unchanged.
+ */
+void
+_mesa_parse_arb_vertex_program(GLcontext *ctx, GLenum target,
+                              const GLvoid *str, GLsizei len,
+                              struct gl_vertex_program *program)
+{
+   struct arb_program ap;
+
+   ASSERT(target == GL_VERTEX_PROGRAM_ARB);
+
+   if (!_mesa_parse_arb_program(ctx, target, (const GLubyte*) str, len, &ap)) {
+      /* Error in the program. Just return. */
+      return;
+   }
+
+   /* Copy the relevant contents of the arb_program struct into the 
+    * vertex_program struct.
+    */
+   program->Base.String          = ap.Base.String;
+   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->Base.NumNativeInstructions = ap.Base.NumNativeInstructions;
+   program->Base.NumNativeTemporaries = ap.Base.NumNativeTemporaries;
+   program->Base.NumNativeParameters = ap.Base.NumNativeParameters;
+   program->Base.NumNativeAttributes = ap.Base.NumNativeAttributes;
+   program->Base.NumNativeAddressRegs = ap.Base.NumNativeAddressRegs;
+   program->Base.InputsRead     = ap.Base.InputsRead;
+   program->Base.OutputsWritten = ap.Base.OutputsWritten;
+   program->IsPositionInvariant = ap.HintPositionInvariant;
+
+   if (program->Base.Instructions)
+      _mesa_free(program->Base.Instructions);
+   program->Base.Instructions = ap.Base.Instructions;
+
+   if (program->Base.Parameters)
+      _mesa_free_parameter_list(program->Base.Parameters);
+   program->Base.Parameters = ap.Base.Parameters; 
+
+#if DEBUG_VP
+   _mesa_print_program(&program->Base);
+#endif
+}