nvfragparse.c revision 2861e737e84e4884109b9526ac645194ba892a74
1/*
2 * Mesa 3-D graphics library
3 * Version:  6.0
4 *
5 * Copyright (C) 1999-2004  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 "glheader.h"
41#include "context.h"
42#include "hash.h"
43#include "imports.h"
44#include "macros.h"
45#include "mtypes.h"
46#include "nvfragprog.h"
47#include "nvfragparse.h"
48#include "nvprogram.h"
49#include "program.h"
50
51
52#define INPUT_1V     1
53#define INPUT_2V     2
54#define INPUT_3V     3
55#define INPUT_1S     4
56#define INPUT_2S     5
57#define INPUT_CC     6
58#define INPUT_1V_T   7  /* one source vector, plus textureId */
59#define INPUT_3V_T   8  /* one source vector, plus textureId */
60#define INPUT_NONE   9
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
79struct instruction_pattern {
80   const char *name;
81   enum fp_opcode opcode;
82   GLuint inputs;
83   GLuint outputs;
84   GLuint suffixes;
85};
86
87static const struct instruction_pattern Instructions[] = {
88   { "ADD", FP_OPCODE_ADD, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
89   { "COS", FP_OPCODE_COS, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
90   { "DDX", FP_OPCODE_DDX, INPUT_1V, OUTPUT_V, _R | _H |      _C | _S },
91   { "DDY", FP_OPCODE_DDY, INPUT_1V, OUTPUT_V, _R | _H |      _C | _S },
92   { "DP3", FP_OPCODE_DP3, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S },
93   { "DP4", FP_OPCODE_DP4, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S },
94   { "DST", FP_OPCODE_DP4, INPUT_2V, OUTPUT_V, _R | _H |      _C | _S },
95   { "EX2", FP_OPCODE_DP4, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
96   { "FLR", FP_OPCODE_FLR, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
97   { "FRC", FP_OPCODE_FRC, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
98   { "KIL", FP_OPCODE_KIL, INPUT_CC, OUTPUT_NONE, 0                   },
99   { "LG2", FP_OPCODE_LG2, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
100   { "LIT", FP_OPCODE_LIT, INPUT_1V, OUTPUT_V, _R | _H |      _C | _S },
101   { "LRP", FP_OPCODE_LRP, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S },
102   { "MAD", FP_OPCODE_MAD, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S },
103   { "MAX", FP_OPCODE_MAX, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
104   { "MIN", FP_OPCODE_MIN, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
105   { "MOV", FP_OPCODE_MOV, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
106   { "MUL", FP_OPCODE_MUL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
107   { "PK2H",  FP_OPCODE_PK2H,  INPUT_1V, OUTPUT_S, 0                  },
108   { "PK2US", FP_OPCODE_PK2US, INPUT_1V, OUTPUT_S, 0                  },
109   { "PK4B",  FP_OPCODE_PK4B,  INPUT_1V, OUTPUT_S, 0                  },
110   { "PK4UB", FP_OPCODE_PK4UB, INPUT_1V, OUTPUT_S, 0                  },
111   { "POW", FP_OPCODE_POW, INPUT_2S, OUTPUT_S, _R | _H |      _C | _S },
112   { "RCP", FP_OPCODE_RCP, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
113   { "RFL", FP_OPCODE_RFL, INPUT_2V, OUTPUT_V, _R | _H |      _C | _S },
114   { "RSQ", FP_OPCODE_RSQ, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
115   { "SEQ", FP_OPCODE_SEQ, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
116   { "SFL", FP_OPCODE_SFL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
117   { "SGE", FP_OPCODE_SGE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
118   { "SGT", FP_OPCODE_SGT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
119   { "SIN", FP_OPCODE_SIN, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
120   { "SLE", FP_OPCODE_SLE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
121   { "SLT", FP_OPCODE_SLT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
122   { "SNE", FP_OPCODE_SNE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
123   { "STR", FP_OPCODE_STR, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
124   { "SUB", FP_OPCODE_SUB, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
125   { "TEX", FP_OPCODE_TEX, INPUT_1V_T, OUTPUT_V,              _C | _S },
126   { "TXD", FP_OPCODE_TXD, INPUT_3V_T, OUTPUT_V,              _C | _S },
127   { "TXP", FP_OPCODE_TXP, INPUT_1V_T, OUTPUT_V,              _C | _S },
128   { "UP2H",  FP_OPCODE_UP2H,  INPUT_1S, OUTPUT_V,            _C | _S },
129   { "UP2US", FP_OPCODE_UP2US, INPUT_1S, OUTPUT_V,            _C | _S },
130   { "UP4B",  FP_OPCODE_UP4B,  INPUT_1S, OUTPUT_V,            _C | _S },
131   { "UP4UB", FP_OPCODE_UP4UB, INPUT_1S, OUTPUT_V,            _C | _S },
132   { "X2D", FP_OPCODE_X2D, INPUT_3V, OUTPUT_V, _R | _H |      _C | _S },
133   { NULL, (enum fp_opcode) -1, 0, 0, 0 }
134};
135
136
137/*
138 * Information needed or computed during parsing.
139 * Remember, we can't modify the target program object until we've
140 * _successfully_ parsed the program text.
141 */
142struct parse_state {
143   GLcontext *ctx;
144   const GLubyte *start;              /* start of program string */
145   const GLubyte *pos;                /* current position */
146   const GLubyte *curLine;
147   struct fragment_program *program;  /* current program */
148
149   struct program_parameter_list *parameters;
150
151   GLuint numInst;                    /* number of instructions parsed */
152   GLuint inputsRead;                 /* bitmask of input registers used */
153   GLuint outputsWritten;             /* bitmask of 1 << FRAG_OUTPUT_* bits */
154   GLuint texturesUsed[MAX_TEXTURE_IMAGE_UNITS];
155};
156
157
158
159/*
160 * Called whenever we find an error during parsing.
161 */
162static void
163record_error(struct parse_state *parseState, const char *msg, int lineNo)
164{
165#ifdef DEBUG
166   GLint line, column;
167   const GLubyte *lineStr;
168   lineStr = _mesa_find_line_column(parseState->start,
169                                    parseState->pos, &line, &column);
170   _mesa_debug(parseState->ctx,
171               "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
172               lineNo, line, column, (char *) lineStr, msg);
173   _mesa_free((void *) lineStr);
174#else
175   (void) lineNo;
176#endif
177
178   /* Check that no error was already recorded.  Only record the first one. */
179   if (parseState->ctx->Program.ErrorString[0] == 0) {
180      _mesa_set_program_error(parseState->ctx,
181                              parseState->pos - parseState->start,
182                              msg);
183   }
184}
185
186
187#define RETURN_ERROR							\
188do {									\
189   record_error(parseState, "Unexpected end of input.", __LINE__);	\
190   return GL_FALSE;							\
191} while(0)
192
193#define RETURN_ERROR1(msg)						\
194do {									\
195   record_error(parseState, msg, __LINE__);				\
196   return GL_FALSE;							\
197} while(0)
198
199#define RETURN_ERROR2(msg1, msg2)					\
200do {									\
201   char err[1000];							\
202   _mesa_sprintf(err, "%s %s", msg1, msg2);				\
203   record_error(parseState, err, __LINE__);				\
204   return GL_FALSE;							\
205} while(0)
206
207
208
209
210/*
211 * Search a list of instruction structures for a match.
212 */
213static struct instruction_pattern
214MatchInstruction(const GLubyte *token)
215{
216   const struct instruction_pattern *inst;
217   struct instruction_pattern result;
218
219   for (inst = Instructions; inst->name; inst++) {
220      if (_mesa_strncmp((const char *) token, inst->name, 3) == 0) {
221         /* matched! */
222         int i = 3;
223         result = *inst;
224         result.suffixes = 0;
225         /* look at suffix */
226         if (token[i] == 'R') {
227            result.suffixes |= _R;
228            i++;
229         }
230         else if (token[i] == 'H') {
231            result.suffixes |= _H;
232            i++;
233         }
234         else if (token[i] == 'X') {
235            result.suffixes |= _X;
236            i++;
237         }
238         if (token[i] == 'C') {
239            result.suffixes |= _C;
240            i++;
241         }
242         if (token[i] == '_' && token[i+1] == 'S' &&
243             token[i+2] == 'A' && token[i+3] == 'T') {
244            result.suffixes |= _S;
245         }
246         return result;
247      }
248   }
249   result.opcode = (enum fp_opcode) -1;
250   return result;
251}
252
253
254
255
256/**********************************************************************/
257
258
259static GLboolean IsLetter(GLubyte b)
260{
261   return (b >= 'a' && b <= 'z') ||
262          (b >= 'A' && b <= 'Z') ||
263          (b == '_') ||
264          (b == '$');
265}
266
267
268static GLboolean IsDigit(GLubyte b)
269{
270   return b >= '0' && b <= '9';
271}
272
273
274static GLboolean IsWhitespace(GLubyte b)
275{
276   return b == ' ' || b == '\t' || b == '\n' || b == '\r';
277}
278
279
280/**
281 * Starting at 'str' find the next token.  A token can be an integer,
282 * an identifier or punctuation symbol.
283 * \return <= 0 we found an error, else, return number of characters parsed.
284 */
285static GLint
286GetToken(struct parse_state *parseState, GLubyte *token)
287{
288   const GLubyte *str = parseState->pos;
289   GLint i = 0, j = 0;
290
291   token[0] = 0;
292
293   /* skip whitespace and comments */
294   while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) {
295      if (str[i] == '#') {
296         /* skip comment */
297         while (str[i] && (str[i] != '\n' && str[i] != '\r')) {
298            i++;
299         }
300         if (str[i] == '\n' || str[i] == '\r')
301            parseState->curLine = str + i + 1;
302      }
303      else {
304         /* skip whitespace */
305         if (str[i] == '\n' || str[i] == '\r')
306            parseState->curLine = str + i + 1;
307         i++;
308      }
309   }
310
311   if (str[i] == 0)
312      return -i;
313
314   /* try matching an integer */
315   while (str[i] && IsDigit(str[i])) {
316      token[j++] = str[i++];
317   }
318   if (j > 0 || !str[i]) {
319      token[j] = 0;
320      return i;
321   }
322
323   /* try matching an identifier */
324   if (IsLetter(str[i])) {
325      while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) {
326         token[j++] = str[i++];
327      }
328      token[j] = 0;
329      return i;
330   }
331
332   /* punctuation character */
333   if (str[i]) {
334      token[0] = str[i++];
335      token[1] = 0;
336      return i;
337   }
338
339   /* end of input */
340   token[0] = 0;
341   return i;
342}
343
344
345/**
346 * Get next token from input stream and increment stream pointer past token.
347 */
348static GLboolean
349Parse_Token(struct parse_state *parseState, GLubyte *token)
350{
351   GLint i;
352   i = GetToken(parseState, token);
353   if (i <= 0) {
354      parseState->pos += (-i);
355      return GL_FALSE;
356   }
357   parseState->pos += i;
358   return GL_TRUE;
359}
360
361
362/**
363 * Get next token from input stream but don't increment stream pointer.
364 */
365static GLboolean
366Peek_Token(struct parse_state *parseState, GLubyte *token)
367{
368   GLint i, len;
369   i = GetToken(parseState, token);
370   if (i <= 0) {
371      parseState->pos += (-i);
372      return GL_FALSE;
373   }
374   len = _mesa_strlen((const char *) token);
375   parseState->pos += (i - len);
376   return GL_TRUE;
377}
378
379
380/**********************************************************************/
381
382static const char *InputRegisters[MAX_NV_FRAGMENT_PROGRAM_INPUTS + 1] = {
383   "WPOS", "COL0", "COL1", "FOGC",
384   "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
385};
386
387static const char *OutputRegisters[MAX_NV_FRAGMENT_PROGRAM_OUTPUTS + 1] = {
388   "COLR", "COLH",
389   /* These are only allows for register combiners */
390   /*
391   "TEX0", "TEX1", "TEX2", "TEX3",
392   */
393   "DEPR", NULL
394};
395
396
397
398
399/**********************************************************************/
400
401/**
402 * Try to match 'pattern' as the next token after any whitespace/comments.
403 */
404static GLboolean
405Parse_String(struct parse_state *parseState, const char *pattern)
406{
407   const GLubyte *m;
408   GLint i;
409
410   /* skip whitespace and comments */
411   while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') {
412      if (*parseState->pos == '#') {
413         while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) {
414            parseState->pos += 1;
415         }
416         if (*parseState->pos == '\n' || *parseState->pos == '\r')
417            parseState->curLine = parseState->pos + 1;
418      }
419      else {
420         /* skip whitespace */
421         if (*parseState->pos == '\n' || *parseState->pos == '\r')
422            parseState->curLine = parseState->pos + 1;
423         parseState->pos += 1;
424      }
425   }
426
427   /* Try to match the pattern */
428   m = parseState->pos;
429   for (i = 0; pattern[i]; i++) {
430      if (*m != (GLubyte) pattern[i])
431         return GL_FALSE;
432      m += 1;
433   }
434   parseState->pos = m;
435
436   return GL_TRUE; /* success */
437}
438
439
440static GLboolean
441Parse_Identifier(struct parse_state *parseState, GLubyte *ident)
442{
443   if (!Parse_Token(parseState, ident))
444      RETURN_ERROR;
445   if (IsLetter(ident[0]))
446      return GL_TRUE;
447   else
448      RETURN_ERROR1("Expected an identfier");
449}
450
451
452/**
453 * Parse a floating point constant, or a defined symbol name.
454 * [+/-]N[.N[eN]]
455 * Output:  number[0 .. 3] will get the value.
456 */
457static GLboolean
458Parse_ScalarConstant(struct parse_state *parseState, GLfloat *number)
459{
460   char *end = NULL;
461
462   *number = (GLfloat) _mesa_strtod((const char *) parseState->pos, &end);
463
464   if (end && end > (char *) parseState->pos) {
465      /* got a number */
466      parseState->pos = (GLubyte *) end;
467      number[1] = *number;
468      number[2] = *number;
469      number[3] = *number;
470      return GL_TRUE;
471   }
472   else {
473      /* should be an identifier */
474      GLubyte ident[100];
475      const GLfloat *constant;
476      if (!Parse_Identifier(parseState, ident))
477         RETURN_ERROR1("Expected an identifier");
478      constant = _mesa_lookup_parameter_value(parseState->parameters,
479                                              -1, (const char *) ident);
480      /* XXX Check that it's a constant and not a parameter */
481      if (!constant) {
482         RETURN_ERROR1("Undefined symbol");
483      }
484      else {
485         COPY_4V(number, constant);
486         return GL_TRUE;
487      }
488   }
489}
490
491
492
493/**
494 * Parse a vector constant, one of:
495 *   { float }
496 *   { float, float }
497 *   { float, float, float }
498 *   { float, float, float, float }
499 */
500static GLboolean
501Parse_VectorConstant(struct parse_state *parseState, GLfloat *vec)
502{
503   /* "{" was already consumed */
504
505   ASSIGN_4V(vec, 0.0, 0.0, 0.0, 1.0);
506
507   if (!Parse_ScalarConstant(parseState, vec+0))  /* X */
508      return GL_FALSE;
509
510   if (Parse_String(parseState, "}")) {
511      return GL_TRUE;
512   }
513
514   if (!Parse_String(parseState, ","))
515      RETURN_ERROR1("Expected comma in vector constant");
516
517   if (!Parse_ScalarConstant(parseState, vec+1))  /* Y */
518      return GL_FALSE;
519
520   if (Parse_String(parseState, "}")) {
521      return GL_TRUE;
522   }
523
524   if (!Parse_String(parseState, ","))
525      RETURN_ERROR1("Expected comma in vector constant");
526
527   if (!Parse_ScalarConstant(parseState, vec+2))  /* Z */
528      return GL_FALSE;
529
530   if (Parse_String(parseState, "}")) {
531      return GL_TRUE;
532   }
533
534   if (!Parse_String(parseState, ","))
535      RETURN_ERROR1("Expected comma in vector constant");
536
537   if (!Parse_ScalarConstant(parseState, vec+3))  /* W */
538      return GL_FALSE;
539
540   if (!Parse_String(parseState, "}"))
541      RETURN_ERROR1("Expected closing brace in vector constant");
542
543   return GL_TRUE;
544}
545
546
547/**
548 * Parse <number>, <varname> or {a, b, c, d}.
549 * Return number of values in the vector or scalar, or zero if parse error.
550 */
551static GLuint
552Parse_VectorOrScalarConstant(struct parse_state *parseState, GLfloat *vec)
553{
554   if (Parse_String(parseState, "{")) {
555      return Parse_VectorConstant(parseState, vec);
556   }
557   else {
558      GLboolean b = Parse_ScalarConstant(parseState, vec);
559      if (b) {
560         vec[1] = vec[2] = vec[3] = vec[0];
561      }
562      return b;
563   }
564}
565
566
567/**
568 * Parse a texture image source:
569 *    [TEX0 | TEX1 | .. | TEX15] , [1D | 2D | 3D | CUBE | RECT]
570 */
571static GLboolean
572Parse_TextureImageId(struct parse_state *parseState,
573                     GLubyte *texUnit, GLubyte *texTargetBit)
574{
575   GLubyte imageSrc[100];
576   GLint unit;
577
578   if (!Parse_Token(parseState, imageSrc))
579      RETURN_ERROR;
580
581   if (imageSrc[0] != 'T' ||
582       imageSrc[1] != 'E' ||
583       imageSrc[2] != 'X') {
584      RETURN_ERROR1("Expected TEX# source");
585   }
586   unit = _mesa_atoi((const char *) imageSrc + 3);
587   if ((unit < 0 || unit > MAX_TEXTURE_IMAGE_UNITS) ||
588       (unit == 0 && (imageSrc[3] != '0' || imageSrc[4] != 0))) {
589      RETURN_ERROR1("Invalied TEX# source index");
590   }
591   *texUnit = unit;
592
593   if (!Parse_String(parseState, ","))
594      RETURN_ERROR1("Expected ,");
595
596   if (Parse_String(parseState, "1D")) {
597      *texTargetBit = TEXTURE_1D_BIT;
598   }
599   else if (Parse_String(parseState, "2D")) {
600      *texTargetBit = TEXTURE_2D_BIT;
601   }
602   else if (Parse_String(parseState, "3D")) {
603      *texTargetBit = TEXTURE_3D_BIT;
604   }
605   else if (Parse_String(parseState, "CUBE")) {
606      *texTargetBit = TEXTURE_CUBE_BIT;
607   }
608   else if (Parse_String(parseState, "RECT")) {
609      *texTargetBit = TEXTURE_RECT_BIT;
610   }
611   else {
612      RETURN_ERROR1("Invalid texture target token");
613   }
614
615   /* update record of referenced texture units */
616   parseState->texturesUsed[*texUnit] |= *texTargetBit;
617   if (_mesa_bitcount(parseState->texturesUsed[*texUnit]) > 1) {
618      RETURN_ERROR1("Only one texture target can be used per texture unit.");
619   }
620
621   return GL_TRUE;
622}
623
624
625/**
626 * Parse a scalar suffix like .x, .y, .z or .w or parse a swizzle suffix
627 * like .wxyz, .xxyy, etc and return the swizzle indexes.
628 */
629static GLboolean
630Parse_SwizzleSuffix(const GLubyte *token, GLuint swizzle[4])
631{
632   if (token[1] == 0) {
633      /* single letter swizzle (scalar) */
634      if (token[0] == 'x')
635         ASSIGN_4V(swizzle, 0, 0, 0, 0);
636      else if (token[0] == 'y')
637         ASSIGN_4V(swizzle, 1, 1, 1, 1);
638      else if (token[0] == 'z')
639         ASSIGN_4V(swizzle, 2, 2, 2, 2);
640      else if (token[0] == 'w')
641         ASSIGN_4V(swizzle, 3, 3, 3, 3);
642      else
643         return GL_FALSE;
644   }
645   else {
646      /* 4-component swizzle (vector) */
647      GLint k;
648      for (k = 0; token[k] && k < 4; k++) {
649         if (token[k] == 'x')
650            swizzle[k] = 0;
651         else if (token[k] == 'y')
652            swizzle[k] = 1;
653         else if (token[k] == 'z')
654            swizzle[k] = 2;
655         else if (token[k] == 'w')
656            swizzle[k] = 3;
657         else
658            return GL_FALSE;
659      }
660      if (k != 4)
661         return GL_FALSE;
662   }
663   return GL_TRUE;
664}
665
666
667static GLboolean
668Parse_CondCodeMask(struct parse_state *parseState,
669                   struct fp_dst_register *dstReg)
670{
671   if (Parse_String(parseState, "EQ"))
672      dstReg->CondMask = COND_EQ;
673   else if (Parse_String(parseState, "GE"))
674      dstReg->CondMask = COND_GE;
675   else if (Parse_String(parseState, "GT"))
676      dstReg->CondMask = COND_GT;
677   else if (Parse_String(parseState, "LE"))
678      dstReg->CondMask = COND_LE;
679   else if (Parse_String(parseState, "LT"))
680      dstReg->CondMask = COND_LT;
681   else if (Parse_String(parseState, "NE"))
682      dstReg->CondMask = COND_NE;
683   else if (Parse_String(parseState, "TR"))
684      dstReg->CondMask = COND_TR;
685   else if (Parse_String(parseState, "FL"))
686      dstReg->CondMask = COND_FL;
687   else
688      RETURN_ERROR1("Invalid condition code mask");
689
690   /* look for optional .xyzw swizzle */
691   if (Parse_String(parseState, ".")) {
692      GLubyte token[100];
693      if (!Parse_Token(parseState, token))  /* get xyzw suffix */
694         RETURN_ERROR;
695
696      if (!Parse_SwizzleSuffix(token, dstReg->CondSwizzle))
697         RETURN_ERROR1("Invalid swizzle suffix");
698   }
699
700   return GL_TRUE;
701}
702
703
704/**
705 * Parse a temporary register: Rnn or Hnn
706 */
707static GLboolean
708Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum)
709{
710   GLubyte token[100];
711
712   /* Should be 'R##' or 'H##' */
713   if (!Parse_Token(parseState, token))
714      RETURN_ERROR;
715   if (token[0] != 'R' && token[0] != 'H')
716      RETURN_ERROR1("Expected R## or H##");
717
718   if (IsDigit(token[1])) {
719      GLint reg = _mesa_atoi((const char *) (token + 1));
720      if (token[0] == 'H')
721         reg += 32;
722      if (reg >= MAX_NV_FRAGMENT_PROGRAM_TEMPS)
723         RETURN_ERROR1("Invalid temporary register name");
724      *tempRegNum = reg;
725   }
726   else {
727      RETURN_ERROR1("Invalid temporary register name");
728   }
729
730   return GL_TRUE;
731}
732
733
734/**
735 * Parse a write-only dummy register: RC or HC.
736 */
737static GLboolean
738Parse_DummyReg(struct parse_state *parseState, GLint *regNum)
739{
740   if (Parse_String(parseState, "RC")) {
741       *regNum = 0;
742   }
743   else if (Parse_String(parseState, "HC")) {
744       *regNum = 1;
745   }
746   else {
747      RETURN_ERROR1("Invalid write-only register name");
748   }
749
750   return GL_TRUE;
751}
752
753
754/**
755 * Parse a program local parameter register "p[##]"
756 */
757static GLboolean
758Parse_ProgramParamReg(struct parse_state *parseState, GLint *regNum)
759{
760   GLubyte token[100];
761
762   if (!Parse_String(parseState, "p["))
763      RETURN_ERROR1("Expected p[");
764
765   if (!Parse_Token(parseState, token))
766      RETURN_ERROR;
767
768   if (IsDigit(token[0])) {
769      /* a numbered program parameter register */
770      GLint reg = _mesa_atoi((const char *) token);
771      if (reg >= MAX_NV_FRAGMENT_PROGRAM_PARAMS)
772         RETURN_ERROR1("Invalid constant program number");
773      *regNum = reg;
774   }
775   else {
776      RETURN_ERROR;
777   }
778
779   if (!Parse_String(parseState, "]"))
780      RETURN_ERROR1("Expected ]");
781
782   return GL_TRUE;
783}
784
785
786/**
787 * Parse f[name]  - fragment input register
788 */
789static GLboolean
790Parse_FragReg(struct parse_state *parseState, GLint *tempRegNum)
791{
792   GLubyte token[100];
793   GLint j;
794
795   /* Match 'f[' */
796   if (!Parse_String(parseState, "f["))
797      RETURN_ERROR1("Expected f[");
798
799   /* get <name> and look for match */
800   if (!Parse_Token(parseState, token)) {
801      RETURN_ERROR;
802   }
803   for (j = 0; InputRegisters[j]; j++) {
804      if (_mesa_strcmp((const char *) token, InputRegisters[j]) == 0) {
805         *tempRegNum = j;
806         parseState->inputsRead |= (1 << j);
807         break;
808      }
809   }
810   if (!InputRegisters[j]) {
811      /* unknown input register label */
812      RETURN_ERROR2("Invalid register name", token);
813   }
814
815   /* Match '[' */
816   if (!Parse_String(parseState, "]"))
817      RETURN_ERROR1("Expected ]");
818
819   return GL_TRUE;
820}
821
822
823static GLboolean
824Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
825{
826   GLubyte token[100];
827   GLint j;
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   for (j = 0; OutputRegisters[j]; j++) {
839      if (_mesa_strcmp((const char *) token, OutputRegisters[j]) == 0) {
840         static GLuint bothColors = (1 << FRAG_OUTPUT_COLR) | (1 << FRAG_OUTPUT_COLH);
841         *outputRegNum = j;
842         parseState->outputsWritten |= (1 << j);
843         if ((parseState->outputsWritten & bothColors) == bothColors) {
844            RETURN_ERROR1("Illegal to write to both o[COLR] and o[COLH]");
845         }
846         break;
847      }
848   }
849   if (!OutputRegisters[j])
850      RETURN_ERROR1("Invalid output register name");
851
852   /* Match ']' */
853   if (!Parse_String(parseState, "]"))
854      RETURN_ERROR1("Expected ]");
855
856   return GL_TRUE;
857}
858
859
860static GLboolean
861Parse_MaskedDstReg(struct parse_state *parseState,
862                   struct fp_dst_register *dstReg)
863{
864   GLubyte token[100];
865
866   /* Dst reg can be R<n>, H<n>, o[n], RC or HC */
867   if (!Peek_Token(parseState, token))
868      RETURN_ERROR;
869
870   if (_mesa_strcmp((const char *) token, "RC") == 0 ||
871       _mesa_strcmp((const char *) token, "HC") == 0) {
872      /* a write-only register */
873      dstReg->File = PROGRAM_WRITE_ONLY;
874      if (!Parse_DummyReg(parseState, &dstReg->Index))
875         RETURN_ERROR;
876   }
877   else if (token[0] == 'R' || token[0] == 'H') {
878      /* a temporary register */
879      dstReg->File = PROGRAM_TEMPORARY;
880      if (!Parse_TempReg(parseState, &dstReg->Index))
881         RETURN_ERROR;
882   }
883   else if (token[0] == 'o') {
884      /* an output register */
885      dstReg->File = PROGRAM_OUTPUT;
886      if (!Parse_OutputReg(parseState, &dstReg->Index))
887         RETURN_ERROR;
888   }
889   else {
890      RETURN_ERROR1("Invalid destination register name");
891   }
892
893   /* Parse optional write mask */
894   if (Parse_String(parseState, ".")) {
895      /* got a mask */
896      GLint k = 0;
897
898      if (!Parse_Token(parseState, token))  /* get xyzw writemask */
899         RETURN_ERROR;
900
901      dstReg->WriteMask[0] = GL_FALSE;
902      dstReg->WriteMask[1] = GL_FALSE;
903      dstReg->WriteMask[2] = GL_FALSE;
904      dstReg->WriteMask[3] = GL_FALSE;
905
906      if (token[k] == 'x') {
907         dstReg->WriteMask[0] = GL_TRUE;
908         k++;
909      }
910      if (token[k] == 'y') {
911         dstReg->WriteMask[1] = GL_TRUE;
912         k++;
913      }
914      if (token[k] == 'z') {
915         dstReg->WriteMask[2] = GL_TRUE;
916         k++;
917      }
918      if (token[k] == 'w') {
919         dstReg->WriteMask[3] = GL_TRUE;
920         k++;
921      }
922      if (k == 0) {
923         RETURN_ERROR1("Invalid writemask character");
924      }
925
926   }
927   else {
928      dstReg->WriteMask[0] = GL_TRUE;
929      dstReg->WriteMask[1] = GL_TRUE;
930      dstReg->WriteMask[2] = GL_TRUE;
931      dstReg->WriteMask[3] = GL_TRUE;
932   }
933
934   /* optional condition code mask */
935   if (Parse_String(parseState, "(")) {
936      /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */
937      /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */
938      if (!Parse_CondCodeMask(parseState, dstReg))
939         RETURN_ERROR;
940
941      if (!Parse_String(parseState, ")"))  /* consume ")" */
942         RETURN_ERROR1("Expected )");
943
944      return GL_TRUE;
945   }
946   else {
947      /* no cond code mask */
948      dstReg->CondMask = COND_TR;
949      dstReg->CondSwizzle[0] = 0;
950      dstReg->CondSwizzle[1] = 1;
951      dstReg->CondSwizzle[2] = 2;
952      dstReg->CondSwizzle[3] = 3;
953      return GL_TRUE;
954   }
955}
956
957
958/**
959 * Parse a vector source (register, constant, etc):
960 *   <vectorSrc>    ::= <absVectorSrc>
961 *                    | <baseVectorSrc>
962 *   <absVectorSrc> ::= <negate> "|" <baseVectorSrc> "|"
963 */
964static GLboolean
965Parse_VectorSrc(struct parse_state *parseState,
966                struct fp_src_register *srcReg)
967{
968   GLfloat sign = 1.0F;
969   GLubyte token[100];
970
971   /*
972    * First, take care of +/- and absolute value stuff.
973    */
974   if (Parse_String(parseState, "-"))
975      sign = -1.0F;
976   else if (Parse_String(parseState, "+"))
977      sign = +1.0F;
978
979   if (Parse_String(parseState, "|")) {
980      srcReg->Abs = GL_TRUE;
981      srcReg->NegateAbs = (sign < 0.0F) ? GL_TRUE : GL_FALSE;
982
983      if (Parse_String(parseState, "-"))
984         srcReg->NegateBase = GL_TRUE;
985      else if (Parse_String(parseState, "+"))
986         srcReg->NegateBase = GL_FALSE;
987      else
988         srcReg->NegateBase = GL_FALSE;
989   }
990   else {
991      srcReg->Abs = GL_FALSE;
992      srcReg->NegateAbs = GL_FALSE;
993      srcReg->NegateBase = (sign < 0.0F) ? GL_TRUE : GL_FALSE;
994   }
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, &srcReg->Index))
1006         RETURN_ERROR;
1007   }
1008   else if (token[0] == 'f') {
1009      /* XXX this might be an identier! */
1010      srcReg->File = PROGRAM_INPUT;
1011      if (!Parse_FragReg(parseState, &srcReg->Index))
1012         RETURN_ERROR;
1013   }
1014   else if (token[0] == 'p') {
1015      /* XXX this might be an identier! */
1016      srcReg->File = PROGRAM_LOCAL_PARAM;
1017      if (!Parse_ProgramParamReg(parseState, &srcReg->Index))
1018         RETURN_ERROR;
1019   }
1020   else if (IsLetter(token[0])){
1021      GLubyte ident[100];
1022      GLint paramIndex;
1023      if (!Parse_Identifier(parseState, ident))
1024         RETURN_ERROR;
1025      paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
1026                                                -1, (const char *) ident);
1027      if (paramIndex < 0) {
1028         RETURN_ERROR2("Undefined constant or parameter: ", ident);
1029      }
1030      srcReg->File = PROGRAM_NAMED_PARAM;
1031      srcReg->Index = paramIndex;
1032   }
1033   else if (IsDigit(token[0]) || token[0] == '-' || token[0] == '+' || token[0] == '.'){
1034      /* literal scalar constant */
1035      GLfloat values[4];
1036      GLuint paramIndex;
1037      if (!Parse_ScalarConstant(parseState, values))
1038         RETURN_ERROR;
1039      paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values);
1040      srcReg->File = PROGRAM_NAMED_PARAM;
1041      srcReg->Index = paramIndex;
1042   }
1043   else if (token[0] == '{'){
1044      /* literal vector constant */
1045      GLfloat values[4];
1046      GLuint paramIndex;
1047      (void) Parse_String(parseState, "{");
1048      if (!Parse_VectorConstant(parseState, values))
1049         RETURN_ERROR;
1050      paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values);
1051      srcReg->File = PROGRAM_NAMED_PARAM;
1052      srcReg->Index = paramIndex;
1053   }
1054   else {
1055      RETURN_ERROR2("Invalid source register name", token);
1056   }
1057
1058   /* init swizzle fields */
1059   srcReg->Swizzle[0] = 0;
1060   srcReg->Swizzle[1] = 1;
1061   srcReg->Swizzle[2] = 2;
1062   srcReg->Swizzle[3] = 3;
1063
1064   /* Look for optional swizzle suffix */
1065   if (Parse_String(parseState, ".")) {
1066      if (!Parse_Token(parseState, token))
1067         RETURN_ERROR;
1068
1069      if (!Parse_SwizzleSuffix(token, srcReg->Swizzle))
1070         RETURN_ERROR1("Invalid swizzle suffix");
1071   }
1072
1073   /* Finish absolute value */
1074   if (srcReg->Abs && !Parse_String(parseState, "|")) {
1075      RETURN_ERROR1("Expected |");
1076   }
1077
1078   return GL_TRUE;
1079}
1080
1081
1082static GLboolean
1083Parse_ScalarSrcReg(struct parse_state *parseState,
1084                   struct fp_src_register *srcReg)
1085{
1086   GLubyte token[100];
1087   GLfloat sign = 1.0F;
1088   GLboolean needSuffix = GL_TRUE;
1089
1090   /*
1091    * First, take care of +/- and absolute value stuff.
1092    */
1093   if (Parse_String(parseState, "-"))
1094      sign = -1.0F;
1095   else if (Parse_String(parseState, "+"))
1096      sign = +1.0F;
1097
1098   if (Parse_String(parseState, "|")) {
1099      srcReg->Abs = GL_TRUE;
1100      srcReg->NegateAbs = (sign < 0.0F) ? GL_TRUE : GL_FALSE;
1101
1102      if (Parse_String(parseState, "-"))
1103         srcReg->NegateBase = GL_TRUE;
1104      else if (Parse_String(parseState, "+"))
1105         srcReg->NegateBase = GL_FALSE;
1106      else
1107         srcReg->NegateBase = GL_FALSE;
1108   }
1109   else {
1110      srcReg->Abs = GL_FALSE;
1111      srcReg->NegateAbs = GL_FALSE;
1112      srcReg->NegateBase = (sign < 0.0F) ? GL_TRUE : GL_FALSE;
1113   }
1114
1115   if (!Peek_Token(parseState, token))
1116      RETURN_ERROR;
1117
1118   /* Src reg can be R<n>, H<n> or a named fragment attrib */
1119   if (token[0] == 'R' || token[0] == 'H') {
1120      srcReg->File = PROGRAM_TEMPORARY;
1121      if (!Parse_TempReg(parseState, &srcReg->Index))
1122         RETURN_ERROR;
1123   }
1124   else if (token[0] == 'f') {
1125      srcReg->File = PROGRAM_INPUT;
1126      if (!Parse_FragReg(parseState, &srcReg->Index))
1127         RETURN_ERROR;
1128   }
1129   else if (token[0] == '{') {
1130      /* vector literal */
1131      GLfloat values[4];
1132      GLuint paramIndex;
1133      (void) Parse_String(parseState, "{");
1134      if (!Parse_VectorConstant(parseState, values))
1135         RETURN_ERROR;
1136      paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values);
1137      srcReg->File = PROGRAM_NAMED_PARAM;
1138      srcReg->Index = paramIndex;
1139   }
1140   else if (IsDigit(token[0])) {
1141      /* scalar literal */
1142      GLfloat values[4];
1143      GLuint paramIndex;
1144      if (!Parse_ScalarConstant(parseState, values))
1145         RETURN_ERROR;
1146      paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values);
1147      srcReg->Index = paramIndex;
1148      srcReg->File = PROGRAM_NAMED_PARAM;
1149      needSuffix = GL_FALSE;
1150   }
1151   else {
1152      RETURN_ERROR2("Invalid scalar source argument", token);
1153   }
1154
1155   if (needSuffix) {
1156      /* parse .[xyzw] suffix */
1157      if (!Parse_String(parseState, "."))
1158         RETURN_ERROR1("Expected .");
1159
1160      if (!Parse_Token(parseState, token))
1161         RETURN_ERROR;
1162
1163      if (token[0] == 'x' && token[1] == 0) {
1164         srcReg->Swizzle[0] = 0;
1165      }
1166      else if (token[0] == 'y' && token[1] == 0) {
1167         srcReg->Swizzle[0] = 1;
1168      }
1169      else if (token[0] == 'z' && token[1] == 0) {
1170         srcReg->Swizzle[0] = 2;
1171      }
1172      else if (token[0] == 'w' && token[1] == 0) {
1173         srcReg->Swizzle[0] = 3;
1174      }
1175      else {
1176         RETURN_ERROR1("Invalid scalar source suffix");
1177      }
1178   }
1179   else {
1180      srcReg->Swizzle[0] = 0;
1181   }
1182   srcReg->Swizzle[1] = srcReg->Swizzle[2] = srcReg->Swizzle[3] = 0;
1183
1184   /* Finish absolute value */
1185   if (srcReg->Abs && !Parse_String(parseState, "|")) {
1186      RETURN_ERROR1("Expected |");
1187   }
1188
1189   return GL_TRUE;
1190}
1191
1192
1193
1194static GLboolean
1195Parse_InstructionSequence(struct parse_state *parseState,
1196                          struct fp_instruction program[])
1197{
1198   while (1) {
1199      struct fp_instruction *inst = program + parseState->numInst;
1200      struct instruction_pattern instMatch;
1201      GLubyte token[100];
1202
1203      /* Initialize the instruction */
1204      inst->SrcReg[0].File = (enum register_file) -1;
1205      inst->SrcReg[1].File = (enum register_file) -1;
1206      inst->SrcReg[2].File = (enum register_file) -1;
1207      inst->DstReg.File = (enum register_file) -1;
1208      inst->DstReg.CondSwizzle[0] = 0;
1209      inst->DstReg.CondSwizzle[1] = 1;
1210      inst->DstReg.CondSwizzle[2] = 2;
1211      inst->DstReg.CondSwizzle[3] = 3;
1212
1213      /* special instructions */
1214      if (Parse_String(parseState, "DEFINE")) {
1215         GLubyte id[100];
1216         GLfloat value[7];  /* yes, 7 to be safe */
1217         if (!Parse_Identifier(parseState, id))
1218            RETURN_ERROR;
1219         /* XXX make sure id is not a reserved identifer, like R9 */
1220         if (!Parse_String(parseState, "="))
1221            RETURN_ERROR1("Expected =");
1222         if (!Parse_VectorOrScalarConstant(parseState, value))
1223            RETURN_ERROR;
1224         if (!Parse_String(parseState, ";"))
1225            RETURN_ERROR1("Expected ;");
1226         if (_mesa_lookup_parameter_index(parseState->parameters,
1227                                          -1, (const char *) id) >= 0) {
1228            RETURN_ERROR2(id, "already defined");
1229         }
1230         _mesa_add_named_parameter(parseState->parameters,
1231                                   (const char *) id, value);
1232      }
1233      else if (Parse_String(parseState, "DECLARE")) {
1234         GLubyte id[100];
1235         GLfloat value[7] = {0, 0, 0, 0, 0, 0, 0};  /* yes, to be safe */
1236         if (!Parse_Identifier(parseState, id))
1237            RETURN_ERROR;
1238         /* XXX make sure id is not a reserved identifer, like R9 */
1239         if (Parse_String(parseState, "=")) {
1240            if (!Parse_VectorOrScalarConstant(parseState, value))
1241               RETURN_ERROR;
1242         }
1243         if (!Parse_String(parseState, ";"))
1244            RETURN_ERROR1("Expected ;");
1245         if (_mesa_lookup_parameter_index(parseState->parameters,
1246                                          -1, (const char *) id) >= 0) {
1247            RETURN_ERROR2(id, "already declared");
1248         }
1249         _mesa_add_named_parameter(parseState->parameters,
1250                                   (const char *) id, value);
1251      }
1252      else if (Parse_String(parseState, "END")) {
1253         inst->Opcode = FP_OPCODE_END;
1254         inst->StringPos = parseState->curLine - parseState->start;
1255         assert(inst->StringPos >= 0);
1256         parseState->numInst++;
1257         if (Parse_Token(parseState, token)) {
1258            RETURN_ERROR1("Code after END opcode.");
1259         }
1260         break;
1261      }
1262      else {
1263         /* general/arithmetic instruction */
1264
1265         /* get token */
1266         if (!Parse_Token(parseState, token)) {
1267            RETURN_ERROR1("Missing END instruction.");
1268         }
1269
1270         /* try to find matching instuction */
1271         instMatch = MatchInstruction(token);
1272         if (instMatch.opcode < 0) {
1273            /* bad instruction name */
1274            RETURN_ERROR2("Unexpected token: ", token);
1275         }
1276
1277         inst->Opcode = instMatch.opcode;
1278         inst->Precision = instMatch.suffixes & (_R | _H | _X);
1279         inst->Saturate = (instMatch.suffixes & (_S)) ? GL_TRUE : GL_FALSE;
1280         inst->UpdateCondRegister = (instMatch.suffixes & (_C)) ? GL_TRUE : GL_FALSE;
1281         inst->StringPos = parseState->curLine - parseState->start;
1282         assert(inst->StringPos >= 0);
1283
1284         /*
1285          * parse the input and output operands
1286          */
1287         if (instMatch.outputs == OUTPUT_S || instMatch.outputs == OUTPUT_V) {
1288            if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
1289               RETURN_ERROR;
1290            if (!Parse_String(parseState, ","))
1291               RETURN_ERROR1("Expected ,");
1292         }
1293         else if (instMatch.outputs == OUTPUT_NONE) {
1294            ASSERT(instMatch.opcode == FP_OPCODE_KIL);
1295            /* This is a little weird, the cond code info is in the dest register */
1296            if (!Parse_CondCodeMask(parseState, &inst->DstReg))
1297               RETURN_ERROR;
1298         }
1299
1300         if (instMatch.inputs == INPUT_1V) {
1301            if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1302               RETURN_ERROR;
1303         }
1304         else if (instMatch.inputs == INPUT_2V) {
1305            if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1306               RETURN_ERROR;
1307            if (!Parse_String(parseState, ","))
1308               RETURN_ERROR1("Expected ,");
1309            if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1310               RETURN_ERROR;
1311         }
1312         else if (instMatch.inputs == INPUT_3V) {
1313            if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1314               RETURN_ERROR;
1315            if (!Parse_String(parseState, ","))
1316               RETURN_ERROR1("Expected ,");
1317            if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1318               RETURN_ERROR;
1319            if (!Parse_String(parseState, ","))
1320               RETURN_ERROR1("Expected ,");
1321            if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
1322               RETURN_ERROR;
1323         }
1324         else if (instMatch.inputs == INPUT_1S) {
1325            if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1326               RETURN_ERROR;
1327         }
1328         else if (instMatch.inputs == INPUT_2S) {
1329            if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1330               RETURN_ERROR;
1331            if (!Parse_String(parseState, ","))
1332               RETURN_ERROR1("Expected ,");
1333            if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[1]))
1334               RETURN_ERROR;
1335         }
1336         else if (instMatch.inputs == INPUT_CC) {
1337            /* XXX to-do */
1338         }
1339         else if (instMatch.inputs == INPUT_1V_T) {
1340            if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1341               RETURN_ERROR;
1342            if (!Parse_String(parseState, ","))
1343               RETURN_ERROR1("Expected ,");
1344            if (!Parse_TextureImageId(parseState, &inst->TexSrcUnit,
1345                                      &inst->TexSrcBit))
1346               RETURN_ERROR;
1347         }
1348         else if (instMatch.inputs == INPUT_3V_T) {
1349            if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1350               RETURN_ERROR;
1351            if (!Parse_String(parseState, ","))
1352               RETURN_ERROR1("Expected ,");
1353            if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1354               RETURN_ERROR;
1355            if (!Parse_String(parseState, ","))
1356               RETURN_ERROR1("Expected ,");
1357            if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
1358               RETURN_ERROR;
1359            if (!Parse_String(parseState, ","))
1360               RETURN_ERROR1("Expected ,");
1361            if (!Parse_TextureImageId(parseState, &inst->TexSrcUnit,
1362                                      &inst->TexSrcBit))
1363               RETURN_ERROR;
1364         }
1365
1366         /* end of statement semicolon */
1367         if (!Parse_String(parseState, ";"))
1368            RETURN_ERROR1("Expected ;");
1369
1370         parseState->numInst++;
1371
1372         if (parseState->numInst >= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS)
1373            RETURN_ERROR1("Program too long");
1374      }
1375   }
1376   return GL_TRUE;
1377}
1378
1379
1380
1381/**
1382 * Parse/compile the 'str' returning the compiled 'program'.
1383 * ctx->Program.ErrorPos will be -1 if successful.  Otherwise, ErrorPos
1384 * indicates the position of the error in 'str'.
1385 */
1386void
1387_mesa_parse_nv_fragment_program(GLcontext *ctx, GLenum dstTarget,
1388                                const GLubyte *str, GLsizei len,
1389                                struct fragment_program *program)
1390{
1391   struct parse_state parseState;
1392   struct fp_instruction instBuffer[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS];
1393   struct fp_instruction *newInst;
1394   GLenum target;
1395   GLubyte *programString;
1396
1397   /* Make a null-terminated copy of the program string */
1398   programString = (GLubyte *) MALLOC(len + 1);
1399   if (!programString) {
1400      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1401      return;
1402   }
1403   MEMCPY(programString, str, len);
1404   programString[len] = 0;
1405
1406   /* Get ready to parse */
1407   _mesa_bzero(&parseState, sizeof(struct parse_state));
1408   parseState.ctx = ctx;
1409   parseState.start = programString;
1410   parseState.program = program;
1411   parseState.numInst = 0;
1412   parseState.curLine = programString;
1413   parseState.parameters = _mesa_new_parameter_list();
1414
1415   /* Reset error state */
1416   _mesa_set_program_error(ctx, -1, NULL);
1417
1418   /* check the program header */
1419   if (_mesa_strncmp((const char *) programString, "!!FP1.0", 7) == 0) {
1420      target = GL_FRAGMENT_PROGRAM_NV;
1421      parseState.pos = programString + 7;
1422   }
1423   else if (_mesa_strncmp((const char *) programString, "!!FCP1.0", 8) == 0) {
1424      /* fragment / register combiner program - not supported */
1425      _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1426      _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1427      return;
1428   }
1429   else {
1430      /* invalid header */
1431      _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1432      _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1433      return;
1434   }
1435
1436   /* make sure target and header match */
1437   if (target != dstTarget) {
1438      _mesa_error(ctx, GL_INVALID_OPERATION,
1439                  "glLoadProgramNV(target mismatch 0x%x != 0x%x)",
1440                  target, dstTarget);
1441      return;
1442   }
1443
1444   if (Parse_InstructionSequence(&parseState, instBuffer)) {
1445      GLuint u;
1446      /* successful parse! */
1447
1448      if (parseState.outputsWritten == 0) {
1449         /* must write at least one output! */
1450         _mesa_error(ctx, GL_INVALID_OPERATION,
1451                     "Invalid fragment program - no outputs written.");
1452         return;
1453      }
1454
1455      /* copy the compiled instructions */
1456      assert(parseState.numInst <= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS);
1457      newInst = (struct fp_instruction *)
1458         MALLOC(parseState.numInst * sizeof(struct fp_instruction));
1459      if (!newInst) {
1460         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1461         return;  /* out of memory */
1462      }
1463      MEMCPY(newInst, instBuffer,
1464             parseState.numInst * sizeof(struct fp_instruction));
1465
1466      /* install the program */
1467      program->Base.Target = target;
1468      if (program->Base.String) {
1469         FREE(program->Base.String);
1470      }
1471      program->Base.String = programString;
1472      program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
1473      if (program->Instructions) {
1474         FREE(program->Instructions);
1475      }
1476      program->Instructions = newInst;
1477      program->InputsRead = parseState.inputsRead;
1478      program->OutputsWritten = parseState.outputsWritten;
1479      for (u = 0; u < ctx->Const.MaxTextureImageUnits; u++)
1480         program->TexturesUsed[u] = parseState.texturesUsed[u];
1481
1482      /* save program parameters */
1483      program->Parameters = parseState.parameters;
1484
1485      /* allocate registers for declared program parameters */
1486#if 00
1487      _mesa_assign_program_registers(&(program->SymbolTable));
1488#endif
1489
1490#ifdef DEBUG
1491      _mesa_printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id);
1492      _mesa_print_nv_fragment_program(program);
1493      _mesa_printf("----------------------------------\n");
1494#endif
1495   }
1496   else {
1497      /* Error! */
1498      _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1499      /* NOTE: _mesa_set_program_error would have been called already */
1500   }
1501}
1502
1503
1504static void
1505PrintSrcReg(const struct fragment_program *program,
1506            const struct fp_src_register *src)
1507{
1508   static const char comps[5] = "xyzw";
1509
1510   if (src->NegateAbs) {
1511      _mesa_printf("-");
1512   }
1513   if (src->Abs) {
1514      _mesa_printf("|");
1515   }
1516   if (src->NegateBase) {
1517      _mesa_printf("-");
1518   }
1519   if (src->File == PROGRAM_NAMED_PARAM) {
1520      if (program->Parameters->Parameters[src->Index].Type == CONSTANT) {
1521         printf("{%g, %g, %g, %g}",
1522                program->Parameters->Parameters[src->Index].Values[0],
1523                program->Parameters->Parameters[src->Index].Values[1],
1524                program->Parameters->Parameters[src->Index].Values[2],
1525                program->Parameters->Parameters[src->Index].Values[3]);
1526      }
1527      else {
1528         ASSERT(program->Parameters->Parameters[src->Index].Type
1529                == NAMED_PARAMETER);
1530         printf("%s", program->Parameters->Parameters[src->Index].Name);
1531      }
1532   }
1533   else if (src->File == PROGRAM_OUTPUT) {
1534      _mesa_printf("o[%s]", OutputRegisters[src->Index]);
1535   }
1536   else if (src->File == PROGRAM_INPUT) {
1537      _mesa_printf("f[%s]", InputRegisters[src->Index]);
1538   }
1539   else if (src->File == PROGRAM_LOCAL_PARAM) {
1540      _mesa_printf("p[%d]", src->Index);
1541   }
1542   else if (src->File == PROGRAM_TEMPORARY) {
1543      if (src->Index >= 32)
1544         _mesa_printf("H%d", src->Index);
1545      else
1546         _mesa_printf("R%d", src->Index);
1547   }
1548   else if (src->File == PROGRAM_WRITE_ONLY) {
1549      _mesa_printf("%cC", "HR"[src->Index]);
1550   }
1551   else {
1552      _mesa_problem(NULL, "Invalid fragment register %d", src->Index);
1553      return;
1554   }
1555   if (src->Swizzle[0] == src->Swizzle[1] &&
1556       src->Swizzle[0] == src->Swizzle[2] &&
1557       src->Swizzle[0] == src->Swizzle[3]) {
1558      _mesa_printf(".%c", comps[src->Swizzle[0]]);
1559   }
1560   else if (src->Swizzle[0] != 0 ||
1561            src->Swizzle[1] != 1 ||
1562            src->Swizzle[2] != 2 ||
1563            src->Swizzle[3] != 3) {
1564      _mesa_printf(".%c%c%c%c",
1565                   comps[src->Swizzle[0]],
1566                   comps[src->Swizzle[1]],
1567                   comps[src->Swizzle[2]],
1568                   comps[src->Swizzle[3]]);
1569   }
1570   if (src->Abs) {
1571      _mesa_printf("|");
1572   }
1573}
1574
1575static void
1576PrintTextureSrc(const struct fp_instruction *inst)
1577{
1578   _mesa_printf("TEX%d, ", inst->TexSrcUnit);
1579   switch (inst->TexSrcBit) {
1580   case TEXTURE_1D_BIT:
1581      _mesa_printf("1D");
1582      break;
1583   case TEXTURE_2D_BIT:
1584      _mesa_printf("2D");
1585      break;
1586   case TEXTURE_3D_BIT:
1587      _mesa_printf("3D");
1588      break;
1589   case TEXTURE_RECT_BIT:
1590      _mesa_printf("RECT");
1591      break;
1592   case TEXTURE_CUBE_BIT:
1593      _mesa_printf("CUBE");
1594      break;
1595   default:
1596      _mesa_problem(NULL, "Invalid textue target in PrintTextureSrc");
1597   }
1598}
1599
1600static void
1601PrintCondCode(const struct fp_dst_register *dst)
1602{
1603   static const char *comps = "xyzw";
1604   static const char *ccString[] = {
1605      "??", "GT", "EQ", "LT", "UN", "GE", "LE", "NE", "TR", "FL", "??"
1606   };
1607
1608   _mesa_printf("%s", ccString[dst->CondMask]);
1609   if (dst->CondSwizzle[0] == dst->CondSwizzle[1] &&
1610       dst->CondSwizzle[0] == dst->CondSwizzle[2] &&
1611       dst->CondSwizzle[0] == dst->CondSwizzle[3]) {
1612      _mesa_printf(".%c", comps[dst->CondSwizzle[0]]);
1613   }
1614   else if (dst->CondSwizzle[0] != 0 ||
1615            dst->CondSwizzle[1] != 1 ||
1616            dst->CondSwizzle[2] != 2 ||
1617            dst->CondSwizzle[3] != 3) {
1618      _mesa_printf(".%c%c%c%c",
1619                   comps[dst->CondSwizzle[0]],
1620                   comps[dst->CondSwizzle[1]],
1621                   comps[dst->CondSwizzle[2]],
1622                   comps[dst->CondSwizzle[3]]);
1623   }
1624}
1625
1626
1627static void
1628PrintDstReg(const struct fp_dst_register *dst)
1629{
1630   GLint w = dst->WriteMask[0] + dst->WriteMask[1]
1631           + dst->WriteMask[2] + dst->WriteMask[3];
1632
1633   if (dst->File == PROGRAM_OUTPUT) {
1634      _mesa_printf("o[%s]", OutputRegisters[dst->Index]);
1635   }
1636   else if (dst->File == PROGRAM_TEMPORARY) {
1637      if (dst->Index >= 32)
1638         _mesa_printf("H%d", dst->Index);
1639      else
1640         _mesa_printf("R%d", dst->Index);
1641   }
1642   else if (dst->File == PROGRAM_LOCAL_PARAM) {
1643      _mesa_printf("p[%d]", dst->Index);
1644   }
1645   else if (dst->File == PROGRAM_WRITE_ONLY) {
1646      _mesa_printf("%cC", "HR"[dst->Index]);
1647   }
1648   else {
1649      _mesa_printf("???");
1650   }
1651
1652   if (w != 0 && w != 4) {
1653      _mesa_printf(".");
1654      if (dst->WriteMask[0])
1655         _mesa_printf("x");
1656      if (dst->WriteMask[1])
1657         _mesa_printf("y");
1658      if (dst->WriteMask[2])
1659         _mesa_printf("z");
1660      if (dst->WriteMask[3])
1661         _mesa_printf("w");
1662   }
1663
1664   if (dst->CondMask != COND_TR ||
1665       dst->CondSwizzle[0] != 0 ||
1666       dst->CondSwizzle[1] != 1 ||
1667       dst->CondSwizzle[2] != 2 ||
1668       dst->CondSwizzle[3] != 3) {
1669      _mesa_printf(" (");
1670      PrintCondCode(dst);
1671      _mesa_printf(")");
1672   }
1673}
1674
1675
1676/**
1677 * Print (unparse) the given vertex program.  Just for debugging.
1678 */
1679void
1680_mesa_print_nv_fragment_program(const struct fragment_program *program)
1681{
1682   const struct fp_instruction *inst;
1683
1684   for (inst = program->Instructions; inst->Opcode != FP_OPCODE_END; inst++) {
1685      int i;
1686      for (i = 0; Instructions[i].name; i++) {
1687         if (inst->Opcode == Instructions[i].opcode) {
1688            /* print instruction name */
1689            _mesa_printf("%s", Instructions[i].name);
1690            if (inst->Precision == FLOAT16)
1691               _mesa_printf("H");
1692            else if (inst->Precision == FIXED12)
1693               _mesa_printf("X");
1694            if (inst->UpdateCondRegister)
1695               _mesa_printf("C");
1696            if (inst->Saturate)
1697               _mesa_printf("_SAT");
1698            _mesa_printf(" ");
1699
1700            if (Instructions[i].inputs == INPUT_CC) {
1701               PrintCondCode(&inst->DstReg);
1702            }
1703            else if (Instructions[i].outputs == OUTPUT_V ||
1704                     Instructions[i].outputs == OUTPUT_S) {
1705               /* print dest register */
1706               PrintDstReg(&inst->DstReg);
1707               _mesa_printf(", ");
1708            }
1709
1710            /* print source register(s) */
1711            if (Instructions[i].inputs == INPUT_1V ||
1712                Instructions[i].inputs == INPUT_1S) {
1713               PrintSrcReg(program, &inst->SrcReg[0]);
1714            }
1715            else if (Instructions[i].inputs == INPUT_2V ||
1716                     Instructions[i].inputs == INPUT_2S) {
1717               PrintSrcReg(program, &inst->SrcReg[0]);
1718               _mesa_printf(", ");
1719               PrintSrcReg(program, &inst->SrcReg[1]);
1720            }
1721            else if (Instructions[i].inputs == INPUT_3V) {
1722               PrintSrcReg(program, &inst->SrcReg[0]);
1723               _mesa_printf(", ");
1724               PrintSrcReg(program, &inst->SrcReg[1]);
1725               _mesa_printf(", ");
1726               PrintSrcReg(program, &inst->SrcReg[2]);
1727            }
1728            else if (Instructions[i].inputs == INPUT_1V_T) {
1729               PrintSrcReg(program, &inst->SrcReg[0]);
1730               _mesa_printf(", ");
1731               PrintTextureSrc(inst);
1732            }
1733            else if (Instructions[i].inputs == INPUT_3V_T) {
1734               PrintSrcReg(program, &inst->SrcReg[0]);
1735               _mesa_printf(", ");
1736               PrintSrcReg(program, &inst->SrcReg[1]);
1737               _mesa_printf(", ");
1738               PrintSrcReg(program, &inst->SrcReg[2]);
1739               _mesa_printf(", ");
1740               PrintTextureSrc(inst);
1741            }
1742            _mesa_printf(";\n");
1743            break;
1744         }
1745      }
1746      if (!Instructions[i].name) {
1747         _mesa_printf("Invalid opcode %d\n", inst->Opcode);
1748      }
1749   }
1750   _mesa_printf("END\n");
1751}
1752
1753
1754const char *
1755_mesa_nv_fragment_input_register_name(GLuint i)
1756{
1757   ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_INPUTS);
1758   return InputRegisters[i];
1759}
1760
1761
1762const char *
1763_mesa_nv_fragment_output_register_name(GLuint i)
1764{
1765   ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_OUTPUTS);
1766   return OutputRegisters[i];
1767}
1768