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