tgsi_text.c revision 848b8605
1/**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28#include "util/u_debug.h"
29#include "util/u_memory.h"
30#include "util/u_prim.h"
31#include "pipe/p_defines.h"
32#include "util/u_inlines.h"
33#include "tgsi_text.h"
34#include "tgsi_build.h"
35#include "tgsi_info.h"
36#include "tgsi_parse.h"
37#include "tgsi_sanity.h"
38#include "tgsi_strings.h"
39#include "tgsi_util.h"
40#include "tgsi_dump.h"
41
42static boolean is_alpha_underscore( const char *cur )
43{
44   return
45      (*cur >= 'a' && *cur <= 'z') ||
46      (*cur >= 'A' && *cur <= 'Z') ||
47      *cur == '_';
48}
49
50static boolean is_digit( const char *cur )
51{
52   return *cur >= '0' && *cur <= '9';
53}
54
55static boolean is_digit_alpha_underscore( const char *cur )
56{
57   return is_digit( cur ) || is_alpha_underscore( cur );
58}
59
60static char uprcase( char c )
61{
62   if (c >= 'a' && c <= 'z')
63      return c + 'A' - 'a';
64   return c;
65}
66
67/*
68 * Ignore case of str1 and assume str1 is already uppercase.
69 * Return TRUE iff str1 and str2 are equal.
70 */
71static int
72streq_nocase_uprcase(const char *str1,
73                     const char *str2)
74{
75   while (*str1 && *str2) {
76      if (*str1 != uprcase(*str2))
77         return FALSE;
78      str1++;
79      str2++;
80   }
81   return *str1 == 0 && *str2 == 0;
82}
83
84/* Return TRUE if both strings match.
85 * The second string is terminated by zero.
86 * The pointer to the first string is moved at end of the read word
87 * on success.
88 */
89static boolean str_match_no_case( const char **pcur, const char *str )
90{
91   const char *cur = *pcur;
92
93   while (*str != '\0' && *str == uprcase( *cur )) {
94      str++;
95      cur++;
96   }
97   if (*str == '\0') {
98      *pcur = cur;
99      return TRUE;
100   }
101   return FALSE;
102}
103
104/* Return TRUE if both strings match.
105 * The first string is be terminated by a non-digit non-letter non-underscore
106 * character, the second string is terminated by zero.
107 * The pointer to the first string is moved at end of the read word
108 * on success.
109 */
110static boolean str_match_nocase_whole( const char **pcur, const char *str )
111{
112   const char *cur = *pcur;
113
114   if (str_match_no_case(&cur, str) &&
115       !is_digit_alpha_underscore(cur)) {
116      *pcur = cur;
117      return TRUE;
118   }
119   return FALSE;
120}
121
122/* Eat zero or more whitespaces.
123 */
124static void eat_opt_white( const char **pcur )
125{
126   while (**pcur == ' ' || **pcur == '\t' || **pcur == '\n')
127      (*pcur)++;
128}
129
130/* Eat one or more whitespaces.
131 * Return TRUE if at least one whitespace eaten.
132 */
133static boolean eat_white( const char **pcur )
134{
135   const char *cur = *pcur;
136
137   eat_opt_white( pcur );
138   return *pcur > cur;
139}
140
141/* Parse unsigned integer.
142 * No checks for overflow.
143 */
144static boolean parse_uint( const char **pcur, uint *val )
145{
146   const char *cur = *pcur;
147
148   if (is_digit( cur )) {
149      *val = *cur++ - '0';
150      while (is_digit( cur ))
151         *val = *val * 10 + *cur++ - '0';
152      *pcur = cur;
153      return TRUE;
154   }
155   return FALSE;
156}
157
158static boolean parse_int( const char **pcur, int *val )
159{
160   const char *cur = *pcur;
161   int sign = (*cur == '-' ? -1 : 1);
162
163   if (*cur == '+' || *cur == '-')
164      cur++;
165
166   if (parse_uint(&cur, (uint *)val)) {
167      *val *= sign;
168      *pcur = cur;
169      return TRUE;
170   }
171
172   return FALSE;
173}
174
175static boolean parse_identifier( const char **pcur, char *ret )
176{
177   const char *cur = *pcur;
178   int i = 0;
179   if (is_alpha_underscore( cur )) {
180      ret[i++] = *cur++;
181      while (is_alpha_underscore( cur ) || is_digit( cur ))
182         ret[i++] = *cur++;
183      ret[i++] = '\0';
184      *pcur = cur;
185      return TRUE;
186   }
187   return FALSE;
188}
189
190/* Parse floating point.
191 */
192static boolean parse_float( const char **pcur, float *val )
193{
194   const char *cur = *pcur;
195   boolean integral_part = FALSE;
196   boolean fractional_part = FALSE;
197
198   *val = (float) atof( cur );
199
200   if (*cur == '-' || *cur == '+')
201      cur++;
202   if (is_digit( cur )) {
203      cur++;
204      integral_part = TRUE;
205      while (is_digit( cur ))
206         cur++;
207   }
208   if (*cur == '.') {
209      cur++;
210      if (is_digit( cur )) {
211         cur++;
212         fractional_part = TRUE;
213         while (is_digit( cur ))
214            cur++;
215      }
216   }
217   if (!integral_part && !fractional_part)
218      return FALSE;
219   if (uprcase( *cur ) == 'E') {
220      cur++;
221      if (*cur == '-' || *cur == '+')
222         cur++;
223      if (is_digit( cur )) {
224         cur++;
225         while (is_digit( cur ))
226            cur++;
227      }
228      else
229         return FALSE;
230   }
231   *pcur = cur;
232   return TRUE;
233}
234
235struct translate_ctx
236{
237   const char *text;
238   const char *cur;
239   struct tgsi_token *tokens;
240   struct tgsi_token *tokens_cur;
241   struct tgsi_token *tokens_end;
242   struct tgsi_header *header;
243   unsigned processor : 4;
244   int implied_array_size : 5;
245   unsigned num_immediates;
246};
247
248static void report_error( struct translate_ctx *ctx, const char *msg )
249{
250   int line = 1;
251   int column = 1;
252   const char *itr = ctx->text;
253
254   while (itr != ctx->cur) {
255      if (*itr == '\n') {
256         column = 1;
257         ++line;
258      }
259      ++column;
260      ++itr;
261   }
262
263   debug_printf( "\nTGSI asm error: %s [%d : %d] \n", msg, line, column );
264}
265
266/* Parse shader header.
267 * Return TRUE for one of the following headers.
268 *    FRAG
269 *    GEOM
270 *    VERT
271 */
272static boolean parse_header( struct translate_ctx *ctx )
273{
274   uint processor;
275
276   if (str_match_nocase_whole( &ctx->cur, "FRAG" ))
277      processor = TGSI_PROCESSOR_FRAGMENT;
278   else if (str_match_nocase_whole( &ctx->cur, "VERT" ))
279      processor = TGSI_PROCESSOR_VERTEX;
280   else if (str_match_nocase_whole( &ctx->cur, "GEOM" ))
281      processor = TGSI_PROCESSOR_GEOMETRY;
282   else if (str_match_nocase_whole( &ctx->cur, "COMP" ))
283      processor = TGSI_PROCESSOR_COMPUTE;
284   else {
285      report_error( ctx, "Unknown header" );
286      return FALSE;
287   }
288
289   if (ctx->tokens_cur >= ctx->tokens_end)
290      return FALSE;
291   ctx->header = (struct tgsi_header *) ctx->tokens_cur++;
292   *ctx->header = tgsi_build_header();
293
294   if (ctx->tokens_cur >= ctx->tokens_end)
295      return FALSE;
296   *(struct tgsi_processor *) ctx->tokens_cur++ = tgsi_build_processor( processor, ctx->header );
297   ctx->processor = processor;
298
299   return TRUE;
300}
301
302static boolean parse_label( struct translate_ctx *ctx, uint *val )
303{
304   const char *cur = ctx->cur;
305
306   if (parse_uint( &cur, val )) {
307      eat_opt_white( &cur );
308      if (*cur == ':') {
309         cur++;
310         ctx->cur = cur;
311         return TRUE;
312      }
313   }
314   return FALSE;
315}
316
317static boolean
318parse_file( const char **pcur, uint *file )
319{
320   uint i;
321
322   for (i = 0; i < TGSI_FILE_COUNT; i++) {
323      const char *cur = *pcur;
324
325      if (str_match_nocase_whole( &cur, tgsi_file_name(i) )) {
326         *pcur = cur;
327         *file = i;
328         return TRUE;
329      }
330   }
331   return FALSE;
332}
333
334static boolean
335parse_opt_writemask(
336   struct translate_ctx *ctx,
337   uint *writemask )
338{
339   const char *cur;
340
341   cur = ctx->cur;
342   eat_opt_white( &cur );
343   if (*cur == '.') {
344      cur++;
345      *writemask = TGSI_WRITEMASK_NONE;
346      eat_opt_white( &cur );
347      if (uprcase( *cur ) == 'X') {
348         cur++;
349         *writemask |= TGSI_WRITEMASK_X;
350      }
351      if (uprcase( *cur ) == 'Y') {
352         cur++;
353         *writemask |= TGSI_WRITEMASK_Y;
354      }
355      if (uprcase( *cur ) == 'Z') {
356         cur++;
357         *writemask |= TGSI_WRITEMASK_Z;
358      }
359      if (uprcase( *cur ) == 'W') {
360         cur++;
361         *writemask |= TGSI_WRITEMASK_W;
362      }
363
364      if (*writemask == TGSI_WRITEMASK_NONE) {
365         report_error( ctx, "Writemask expected" );
366         return FALSE;
367      }
368
369      ctx->cur = cur;
370   }
371   else {
372      *writemask = TGSI_WRITEMASK_XYZW;
373   }
374   return TRUE;
375}
376
377
378/* <register_file_bracket> ::= <file> `['
379 */
380static boolean
381parse_register_file_bracket(
382   struct translate_ctx *ctx,
383   uint *file )
384{
385   if (!parse_file( &ctx->cur, file )) {
386      report_error( ctx, "Unknown register file" );
387      return FALSE;
388   }
389   eat_opt_white( &ctx->cur );
390   if (*ctx->cur != '[') {
391      report_error( ctx, "Expected `['" );
392      return FALSE;
393   }
394   ctx->cur++;
395   return TRUE;
396}
397
398/* <register_file_bracket_index> ::= <register_file_bracket> <uint>
399 */
400static boolean
401parse_register_file_bracket_index(
402   struct translate_ctx *ctx,
403   uint *file,
404   int *index )
405{
406   uint uindex;
407
408   if (!parse_register_file_bracket( ctx, file ))
409      return FALSE;
410   eat_opt_white( &ctx->cur );
411   if (!parse_uint( &ctx->cur, &uindex )) {
412      report_error( ctx, "Expected literal unsigned integer" );
413      return FALSE;
414   }
415   *index = (int) uindex;
416   return TRUE;
417}
418
419/* Parse simple 1d register operand.
420 *    <register_dst> ::= <register_file_bracket_index> `]'
421 */
422static boolean
423parse_register_1d(struct translate_ctx *ctx,
424                  uint *file,
425                  int *index )
426{
427   if (!parse_register_file_bracket_index( ctx, file, index ))
428      return FALSE;
429   eat_opt_white( &ctx->cur );
430   if (*ctx->cur != ']') {
431      report_error( ctx, "Expected `]'" );
432      return FALSE;
433   }
434   ctx->cur++;
435   return TRUE;
436}
437
438struct parsed_bracket {
439   int index;
440
441   uint ind_file;
442   int ind_index;
443   uint ind_comp;
444   uint ind_array;
445};
446
447
448static boolean
449parse_register_bracket(
450   struct translate_ctx *ctx,
451   struct parsed_bracket *brackets)
452{
453   const char *cur;
454   uint uindex;
455
456   memset(brackets, 0, sizeof(struct parsed_bracket));
457
458   eat_opt_white( &ctx->cur );
459
460   cur = ctx->cur;
461   if (parse_file( &cur, &brackets->ind_file )) {
462      if (!parse_register_1d( ctx, &brackets->ind_file,
463                              &brackets->ind_index ))
464         return FALSE;
465      eat_opt_white( &ctx->cur );
466
467      if (*ctx->cur == '.') {
468         ctx->cur++;
469         eat_opt_white(&ctx->cur);
470
471         switch (uprcase(*ctx->cur)) {
472         case 'X':
473            brackets->ind_comp = TGSI_SWIZZLE_X;
474            break;
475         case 'Y':
476            brackets->ind_comp = TGSI_SWIZZLE_Y;
477            break;
478         case 'Z':
479            brackets->ind_comp = TGSI_SWIZZLE_Z;
480            break;
481         case 'W':
482            brackets->ind_comp = TGSI_SWIZZLE_W;
483            break;
484         default:
485            report_error(ctx, "Expected indirect register swizzle component `x', `y', `z' or `w'");
486            return FALSE;
487         }
488         ctx->cur++;
489         eat_opt_white(&ctx->cur);
490      }
491
492      if (*ctx->cur == '+' || *ctx->cur == '-')
493         parse_int( &ctx->cur, &brackets->index );
494      else
495         brackets->index = 0;
496   }
497   else {
498      if (!parse_uint( &ctx->cur, &uindex )) {
499         report_error( ctx, "Expected literal unsigned integer" );
500         return FALSE;
501      }
502      brackets->index = (int) uindex;
503      brackets->ind_file = TGSI_FILE_NULL;
504      brackets->ind_index = 0;
505   }
506   eat_opt_white( &ctx->cur );
507   if (*ctx->cur != ']') {
508      report_error( ctx, "Expected `]'" );
509      return FALSE;
510   }
511   ctx->cur++;
512   if (*ctx->cur == '(') {
513      ctx->cur++;
514      eat_opt_white( &ctx->cur );
515      if (!parse_uint( &ctx->cur, &brackets->ind_array )) {
516         report_error( ctx, "Expected literal unsigned integer" );
517         return FALSE;
518      }
519      eat_opt_white( &ctx->cur );
520      if (*ctx->cur != ')') {
521         report_error( ctx, "Expected `)'" );
522         return FALSE;
523      }
524      ctx->cur++;
525   }
526   return TRUE;
527}
528
529static boolean
530parse_opt_register_src_bracket(
531   struct translate_ctx *ctx,
532   struct parsed_bracket *brackets,
533   int *parsed_brackets)
534{
535   const char *cur = ctx->cur;
536
537   *parsed_brackets = 0;
538
539   eat_opt_white( &cur );
540   if (cur[0] == '[') {
541      ++cur;
542      ctx->cur = cur;
543
544      if (!parse_register_bracket(ctx, brackets))
545         return FALSE;
546
547      *parsed_brackets = 1;
548   }
549
550   return TRUE;
551}
552
553
554/* Parse source register operand.
555 *    <register_src> ::= <register_file_bracket_index> `]' |
556 *                       <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `]' |
557 *                       <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `+' <uint> `]' |
558 *                       <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `-' <uint> `]'
559 */
560static boolean
561parse_register_src(
562   struct translate_ctx *ctx,
563   uint *file,
564   struct parsed_bracket *brackets)
565{
566   brackets->ind_comp = TGSI_SWIZZLE_X;
567   if (!parse_register_file_bracket( ctx, file ))
568      return FALSE;
569   if (!parse_register_bracket( ctx, brackets ))
570       return FALSE;
571
572   return TRUE;
573}
574
575struct parsed_dcl_bracket {
576   uint first;
577   uint last;
578};
579
580static boolean
581parse_register_dcl_bracket(
582   struct translate_ctx *ctx,
583   struct parsed_dcl_bracket *bracket)
584{
585   uint uindex;
586   memset(bracket, 0, sizeof(struct parsed_dcl_bracket));
587
588   eat_opt_white( &ctx->cur );
589
590   if (!parse_uint( &ctx->cur, &uindex )) {
591      /* it can be an empty bracket [] which means its range
592       * is from 0 to some implied size */
593      if (ctx->cur[0] == ']' && ctx->implied_array_size != 0) {
594         bracket->first = 0;
595         bracket->last = ctx->implied_array_size - 1;
596         goto cleanup;
597      }
598      report_error( ctx, "Expected literal unsigned integer" );
599      return FALSE;
600   }
601   bracket->first = uindex;
602
603   eat_opt_white( &ctx->cur );
604
605   if (ctx->cur[0] == '.' && ctx->cur[1] == '.') {
606      uint uindex;
607
608      ctx->cur += 2;
609      eat_opt_white( &ctx->cur );
610      if (!parse_uint( &ctx->cur, &uindex )) {
611         report_error( ctx, "Expected literal integer" );
612         return FALSE;
613      }
614      bracket->last = (int) uindex;
615      eat_opt_white( &ctx->cur );
616   }
617   else {
618      bracket->last = bracket->first;
619   }
620
621cleanup:
622   if (*ctx->cur != ']') {
623      report_error( ctx, "Expected `]' or `..'" );
624      return FALSE;
625   }
626   ctx->cur++;
627   return TRUE;
628}
629
630/* Parse register declaration.
631 *    <register_dcl> ::= <register_file_bracket_index> `]' |
632 *                       <register_file_bracket_index> `..' <index> `]'
633 */
634static boolean
635parse_register_dcl(
636   struct translate_ctx *ctx,
637   uint *file,
638   struct parsed_dcl_bracket *brackets,
639   int *num_brackets)
640{
641   const char *cur;
642
643   *num_brackets = 0;
644
645   if (!parse_register_file_bracket( ctx, file ))
646      return FALSE;
647   if (!parse_register_dcl_bracket( ctx, &brackets[0] ))
648      return FALSE;
649
650   *num_brackets = 1;
651
652   cur = ctx->cur;
653   eat_opt_white( &cur );
654
655   if (cur[0] == '[') {
656      ++cur;
657      ctx->cur = cur;
658      if (!parse_register_dcl_bracket( ctx, &brackets[1] ))
659         return FALSE;
660      /* for geometry shader we don't really care about
661       * the first brackets it's always the size of the
662       * input primitive. so we want to declare just
663       * the index relevant to the semantics which is in
664       * the second bracket */
665      if (ctx->processor == TGSI_PROCESSOR_GEOMETRY && *file == TGSI_FILE_INPUT) {
666         brackets[0] = brackets[1];
667         *num_brackets = 1;
668      } else {
669         *num_brackets = 2;
670      }
671   }
672
673   return TRUE;
674}
675
676
677/* Parse destination register operand.*/
678static boolean
679parse_register_dst(
680   struct translate_ctx *ctx,
681   uint *file,
682   struct parsed_bracket *brackets)
683{
684   brackets->ind_comp = TGSI_SWIZZLE_X;
685   if (!parse_register_file_bracket( ctx, file ))
686      return FALSE;
687   if (!parse_register_bracket( ctx, brackets ))
688       return FALSE;
689
690   return TRUE;
691}
692
693static boolean
694parse_dst_operand(
695   struct translate_ctx *ctx,
696   struct tgsi_full_dst_register *dst )
697{
698   uint file;
699   uint writemask;
700   const char *cur;
701   struct parsed_bracket bracket[2];
702   int parsed_opt_brackets;
703
704   if (!parse_register_dst( ctx, &file, &bracket[0] ))
705      return FALSE;
706   if (!parse_opt_register_src_bracket(ctx, &bracket[1], &parsed_opt_brackets))
707      return FALSE;
708
709   cur = ctx->cur;
710   eat_opt_white( &cur );
711
712   if (!parse_opt_writemask( ctx, &writemask ))
713      return FALSE;
714
715   dst->Register.File = file;
716   if (parsed_opt_brackets) {
717      dst->Register.Dimension = 1;
718      dst->Dimension.Indirect = 0;
719      dst->Dimension.Dimension = 0;
720      dst->Dimension.Index = bracket[0].index;
721      bracket[0] = bracket[1];
722   }
723   dst->Register.Index = bracket[0].index;
724   dst->Register.WriteMask = writemask;
725   if (bracket[0].ind_file != TGSI_FILE_NULL) {
726      dst->Register.Indirect = 1;
727      dst->Indirect.File = bracket[0].ind_file;
728      dst->Indirect.Index = bracket[0].ind_index;
729      dst->Indirect.Swizzle = bracket[0].ind_comp;
730      dst->Indirect.ArrayID = bracket[0].ind_array;
731   }
732   return TRUE;
733}
734
735static boolean
736parse_optional_swizzle(
737   struct translate_ctx *ctx,
738   uint *swizzle,
739   boolean *parsed_swizzle,
740   int components)
741{
742   const char *cur = ctx->cur;
743
744   *parsed_swizzle = FALSE;
745
746   eat_opt_white( &cur );
747   if (*cur == '.') {
748      uint i;
749
750      cur++;
751      eat_opt_white( &cur );
752      for (i = 0; i < components; i++) {
753         if (uprcase( *cur ) == 'X')
754            swizzle[i] = TGSI_SWIZZLE_X;
755         else if (uprcase( *cur ) == 'Y')
756            swizzle[i] = TGSI_SWIZZLE_Y;
757         else if (uprcase( *cur ) == 'Z')
758            swizzle[i] = TGSI_SWIZZLE_Z;
759         else if (uprcase( *cur ) == 'W')
760            swizzle[i] = TGSI_SWIZZLE_W;
761         else {
762	    report_error( ctx, "Expected register swizzle component `x', `y', `z' or `w'" );
763	    return FALSE;
764         }
765         cur++;
766      }
767      *parsed_swizzle = TRUE;
768      ctx->cur = cur;
769   }
770   return TRUE;
771}
772
773static boolean
774parse_src_operand(
775   struct translate_ctx *ctx,
776   struct tgsi_full_src_register *src )
777{
778   uint file;
779   uint swizzle[4];
780   boolean parsed_swizzle;
781   struct parsed_bracket bracket[2];
782   int parsed_opt_brackets;
783
784   if (*ctx->cur == '-') {
785      ctx->cur++;
786      eat_opt_white( &ctx->cur );
787      src->Register.Negate = 1;
788   }
789
790   if (*ctx->cur == '|') {
791      ctx->cur++;
792      eat_opt_white( &ctx->cur );
793      src->Register.Absolute = 1;
794   }
795
796   if (!parse_register_src(ctx, &file, &bracket[0]))
797      return FALSE;
798   if (!parse_opt_register_src_bracket(ctx, &bracket[1], &parsed_opt_brackets))
799      return FALSE;
800
801   src->Register.File = file;
802   if (parsed_opt_brackets) {
803      src->Register.Dimension = 1;
804      src->Dimension.Indirect = 0;
805      src->Dimension.Dimension = 0;
806      src->Dimension.Index = bracket[0].index;
807      if (bracket[0].ind_file != TGSI_FILE_NULL) {
808         src->Dimension.Indirect = 1;
809         src->DimIndirect.File = bracket[0].ind_file;
810         src->DimIndirect.Index = bracket[0].ind_index;
811         src->DimIndirect.Swizzle = bracket[0].ind_comp;
812         src->DimIndirect.ArrayID = bracket[0].ind_array;
813      }
814      bracket[0] = bracket[1];
815   }
816   src->Register.Index = bracket[0].index;
817   if (bracket[0].ind_file != TGSI_FILE_NULL) {
818      src->Register.Indirect = 1;
819      src->Indirect.File = bracket[0].ind_file;
820      src->Indirect.Index = bracket[0].ind_index;
821      src->Indirect.Swizzle = bracket[0].ind_comp;
822      src->Indirect.ArrayID = bracket[0].ind_array;
823   }
824
825   /* Parse optional swizzle.
826    */
827   if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle, 4 )) {
828      if (parsed_swizzle) {
829         src->Register.SwizzleX = swizzle[0];
830         src->Register.SwizzleY = swizzle[1];
831         src->Register.SwizzleZ = swizzle[2];
832         src->Register.SwizzleW = swizzle[3];
833      }
834   }
835
836   if (src->Register.Absolute) {
837      eat_opt_white( &ctx->cur );
838      if (*ctx->cur != '|') {
839         report_error( ctx, "Expected `|'" );
840         return FALSE;
841      }
842      ctx->cur++;
843   }
844
845
846   return TRUE;
847}
848
849static boolean
850parse_texoffset_operand(
851   struct translate_ctx *ctx,
852   struct tgsi_texture_offset *src )
853{
854   uint file;
855   uint swizzle[3];
856   boolean parsed_swizzle;
857   struct parsed_bracket bracket;
858
859   if (!parse_register_src(ctx, &file, &bracket))
860      return FALSE;
861
862   src->File = file;
863   src->Index = bracket.index;
864
865   /* Parse optional swizzle.
866    */
867   if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle, 3 )) {
868      if (parsed_swizzle) {
869         src->SwizzleX = swizzle[0];
870         src->SwizzleY = swizzle[1];
871         src->SwizzleZ = swizzle[2];
872      }
873   }
874
875   return TRUE;
876}
877
878static boolean
879match_inst(const char **pcur,
880           unsigned *saturate,
881           const struct tgsi_opcode_info *info)
882{
883   const char *cur = *pcur;
884
885   /* simple case: the whole string matches the instruction name */
886   if (str_match_nocase_whole(&cur, info->mnemonic)) {
887      *pcur = cur;
888      *saturate = TGSI_SAT_NONE;
889      return TRUE;
890   }
891
892   if (str_match_no_case(&cur, info->mnemonic)) {
893      /* the instruction has a suffix, figure it out */
894      if (str_match_nocase_whole(&cur, "_SAT")) {
895         *pcur = cur;
896         *saturate = TGSI_SAT_ZERO_ONE;
897         return TRUE;
898      }
899
900      if (str_match_nocase_whole(&cur, "_SATNV")) {
901         *pcur = cur;
902         *saturate = TGSI_SAT_MINUS_PLUS_ONE;
903         return TRUE;
904      }
905   }
906
907   return FALSE;
908}
909
910static boolean
911parse_instruction(
912   struct translate_ctx *ctx,
913   boolean has_label )
914{
915   uint i;
916   uint saturate = TGSI_SAT_NONE;
917   const struct tgsi_opcode_info *info;
918   struct tgsi_full_instruction inst;
919   const char *cur;
920   uint advance;
921
922   inst = tgsi_default_full_instruction();
923
924   /* Parse predicate.
925    */
926   eat_opt_white( &ctx->cur );
927   if (*ctx->cur == '(') {
928      uint file;
929      int index;
930      uint swizzle[4];
931      boolean parsed_swizzle;
932
933      inst.Instruction.Predicate = 1;
934
935      ctx->cur++;
936      if (*ctx->cur == '!') {
937         ctx->cur++;
938         inst.Predicate.Negate = 1;
939      }
940
941      if (!parse_register_1d( ctx, &file, &index ))
942         return FALSE;
943
944      if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle, 4 )) {
945         if (parsed_swizzle) {
946            inst.Predicate.SwizzleX = swizzle[0];
947            inst.Predicate.SwizzleY = swizzle[1];
948            inst.Predicate.SwizzleZ = swizzle[2];
949            inst.Predicate.SwizzleW = swizzle[3];
950         }
951      }
952
953      if (*ctx->cur != ')') {
954         report_error( ctx, "Expected `)'" );
955         return FALSE;
956      }
957
958      ctx->cur++;
959   }
960
961   /* Parse instruction name.
962    */
963   eat_opt_white( &ctx->cur );
964   for (i = 0; i < TGSI_OPCODE_LAST; i++) {
965      cur = ctx->cur;
966
967      info = tgsi_get_opcode_info( i );
968      if (match_inst(&cur, &saturate, info)) {
969         if (info->num_dst + info->num_src + info->is_tex == 0) {
970            ctx->cur = cur;
971            break;
972         }
973         else if (*cur == '\0' || eat_white( &cur )) {
974            ctx->cur = cur;
975            break;
976         }
977      }
978   }
979   if (i == TGSI_OPCODE_LAST) {
980      if (has_label)
981         report_error( ctx, "Unknown opcode" );
982      else
983         report_error( ctx, "Expected `DCL', `IMM' or a label" );
984      return FALSE;
985   }
986
987   inst.Instruction.Opcode = i;
988   inst.Instruction.Saturate = saturate;
989   inst.Instruction.NumDstRegs = info->num_dst;
990   inst.Instruction.NumSrcRegs = info->num_src;
991
992   if (i >= TGSI_OPCODE_SAMPLE && i <= TGSI_OPCODE_GATHER4) {
993      /*
994       * These are not considered tex opcodes here (no additional
995       * target argument) however we're required to set the Texture
996       * bit so we can set the number of tex offsets (offsets aren't
997       * actually handled here yet in any case).
998       */
999      inst.Instruction.Texture = 1;
1000      inst.Texture.Texture = TGSI_TEXTURE_UNKNOWN;
1001   }
1002
1003   /* Parse instruction operands.
1004    */
1005   for (i = 0; i < info->num_dst + info->num_src + info->is_tex; i++) {
1006      if (i > 0) {
1007         eat_opt_white( &ctx->cur );
1008         if (*ctx->cur != ',') {
1009            report_error( ctx, "Expected `,'" );
1010            return FALSE;
1011         }
1012         ctx->cur++;
1013         eat_opt_white( &ctx->cur );
1014      }
1015
1016      if (i < info->num_dst) {
1017         if (!parse_dst_operand( ctx, &inst.Dst[i] ))
1018            return FALSE;
1019      }
1020      else if (i < info->num_dst + info->num_src) {
1021         if (!parse_src_operand( ctx, &inst.Src[i - info->num_dst] ))
1022            return FALSE;
1023      }
1024      else {
1025         uint j;
1026
1027         for (j = 0; j < TGSI_TEXTURE_COUNT; j++) {
1028            if (str_match_nocase_whole( &ctx->cur, tgsi_texture_names[j] )) {
1029               inst.Instruction.Texture = 1;
1030               inst.Texture.Texture = j;
1031               break;
1032            }
1033         }
1034         if (j == TGSI_TEXTURE_COUNT) {
1035            report_error( ctx, "Expected texture target" );
1036            return FALSE;
1037         }
1038      }
1039   }
1040
1041   cur = ctx->cur;
1042   eat_opt_white( &cur );
1043   for (i = 0; info->is_tex && *cur == ','; i++) {
1044         cur++;
1045         eat_opt_white( &cur );
1046         ctx->cur = cur;
1047         if (!parse_texoffset_operand( ctx, &inst.TexOffsets[i] ))
1048            return FALSE;
1049         cur = ctx->cur;
1050         eat_opt_white( &cur );
1051   }
1052   inst.Texture.NumOffsets = i;
1053
1054   cur = ctx->cur;
1055   eat_opt_white( &cur );
1056   if (info->is_branch && *cur == ':') {
1057      uint target;
1058
1059      cur++;
1060      eat_opt_white( &cur );
1061      if (!parse_uint( &cur, &target )) {
1062         report_error( ctx, "Expected a label" );
1063         return FALSE;
1064      }
1065      inst.Instruction.Label = 1;
1066      inst.Label.Label = target;
1067      ctx->cur = cur;
1068   }
1069
1070   advance = tgsi_build_full_instruction(
1071      &inst,
1072      ctx->tokens_cur,
1073      ctx->header,
1074      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1075   if (advance == 0)
1076      return FALSE;
1077   ctx->tokens_cur += advance;
1078
1079   return TRUE;
1080}
1081
1082/* parses a 4-touple of the form {x, y, z, w}
1083 * where x, y, z, w are numbers */
1084static boolean parse_immediate_data(struct translate_ctx *ctx, unsigned type,
1085                                    union tgsi_immediate_data *values)
1086{
1087   unsigned i;
1088   int ret;
1089
1090   eat_opt_white( &ctx->cur );
1091   if (*ctx->cur != '{') {
1092      report_error( ctx, "Expected `{'" );
1093      return FALSE;
1094   }
1095   ctx->cur++;
1096   for (i = 0; i < 4; i++) {
1097      eat_opt_white( &ctx->cur );
1098      if (i > 0) {
1099         if (*ctx->cur != ',') {
1100            report_error( ctx, "Expected `,'" );
1101            return FALSE;
1102         }
1103         ctx->cur++;
1104         eat_opt_white( &ctx->cur );
1105      }
1106
1107      switch (type) {
1108      case TGSI_IMM_FLOAT32:
1109         ret = parse_float(&ctx->cur, &values[i].Float);
1110         break;
1111      case TGSI_IMM_UINT32:
1112         ret = parse_uint(&ctx->cur, &values[i].Uint);
1113         break;
1114      case TGSI_IMM_INT32:
1115         ret = parse_int(&ctx->cur, &values[i].Int);
1116         break;
1117      default:
1118         assert(0);
1119         ret = FALSE;
1120         break;
1121      }
1122
1123      if (!ret) {
1124         report_error( ctx, "Expected immediate constant" );
1125         return FALSE;
1126      }
1127   }
1128   eat_opt_white( &ctx->cur );
1129   if (*ctx->cur != '}') {
1130      report_error( ctx, "Expected `}'" );
1131      return FALSE;
1132   }
1133   ctx->cur++;
1134
1135   return TRUE;
1136}
1137
1138static boolean parse_declaration( struct translate_ctx *ctx )
1139{
1140   struct tgsi_full_declaration decl;
1141   uint file;
1142   struct parsed_dcl_bracket brackets[2];
1143   int num_brackets;
1144   uint writemask;
1145   const char *cur, *cur2;
1146   uint advance;
1147   boolean is_vs_input;
1148
1149   if (!eat_white( &ctx->cur )) {
1150      report_error( ctx, "Syntax error" );
1151      return FALSE;
1152   }
1153   if (!parse_register_dcl( ctx, &file, brackets, &num_brackets))
1154      return FALSE;
1155   if (!parse_opt_writemask( ctx, &writemask ))
1156      return FALSE;
1157
1158   decl = tgsi_default_full_declaration();
1159   decl.Declaration.File = file;
1160   decl.Declaration.UsageMask = writemask;
1161
1162   if (num_brackets == 1) {
1163      decl.Range.First = brackets[0].first;
1164      decl.Range.Last = brackets[0].last;
1165   } else {
1166      decl.Range.First = brackets[1].first;
1167      decl.Range.Last = brackets[1].last;
1168
1169      decl.Declaration.Dimension = 1;
1170      decl.Dim.Index2D = brackets[0].first;
1171   }
1172
1173   is_vs_input = (file == TGSI_FILE_INPUT &&
1174                  ctx->processor == TGSI_PROCESSOR_VERTEX);
1175
1176   cur = ctx->cur;
1177   eat_opt_white( &cur );
1178   if (*cur == ',') {
1179      cur2 = cur;
1180      cur2++;
1181      eat_opt_white( &cur2 );
1182      if (str_match_nocase_whole( &cur2, "ARRAY" )) {
1183         int arrayid;
1184         if (*cur2 != '(') {
1185            report_error( ctx, "Expected `('" );
1186            return FALSE;
1187         }
1188         cur2++;
1189         eat_opt_white( &cur2 );
1190         if (!parse_int( &cur2, &arrayid )) {
1191            report_error( ctx, "Expected `,'" );
1192            return FALSE;
1193         }
1194         eat_opt_white( &cur2 );
1195         if (*cur2 != ')') {
1196            report_error( ctx, "Expected `)'" );
1197            return FALSE;
1198         }
1199         cur2++;
1200         decl.Declaration.Array = 1;
1201         decl.Array.ArrayID = arrayid;
1202         ctx->cur = cur = cur2;
1203      }
1204   }
1205
1206   if (*cur == ',' && !is_vs_input) {
1207      uint i, j;
1208
1209      cur++;
1210      eat_opt_white( &cur );
1211      if (file == TGSI_FILE_RESOURCE) {
1212         for (i = 0; i < TGSI_TEXTURE_COUNT; i++) {
1213            if (str_match_nocase_whole(&cur, tgsi_texture_names[i])) {
1214               decl.Resource.Resource = i;
1215               break;
1216            }
1217         }
1218         if (i == TGSI_TEXTURE_COUNT) {
1219            report_error(ctx, "Expected texture target");
1220            return FALSE;
1221         }
1222
1223         cur2 = cur;
1224         eat_opt_white(&cur2);
1225         while (*cur2 == ',') {
1226            cur2++;
1227            eat_opt_white(&cur2);
1228            if (str_match_nocase_whole(&cur2, "RAW")) {
1229               decl.Resource.Raw = 1;
1230
1231            } else if (str_match_nocase_whole(&cur2, "WR")) {
1232               decl.Resource.Writable = 1;
1233
1234            } else {
1235               break;
1236            }
1237            cur = cur2;
1238            eat_opt_white(&cur2);
1239         }
1240
1241         ctx->cur = cur;
1242
1243      } else if (file == TGSI_FILE_SAMPLER_VIEW) {
1244         for (i = 0; i < TGSI_TEXTURE_COUNT; i++) {
1245            if (str_match_nocase_whole(&cur, tgsi_texture_names[i])) {
1246               decl.SamplerView.Resource = i;
1247               break;
1248            }
1249         }
1250         if (i == TGSI_TEXTURE_COUNT) {
1251            report_error(ctx, "Expected texture target");
1252            return FALSE;
1253         }
1254         eat_opt_white( &cur );
1255         if (*cur != ',') {
1256            report_error( ctx, "Expected `,'" );
1257            return FALSE;
1258         }
1259         ++cur;
1260         eat_opt_white( &cur );
1261         for (j = 0; j < 4; ++j) {
1262            for (i = 0; i < PIPE_TYPE_COUNT; ++i) {
1263               if (str_match_nocase_whole(&cur, tgsi_type_names[i])) {
1264                  switch (j) {
1265                  case 0:
1266                     decl.SamplerView.ReturnTypeX = i;
1267                     break;
1268                  case 1:
1269                     decl.SamplerView.ReturnTypeY = i;
1270                     break;
1271                  case 2:
1272                     decl.SamplerView.ReturnTypeZ = i;
1273                     break;
1274                  case 3:
1275                     decl.SamplerView.ReturnTypeW = i;
1276                     break;
1277                  default:
1278                     assert(0);
1279                  }
1280                  break;
1281               }
1282            }
1283            if (i == PIPE_TYPE_COUNT) {
1284               if (j == 0 || j >  2) {
1285                  report_error(ctx, "Expected type name");
1286                  return FALSE;
1287               }
1288               break;
1289            } else {
1290               cur2 = cur;
1291               eat_opt_white( &cur2 );
1292               if (*cur2 == ',') {
1293                  cur2++;
1294                  eat_opt_white( &cur2 );
1295                  cur = cur2;
1296                  continue;
1297               } else
1298                  break;
1299            }
1300         }
1301         if (j < 4) {
1302            decl.SamplerView.ReturnTypeY =
1303               decl.SamplerView.ReturnTypeZ =
1304               decl.SamplerView.ReturnTypeW =
1305               decl.SamplerView.ReturnTypeX;
1306         }
1307         ctx->cur = cur;
1308      } else {
1309         if (str_match_nocase_whole(&cur, "LOCAL")) {
1310            decl.Declaration.Local = 1;
1311            ctx->cur = cur;
1312         }
1313
1314         cur = ctx->cur;
1315         eat_opt_white( &cur );
1316         if (*cur == ',') {
1317            cur++;
1318            eat_opt_white( &cur );
1319
1320            for (i = 0; i < TGSI_SEMANTIC_COUNT; i++) {
1321               if (str_match_nocase_whole(&cur, tgsi_semantic_names[i])) {
1322                  uint index;
1323
1324                  cur2 = cur;
1325                  eat_opt_white( &cur2 );
1326                  if (*cur2 == '[') {
1327                     cur2++;
1328                     eat_opt_white( &cur2 );
1329                     if (!parse_uint( &cur2, &index )) {
1330                        report_error( ctx, "Expected literal integer" );
1331                        return FALSE;
1332                     }
1333                     eat_opt_white( &cur2 );
1334                     if (*cur2 != ']') {
1335                        report_error( ctx, "Expected `]'" );
1336                        return FALSE;
1337                     }
1338                     cur2++;
1339
1340                     decl.Semantic.Index = index;
1341
1342                     cur = cur2;
1343                  }
1344
1345                  decl.Declaration.Semantic = 1;
1346                  decl.Semantic.Name = i;
1347
1348                  ctx->cur = cur;
1349                  break;
1350               }
1351            }
1352         }
1353      }
1354   }
1355
1356   cur = ctx->cur;
1357   eat_opt_white( &cur );
1358   if (*cur == ',' && !is_vs_input) {
1359      uint i;
1360
1361      cur++;
1362      eat_opt_white( &cur );
1363      for (i = 0; i < TGSI_INTERPOLATE_COUNT; i++) {
1364         if (str_match_nocase_whole( &cur, tgsi_interpolate_names[i] )) {
1365            decl.Declaration.Interpolate = 1;
1366            decl.Interp.Interpolate = i;
1367
1368            ctx->cur = cur;
1369            break;
1370         }
1371      }
1372      if (i == TGSI_INTERPOLATE_COUNT) {
1373         report_error( ctx, "Expected semantic or interpolate attribute" );
1374         return FALSE;
1375      }
1376   }
1377
1378   cur = ctx->cur;
1379   eat_opt_white( &cur );
1380   if (*cur == ',' && !is_vs_input) {
1381      uint i;
1382
1383      cur++;
1384      eat_opt_white( &cur );
1385      for (i = 0; i < TGSI_INTERPOLATE_LOC_COUNT; i++) {
1386         if (str_match_nocase_whole( &cur, tgsi_interpolate_locations[i] )) {
1387            decl.Interp.Location = i;
1388
1389            ctx->cur = cur;
1390            break;
1391         }
1392      }
1393   }
1394
1395   advance = tgsi_build_full_declaration(
1396      &decl,
1397      ctx->tokens_cur,
1398      ctx->header,
1399      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1400
1401   if (advance == 0)
1402      return FALSE;
1403   ctx->tokens_cur += advance;
1404
1405   return TRUE;
1406}
1407
1408static boolean parse_immediate( struct translate_ctx *ctx )
1409{
1410   struct tgsi_full_immediate imm;
1411   uint advance;
1412   int type;
1413
1414   if (*ctx->cur == '[') {
1415      uint uindex;
1416
1417      ++ctx->cur;
1418
1419      eat_opt_white( &ctx->cur );
1420      if (!parse_uint( &ctx->cur, &uindex )) {
1421         report_error( ctx, "Expected literal unsigned integer" );
1422         return FALSE;
1423      }
1424
1425      if (uindex != ctx->num_immediates) {
1426         report_error( ctx, "Immediates must be sorted" );
1427         return FALSE;
1428      }
1429
1430      eat_opt_white( &ctx->cur );
1431      if (*ctx->cur != ']') {
1432         report_error( ctx, "Expected `]'" );
1433         return FALSE;
1434      }
1435
1436      ctx->cur++;
1437   }
1438
1439   if (!eat_white( &ctx->cur )) {
1440      report_error( ctx, "Syntax error" );
1441      return FALSE;
1442   }
1443   for (type = 0; type < Elements(tgsi_immediate_type_names); ++type) {
1444      if (str_match_nocase_whole(&ctx->cur, tgsi_immediate_type_names[type]))
1445         break;
1446   }
1447   if (type == Elements(tgsi_immediate_type_names)) {
1448      report_error( ctx, "Expected immediate type" );
1449      return FALSE;
1450   }
1451
1452   imm = tgsi_default_full_immediate();
1453   imm.Immediate.NrTokens += 4;
1454   imm.Immediate.DataType = type;
1455   parse_immediate_data(ctx, type, imm.u);
1456
1457   advance = tgsi_build_full_immediate(
1458      &imm,
1459      ctx->tokens_cur,
1460      ctx->header,
1461      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1462   if (advance == 0)
1463      return FALSE;
1464   ctx->tokens_cur += advance;
1465
1466   ctx->num_immediates++;
1467
1468   return TRUE;
1469}
1470
1471static boolean
1472parse_primitive( const char **pcur, uint *primitive )
1473{
1474   uint i;
1475
1476   for (i = 0; i < PIPE_PRIM_MAX; i++) {
1477      const char *cur = *pcur;
1478
1479      if (str_match_nocase_whole( &cur, tgsi_primitive_names[i])) {
1480         *primitive = i;
1481         *pcur = cur;
1482         return TRUE;
1483      }
1484   }
1485   return FALSE;
1486}
1487
1488static boolean
1489parse_fs_coord_origin( const char **pcur, uint *fs_coord_origin )
1490{
1491   uint i;
1492
1493   for (i = 0; i < Elements(tgsi_fs_coord_origin_names); i++) {
1494      const char *cur = *pcur;
1495
1496      if (str_match_nocase_whole( &cur, tgsi_fs_coord_origin_names[i])) {
1497         *fs_coord_origin = i;
1498         *pcur = cur;
1499         return TRUE;
1500      }
1501   }
1502   return FALSE;
1503}
1504
1505static boolean
1506parse_fs_coord_pixel_center( const char **pcur, uint *fs_coord_pixel_center )
1507{
1508   uint i;
1509
1510   for (i = 0; i < Elements(tgsi_fs_coord_pixel_center_names); i++) {
1511      const char *cur = *pcur;
1512
1513      if (str_match_nocase_whole( &cur, tgsi_fs_coord_pixel_center_names[i])) {
1514         *fs_coord_pixel_center = i;
1515         *pcur = cur;
1516         return TRUE;
1517      }
1518   }
1519   return FALSE;
1520}
1521
1522
1523static boolean parse_property( struct translate_ctx *ctx )
1524{
1525   struct tgsi_full_property prop;
1526   uint property_name;
1527   uint values[8];
1528   uint advance;
1529   char id[64];
1530
1531   if (!eat_white( &ctx->cur )) {
1532      report_error( ctx, "Syntax error" );
1533      return FALSE;
1534   }
1535   if (!parse_identifier( &ctx->cur, id )) {
1536      report_error( ctx, "Syntax error" );
1537      return FALSE;
1538   }
1539   for (property_name = 0; property_name < TGSI_PROPERTY_COUNT;
1540        ++property_name) {
1541      if (streq_nocase_uprcase(tgsi_property_names[property_name], id)) {
1542         break;
1543      }
1544   }
1545   if (property_name >= TGSI_PROPERTY_COUNT) {
1546      debug_printf( "\nError: Unknown property : '%s'", id );
1547      return FALSE;
1548   }
1549
1550   eat_opt_white( &ctx->cur );
1551   switch(property_name) {
1552   case TGSI_PROPERTY_GS_INPUT_PRIM:
1553   case TGSI_PROPERTY_GS_OUTPUT_PRIM:
1554      if (!parse_primitive(&ctx->cur, &values[0] )) {
1555         report_error( ctx, "Unknown primitive name as property!" );
1556         return FALSE;
1557      }
1558      if (property_name == TGSI_PROPERTY_GS_INPUT_PRIM &&
1559          ctx->processor == TGSI_PROCESSOR_GEOMETRY) {
1560         ctx->implied_array_size = u_vertices_per_prim(values[0]);
1561      }
1562      break;
1563   case TGSI_PROPERTY_FS_COORD_ORIGIN:
1564      if (!parse_fs_coord_origin(&ctx->cur, &values[0] )) {
1565         report_error( ctx, "Unknown coord origin as property: must be UPPER_LEFT or LOWER_LEFT!" );
1566         return FALSE;
1567      }
1568      break;
1569   case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER:
1570      if (!parse_fs_coord_pixel_center(&ctx->cur, &values[0] )) {
1571         report_error( ctx, "Unknown coord pixel center as property: must be HALF_INTEGER or INTEGER!" );
1572         return FALSE;
1573      }
1574      break;
1575   case TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS:
1576   default:
1577      if (!parse_uint(&ctx->cur, &values[0] )) {
1578         report_error( ctx, "Expected unsigned integer as property!" );
1579         return FALSE;
1580      }
1581   }
1582
1583   prop = tgsi_default_full_property();
1584   prop.Property.PropertyName = property_name;
1585   prop.Property.NrTokens += 1;
1586   prop.u[0].Data = values[0];
1587
1588   advance = tgsi_build_full_property(
1589      &prop,
1590      ctx->tokens_cur,
1591      ctx->header,
1592      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1593   if (advance == 0)
1594      return FALSE;
1595   ctx->tokens_cur += advance;
1596
1597   return TRUE;
1598}
1599
1600
1601static boolean translate( struct translate_ctx *ctx )
1602{
1603   eat_opt_white( &ctx->cur );
1604   if (!parse_header( ctx ))
1605      return FALSE;
1606
1607   while (*ctx->cur != '\0') {
1608      uint label_val = 0;
1609      if (!eat_white( &ctx->cur )) {
1610         report_error( ctx, "Syntax error" );
1611         return FALSE;
1612      }
1613
1614      if (*ctx->cur == '\0')
1615         break;
1616      if (parse_label( ctx, &label_val )) {
1617         if (!parse_instruction( ctx, TRUE ))
1618            return FALSE;
1619      }
1620      else if (str_match_nocase_whole( &ctx->cur, "DCL" )) {
1621         if (!parse_declaration( ctx ))
1622            return FALSE;
1623      }
1624      else if (str_match_nocase_whole( &ctx->cur, "IMM" )) {
1625         if (!parse_immediate( ctx ))
1626            return FALSE;
1627      }
1628      else if (str_match_nocase_whole( &ctx->cur, "PROPERTY" )) {
1629         if (!parse_property( ctx ))
1630            return FALSE;
1631      }
1632      else if (!parse_instruction( ctx, FALSE )) {
1633         return FALSE;
1634      }
1635   }
1636
1637   return TRUE;
1638}
1639
1640boolean
1641tgsi_text_translate(
1642   const char *text,
1643   struct tgsi_token *tokens,
1644   uint num_tokens )
1645{
1646   struct translate_ctx ctx = {0};
1647
1648   ctx.text = text;
1649   ctx.cur = text;
1650   ctx.tokens = tokens;
1651   ctx.tokens_cur = tokens;
1652   ctx.tokens_end = tokens + num_tokens;
1653
1654   if (!translate( &ctx ))
1655      return FALSE;
1656
1657   return tgsi_sanity_check( tokens );
1658}
1659