Home | History | Annotate | Download | only in program
      1 /*
      2  * Mesa 3-D graphics library
      3  * Version:  6.5
      4  *
      5  * Copyright (C) 1999-2005  Brian Paul   All Rights Reserved.
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a
      8  * copy of this software and associated documentation files (the "Software"),
      9  * to deal in the Software without restriction, including without limitation
     10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     11  * and/or sell copies of the Software, and to permit persons to whom the
     12  * Software is furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included
     15  * in all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     21  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23  */
     24 
     25 /**
     26  * \file nvfragparse.c
     27  * NVIDIA fragment program parser.
     28  * \author Brian Paul
     29  */
     30 
     31 /*
     32  * Regarding GL_NV_fragment_program:
     33  *
     34  * Portions of this software may use or implement intellectual
     35  * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
     36  * any and all warranties with respect to such intellectual property,
     37  * including any use thereof or modifications thereto.
     38  */
     39 
     40 #include "main/glheader.h"
     41 #include "main/context.h"
     42 #include "main/imports.h"
     43 #include "main/macros.h"
     44 #include "program.h"
     45 #include "prog_parameter.h"
     46 #include "prog_print.h"
     47 #include "prog_instruction.h"
     48 #include "nvfragparse.h"
     49 
     50 
     51 #define INPUT_1V     1
     52 #define INPUT_2V     2
     53 #define INPUT_3V     3
     54 #define INPUT_1S     4
     55 #define INPUT_2S     5
     56 #define INPUT_CC     6
     57 #define INPUT_1V_T   7  /* one source vector, plus textureId */
     58 #define INPUT_3V_T   8  /* one source vector, plus textureId */
     59 #define INPUT_NONE   9
     60 #define INPUT_1V_S  10  /* a string and a vector register */
     61 #define OUTPUT_V    20
     62 #define OUTPUT_S    21
     63 #define OUTPUT_NONE 22
     64 
     65 /* IRIX defines some of these */
     66 #undef _R
     67 #undef _H
     68 #undef _X
     69 #undef _C
     70 #undef _S
     71 
     72 /* Optional suffixes */
     73 #define _R  FLOAT32  /* float */
     74 #define _H  FLOAT16  /* half-float */
     75 #define _X  FIXED12  /* fixed */
     76 #define _C  0x08     /* set cond codes */
     77 #define _S  0x10     /* saturate, clamp result to [0,1] */
     78 
     79 struct instruction_pattern {
     80    const char *name;
     81    enum prog_opcode opcode;
     82    GLuint inputs;
     83    GLuint outputs;
     84    GLuint suffixes;
     85 };
     86 
     87 static const struct instruction_pattern Instructions[] = {
     88    { "ADD", OPCODE_ADD, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
     89    { "COS", OPCODE_COS, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
     90    { "DDX", OPCODE_DDX, INPUT_1V, OUTPUT_V, _R | _H |      _C | _S },
     91    { "DDY", OPCODE_DDY, INPUT_1V, OUTPUT_V, _R | _H |      _C | _S },
     92    { "DP3", OPCODE_DP3, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S },
     93    { "DP4", OPCODE_DP4, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S },
     94    { "DST", OPCODE_DP4, INPUT_2V, OUTPUT_V, _R | _H |      _C | _S },
     95    { "EX2", OPCODE_DP4, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
     96    { "FLR", OPCODE_FLR, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
     97    { "FRC", OPCODE_FRC, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
     98    { "KIL", OPCODE_KIL_NV, INPUT_CC, OUTPUT_NONE, 0                },
     99    { "LG2", OPCODE_LG2, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
    100    { "LIT", OPCODE_LIT, INPUT_1V, OUTPUT_V, _R | _H |      _C | _S },
    101    { "LRP", OPCODE_LRP, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S },
    102    { "MAD", OPCODE_MAD, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S },
    103    { "MAX", OPCODE_MAX, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
    104    { "MIN", OPCODE_MIN, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
    105    { "MOV", OPCODE_MOV, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
    106    { "MUL", OPCODE_MUL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
    107    { "PK2H",  OPCODE_PK2H,  INPUT_1V, OUTPUT_S, 0                  },
    108    { "PK2US", OPCODE_PK2US, INPUT_1V, OUTPUT_S, 0                  },
    109    { "PK4B",  OPCODE_PK4B,  INPUT_1V, OUTPUT_S, 0                  },
    110    { "PK4UB", OPCODE_PK4UB, INPUT_1V, OUTPUT_S, 0                  },
    111    { "POW", OPCODE_POW, INPUT_2S, OUTPUT_S, _R | _H |      _C | _S },
    112    { "RCP", OPCODE_RCP, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
    113    { "RFL", OPCODE_RFL, INPUT_2V, OUTPUT_V, _R | _H |      _C | _S },
    114    { "RSQ", OPCODE_RSQ, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
    115    { "SEQ", OPCODE_SEQ, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
    116    { "SFL", OPCODE_SFL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
    117    { "SGE", OPCODE_SGE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
    118    { "SGT", OPCODE_SGT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
    119    { "SIN", OPCODE_SIN, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
    120    { "SLE", OPCODE_SLE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
    121    { "SLT", OPCODE_SLT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
    122    { "SNE", OPCODE_SNE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
    123    { "STR", OPCODE_STR, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
    124    { "SUB", OPCODE_SUB, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
    125    { "TEX", OPCODE_TEX, INPUT_1V_T, OUTPUT_V,              _C | _S },
    126    { "TXD", OPCODE_TXD, INPUT_3V_T, OUTPUT_V,              _C | _S },
    127    { "TXP", OPCODE_TXP_NV, INPUT_1V_T, OUTPUT_V,           _C | _S },
    128    { "UP2H",  OPCODE_UP2H,  INPUT_1S, OUTPUT_V,            _C | _S },
    129    { "UP2US", OPCODE_UP2US, INPUT_1S, OUTPUT_V,            _C | _S },
    130    { "UP4B",  OPCODE_UP4B,  INPUT_1S, OUTPUT_V,            _C | _S },
    131    { "UP4UB", OPCODE_UP4UB, INPUT_1S, OUTPUT_V,            _C | _S },
    132    { "X2D", OPCODE_X2D, INPUT_3V, OUTPUT_V, _R | _H |      _C | _S },
    133    { "PRINT", OPCODE_PRINT, INPUT_1V_S, OUTPUT_NONE, 0               },
    134    { NULL, (enum prog_opcode) -1, 0, 0, 0 }
    135 };
    136 
    137 
    138 /*
    139  * Information needed or computed during parsing.
    140  * Remember, we can't modify the target program object until we've
    141  * _successfully_ parsed the program text.
    142  */
    143 struct parse_state {
    144    struct gl_context *ctx;
    145    const GLubyte *start;              /* start of program string */
    146    const GLubyte *pos;                /* current position */
    147    const GLubyte *curLine;
    148    struct gl_fragment_program *program;  /* current program */
    149 
    150    struct gl_program_parameter_list *parameters;
    151 
    152    GLuint numInst;                    /* number of instructions parsed */
    153    GLuint inputsRead;                 /* bitmask of input registers used */
    154    GLuint outputsWritten;             /* bitmask of 1 << FRAG_OUTPUT_* bits */
    155    GLuint texturesUsed[MAX_TEXTURE_IMAGE_UNITS];
    156 };
    157 
    158 
    159 
    160 /*
    161  * Called whenever we find an error during parsing.
    162  */
    163 static void
    164 record_error(struct parse_state *parseState, const char *msg, int lineNo)
    165 {
    166 #ifdef DEBUG
    167    GLint line, column;
    168    const GLubyte *lineStr;
    169    lineStr = _mesa_find_line_column(parseState->start,
    170                                     parseState->pos, &line, &column);
    171    _mesa_debug(parseState->ctx,
    172                "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
    173                lineNo, line, column, (char *) lineStr, msg);
    174    free((void *) lineStr);
    175 #else
    176    (void) lineNo;
    177 #endif
    178 
    179    /* Check that no error was already recorded.  Only record the first one. */
    180    if (parseState->ctx->Program.ErrorString[0] == 0) {
    181       _mesa_set_program_error(parseState->ctx,
    182                               parseState->pos - parseState->start,
    183                               msg);
    184    }
    185 }
    186 
    187 
    188 #define RETURN_ERROR							\
    189 do {									\
    190    record_error(parseState, "Unexpected end of input.", __LINE__);	\
    191    return GL_FALSE;							\
    192 } while(0)
    193 
    194 #define RETURN_ERROR1(msg)						\
    195 do {									\
    196    record_error(parseState, msg, __LINE__);				\
    197    return GL_FALSE;							\
    198 } while(0)
    199 
    200 #define RETURN_ERROR2(msg1, msg2)					\
    201 do {									\
    202    char err[1000];							\
    203    sprintf(err, "%s %s", msg1, msg2);				\
    204    record_error(parseState, err, __LINE__);				\
    205    return GL_FALSE;							\
    206 } while(0)
    207 
    208 
    209 
    210 
    211 /*
    212  * Search a list of instruction structures for a match.
    213  */
    214 static struct instruction_pattern
    215 MatchInstruction(const GLubyte *token)
    216 {
    217    const struct instruction_pattern *inst;
    218    struct instruction_pattern result;
    219 
    220    result.name = NULL;
    221    result.opcode = MAX_OPCODE; /* i.e. invalid instruction */
    222    result.inputs = 0;
    223    result.outputs = 0;
    224    result.suffixes = 0;
    225 
    226    for (inst = Instructions; inst->name; inst++) {
    227       if (strncmp((const char *) token, inst->name, 3) == 0) {
    228          /* matched! */
    229          int i = 3;
    230          result = *inst;
    231          result.suffixes = 0;
    232          /* look at suffix */
    233          if (token[i] == 'R') {
    234             result.suffixes |= _R;
    235             i++;
    236          }
    237          else if (token[i] == 'H') {
    238             result.suffixes |= _H;
    239             i++;
    240          }
    241          else if (token[i] == 'X') {
    242             result.suffixes |= _X;
    243             i++;
    244          }
    245          if (token[i] == 'C') {
    246             result.suffixes |= _C;
    247             i++;
    248          }
    249          if (token[i] == '_' && token[i+1] == 'S' &&
    250              token[i+2] == 'A' && token[i+3] == 'T') {
    251             result.suffixes |= _S;
    252          }
    253          return result;
    254       }
    255    }
    256 
    257    return result;
    258 }
    259 
    260 
    261 
    262 
    263 /**********************************************************************/
    264 
    265 
    266 static GLboolean IsLetter(GLubyte b)
    267 {
    268    return (b >= 'a' && b <= 'z') ||
    269           (b >= 'A' && b <= 'Z') ||
    270           (b == '_') ||
    271           (b == '$');
    272 }
    273 
    274 
    275 static GLboolean IsDigit(GLubyte b)
    276 {
    277    return b >= '0' && b <= '9';
    278 }
    279 
    280 
    281 static GLboolean IsWhitespace(GLubyte b)
    282 {
    283    return b == ' ' || b == '\t' || b == '\n' || b == '\r';
    284 }
    285 
    286 
    287 /**
    288  * Starting at 'str' find the next token.  A token can be an integer,
    289  * an identifier or punctuation symbol.
    290  * \return <= 0 we found an error, else, return number of characters parsed.
    291  */
    292 static GLint
    293 GetToken(struct parse_state *parseState, GLubyte *token)
    294 {
    295    const GLubyte *str = parseState->pos;
    296    GLint i = 0, j = 0;
    297 
    298    token[0] = 0;
    299 
    300    /* skip whitespace and comments */
    301    while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) {
    302       if (str[i] == '#') {
    303          /* skip comment */
    304          while (str[i] && (str[i] != '\n' && str[i] != '\r')) {
    305             i++;
    306          }
    307          if (str[i] == '\n' || str[i] == '\r')
    308             parseState->curLine = str + i + 1;
    309       }
    310       else {
    311          /* skip whitespace */
    312          if (str[i] == '\n' || str[i] == '\r')
    313             parseState->curLine = str + i + 1;
    314          i++;
    315       }
    316    }
    317 
    318    if (str[i] == 0)
    319       return -i;
    320 
    321    /* try matching an integer */
    322    while (str[i] && IsDigit(str[i])) {
    323       token[j++] = str[i++];
    324    }
    325    if (j > 0 || !str[i]) {
    326       token[j] = 0;
    327       return i;
    328    }
    329 
    330    /* try matching an identifier */
    331    if (IsLetter(str[i])) {
    332       while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) {
    333          token[j++] = str[i++];
    334       }
    335       token[j] = 0;
    336       return i;
    337    }
    338 
    339    /* punctuation character */
    340    if (str[i]) {
    341       token[0] = str[i++];
    342       token[1] = 0;
    343       return i;
    344    }
    345 
    346    /* end of input */
    347    token[0] = 0;
    348    return i;
    349 }
    350 
    351 
    352 /**
    353  * Get next token from input stream and increment stream pointer past token.
    354  */
    355 static GLboolean
    356 Parse_Token(struct parse_state *parseState, GLubyte *token)
    357 {
    358    GLint i;
    359    i = GetToken(parseState, token);
    360    if (i <= 0) {
    361       parseState->pos += (-i);
    362       return GL_FALSE;
    363    }
    364    parseState->pos += i;
    365    return GL_TRUE;
    366 }
    367 
    368 
    369 /**
    370  * Get next token from input stream but don't increment stream pointer.
    371  */
    372 static GLboolean
    373 Peek_Token(struct parse_state *parseState, GLubyte *token)
    374 {
    375    GLint i, len;
    376    i = GetToken(parseState, token);
    377    if (i <= 0) {
    378       parseState->pos += (-i);
    379       return GL_FALSE;
    380    }
    381    len = (GLint) strlen((const char *) token);
    382    parseState->pos += (i - len);
    383    return GL_TRUE;
    384 }
    385 
    386 
    387 /**********************************************************************/
    388 
    389 static const char *InputRegisters[MAX_NV_FRAGMENT_PROGRAM_INPUTS + 1] = {
    390    "WPOS", "COL0", "COL1", "FOGC",
    391    "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
    392 };
    393 
    394 
    395 
    396 /**********************************************************************/
    397 
    398 /**
    399  * Try to match 'pattern' as the next token after any whitespace/comments.
    400  */
    401 static GLboolean
    402 Parse_String(struct parse_state *parseState, const char *pattern)
    403 {
    404    const GLubyte *m;
    405    GLint i;
    406 
    407    /* skip whitespace and comments */
    408    while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') {
    409       if (*parseState->pos == '#') {
    410          while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) {
    411             parseState->pos += 1;
    412          }
    413          if (*parseState->pos == '\n' || *parseState->pos == '\r')
    414             parseState->curLine = parseState->pos + 1;
    415       }
    416       else {
    417          /* skip whitespace */
    418          if (*parseState->pos == '\n' || *parseState->pos == '\r')
    419             parseState->curLine = parseState->pos + 1;
    420          parseState->pos += 1;
    421       }
    422    }
    423 
    424    /* Try to match the pattern */
    425    m = parseState->pos;
    426    for (i = 0; pattern[i]; i++) {
    427       if (*m != (GLubyte) pattern[i])
    428          return GL_FALSE;
    429       m += 1;
    430    }
    431    parseState->pos = m;
    432 
    433    return GL_TRUE; /* success */
    434 }
    435 
    436 
    437 static GLboolean
    438 Parse_Identifier(struct parse_state *parseState, GLubyte *ident)
    439 {
    440    if (!Parse_Token(parseState, ident))
    441       RETURN_ERROR;
    442    if (IsLetter(ident[0]))
    443       return GL_TRUE;
    444    else
    445       RETURN_ERROR1("Expected an identfier");
    446 }
    447 
    448 
    449 /**
    450  * Parse a floating point constant, or a defined symbol name.
    451  * [+/-]N[.N[eN]]
    452  * Output:  number[0 .. 3] will get the value.
    453  */
    454 static GLboolean
    455 Parse_ScalarConstant(struct parse_state *parseState, GLfloat *number)
    456 {
    457    char *end = NULL;
    458 
    459    *number = (GLfloat) _mesa_strtof((const char *) parseState->pos, &end);
    460 
    461    if (end && end > (char *) parseState->pos) {
    462       /* got a number */
    463       parseState->pos = (GLubyte *) end;
    464       number[1] = *number;
    465       number[2] = *number;
    466       number[3] = *number;
    467       return GL_TRUE;
    468    }
    469    else {
    470       /* should be an identifier */
    471       GLubyte ident[100];
    472       const GLfloat *constant;
    473       if (!Parse_Identifier(parseState, ident))
    474          RETURN_ERROR1("Expected an identifier");
    475       constant = (GLfloat *)_mesa_lookup_parameter_value(parseState->parameters,
    476                                                          -1,
    477                                                          (const char *) ident);
    478       /* XXX Check that it's a constant and not a parameter */
    479       if (!constant) {
    480          RETURN_ERROR1("Undefined symbol");
    481       }
    482       else {
    483          COPY_4V(number, constant);
    484          return GL_TRUE;
    485       }
    486    }
    487 }
    488 
    489 
    490 
    491 /**
    492  * Parse a vector constant, one of:
    493  *   { float }
    494  *   { float, float }
    495  *   { float, float, float }
    496  *   { float, float, float, float }
    497  */
    498 static GLboolean
    499 Parse_VectorConstant(struct parse_state *parseState, GLfloat *vec)
    500 {
    501    /* "{" was already consumed */
    502 
    503    ASSIGN_4V(vec, 0.0, 0.0, 0.0, 1.0);
    504 
    505    if (!Parse_ScalarConstant(parseState, vec+0))  /* X */
    506       return GL_FALSE;
    507 
    508    if (Parse_String(parseState, "}")) {
    509       return GL_TRUE;
    510    }
    511 
    512    if (!Parse_String(parseState, ","))
    513       RETURN_ERROR1("Expected comma in vector constant");
    514 
    515    if (!Parse_ScalarConstant(parseState, vec+1))  /* Y */
    516       return GL_FALSE;
    517 
    518    if (Parse_String(parseState, "}")) {
    519       return GL_TRUE;
    520    }
    521 
    522    if (!Parse_String(parseState, ","))
    523       RETURN_ERROR1("Expected comma in vector constant");
    524 
    525    if (!Parse_ScalarConstant(parseState, vec+2))  /* Z */
    526       return GL_FALSE;
    527 
    528    if (Parse_String(parseState, "}")) {
    529       return GL_TRUE;
    530    }
    531 
    532    if (!Parse_String(parseState, ","))
    533       RETURN_ERROR1("Expected comma in vector constant");
    534 
    535    if (!Parse_ScalarConstant(parseState, vec+3))  /* W */
    536       return GL_FALSE;
    537 
    538    if (!Parse_String(parseState, "}"))
    539       RETURN_ERROR1("Expected closing brace in vector constant");
    540 
    541    return GL_TRUE;
    542 }
    543 
    544 
    545 /**
    546  * Parse <number>, <varname> or {a, b, c, d}.
    547  * Return number of values in the vector or scalar, or zero if parse error.
    548  */
    549 static GLuint
    550 Parse_VectorOrScalarConstant(struct parse_state *parseState, GLfloat *vec)
    551 {
    552    if (Parse_String(parseState, "{")) {
    553       return Parse_VectorConstant(parseState, vec);
    554    }
    555    else {
    556       GLboolean b = Parse_ScalarConstant(parseState, vec);
    557       if (b) {
    558          vec[1] = vec[2] = vec[3] = vec[0];
    559       }
    560       return b;
    561    }
    562 }
    563 
    564 
    565 /**
    566  * Parse a texture image source:
    567  *    [TEX0 | TEX1 | .. | TEX15] , [1D | 2D | 3D | CUBE | RECT]
    568  */
    569 static GLboolean
    570 Parse_TextureImageId(struct parse_state *parseState,
    571                      GLubyte *texUnit, GLubyte *texTarget)
    572 {
    573    GLubyte imageSrc[100];
    574    GLint unit;
    575 
    576    if (!Parse_Token(parseState, imageSrc))
    577       RETURN_ERROR;
    578 
    579    if (imageSrc[0] != 'T' ||
    580        imageSrc[1] != 'E' ||
    581        imageSrc[2] != 'X') {
    582       RETURN_ERROR1("Expected TEX# source");
    583    }
    584    unit = atoi((const char *) imageSrc + 3);
    585    if ((unit < 0 || unit >= MAX_TEXTURE_IMAGE_UNITS) ||
    586        (unit == 0 && (imageSrc[3] != '0' || imageSrc[4] != 0))) {
    587       RETURN_ERROR1("Invalied TEX# source index");
    588    }
    589    *texUnit = unit;
    590 
    591    if (!Parse_String(parseState, ","))
    592       RETURN_ERROR1("Expected ,");
    593 
    594    if (Parse_String(parseState, "1D")) {
    595       *texTarget = TEXTURE_1D_INDEX;
    596    }
    597    else if (Parse_String(parseState, "2D")) {
    598       *texTarget = TEXTURE_2D_INDEX;
    599    }
    600    else if (Parse_String(parseState, "3D")) {
    601       *texTarget = TEXTURE_3D_INDEX;
    602    }
    603    else if (Parse_String(parseState, "CUBE")) {
    604       *texTarget = TEXTURE_CUBE_INDEX;
    605    }
    606    else if (Parse_String(parseState, "RECT")) {
    607       *texTarget = TEXTURE_RECT_INDEX;
    608    }
    609    else {
    610       RETURN_ERROR1("Invalid texture target token");
    611    }
    612 
    613    /* update record of referenced texture units */
    614    parseState->texturesUsed[*texUnit] |= (1 << *texTarget);
    615    if (_mesa_bitcount(parseState->texturesUsed[*texUnit]) > 1) {
    616       RETURN_ERROR1("Only one texture target can be used per texture unit.");
    617    }
    618 
    619    return GL_TRUE;
    620 }
    621 
    622 
    623 /**
    624  * Parse a scalar suffix like .x, .y, .z or .w or parse a swizzle suffix
    625  * like .wxyz, .xxyy, etc and return the swizzle indexes.
    626  */
    627 static GLboolean
    628 Parse_SwizzleSuffix(const GLubyte *token, GLuint swizzle[4])
    629 {
    630    if (token[1] == 0) {
    631       /* single letter swizzle (scalar) */
    632       if (token[0] == 'x')
    633          ASSIGN_4V(swizzle, 0, 0, 0, 0);
    634       else if (token[0] == 'y')
    635          ASSIGN_4V(swizzle, 1, 1, 1, 1);
    636       else if (token[0] == 'z')
    637          ASSIGN_4V(swizzle, 2, 2, 2, 2);
    638       else if (token[0] == 'w')
    639          ASSIGN_4V(swizzle, 3, 3, 3, 3);
    640       else
    641          return GL_FALSE;
    642    }
    643    else {
    644       /* 4-component swizzle (vector) */
    645       GLint k;
    646       for (k = 0; k < 4 && token[k]; k++) {
    647          if (token[k] == 'x')
    648             swizzle[k] = 0;
    649          else if (token[k] == 'y')
    650             swizzle[k] = 1;
    651          else if (token[k] == 'z')
    652             swizzle[k] = 2;
    653          else if (token[k] == 'w')
    654             swizzle[k] = 3;
    655          else
    656             return GL_FALSE;
    657       }
    658       if (k != 4)
    659          return GL_FALSE;
    660    }
    661    return GL_TRUE;
    662 }
    663 
    664 
    665 static GLboolean
    666 Parse_CondCodeMask(struct parse_state *parseState,
    667                    struct prog_dst_register *dstReg)
    668 {
    669    if (Parse_String(parseState, "EQ"))
    670       dstReg->CondMask = COND_EQ;
    671    else if (Parse_String(parseState, "GE"))
    672       dstReg->CondMask = COND_GE;
    673    else if (Parse_String(parseState, "GT"))
    674       dstReg->CondMask = COND_GT;
    675    else if (Parse_String(parseState, "LE"))
    676       dstReg->CondMask = COND_LE;
    677    else if (Parse_String(parseState, "LT"))
    678       dstReg->CondMask = COND_LT;
    679    else if (Parse_String(parseState, "NE"))
    680       dstReg->CondMask = COND_NE;
    681    else if (Parse_String(parseState, "TR"))
    682       dstReg->CondMask = COND_TR;
    683    else if (Parse_String(parseState, "FL"))
    684       dstReg->CondMask = COND_FL;
    685    else
    686       RETURN_ERROR1("Invalid condition code mask");
    687 
    688    /* look for optional .xyzw swizzle */
    689    if (Parse_String(parseState, ".")) {
    690       GLubyte token[100];
    691       GLuint swz[4];
    692 
    693       if (!Parse_Token(parseState, token))  /* get xyzw suffix */
    694          RETURN_ERROR;
    695 
    696       if (!Parse_SwizzleSuffix(token, swz))
    697          RETURN_ERROR1("Invalid swizzle suffix");
    698 
    699       dstReg->CondSwizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
    700    }
    701 
    702    return GL_TRUE;
    703 }
    704 
    705 
    706 /**
    707  * Parse a temporary register: Rnn or Hnn
    708  */
    709 static GLboolean
    710 Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum)
    711 {
    712    GLubyte token[100];
    713 
    714    /* Should be 'R##' or 'H##' */
    715    if (!Parse_Token(parseState, token))
    716       RETURN_ERROR;
    717    if (token[0] != 'R' && token[0] != 'H')
    718       RETURN_ERROR1("Expected R## or H##");
    719 
    720    if (IsDigit(token[1])) {
    721       GLint reg = atoi((const char *) (token + 1));
    722       if (token[0] == 'H')
    723          reg += 32;
    724       if (reg >= MAX_NV_FRAGMENT_PROGRAM_TEMPS)
    725          RETURN_ERROR1("Invalid temporary register name");
    726       *tempRegNum = reg;
    727    }
    728    else {
    729       RETURN_ERROR1("Invalid temporary register name");
    730    }
    731 
    732    return GL_TRUE;
    733 }
    734 
    735 
    736 /**
    737  * Parse a write-only dummy register: RC or HC.
    738  */
    739 static GLboolean
    740 Parse_DummyReg(struct parse_state *parseState, GLint *regNum)
    741 {
    742    if (Parse_String(parseState, "RC")) {
    743        *regNum = 0;
    744    }
    745    else if (Parse_String(parseState, "HC")) {
    746        *regNum = 1;
    747    }
    748    else {
    749       RETURN_ERROR1("Invalid write-only register name");
    750    }
    751 
    752    return GL_TRUE;
    753 }
    754 
    755 
    756 /**
    757  * Parse a program local parameter register "p[##]"
    758  */
    759 static GLboolean
    760 Parse_ProgramParamReg(struct parse_state *parseState, GLint *regNum)
    761 {
    762    GLubyte token[100];
    763 
    764    if (!Parse_String(parseState, "p["))
    765       RETURN_ERROR1("Expected p[");
    766 
    767    if (!Parse_Token(parseState, token))
    768       RETURN_ERROR;
    769 
    770    if (IsDigit(token[0])) {
    771       /* a numbered program parameter register */
    772       GLint reg = atoi((const char *) token);
    773       if (reg >= MAX_NV_FRAGMENT_PROGRAM_PARAMS)
    774          RETURN_ERROR1("Invalid constant program number");
    775       *regNum = reg;
    776    }
    777    else {
    778       RETURN_ERROR;
    779    }
    780 
    781    if (!Parse_String(parseState, "]"))
    782       RETURN_ERROR1("Expected ]");
    783 
    784    return GL_TRUE;
    785 }
    786 
    787 
    788 /**
    789  * Parse f[name]  - fragment input register
    790  */
    791 static GLboolean
    792 Parse_FragReg(struct parse_state *parseState, GLint *tempRegNum)
    793 {
    794    GLubyte token[100];
    795    GLint j;
    796 
    797    /* Match 'f[' */
    798    if (!Parse_String(parseState, "f["))
    799       RETURN_ERROR1("Expected f[");
    800 
    801    /* get <name> and look for match */
    802    if (!Parse_Token(parseState, token)) {
    803       RETURN_ERROR;
    804    }
    805    for (j = 0; InputRegisters[j]; j++) {
    806       if (strcmp((const char *) token, InputRegisters[j]) == 0) {
    807          *tempRegNum = j;
    808          parseState->inputsRead |= (1 << j);
    809          break;
    810       }
    811    }
    812    if (!InputRegisters[j]) {
    813       /* unknown input register label */
    814       RETURN_ERROR2("Invalid register name", token);
    815    }
    816 
    817    /* Match '[' */
    818    if (!Parse_String(parseState, "]"))
    819       RETURN_ERROR1("Expected ]");
    820 
    821    return GL_TRUE;
    822 }
    823 
    824 
    825 static GLboolean
    826 Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
    827 {
    828    GLubyte token[100];
    829 
    830    /* Match "o[" */
    831    if (!Parse_String(parseState, "o["))
    832       RETURN_ERROR1("Expected o[");
    833 
    834    /* Get output reg name */
    835    if (!Parse_Token(parseState, token))
    836       RETURN_ERROR;
    837 
    838    /* try to match an output register name */
    839    if (strcmp((char *) token, "COLR") == 0 ||
    840        strcmp((char *) token, "COLH") == 0) {
    841       /* note that we don't distinguish between COLR and COLH */
    842       *outputRegNum = FRAG_RESULT_COLOR;
    843       parseState->outputsWritten |= (1 << FRAG_RESULT_COLOR);
    844    }
    845    else if (strcmp((char *) token, "DEPR") == 0) {
    846       *outputRegNum = FRAG_RESULT_DEPTH;
    847       parseState->outputsWritten |= (1 << FRAG_RESULT_DEPTH);
    848    }
    849    else {
    850       RETURN_ERROR1("Invalid output register name");
    851    }
    852 
    853    /* Match ']' */
    854    if (!Parse_String(parseState, "]"))
    855       RETURN_ERROR1("Expected ]");
    856 
    857    return GL_TRUE;
    858 }
    859 
    860 
    861 static GLboolean
    862 Parse_MaskedDstReg(struct parse_state *parseState,
    863                    struct prog_dst_register *dstReg)
    864 {
    865    GLubyte token[100];
    866    GLint idx;
    867 
    868    /* Dst reg can be R<n>, H<n>, o[n], RC or HC */
    869    if (!Peek_Token(parseState, token))
    870       RETURN_ERROR;
    871 
    872    if (strcmp((const char *) token, "RC") == 0 ||
    873        strcmp((const char *) token, "HC") == 0) {
    874       /* a write-only register */
    875       dstReg->File = PROGRAM_WRITE_ONLY;
    876       if (!Parse_DummyReg(parseState, &idx))
    877          RETURN_ERROR;
    878       dstReg->Index = idx;
    879    }
    880    else if (token[0] == 'R' || token[0] == 'H') {
    881       /* a temporary register */
    882       dstReg->File = PROGRAM_TEMPORARY;
    883       if (!Parse_TempReg(parseState, &idx))
    884          RETURN_ERROR;
    885       dstReg->Index = idx;
    886    }
    887    else if (token[0] == 'o') {
    888       /* an output register */
    889       dstReg->File = PROGRAM_OUTPUT;
    890       if (!Parse_OutputReg(parseState, &idx))
    891          RETURN_ERROR;
    892       dstReg->Index = idx;
    893    }
    894    else {
    895       RETURN_ERROR1("Invalid destination register name");
    896    }
    897 
    898    /* Parse optional write mask */
    899    if (Parse_String(parseState, ".")) {
    900       /* got a mask */
    901       GLint k = 0;
    902 
    903       if (!Parse_Token(parseState, token))  /* get xyzw writemask */
    904          RETURN_ERROR;
    905 
    906       dstReg->WriteMask = 0;
    907 
    908       if (token[k] == 'x') {
    909          dstReg->WriteMask |= WRITEMASK_X;
    910          k++;
    911       }
    912       if (token[k] == 'y') {
    913          dstReg->WriteMask |= WRITEMASK_Y;
    914          k++;
    915       }
    916       if (token[k] == 'z') {
    917          dstReg->WriteMask |= WRITEMASK_Z;
    918          k++;
    919       }
    920       if (token[k] == 'w') {
    921          dstReg->WriteMask |= WRITEMASK_W;
    922          k++;
    923       }
    924       if (k == 0) {
    925          RETURN_ERROR1("Invalid writemask character");
    926       }
    927 
    928    }
    929    else {
    930       dstReg->WriteMask = WRITEMASK_XYZW;
    931    }
    932 
    933    /* optional condition code mask */
    934    if (Parse_String(parseState, "(")) {
    935       /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */
    936       /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */
    937       if (!Parse_CondCodeMask(parseState, dstReg))
    938          RETURN_ERROR;
    939 
    940       if (!Parse_String(parseState, ")"))  /* consume ")" */
    941          RETURN_ERROR1("Expected )");
    942 
    943       return GL_TRUE;
    944    }
    945    else {
    946       /* no cond code mask */
    947       dstReg->CondMask = COND_TR;
    948       dstReg->CondSwizzle = SWIZZLE_NOOP;
    949       return GL_TRUE;
    950    }
    951 }
    952 
    953 
    954 /**
    955  * Parse a vector source (register, constant, etc):
    956  *   <vectorSrc>    ::= <absVectorSrc>
    957  *                    | <baseVectorSrc>
    958  *   <absVectorSrc> ::= <negate> "|" <baseVectorSrc> "|"
    959  */
    960 static GLboolean
    961 Parse_VectorSrc(struct parse_state *parseState,
    962                 struct prog_src_register *srcReg)
    963 {
    964    GLfloat sign = 1.0F;
    965    GLubyte token[100];
    966    GLint idx;
    967    GLuint negateBase, negateAbs;
    968 
    969    /*
    970     * First, take care of +/- and absolute value stuff.
    971     */
    972    if (Parse_String(parseState, "-"))
    973       sign = -1.0F;
    974    else if (Parse_String(parseState, "+"))
    975       sign = +1.0F;
    976 
    977    if (Parse_String(parseState, "|")) {
    978       srcReg->Abs = GL_TRUE;
    979       negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
    980 
    981       if (Parse_String(parseState, "-"))
    982          negateBase = NEGATE_XYZW;
    983       else if (Parse_String(parseState, "+"))
    984          negateBase = NEGATE_NONE;
    985       else
    986          negateBase = NEGATE_NONE;
    987    }
    988    else {
    989       srcReg->Abs = GL_FALSE;
    990       negateAbs = NEGATE_NONE;
    991       negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
    992    }
    993 
    994    srcReg->Negate = srcReg->Abs ? negateAbs : negateBase;
    995 
    996    /* This should be the real src vector/register name */
    997    if (!Peek_Token(parseState, token))
    998       RETURN_ERROR;
    999 
   1000    /* Src reg can be Rn, Hn, f[n], p[n], a named parameter, a scalar
   1001     * literal or vector literal.
   1002     */
   1003    if (token[0] == 'R' || token[0] == 'H') {
   1004       srcReg->File = PROGRAM_TEMPORARY;
   1005       if (!Parse_TempReg(parseState, &idx))
   1006          RETURN_ERROR;
   1007       srcReg->Index = idx;
   1008    }
   1009    else if (token[0] == 'f') {
   1010       /* XXX this might be an identifier! */
   1011       srcReg->File = PROGRAM_INPUT;
   1012       if (!Parse_FragReg(parseState, &idx))
   1013          RETURN_ERROR;
   1014       srcReg->Index = idx;
   1015    }
   1016    else if (token[0] == 'p') {
   1017       /* XXX this might be an identifier! */
   1018       srcReg->File = PROGRAM_LOCAL_PARAM;
   1019       if (!Parse_ProgramParamReg(parseState, &idx))
   1020          RETURN_ERROR;
   1021       srcReg->Index = idx;
   1022    }
   1023    else if (IsLetter(token[0])){
   1024       GLubyte ident[100];
   1025       GLint paramIndex;
   1026       if (!Parse_Identifier(parseState, ident))
   1027          RETURN_ERROR;
   1028       paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
   1029                                                 -1, (const char *) ident);
   1030       if (paramIndex < 0) {
   1031          RETURN_ERROR2("Undefined constant or parameter: ", ident);
   1032       }
   1033       srcReg->File = PROGRAM_NAMED_PARAM;
   1034       srcReg->Index = paramIndex;
   1035    }
   1036    else if (IsDigit(token[0]) || token[0] == '-' || token[0] == '+' || token[0] == '.'){
   1037       /* literal scalar constant */
   1038       GLfloat values[4];
   1039       GLuint paramIndex;
   1040       if (!Parse_ScalarConstant(parseState, values))
   1041          RETURN_ERROR;
   1042       paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
   1043                                               (gl_constant_value *) values,
   1044                                               4, NULL);
   1045       srcReg->File = PROGRAM_NAMED_PARAM;
   1046       srcReg->Index = paramIndex;
   1047    }
   1048    else if (token[0] == '{'){
   1049       /* literal vector constant */
   1050       GLfloat values[4];
   1051       GLuint paramIndex;
   1052       (void) Parse_String(parseState, "{");
   1053       if (!Parse_VectorConstant(parseState, values))
   1054          RETURN_ERROR;
   1055       paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
   1056                                               (gl_constant_value *) values,
   1057                                               4, NULL);
   1058       srcReg->File = PROGRAM_NAMED_PARAM;
   1059       srcReg->Index = paramIndex;
   1060    }
   1061    else {
   1062       RETURN_ERROR2("Invalid source register name", token);
   1063    }
   1064 
   1065    /* init swizzle fields */
   1066    srcReg->Swizzle = SWIZZLE_NOOP;
   1067 
   1068    /* Look for optional swizzle suffix */
   1069    if (Parse_String(parseState, ".")) {
   1070       GLuint swz[4];
   1071 
   1072       if (!Parse_Token(parseState, token))
   1073          RETURN_ERROR;
   1074 
   1075       if (!Parse_SwizzleSuffix(token, swz))
   1076          RETURN_ERROR1("Invalid swizzle suffix");
   1077 
   1078       srcReg->Swizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
   1079    }
   1080 
   1081    /* Finish absolute value */
   1082    if (srcReg->Abs && !Parse_String(parseState, "|")) {
   1083       RETURN_ERROR1("Expected |");
   1084    }
   1085 
   1086    return GL_TRUE;
   1087 }
   1088 
   1089 
   1090 static GLboolean
   1091 Parse_ScalarSrcReg(struct parse_state *parseState,
   1092                    struct prog_src_register *srcReg)
   1093 {
   1094    GLubyte token[100];
   1095    GLfloat sign = 1.0F;
   1096    GLboolean needSuffix = GL_TRUE;
   1097    GLint idx;
   1098    GLuint negateBase, negateAbs;
   1099 
   1100    /*
   1101     * First, take care of +/- and absolute value stuff.
   1102     */
   1103    if (Parse_String(parseState, "-"))
   1104       sign = -1.0F;
   1105    else if (Parse_String(parseState, "+"))
   1106       sign = +1.0F;
   1107 
   1108    if (Parse_String(parseState, "|")) {
   1109       srcReg->Abs = GL_TRUE;
   1110       negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
   1111 
   1112       if (Parse_String(parseState, "-"))
   1113          negateBase = NEGATE_XYZW;
   1114       else if (Parse_String(parseState, "+"))
   1115          negateBase = NEGATE_NONE;
   1116       else
   1117          negateBase = NEGATE_NONE;
   1118    }
   1119    else {
   1120       srcReg->Abs = GL_FALSE;
   1121       negateAbs = NEGATE_NONE;
   1122       negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
   1123    }
   1124 
   1125    srcReg->Negate = srcReg->Abs ? negateAbs : negateBase;
   1126 
   1127    if (!Peek_Token(parseState, token))
   1128       RETURN_ERROR;
   1129 
   1130    /* Src reg can be R<n>, H<n> or a named fragment attrib */
   1131    if (token[0] == 'R' || token[0] == 'H') {
   1132       srcReg->File = PROGRAM_TEMPORARY;
   1133       if (!Parse_TempReg(parseState, &idx))
   1134          RETURN_ERROR;
   1135       srcReg->Index = idx;
   1136    }
   1137    else if (token[0] == 'f') {
   1138       srcReg->File = PROGRAM_INPUT;
   1139       if (!Parse_FragReg(parseState, &idx))
   1140          RETURN_ERROR;
   1141       srcReg->Index = idx;
   1142    }
   1143    else if (token[0] == '{') {
   1144       /* vector literal */
   1145       GLfloat values[4];
   1146       GLuint paramIndex;
   1147       (void) Parse_String(parseState, "{");
   1148       if (!Parse_VectorConstant(parseState, values))
   1149          RETURN_ERROR;
   1150       paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
   1151                                               (gl_constant_value *) values,
   1152                                               4, NULL);
   1153       srcReg->File = PROGRAM_NAMED_PARAM;
   1154       srcReg->Index = paramIndex;
   1155    }
   1156    else if (IsLetter(token[0])){
   1157       /* named param/constant */
   1158       GLubyte ident[100];
   1159       GLint paramIndex;
   1160       if (!Parse_Identifier(parseState, ident))
   1161          RETURN_ERROR;
   1162       paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
   1163                                                 -1, (const char *) ident);
   1164       if (paramIndex < 0) {
   1165          RETURN_ERROR2("Undefined constant or parameter: ", ident);
   1166       }
   1167       srcReg->File = PROGRAM_NAMED_PARAM;
   1168       srcReg->Index = paramIndex;
   1169    }
   1170    else if (IsDigit(token[0])) {
   1171       /* scalar literal */
   1172       GLfloat values[4];
   1173       GLuint paramIndex;
   1174       if (!Parse_ScalarConstant(parseState, values))
   1175          RETURN_ERROR;
   1176       paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
   1177                                               (gl_constant_value *) values,
   1178                                               4, NULL);
   1179       srcReg->Index = paramIndex;
   1180       srcReg->File = PROGRAM_NAMED_PARAM;
   1181       needSuffix = GL_FALSE;
   1182    }
   1183    else {
   1184       RETURN_ERROR2("Invalid scalar source argument", token);
   1185    }
   1186 
   1187    srcReg->Swizzle = 0;
   1188    if (needSuffix) {
   1189       /* parse .[xyzw] suffix */
   1190       if (!Parse_String(parseState, "."))
   1191          RETURN_ERROR1("Expected .");
   1192 
   1193       if (!Parse_Token(parseState, token))
   1194          RETURN_ERROR;
   1195 
   1196       if (token[0] == 'x' && token[1] == 0) {
   1197          srcReg->Swizzle = 0;
   1198       }
   1199       else if (token[0] == 'y' && token[1] == 0) {
   1200          srcReg->Swizzle = 1;
   1201       }
   1202       else if (token[0] == 'z' && token[1] == 0) {
   1203          srcReg->Swizzle = 2;
   1204       }
   1205       else if (token[0] == 'w' && token[1] == 0) {
   1206          srcReg->Swizzle = 3;
   1207       }
   1208       else {
   1209          RETURN_ERROR1("Invalid scalar source suffix");
   1210       }
   1211    }
   1212 
   1213    /* Finish absolute value */
   1214    if (srcReg->Abs && !Parse_String(parseState, "|")) {
   1215       RETURN_ERROR1("Expected |");
   1216    }
   1217 
   1218    return GL_TRUE;
   1219 }
   1220 
   1221 
   1222 static GLboolean
   1223 Parse_PrintInstruction(struct parse_state *parseState,
   1224                        struct prog_instruction *inst)
   1225 {
   1226    const GLubyte *str;
   1227    GLubyte *msg;
   1228    GLuint len;
   1229    GLint idx;
   1230 
   1231    /* The first argument is a literal string 'just like this' */
   1232    if (!Parse_String(parseState, "'"))
   1233       RETURN_ERROR1("Expected '");
   1234 
   1235    str = parseState->pos;
   1236    for (len = 0; str[len] != '\''; len++) /* find closing quote */
   1237       ;
   1238    parseState->pos += len + 1;
   1239    msg = (GLubyte*) malloc(len + 1);
   1240 
   1241    memcpy(msg, str, len);
   1242    msg[len] = 0;
   1243    inst->Data = msg;
   1244 
   1245    if (Parse_String(parseState, ",")) {
   1246       /* got an optional register to print */
   1247       GLubyte token[100];
   1248       GetToken(parseState, token);
   1249       if (token[0] == 'o') {
   1250          /* dst reg */
   1251          if (!Parse_OutputReg(parseState, &idx))
   1252             RETURN_ERROR;
   1253 	 inst->SrcReg[0].Index = idx;
   1254          inst->SrcReg[0].File = PROGRAM_OUTPUT;
   1255       }
   1256       else {
   1257          /* src reg */
   1258          if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
   1259             RETURN_ERROR;
   1260       }
   1261    }
   1262    else {
   1263       inst->SrcReg[0].File = PROGRAM_UNDEFINED;
   1264    }
   1265 
   1266    inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
   1267    inst->SrcReg[0].Abs = GL_FALSE;
   1268    inst->SrcReg[0].Negate = NEGATE_NONE;
   1269 
   1270    return GL_TRUE;
   1271 }
   1272 
   1273 
   1274 static GLboolean
   1275 Parse_InstructionSequence(struct parse_state *parseState,
   1276                           struct prog_instruction program[])
   1277 {
   1278    while (1) {
   1279       struct prog_instruction *inst = program + parseState->numInst;
   1280       struct instruction_pattern instMatch;
   1281       GLubyte token[100];
   1282 
   1283       /* Initialize the instruction */
   1284       _mesa_init_instructions(inst, 1);
   1285 
   1286       /* special instructions */
   1287       if (Parse_String(parseState, "DEFINE")) {
   1288          GLubyte id[100];
   1289          GLfloat value[7];  /* yes, 7 to be safe */
   1290          if (!Parse_Identifier(parseState, id))
   1291             RETURN_ERROR;
   1292          /* XXX make sure id is not a reserved identifer, like R9 */
   1293          if (!Parse_String(parseState, "="))
   1294             RETURN_ERROR1("Expected =");
   1295          if (!Parse_VectorOrScalarConstant(parseState, value))
   1296             RETURN_ERROR;
   1297          if (!Parse_String(parseState, ";"))
   1298             RETURN_ERROR1("Expected ;");
   1299          if (_mesa_lookup_parameter_index(parseState->parameters,
   1300                                           -1, (const char *) id) >= 0) {
   1301             RETURN_ERROR2(id, "already defined");
   1302          }
   1303          _mesa_add_named_parameter(parseState->parameters,
   1304                                    (const char *) id,
   1305                                    (gl_constant_value *) value);
   1306       }
   1307       else if (Parse_String(parseState, "DECLARE")) {
   1308          GLubyte id[100];
   1309          GLfloat value[7] = {0, 0, 0, 0, 0, 0, 0};  /* yes, to be safe */
   1310          if (!Parse_Identifier(parseState, id))
   1311             RETURN_ERROR;
   1312          /* XXX make sure id is not a reserved identifer, like R9 */
   1313          if (Parse_String(parseState, "=")) {
   1314             if (!Parse_VectorOrScalarConstant(parseState, value))
   1315                RETURN_ERROR;
   1316          }
   1317          if (!Parse_String(parseState, ";"))
   1318             RETURN_ERROR1("Expected ;");
   1319          if (_mesa_lookup_parameter_index(parseState->parameters,
   1320                                           -1, (const char *) id) >= 0) {
   1321             RETURN_ERROR2(id, "already declared");
   1322          }
   1323          _mesa_add_named_parameter(parseState->parameters,
   1324                                    (const char *) id,
   1325                                    (gl_constant_value *) value);
   1326       }
   1327       else if (Parse_String(parseState, "END")) {
   1328          inst->Opcode = OPCODE_END;
   1329          parseState->numInst++;
   1330          if (Parse_Token(parseState, token)) {
   1331             RETURN_ERROR1("Code after END opcode.");
   1332          }
   1333          break;
   1334       }
   1335       else {
   1336          /* general/arithmetic instruction */
   1337 
   1338          /* get token */
   1339          if (!Parse_Token(parseState, token)) {
   1340             RETURN_ERROR1("Missing END instruction.");
   1341          }
   1342 
   1343          /* try to find matching instuction */
   1344          instMatch = MatchInstruction(token);
   1345          if (instMatch.opcode >= MAX_OPCODE) {
   1346             /* bad instruction name */
   1347             RETURN_ERROR2("Unexpected token: ", token);
   1348          }
   1349 
   1350          inst->Opcode = instMatch.opcode;
   1351          inst->Precision = instMatch.suffixes & (_R | _H | _X);
   1352          inst->SaturateMode = (instMatch.suffixes & (_S))
   1353             ? SATURATE_ZERO_ONE : SATURATE_OFF;
   1354          inst->CondUpdate = (instMatch.suffixes & (_C)) ? GL_TRUE : GL_FALSE;
   1355 
   1356          /*
   1357           * parse the input and output operands
   1358           */
   1359          if (instMatch.outputs == OUTPUT_S || instMatch.outputs == OUTPUT_V) {
   1360             if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
   1361                RETURN_ERROR;
   1362             if (!Parse_String(parseState, ","))
   1363                RETURN_ERROR1("Expected ,");
   1364          }
   1365          else if (instMatch.outputs == OUTPUT_NONE) {
   1366             if (instMatch.opcode == OPCODE_KIL_NV) {
   1367                /* This is a little weird, the cond code info is in
   1368                 * the dest register.
   1369                 */
   1370                if (!Parse_CondCodeMask(parseState, &inst->DstReg))
   1371                   RETURN_ERROR;
   1372             }
   1373             else {
   1374                ASSERT(instMatch.opcode == OPCODE_PRINT);
   1375             }
   1376          }
   1377 
   1378          if (instMatch.inputs == INPUT_1V) {
   1379             if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
   1380                RETURN_ERROR;
   1381          }
   1382          else if (instMatch.inputs == INPUT_2V) {
   1383             if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
   1384                RETURN_ERROR;
   1385             if (!Parse_String(parseState, ","))
   1386                RETURN_ERROR1("Expected ,");
   1387             if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
   1388                RETURN_ERROR;
   1389          }
   1390          else if (instMatch.inputs == INPUT_3V) {
   1391             if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
   1392                RETURN_ERROR;
   1393             if (!Parse_String(parseState, ","))
   1394                RETURN_ERROR1("Expected ,");
   1395             if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
   1396                RETURN_ERROR;
   1397             if (!Parse_String(parseState, ","))
   1398                RETURN_ERROR1("Expected ,");
   1399             if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
   1400                RETURN_ERROR;
   1401          }
   1402          else if (instMatch.inputs == INPUT_1S) {
   1403             if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
   1404                RETURN_ERROR;
   1405          }
   1406          else if (instMatch.inputs == INPUT_2S) {
   1407             if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
   1408                RETURN_ERROR;
   1409             if (!Parse_String(parseState, ","))
   1410                RETURN_ERROR1("Expected ,");
   1411             if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[1]))
   1412                RETURN_ERROR;
   1413          }
   1414          else if (instMatch.inputs == INPUT_CC) {
   1415             /* XXX to-do */
   1416          }
   1417          else if (instMatch.inputs == INPUT_1V_T) {
   1418 	    GLubyte unit, idx;
   1419             if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
   1420                RETURN_ERROR;
   1421             if (!Parse_String(parseState, ","))
   1422                RETURN_ERROR1("Expected ,");
   1423             if (!Parse_TextureImageId(parseState, &unit, &idx))
   1424                RETURN_ERROR;
   1425 	    inst->TexSrcUnit = unit;
   1426 	    inst->TexSrcTarget = idx;
   1427          }
   1428          else if (instMatch.inputs == INPUT_3V_T) {
   1429 	    GLubyte unit, idx;
   1430             if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
   1431                RETURN_ERROR;
   1432             if (!Parse_String(parseState, ","))
   1433                RETURN_ERROR1("Expected ,");
   1434             if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
   1435                RETURN_ERROR;
   1436             if (!Parse_String(parseState, ","))
   1437                RETURN_ERROR1("Expected ,");
   1438             if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
   1439                RETURN_ERROR;
   1440             if (!Parse_String(parseState, ","))
   1441                RETURN_ERROR1("Expected ,");
   1442             if (!Parse_TextureImageId(parseState, &unit, &idx))
   1443                RETURN_ERROR;
   1444 	    inst->TexSrcUnit = unit;
   1445 	    inst->TexSrcTarget = idx;
   1446          }
   1447          else if (instMatch.inputs == INPUT_1V_S) {
   1448             if (!Parse_PrintInstruction(parseState, inst))
   1449                RETURN_ERROR;
   1450          }
   1451 
   1452          /* end of statement semicolon */
   1453          if (!Parse_String(parseState, ";"))
   1454             RETURN_ERROR1("Expected ;");
   1455 
   1456          parseState->numInst++;
   1457 
   1458          if (parseState->numInst >= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS)
   1459             RETURN_ERROR1("Program too long");
   1460       }
   1461    }
   1462    return GL_TRUE;
   1463 }
   1464 
   1465 
   1466 
   1467 /**
   1468  * Parse/compile the 'str' returning the compiled 'program'.
   1469  * ctx->Program.ErrorPos will be -1 if successful.  Otherwise, ErrorPos
   1470  * indicates the position of the error in 'str'.
   1471  */
   1472 void
   1473 _mesa_parse_nv_fragment_program(struct gl_context *ctx, GLenum dstTarget,
   1474                                 const GLubyte *str, GLsizei len,
   1475                                 struct gl_fragment_program *program)
   1476 {
   1477    struct parse_state parseState;
   1478    struct prog_instruction instBuffer[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS];
   1479    struct prog_instruction *newInst;
   1480    GLenum target;
   1481    GLubyte *programString;
   1482 
   1483    /* Make a null-terminated copy of the program string */
   1484    programString = (GLubyte *) MALLOC(len + 1);
   1485    if (!programString) {
   1486       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
   1487       return;
   1488    }
   1489    memcpy(programString, str, len);
   1490    programString[len] = 0;
   1491 
   1492    /* Get ready to parse */
   1493    memset(&parseState, 0, sizeof(struct parse_state));
   1494    parseState.ctx = ctx;
   1495    parseState.start = programString;
   1496    parseState.program = program;
   1497    parseState.numInst = 0;
   1498    parseState.curLine = programString;
   1499    parseState.parameters = _mesa_new_parameter_list();
   1500 
   1501    /* Reset error state */
   1502    _mesa_set_program_error(ctx, -1, NULL);
   1503 
   1504    /* check the program header */
   1505    if (strncmp((const char *) programString, "!!FP1.0", 7) == 0) {
   1506       target = GL_FRAGMENT_PROGRAM_NV;
   1507       parseState.pos = programString + 7;
   1508    }
   1509    else if (strncmp((const char *) programString, "!!FCP1.0", 8) == 0) {
   1510       /* fragment / register combiner program - not supported */
   1511       _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
   1512       _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
   1513       return;
   1514    }
   1515    else {
   1516       /* invalid header */
   1517       _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
   1518       _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
   1519       return;
   1520    }
   1521 
   1522    /* make sure target and header match */
   1523    if (target != dstTarget) {
   1524       _mesa_error(ctx, GL_INVALID_OPERATION,
   1525                   "glLoadProgramNV(target mismatch 0x%x != 0x%x)",
   1526                   target, dstTarget);
   1527       return;
   1528    }
   1529 
   1530    if (Parse_InstructionSequence(&parseState, instBuffer)) {
   1531       GLuint u;
   1532       /* successful parse! */
   1533 
   1534       if (parseState.outputsWritten == 0) {
   1535          /* must write at least one output! */
   1536          _mesa_error(ctx, GL_INVALID_OPERATION,
   1537                      "Invalid fragment program - no outputs written.");
   1538          return;
   1539       }
   1540 
   1541       /* copy the compiled instructions */
   1542       assert(parseState.numInst <= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS);
   1543       newInst = _mesa_alloc_instructions(parseState.numInst);
   1544       if (!newInst) {
   1545          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
   1546          return;  /* out of memory */
   1547       }
   1548       _mesa_copy_instructions(newInst, instBuffer, parseState.numInst);
   1549 
   1550       /* install the program */
   1551       program->Base.Target = target;
   1552       if (program->Base.String) {
   1553          FREE(program->Base.String);
   1554       }
   1555       program->Base.String = programString;
   1556       program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
   1557       if (program->Base.Instructions) {
   1558          free(program->Base.Instructions);
   1559       }
   1560       program->Base.Instructions = newInst;
   1561       program->Base.NumInstructions = parseState.numInst;
   1562       program->Base.InputsRead = parseState.inputsRead;
   1563       program->Base.OutputsWritten = parseState.outputsWritten;
   1564       for (u = 0; u < ctx->Const.MaxTextureImageUnits; u++)
   1565          program->Base.TexturesUsed[u] = parseState.texturesUsed[u];
   1566 
   1567       /* save program parameters */
   1568       program->Base.Parameters = parseState.parameters;
   1569 
   1570       /* allocate registers for declared program parameters */
   1571 #if 00
   1572       _mesa_assign_program_registers(&(program->SymbolTable));
   1573 #endif
   1574 
   1575 #ifdef DEBUG_foo
   1576       printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id);
   1577       _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0);
   1578       printf("----------------------------------\n");
   1579 #endif
   1580    }
   1581    else {
   1582       /* Error! */
   1583       _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
   1584       /* NOTE: _mesa_set_program_error would have been called already */
   1585    }
   1586 }
   1587 
   1588 
   1589 const char *
   1590 _mesa_nv_fragment_input_register_name(GLuint i)
   1591 {
   1592    ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_INPUTS);
   1593    return InputRegisters[i];
   1594 }
   1595 
   1596