Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / program / nvfragparse.c
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 = _mesa_lookup_parameter_value(parseState->parameters,
476                                               -1, (const char *) ident);
477       /* XXX Check that it's a constant and not a parameter */
478       if (!constant) {
479          RETURN_ERROR1("Undefined symbol");
480       }
481       else {
482          COPY_4V(number, constant);
483          return GL_TRUE;
484       }
485    }
486 }
487
488
489
490 /**
491  * Parse a vector constant, one of:
492  *   { float }
493  *   { float, float }
494  *   { float, float, float }
495  *   { float, float, float, float }
496  */
497 static GLboolean
498 Parse_VectorConstant(struct parse_state *parseState, GLfloat *vec)
499 {
500    /* "{" was already consumed */
501
502    ASSIGN_4V(vec, 0.0, 0.0, 0.0, 1.0);
503
504    if (!Parse_ScalarConstant(parseState, vec+0))  /* X */
505       return GL_FALSE;
506
507    if (Parse_String(parseState, "}")) {
508       return GL_TRUE;
509    }
510
511    if (!Parse_String(parseState, ","))
512       RETURN_ERROR1("Expected comma in vector constant");
513
514    if (!Parse_ScalarConstant(parseState, vec+1))  /* Y */
515       return GL_FALSE;
516
517    if (Parse_String(parseState, "}")) {
518       return GL_TRUE;
519    }
520
521    if (!Parse_String(parseState, ","))
522       RETURN_ERROR1("Expected comma in vector constant");
523
524    if (!Parse_ScalarConstant(parseState, vec+2))  /* Z */
525       return GL_FALSE;
526
527    if (Parse_String(parseState, "}")) {
528       return GL_TRUE;
529    }
530
531    if (!Parse_String(parseState, ","))
532       RETURN_ERROR1("Expected comma in vector constant");
533
534    if (!Parse_ScalarConstant(parseState, vec+3))  /* W */
535       return GL_FALSE;
536
537    if (!Parse_String(parseState, "}"))
538       RETURN_ERROR1("Expected closing brace in vector constant");
539
540    return GL_TRUE;
541 }
542
543
544 /**
545  * Parse <number>, <varname> or {a, b, c, d}.
546  * Return number of values in the vector or scalar, or zero if parse error.
547  */
548 static GLuint
549 Parse_VectorOrScalarConstant(struct parse_state *parseState, GLfloat *vec)
550 {
551    if (Parse_String(parseState, "{")) {
552       return Parse_VectorConstant(parseState, vec);
553    }
554    else {
555       GLboolean b = Parse_ScalarConstant(parseState, vec);
556       if (b) {
557          vec[1] = vec[2] = vec[3] = vec[0];
558       }
559       return b;
560    }
561 }
562
563
564 /**
565  * Parse a texture image source:
566  *    [TEX0 | TEX1 | .. | TEX15] , [1D | 2D | 3D | CUBE | RECT]
567  */
568 static GLboolean
569 Parse_TextureImageId(struct parse_state *parseState,
570                      GLubyte *texUnit, GLubyte *texTargetBit)
571 {
572    GLubyte imageSrc[100];
573    GLint unit;
574
575    if (!Parse_Token(parseState, imageSrc))
576       RETURN_ERROR;
577    
578    if (imageSrc[0] != 'T' ||
579        imageSrc[1] != 'E' ||
580        imageSrc[2] != 'X') {
581       RETURN_ERROR1("Expected TEX# source");
582    }
583    unit = atoi((const char *) imageSrc + 3);
584    if ((unit < 0 || unit > MAX_TEXTURE_IMAGE_UNITS) ||
585        (unit == 0 && (imageSrc[3] != '0' || imageSrc[4] != 0))) {
586       RETURN_ERROR1("Invalied TEX# source index");
587    }
588    *texUnit = unit;
589
590    if (!Parse_String(parseState, ","))
591       RETURN_ERROR1("Expected ,");
592
593    if (Parse_String(parseState, "1D")) {
594       *texTargetBit = TEXTURE_1D_BIT;
595    }
596    else if (Parse_String(parseState, "2D")) {
597       *texTargetBit = TEXTURE_2D_BIT;
598    }
599    else if (Parse_String(parseState, "3D")) {
600       *texTargetBit = TEXTURE_3D_BIT;
601    }
602    else if (Parse_String(parseState, "CUBE")) {
603       *texTargetBit = TEXTURE_CUBE_BIT;
604    }
605    else if (Parse_String(parseState, "RECT")) {
606       *texTargetBit = TEXTURE_RECT_BIT;
607    }
608    else {
609       RETURN_ERROR1("Invalid texture target token");
610    }
611
612    /* update record of referenced texture units */
613    parseState->texturesUsed[*texUnit] |= *texTargetBit;
614    if (_mesa_bitcount(parseState->texturesUsed[*texUnit]) > 1) {
615       RETURN_ERROR1("Only one texture target can be used per texture unit.");
616    }
617
618    return GL_TRUE;
619 }
620
621
622 /**
623  * Parse a scalar suffix like .x, .y, .z or .w or parse a swizzle suffix
624  * like .wxyz, .xxyy, etc and return the swizzle indexes.
625  */
626 static GLboolean
627 Parse_SwizzleSuffix(const GLubyte *token, GLuint swizzle[4])
628 {
629    if (token[1] == 0) {
630       /* single letter swizzle (scalar) */
631       if (token[0] == 'x')
632          ASSIGN_4V(swizzle, 0, 0, 0, 0);
633       else if (token[0] == 'y')
634          ASSIGN_4V(swizzle, 1, 1, 1, 1);
635       else if (token[0] == 'z')
636          ASSIGN_4V(swizzle, 2, 2, 2, 2);
637       else if (token[0] == 'w')
638          ASSIGN_4V(swizzle, 3, 3, 3, 3);
639       else
640          return GL_FALSE;
641    }
642    else {
643       /* 4-component swizzle (vector) */
644       GLint k;
645       for (k = 0; k < 4 && token[k]; k++) {
646          if (token[k] == 'x')
647             swizzle[k] = 0;
648          else if (token[k] == 'y')
649             swizzle[k] = 1;
650          else if (token[k] == 'z')
651             swizzle[k] = 2;
652          else if (token[k] == 'w')
653             swizzle[k] = 3;
654          else
655             return GL_FALSE;
656       }
657       if (k != 4)
658          return GL_FALSE;
659    }
660    return GL_TRUE;
661 }
662
663
664 static GLboolean
665 Parse_CondCodeMask(struct parse_state *parseState,
666                    struct prog_dst_register *dstReg)
667 {
668    if (Parse_String(parseState, "EQ"))
669       dstReg->CondMask = COND_EQ;
670    else if (Parse_String(parseState, "GE"))
671       dstReg->CondMask = COND_GE;
672    else if (Parse_String(parseState, "GT"))
673       dstReg->CondMask = COND_GT;
674    else if (Parse_String(parseState, "LE"))
675       dstReg->CondMask = COND_LE;
676    else if (Parse_String(parseState, "LT"))
677       dstReg->CondMask = COND_LT;
678    else if (Parse_String(parseState, "NE"))
679       dstReg->CondMask = COND_NE;
680    else if (Parse_String(parseState, "TR"))
681       dstReg->CondMask = COND_TR;
682    else if (Parse_String(parseState, "FL"))
683       dstReg->CondMask = COND_FL;
684    else
685       RETURN_ERROR1("Invalid condition code mask");
686
687    /* look for optional .xyzw swizzle */
688    if (Parse_String(parseState, ".")) {
689       GLubyte token[100];
690       GLuint swz[4];
691
692       if (!Parse_Token(parseState, token))  /* get xyzw suffix */
693          RETURN_ERROR;
694
695       if (!Parse_SwizzleSuffix(token, swz))
696          RETURN_ERROR1("Invalid swizzle suffix");
697
698       dstReg->CondSwizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
699    }
700
701    return GL_TRUE;
702 }
703
704
705 /**
706  * Parse a temporary register: Rnn or Hnn
707  */
708 static GLboolean
709 Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum)
710 {
711    GLubyte token[100];
712
713    /* Should be 'R##' or 'H##' */
714    if (!Parse_Token(parseState, token))
715       RETURN_ERROR;
716    if (token[0] != 'R' && token[0] != 'H')
717       RETURN_ERROR1("Expected R## or H##");
718
719    if (IsDigit(token[1])) {
720       GLint reg = atoi((const char *) (token + 1));
721       if (token[0] == 'H')
722          reg += 32;
723       if (reg >= MAX_NV_FRAGMENT_PROGRAM_TEMPS)
724          RETURN_ERROR1("Invalid temporary register name");
725       *tempRegNum = reg;
726    }
727    else {
728       RETURN_ERROR1("Invalid temporary register name");
729    }
730
731    return GL_TRUE;
732 }
733
734
735 /**
736  * Parse a write-only dummy register: RC or HC.
737  */
738 static GLboolean
739 Parse_DummyReg(struct parse_state *parseState, GLint *regNum)
740 {
741    if (Parse_String(parseState, "RC")) {
742        *regNum = 0;
743    }
744    else if (Parse_String(parseState, "HC")) {
745        *regNum = 1;
746    }
747    else {
748       RETURN_ERROR1("Invalid write-only register name");
749    }
750
751    return GL_TRUE;
752 }
753
754
755 /**
756  * Parse a program local parameter register "p[##]"
757  */
758 static GLboolean
759 Parse_ProgramParamReg(struct parse_state *parseState, GLint *regNum)
760 {
761    GLubyte token[100];
762
763    if (!Parse_String(parseState, "p["))
764       RETURN_ERROR1("Expected p[");
765
766    if (!Parse_Token(parseState, token))
767       RETURN_ERROR;
768
769    if (IsDigit(token[0])) {
770       /* a numbered program parameter register */
771       GLint reg = atoi((const char *) token);
772       if (reg >= MAX_NV_FRAGMENT_PROGRAM_PARAMS)
773          RETURN_ERROR1("Invalid constant program number");
774       *regNum = reg;
775    }
776    else {
777       RETURN_ERROR;
778    }
779
780    if (!Parse_String(parseState, "]"))
781       RETURN_ERROR1("Expected ]");
782
783    return GL_TRUE;
784 }
785
786
787 /**
788  * Parse f[name]  - fragment input register
789  */
790 static GLboolean
791 Parse_FragReg(struct parse_state *parseState, GLint *tempRegNum)
792 {
793    GLubyte token[100];
794    GLint j;
795
796    /* Match 'f[' */
797    if (!Parse_String(parseState, "f["))
798       RETURN_ERROR1("Expected f[");
799
800    /* get <name> and look for match */
801    if (!Parse_Token(parseState, token)) {
802       RETURN_ERROR;
803    }
804    for (j = 0; InputRegisters[j]; j++) {
805       if (strcmp((const char *) token, InputRegisters[j]) == 0) {
806          *tempRegNum = j;
807          parseState->inputsRead |= (1 << j);
808          break;
809       }
810    }
811    if (!InputRegisters[j]) {
812       /* unknown input register label */
813       RETURN_ERROR2("Invalid register name", token);
814    }
815
816    /* Match '[' */
817    if (!Parse_String(parseState, "]"))
818       RETURN_ERROR1("Expected ]");
819
820    return GL_TRUE;
821 }
822
823
824 static GLboolean
825 Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
826 {
827    GLubyte token[100];
828
829    /* Match "o[" */
830    if (!Parse_String(parseState, "o["))
831       RETURN_ERROR1("Expected o[");
832
833    /* Get output reg name */
834    if (!Parse_Token(parseState, token))
835       RETURN_ERROR;
836
837    /* try to match an output register name */
838    if (strcmp((char *) token, "COLR") == 0 ||
839        strcmp((char *) token, "COLH") == 0) {
840       /* note that we don't distinguish between COLR and COLH */
841       *outputRegNum = FRAG_RESULT_COLOR;
842       parseState->outputsWritten |= (1 << FRAG_RESULT_COLOR);
843    }
844    else if (strcmp((char *) token, "DEPR") == 0) {
845       *outputRegNum = FRAG_RESULT_DEPTH;
846       parseState->outputsWritten |= (1 << FRAG_RESULT_DEPTH);
847    }
848    else {
849       RETURN_ERROR1("Invalid output register name");
850    }
851
852    /* Match ']' */
853    if (!Parse_String(parseState, "]"))
854       RETURN_ERROR1("Expected ]");
855
856    return GL_TRUE;
857 }
858
859
860 static GLboolean
861 Parse_MaskedDstReg(struct parse_state *parseState,
862                    struct prog_dst_register *dstReg)
863 {
864    GLubyte token[100];
865    GLint idx;
866
867    /* Dst reg can be R<n>, H<n>, o[n], RC or HC */
868    if (!Peek_Token(parseState, token))
869       RETURN_ERROR;
870
871    if (strcmp((const char *) token, "RC") == 0 ||
872        strcmp((const char *) token, "HC") == 0) {
873       /* a write-only register */
874       dstReg->File = PROGRAM_WRITE_ONLY;
875       if (!Parse_DummyReg(parseState, &idx))
876          RETURN_ERROR;
877       dstReg->Index = idx;
878    }
879    else if (token[0] == 'R' || token[0] == 'H') {
880       /* a temporary register */
881       dstReg->File = PROGRAM_TEMPORARY;
882       if (!Parse_TempReg(parseState, &idx))
883          RETURN_ERROR;
884       dstReg->Index = idx;
885    }
886    else if (token[0] == 'o') {
887       /* an output register */
888       dstReg->File = PROGRAM_OUTPUT;
889       if (!Parse_OutputReg(parseState, &idx))
890          RETURN_ERROR;
891       dstReg->Index = idx;
892    }
893    else {
894       RETURN_ERROR1("Invalid destination register name");
895    }
896
897    /* Parse optional write mask */
898    if (Parse_String(parseState, ".")) {
899       /* got a mask */
900       GLint k = 0;
901
902       if (!Parse_Token(parseState, token))  /* get xyzw writemask */
903          RETURN_ERROR;
904
905       dstReg->WriteMask = 0;
906
907       if (token[k] == 'x') {
908          dstReg->WriteMask |= WRITEMASK_X;
909          k++;
910       }
911       if (token[k] == 'y') {
912          dstReg->WriteMask |= WRITEMASK_Y;
913          k++;
914       }
915       if (token[k] == 'z') {
916          dstReg->WriteMask |= WRITEMASK_Z;
917          k++;
918       }
919       if (token[k] == 'w') {
920          dstReg->WriteMask |= WRITEMASK_W;
921          k++;
922       }
923       if (k == 0) {
924          RETURN_ERROR1("Invalid writemask character");
925       }
926
927    }
928    else {
929       dstReg->WriteMask = WRITEMASK_XYZW;
930    }
931
932    /* optional condition code mask */
933    if (Parse_String(parseState, "(")) {
934       /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */
935       /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */
936       if (!Parse_CondCodeMask(parseState, dstReg))
937          RETURN_ERROR;
938
939       if (!Parse_String(parseState, ")"))  /* consume ")" */
940          RETURN_ERROR1("Expected )");
941
942       return GL_TRUE;
943    }
944    else {
945       /* no cond code mask */
946       dstReg->CondMask = COND_TR;
947       dstReg->CondSwizzle = SWIZZLE_NOOP;
948       return GL_TRUE;
949    }
950 }
951
952
953 /**
954  * Parse a vector source (register, constant, etc):
955  *   <vectorSrc>    ::= <absVectorSrc>
956  *                    | <baseVectorSrc>
957  *   <absVectorSrc> ::= <negate> "|" <baseVectorSrc> "|"
958  */
959 static GLboolean
960 Parse_VectorSrc(struct parse_state *parseState,
961                 struct prog_src_register *srcReg)
962 {
963    GLfloat sign = 1.0F;
964    GLubyte token[100];
965    GLint idx;
966    GLuint negateBase, negateAbs;
967
968    /*
969     * First, take care of +/- and absolute value stuff.
970     */
971    if (Parse_String(parseState, "-"))
972       sign = -1.0F;
973    else if (Parse_String(parseState, "+"))
974       sign = +1.0F;
975
976    if (Parse_String(parseState, "|")) {
977       srcReg->Abs = GL_TRUE;
978       negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
979
980       if (Parse_String(parseState, "-"))
981          negateBase = NEGATE_XYZW;
982       else if (Parse_String(parseState, "+"))
983          negateBase = NEGATE_NONE;
984       else
985          negateBase = NEGATE_NONE;
986    }
987    else {
988       srcReg->Abs = GL_FALSE;
989       negateAbs = NEGATE_NONE;
990       negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
991    }
992
993    srcReg->Negate = srcReg->Abs ? negateAbs : negateBase;
994
995    /* This should be the real src vector/register name */
996    if (!Peek_Token(parseState, token))
997       RETURN_ERROR;
998
999    /* Src reg can be Rn, Hn, f[n], p[n], a named parameter, a scalar
1000     * literal or vector literal.
1001     */
1002    if (token[0] == 'R' || token[0] == 'H') {
1003       srcReg->File = PROGRAM_TEMPORARY;
1004       if (!Parse_TempReg(parseState, &idx))
1005          RETURN_ERROR;
1006       srcReg->Index = idx;
1007    }
1008    else if (token[0] == 'f') {
1009       /* XXX this might be an identifier! */
1010       srcReg->File = PROGRAM_INPUT;
1011       if (!Parse_FragReg(parseState, &idx))
1012          RETURN_ERROR;
1013       srcReg->Index = idx;
1014    }
1015    else if (token[0] == 'p') {
1016       /* XXX this might be an identifier! */
1017       srcReg->File = PROGRAM_LOCAL_PARAM;
1018       if (!Parse_ProgramParamReg(parseState, &idx))
1019          RETURN_ERROR;
1020       srcReg->Index = idx;
1021    }
1022    else if (IsLetter(token[0])){
1023       GLubyte ident[100];
1024       GLint paramIndex;
1025       if (!Parse_Identifier(parseState, ident))
1026          RETURN_ERROR;
1027       paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
1028                                                 -1, (const char *) ident);
1029       if (paramIndex < 0) {
1030          RETURN_ERROR2("Undefined constant or parameter: ", ident);
1031       }
1032       srcReg->File = PROGRAM_NAMED_PARAM;
1033       srcReg->Index = paramIndex;      
1034    }
1035    else if (IsDigit(token[0]) || token[0] == '-' || token[0] == '+' || token[0] == '.'){
1036       /* literal scalar constant */
1037       GLfloat values[4];
1038       GLuint paramIndex;
1039       if (!Parse_ScalarConstant(parseState, values))
1040          RETURN_ERROR;
1041       paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1042                                               values, 4, NULL);
1043       srcReg->File = PROGRAM_NAMED_PARAM;
1044       srcReg->Index = paramIndex;
1045    }
1046    else if (token[0] == '{'){
1047       /* literal vector constant */
1048       GLfloat values[4];
1049       GLuint paramIndex;
1050       (void) Parse_String(parseState, "{");
1051       if (!Parse_VectorConstant(parseState, values))
1052          RETURN_ERROR;
1053       paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1054                                               values, 4, NULL);
1055       srcReg->File = PROGRAM_NAMED_PARAM;
1056       srcReg->Index = paramIndex;      
1057    }
1058    else {
1059       RETURN_ERROR2("Invalid source register name", token);
1060    }
1061
1062    /* init swizzle fields */
1063    srcReg->Swizzle = SWIZZLE_NOOP;
1064
1065    /* Look for optional swizzle suffix */
1066    if (Parse_String(parseState, ".")) {
1067       GLuint swz[4];
1068
1069       if (!Parse_Token(parseState, token))
1070          RETURN_ERROR;
1071
1072       if (!Parse_SwizzleSuffix(token, swz))
1073          RETURN_ERROR1("Invalid swizzle suffix");
1074
1075       srcReg->Swizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
1076    }
1077
1078    /* Finish absolute value */
1079    if (srcReg->Abs && !Parse_String(parseState, "|")) {
1080       RETURN_ERROR1("Expected |");
1081    }
1082
1083    return GL_TRUE;
1084 }
1085
1086
1087 static GLboolean
1088 Parse_ScalarSrcReg(struct parse_state *parseState,
1089                    struct prog_src_register *srcReg)
1090 {
1091    GLubyte token[100];
1092    GLfloat sign = 1.0F;
1093    GLboolean needSuffix = GL_TRUE;
1094    GLint idx;
1095    GLuint negateBase, negateAbs;
1096
1097    /*
1098     * First, take care of +/- and absolute value stuff.
1099     */
1100    if (Parse_String(parseState, "-"))
1101       sign = -1.0F;
1102    else if (Parse_String(parseState, "+"))
1103       sign = +1.0F;
1104
1105    if (Parse_String(parseState, "|")) {
1106       srcReg->Abs = GL_TRUE;
1107       negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
1108
1109       if (Parse_String(parseState, "-"))
1110          negateBase = NEGATE_XYZW;
1111       else if (Parse_String(parseState, "+"))
1112          negateBase = NEGATE_NONE;
1113       else
1114          negateBase = NEGATE_NONE;
1115    }
1116    else {
1117       srcReg->Abs = GL_FALSE;
1118       negateAbs = NEGATE_NONE;
1119       negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
1120    }
1121
1122    srcReg->Negate = srcReg->Abs ? negateAbs : negateBase;
1123
1124    if (!Peek_Token(parseState, token))
1125       RETURN_ERROR;
1126
1127    /* Src reg can be R<n>, H<n> or a named fragment attrib */
1128    if (token[0] == 'R' || token[0] == 'H') {
1129       srcReg->File = PROGRAM_TEMPORARY;
1130       if (!Parse_TempReg(parseState, &idx))
1131          RETURN_ERROR;
1132       srcReg->Index = idx;
1133    }
1134    else if (token[0] == 'f') {
1135       srcReg->File = PROGRAM_INPUT;
1136       if (!Parse_FragReg(parseState, &idx))
1137          RETURN_ERROR;
1138       srcReg->Index = idx;
1139    }
1140    else if (token[0] == '{') {
1141       /* vector literal */
1142       GLfloat values[4];
1143       GLuint paramIndex;
1144       (void) Parse_String(parseState, "{");
1145       if (!Parse_VectorConstant(parseState, values))
1146          RETURN_ERROR;
1147       paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1148                                               values, 4, NULL);
1149       srcReg->File = PROGRAM_NAMED_PARAM;
1150       srcReg->Index = paramIndex;      
1151    }
1152    else if (IsLetter(token[0])){
1153       /* named param/constant */
1154       GLubyte ident[100];
1155       GLint paramIndex;
1156       if (!Parse_Identifier(parseState, ident))
1157          RETURN_ERROR;
1158       paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
1159                                                 -1, (const char *) ident);
1160       if (paramIndex < 0) {
1161          RETURN_ERROR2("Undefined constant or parameter: ", ident);
1162       }
1163       srcReg->File = PROGRAM_NAMED_PARAM;
1164       srcReg->Index = paramIndex;      
1165    }
1166    else if (IsDigit(token[0])) {
1167       /* scalar literal */
1168       GLfloat values[4];
1169       GLuint paramIndex;
1170       if (!Parse_ScalarConstant(parseState, values))
1171          RETURN_ERROR;
1172       paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1173                                               values, 4, NULL);
1174       srcReg->Index = paramIndex;      
1175       srcReg->File = PROGRAM_NAMED_PARAM;
1176       needSuffix = GL_FALSE;
1177    }
1178    else {
1179       RETURN_ERROR2("Invalid scalar source argument", token);
1180    }
1181
1182    srcReg->Swizzle = 0;
1183    if (needSuffix) {
1184       /* parse .[xyzw] suffix */
1185       if (!Parse_String(parseState, "."))
1186          RETURN_ERROR1("Expected .");
1187
1188       if (!Parse_Token(parseState, token))
1189          RETURN_ERROR;
1190
1191       if (token[0] == 'x' && token[1] == 0) {
1192          srcReg->Swizzle = 0;
1193       }
1194       else if (token[0] == 'y' && token[1] == 0) {
1195          srcReg->Swizzle = 1;
1196       }
1197       else if (token[0] == 'z' && token[1] == 0) {
1198          srcReg->Swizzle = 2;
1199       }
1200       else if (token[0] == 'w' && token[1] == 0) {
1201          srcReg->Swizzle = 3;
1202       }
1203       else {
1204          RETURN_ERROR1("Invalid scalar source suffix");
1205       }
1206    }
1207
1208    /* Finish absolute value */
1209    if (srcReg->Abs && !Parse_String(parseState, "|")) {
1210       RETURN_ERROR1("Expected |");
1211    }
1212
1213    return GL_TRUE;
1214 }
1215
1216
1217 static GLboolean
1218 Parse_PrintInstruction(struct parse_state *parseState,
1219                        struct prog_instruction *inst)
1220 {
1221    const GLubyte *str;
1222    GLubyte *msg;
1223    GLuint len;
1224    GLint idx;
1225
1226    /* The first argument is a literal string 'just like this' */
1227    if (!Parse_String(parseState, "'"))
1228       RETURN_ERROR1("Expected '");
1229
1230    str = parseState->pos;
1231    for (len = 0; str[len] != '\''; len++) /* find closing quote */
1232       ;
1233    parseState->pos += len + 1;
1234    msg = (GLubyte*) malloc(len + 1);
1235
1236    memcpy(msg, str, len);
1237    msg[len] = 0;
1238    inst->Data = msg;
1239
1240    if (Parse_String(parseState, ",")) {
1241       /* got an optional register to print */
1242       GLubyte token[100];
1243       GetToken(parseState, token);
1244       if (token[0] == 'o') {
1245          /* dst reg */
1246          if (!Parse_OutputReg(parseState, &idx))
1247             RETURN_ERROR;
1248          inst->SrcReg[0].Index = idx;
1249          inst->SrcReg[0].File = PROGRAM_OUTPUT;
1250       }
1251       else {
1252          /* src reg */
1253          if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1254             RETURN_ERROR;
1255       }
1256    }
1257    else {
1258       inst->SrcReg[0].File = PROGRAM_UNDEFINED;
1259    }
1260
1261    inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
1262    inst->SrcReg[0].Abs = GL_FALSE;
1263    inst->SrcReg[0].Negate = NEGATE_NONE;
1264
1265    return GL_TRUE;
1266 }
1267
1268
1269 static GLboolean
1270 Parse_InstructionSequence(struct parse_state *parseState,
1271                           struct prog_instruction program[])
1272 {
1273    while (1) {
1274       struct prog_instruction *inst = program + parseState->numInst;
1275       struct instruction_pattern instMatch;
1276       GLubyte token[100];
1277
1278       /* Initialize the instruction */
1279       _mesa_init_instructions(inst, 1);
1280
1281       /* special instructions */
1282       if (Parse_String(parseState, "DEFINE")) {
1283          GLubyte id[100];
1284          GLfloat value[7];  /* yes, 7 to be safe */
1285          if (!Parse_Identifier(parseState, id))
1286             RETURN_ERROR;
1287          /* XXX make sure id is not a reserved identifer, like R9 */
1288          if (!Parse_String(parseState, "="))
1289             RETURN_ERROR1("Expected =");
1290          if (!Parse_VectorOrScalarConstant(parseState, value))
1291             RETURN_ERROR;
1292          if (!Parse_String(parseState, ";"))
1293             RETURN_ERROR1("Expected ;");
1294          if (_mesa_lookup_parameter_index(parseState->parameters,
1295                                           -1, (const char *) id) >= 0) {
1296             RETURN_ERROR2(id, "already defined");
1297          }
1298          _mesa_add_named_parameter(parseState->parameters,
1299                                    (const char *) id, value);
1300       }
1301       else if (Parse_String(parseState, "DECLARE")) {
1302          GLubyte id[100];
1303          GLfloat value[7] = {0, 0, 0, 0, 0, 0, 0};  /* yes, to be safe */
1304          if (!Parse_Identifier(parseState, id))
1305             RETURN_ERROR;
1306          /* XXX make sure id is not a reserved identifer, like R9 */
1307          if (Parse_String(parseState, "=")) {
1308             if (!Parse_VectorOrScalarConstant(parseState, value))
1309                RETURN_ERROR;
1310          }
1311          if (!Parse_String(parseState, ";"))
1312             RETURN_ERROR1("Expected ;");
1313          if (_mesa_lookup_parameter_index(parseState->parameters,
1314                                           -1, (const char *) id) >= 0) {
1315             RETURN_ERROR2(id, "already declared");
1316          }
1317          _mesa_add_named_parameter(parseState->parameters,
1318                                    (const char *) id, value);
1319       }
1320       else if (Parse_String(parseState, "END")) {
1321          inst->Opcode = OPCODE_END;
1322          parseState->numInst++;
1323          if (Parse_Token(parseState, token)) {
1324             RETURN_ERROR1("Code after END opcode.");
1325          }
1326          break;
1327       }
1328       else {
1329          /* general/arithmetic instruction */
1330
1331          /* get token */
1332          if (!Parse_Token(parseState, token)) {
1333             RETURN_ERROR1("Missing END instruction.");
1334          }
1335
1336          /* try to find matching instuction */
1337          instMatch = MatchInstruction(token);
1338          if (instMatch.opcode >= MAX_OPCODE) {
1339             /* bad instruction name */
1340             RETURN_ERROR2("Unexpected token: ", token);
1341          }
1342
1343          inst->Opcode = instMatch.opcode;
1344          inst->Precision = instMatch.suffixes & (_R | _H | _X);
1345          inst->SaturateMode = (instMatch.suffixes & (_S))
1346             ? SATURATE_ZERO_ONE : SATURATE_OFF;
1347          inst->CondUpdate = (instMatch.suffixes & (_C)) ? GL_TRUE : GL_FALSE;
1348
1349          /*
1350           * parse the input and output operands
1351           */
1352          if (instMatch.outputs == OUTPUT_S || instMatch.outputs == OUTPUT_V) {
1353             if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
1354                RETURN_ERROR;
1355             if (!Parse_String(parseState, ","))
1356                RETURN_ERROR1("Expected ,");
1357          }
1358          else if (instMatch.outputs == OUTPUT_NONE) {
1359             if (instMatch.opcode == OPCODE_KIL_NV) {
1360                /* This is a little weird, the cond code info is in
1361                 * the dest register.
1362                 */
1363                if (!Parse_CondCodeMask(parseState, &inst->DstReg))
1364                   RETURN_ERROR;
1365             }
1366             else {
1367                ASSERT(instMatch.opcode == OPCODE_PRINT);
1368             }
1369          }
1370
1371          if (instMatch.inputs == INPUT_1V) {
1372             if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1373                RETURN_ERROR;
1374          }
1375          else if (instMatch.inputs == INPUT_2V) {
1376             if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1377                RETURN_ERROR;
1378             if (!Parse_String(parseState, ","))
1379                RETURN_ERROR1("Expected ,");
1380             if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1381                RETURN_ERROR;
1382          }
1383          else if (instMatch.inputs == INPUT_3V) {
1384             if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1385                RETURN_ERROR;
1386             if (!Parse_String(parseState, ","))
1387                RETURN_ERROR1("Expected ,");
1388             if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1389                RETURN_ERROR;
1390             if (!Parse_String(parseState, ","))
1391                RETURN_ERROR1("Expected ,");
1392             if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
1393                RETURN_ERROR;
1394          }
1395          else if (instMatch.inputs == INPUT_1S) {
1396             if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1397                RETURN_ERROR;
1398          }
1399          else if (instMatch.inputs == INPUT_2S) {
1400             if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1401                RETURN_ERROR;
1402             if (!Parse_String(parseState, ","))
1403                RETURN_ERROR1("Expected ,");
1404             if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[1]))
1405                RETURN_ERROR;
1406          }
1407          else if (instMatch.inputs == INPUT_CC) {
1408             /* XXX to-do */
1409          }
1410          else if (instMatch.inputs == INPUT_1V_T) {
1411             GLubyte unit, idx;
1412             if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1413                RETURN_ERROR;
1414             if (!Parse_String(parseState, ","))
1415                RETURN_ERROR1("Expected ,");
1416             if (!Parse_TextureImageId(parseState, &unit, &idx))
1417                RETURN_ERROR;
1418             inst->TexSrcUnit = unit;
1419             inst->TexSrcTarget = idx;
1420          }
1421          else if (instMatch.inputs == INPUT_3V_T) {
1422             GLubyte unit, idx;
1423             if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1424                RETURN_ERROR;
1425             if (!Parse_String(parseState, ","))
1426                RETURN_ERROR1("Expected ,");
1427             if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1428                RETURN_ERROR;
1429             if (!Parse_String(parseState, ","))
1430                RETURN_ERROR1("Expected ,");
1431             if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
1432                RETURN_ERROR;
1433             if (!Parse_String(parseState, ","))
1434                RETURN_ERROR1("Expected ,");
1435             if (!Parse_TextureImageId(parseState, &unit, &idx))
1436                RETURN_ERROR;
1437             inst->TexSrcUnit = unit;
1438             inst->TexSrcTarget = idx;
1439          }
1440          else if (instMatch.inputs == INPUT_1V_S) {
1441             if (!Parse_PrintInstruction(parseState, inst))
1442                RETURN_ERROR;
1443          }
1444
1445          /* end of statement semicolon */
1446          if (!Parse_String(parseState, ";"))
1447             RETURN_ERROR1("Expected ;");
1448
1449          parseState->numInst++;
1450
1451          if (parseState->numInst >= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS)
1452             RETURN_ERROR1("Program too long");
1453       }
1454    }
1455    return GL_TRUE;
1456 }
1457
1458
1459
1460 /**
1461  * Parse/compile the 'str' returning the compiled 'program'.
1462  * ctx->Program.ErrorPos will be -1 if successful.  Otherwise, ErrorPos
1463  * indicates the position of the error in 'str'.
1464  */
1465 void
1466 _mesa_parse_nv_fragment_program(struct gl_context *ctx, GLenum dstTarget,
1467                                 const GLubyte *str, GLsizei len,
1468                                 struct gl_fragment_program *program)
1469 {
1470    struct parse_state parseState;
1471    struct prog_instruction instBuffer[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS];
1472    struct prog_instruction *newInst;
1473    GLenum target;
1474    GLubyte *programString;
1475
1476    /* Make a null-terminated copy of the program string */
1477    programString = (GLubyte *) MALLOC(len + 1);
1478    if (!programString) {
1479       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1480       return;
1481    }
1482    memcpy(programString, str, len);
1483    programString[len] = 0;
1484
1485    /* Get ready to parse */
1486    memset(&parseState, 0, sizeof(struct parse_state));
1487    parseState.ctx = ctx;
1488    parseState.start = programString;
1489    parseState.program = program;
1490    parseState.numInst = 0;
1491    parseState.curLine = programString;
1492    parseState.parameters = _mesa_new_parameter_list();
1493
1494    /* Reset error state */
1495    _mesa_set_program_error(ctx, -1, NULL);
1496
1497    /* check the program header */
1498    if (strncmp((const char *) programString, "!!FP1.0", 7) == 0) {
1499       target = GL_FRAGMENT_PROGRAM_NV;
1500       parseState.pos = programString + 7;
1501    }
1502    else if (strncmp((const char *) programString, "!!FCP1.0", 8) == 0) {
1503       /* fragment / register combiner program - not supported */
1504       _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1505       _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1506       return;
1507    }
1508    else {
1509       /* invalid header */
1510       _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1511       _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1512       return;
1513    }
1514
1515    /* make sure target and header match */
1516    if (target != dstTarget) {
1517       _mesa_error(ctx, GL_INVALID_OPERATION,
1518                   "glLoadProgramNV(target mismatch 0x%x != 0x%x)",
1519                   target, dstTarget);
1520       return;
1521    }
1522
1523    if (Parse_InstructionSequence(&parseState, instBuffer)) {
1524       GLuint u;
1525       /* successful parse! */
1526
1527       if (parseState.outputsWritten == 0) {
1528          /* must write at least one output! */
1529          _mesa_error(ctx, GL_INVALID_OPERATION,
1530                      "Invalid fragment program - no outputs written.");
1531          return;
1532       }
1533
1534       /* copy the compiled instructions */
1535       assert(parseState.numInst <= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS);
1536       newInst = _mesa_alloc_instructions(parseState.numInst);
1537       if (!newInst) {
1538          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1539          return;  /* out of memory */
1540       }
1541       _mesa_copy_instructions(newInst, instBuffer, parseState.numInst);
1542
1543       /* install the program */
1544       program->Base.Target = target;
1545       if (program->Base.String) {
1546          FREE(program->Base.String);
1547       }
1548       program->Base.String = programString;
1549       program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
1550       if (program->Base.Instructions) {
1551          free(program->Base.Instructions);
1552       }
1553       program->Base.Instructions = newInst;
1554       program->Base.NumInstructions = parseState.numInst;
1555       program->Base.InputsRead = parseState.inputsRead;
1556       program->Base.OutputsWritten = parseState.outputsWritten;
1557       for (u = 0; u < ctx->Const.MaxTextureImageUnits; u++)
1558          program->Base.TexturesUsed[u] = parseState.texturesUsed[u];
1559
1560       /* save program parameters */
1561       program->Base.Parameters = parseState.parameters;
1562
1563       /* allocate registers for declared program parameters */
1564 #if 00
1565       _mesa_assign_program_registers(&(program->SymbolTable));
1566 #endif
1567
1568 #ifdef DEBUG_foo
1569       printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id);
1570       _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0);
1571       printf("----------------------------------\n");
1572 #endif
1573    }
1574    else {
1575       /* Error! */
1576       _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1577       /* NOTE: _mesa_set_program_error would have been called already */
1578    }
1579 }
1580
1581
1582 const char *
1583 _mesa_nv_fragment_input_register_name(GLuint i)
1584 {
1585    ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_INPUTS);
1586    return InputRegisters[i];
1587 }
1588