tgsi_text.c revision e6133564bf2e65fc86f626a45d7977bdeaff8579
1/**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
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 TUNGSTEN GRAPHICS 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 "tgsi_text.h"
31#include "tgsi_build.h"
32#include "tgsi_info.h"
33#include "tgsi_parse.h"
34#include "tgsi_sanity.h"
35#include "tgsi_util.h"
36
37static boolean is_alpha_underscore( const char *cur )
38{
39   return
40      (*cur >= 'a' && *cur <= 'z') ||
41      (*cur >= 'A' && *cur <= 'Z') ||
42      *cur == '_';
43}
44
45static boolean is_digit( const char *cur )
46{
47   return *cur >= '0' && *cur <= '9';
48}
49
50static boolean is_digit_alpha_underscore( const char *cur )
51{
52   return is_digit( cur ) || is_alpha_underscore( cur );
53}
54
55static boolean uprcase( char c )
56{
57   if (c >= 'a' && c <= 'z')
58      return c += 'A' - 'a';
59   return c;
60}
61
62static boolean str_match_no_case( const char **pcur, const char *str )
63{
64   const char *cur = *pcur;
65
66   while (*str != '\0' && *str == uprcase( *cur )) {
67      str++;
68      cur++;
69   }
70   if (*str == '\0') {
71      *pcur = cur;
72      return TRUE;
73   }
74   return FALSE;
75}
76
77/* Eat zero or more whitespaces.
78 */
79static void eat_opt_white( const char **pcur )
80{
81   while (**pcur == ' ' || **pcur == '\t' || **pcur == '\n')
82      (*pcur)++;
83}
84
85/* Eat one or more whitespaces.
86 * Return TRUE if at least one whitespace eaten.
87 */
88static boolean eat_white( const char **pcur )
89{
90   const char *cur = *pcur;
91
92   eat_opt_white( pcur );
93   return *pcur > cur;
94}
95
96/* Parse unsigned integer.
97 * No checks for overflow.
98 */
99static boolean parse_uint( const char **pcur, uint *val )
100{
101   const char *cur = *pcur;
102
103   if (is_digit( cur )) {
104      *val = *cur++ - '0';
105      while (is_digit( cur ))
106         *val = *val * 10 + *cur++ - '0';
107      *pcur = cur;
108      return TRUE;
109   }
110   return FALSE;
111}
112
113/* Parse floating point.
114 */
115static boolean parse_float( const char **pcur, float *val )
116{
117   const char *cur = *pcur;
118   boolean integral_part = FALSE;
119   boolean fractional_part = FALSE;
120
121   *val = (float) atof( cur );
122
123   if (*cur == '-' || *cur == '+')
124      cur++;
125   if (is_digit( cur )) {
126      cur++;
127      integral_part = TRUE;
128      while (is_digit( cur ))
129         cur++;
130   }
131   if (*cur == '.') {
132      cur++;
133      if (is_digit( cur )) {
134         cur++;
135         fractional_part = TRUE;
136         while (is_digit( cur ))
137            cur++;
138      }
139   }
140   if (!integral_part && !fractional_part)
141      return FALSE;
142   if (uprcase( *cur ) == 'E') {
143      cur++;
144      if (*cur == '-' || *cur == '+')
145         cur++;
146      if (is_digit( cur )) {
147         cur++;
148         while (is_digit( cur ))
149            cur++;
150      }
151      else
152         return FALSE;
153   }
154   *pcur = cur;
155   return TRUE;
156}
157
158struct translate_ctx
159{
160   const char *text;
161   const char *cur;
162   struct tgsi_token *tokens;
163   struct tgsi_token *tokens_cur;
164   struct tgsi_token *tokens_end;
165   struct tgsi_header *header;
166};
167
168static void report_error( struct translate_ctx *ctx, const char *msg )
169{
170   debug_printf( "\nError: %s", msg );
171}
172
173/* Parse shader header.
174 * Return TRUE for one of the following headers.
175 *    FRAG
176 *    GEOM
177 *    VERT
178 */
179static boolean parse_header( struct translate_ctx *ctx )
180{
181   uint processor;
182
183   if (str_match_no_case( &ctx->cur, "FRAG" ))
184      processor = TGSI_PROCESSOR_FRAGMENT;
185   else if (str_match_no_case( &ctx->cur, "VERT" ))
186      processor = TGSI_PROCESSOR_VERTEX;
187   else if (str_match_no_case( &ctx->cur, "GEOM" ))
188      processor = TGSI_PROCESSOR_GEOMETRY;
189   else {
190      report_error( ctx, "Unknown header" );
191      return FALSE;
192   }
193
194   if (ctx->tokens_cur >= ctx->tokens_end)
195      return FALSE;
196   ctx->header = (struct tgsi_header *) ctx->tokens_cur++;
197   *ctx->header = tgsi_build_header();
198
199   if (ctx->tokens_cur >= ctx->tokens_end)
200      return FALSE;
201   *(struct tgsi_processor *) ctx->tokens_cur++ = tgsi_build_processor( processor, ctx->header );
202
203   return TRUE;
204}
205
206static boolean parse_label( struct translate_ctx *ctx, uint *val )
207{
208   const char *cur = ctx->cur;
209
210   if (parse_uint( &cur, val )) {
211      eat_opt_white( &cur );
212      if (*cur == ':') {
213         cur++;
214         ctx->cur = cur;
215         return TRUE;
216      }
217   }
218   return FALSE;
219}
220
221static const char *file_names[TGSI_FILE_COUNT] =
222{
223   "NULL",
224   "CONST",
225   "IN",
226   "OUT",
227   "TEMP",
228   "SAMP",
229   "ADDR",
230   "IMM",
231   "LOOP",
232   "PRED"
233};
234
235static boolean
236parse_file( const char **pcur, uint *file )
237{
238   uint i;
239
240   for (i = 0; i < TGSI_FILE_COUNT; i++) {
241      const char *cur = *pcur;
242
243      if (str_match_no_case( &cur, file_names[i] )) {
244         if (!is_digit_alpha_underscore( cur )) {
245            *pcur = cur;
246            *file = i;
247            return TRUE;
248         }
249      }
250   }
251   return FALSE;
252}
253
254static boolean
255parse_opt_writemask(
256   struct translate_ctx *ctx,
257   uint *writemask )
258{
259   const char *cur;
260
261   cur = ctx->cur;
262   eat_opt_white( &cur );
263   if (*cur == '.') {
264      cur++;
265      *writemask = TGSI_WRITEMASK_NONE;
266      eat_opt_white( &cur );
267      if (uprcase( *cur ) == 'X') {
268         cur++;
269         *writemask |= TGSI_WRITEMASK_X;
270      }
271      if (uprcase( *cur ) == 'Y') {
272         cur++;
273         *writemask |= TGSI_WRITEMASK_Y;
274      }
275      if (uprcase( *cur ) == 'Z') {
276         cur++;
277         *writemask |= TGSI_WRITEMASK_Z;
278      }
279      if (uprcase( *cur ) == 'W') {
280         cur++;
281         *writemask |= TGSI_WRITEMASK_W;
282      }
283
284      if (*writemask == TGSI_WRITEMASK_NONE) {
285         report_error( ctx, "Writemask expected" );
286         return FALSE;
287      }
288
289      ctx->cur = cur;
290   }
291   else {
292      *writemask = TGSI_WRITEMASK_XYZW;
293   }
294   return TRUE;
295}
296
297/* <register_file_bracket> ::= <file> `['
298 */
299static boolean
300parse_register_file_bracket(
301   struct translate_ctx *ctx,
302   uint *file )
303{
304   if (!parse_file( &ctx->cur, file )) {
305      report_error( ctx, "Unknown register file" );
306      return FALSE;
307   }
308   eat_opt_white( &ctx->cur );
309   if (*ctx->cur != '[') {
310      report_error( ctx, "Expected `['" );
311      return FALSE;
312   }
313   ctx->cur++;
314   return TRUE;
315}
316
317/* <register_file_bracket_index> ::= <register_file_bracket> <uint>
318 */
319static boolean
320parse_register_file_bracket_index(
321   struct translate_ctx *ctx,
322   uint *file,
323   int *index )
324{
325   uint uindex;
326
327   if (!parse_register_file_bracket( ctx, file ))
328      return FALSE;
329   eat_opt_white( &ctx->cur );
330   if (!parse_uint( &ctx->cur, &uindex )) {
331      report_error( ctx, "Expected literal unsigned integer" );
332      return FALSE;
333   }
334   *index = (int) uindex;
335   return TRUE;
336}
337
338/* Parse destination register operand.
339 *    <register_dst> ::= <register_file_bracket_index> `]'
340 */
341static boolean
342parse_register_dst(
343   struct translate_ctx *ctx,
344   uint *file,
345   int *index )
346{
347   if (!parse_register_file_bracket_index( ctx, file, index ))
348      return FALSE;
349   eat_opt_white( &ctx->cur );
350   if (*ctx->cur != ']') {
351      report_error( ctx, "Expected `]'" );
352      return FALSE;
353   }
354   ctx->cur++;
355   return TRUE;
356}
357
358/* Parse source register operand.
359 *    <register_src> ::= <register_file_bracket_index> `]' |
360 *                       <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `]' |
361 *                       <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `+' <uint> `]' |
362 *                       <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `-' <uint> `]'
363 */
364static boolean
365parse_register_src(
366   struct translate_ctx *ctx,
367   uint *file,
368   int *index,
369   uint *ind_file,
370   int *ind_index,
371   uint *ind_comp)
372{
373   const char *cur;
374   uint uindex;
375
376   *ind_comp = TGSI_SWIZZLE_X;
377   if (!parse_register_file_bracket( ctx, file ))
378      return FALSE;
379   eat_opt_white( &ctx->cur );
380   cur = ctx->cur;
381   if (parse_file( &cur, ind_file )) {
382      if (!parse_register_dst( ctx, ind_file, ind_index ))
383         return FALSE;
384      eat_opt_white( &ctx->cur );
385
386      if (*ctx->cur == '.') {
387         ctx->cur++;
388         eat_opt_white(&ctx->cur);
389
390         switch (uprcase(*ctx->cur)) {
391         case 'X':
392            *ind_comp = TGSI_SWIZZLE_X;
393            break;
394         case 'Y':
395            *ind_comp = TGSI_SWIZZLE_Y;
396            break;
397         case 'Z':
398            *ind_comp = TGSI_SWIZZLE_Z;
399            break;
400         case 'W':
401            *ind_comp = TGSI_SWIZZLE_W;
402            break;
403         default:
404            report_error(ctx, "Expected indirect register swizzle component `x', `y', `z' or `w'");
405            return FALSE;
406         }
407         ctx->cur++;
408         eat_opt_white(&ctx->cur);
409      }
410
411      if (*ctx->cur == '+' || *ctx->cur == '-') {
412         boolean negate;
413
414         negate = *ctx->cur == '-';
415         ctx->cur++;
416         eat_opt_white( &ctx->cur );
417         if (!parse_uint( &ctx->cur, &uindex )) {
418            report_error( ctx, "Expected literal unsigned integer" );
419            return FALSE;
420         }
421         if (negate)
422            *index = -(int) uindex;
423         else
424            *index = (int) uindex;
425      }
426      else {
427         *index = 0;
428      }
429   }
430   else {
431      if (!parse_uint( &ctx->cur, &uindex )) {
432         report_error( ctx, "Expected literal unsigned integer" );
433         return FALSE;
434      }
435      *index = (int) uindex;
436      *ind_file = TGSI_FILE_NULL;
437      *ind_index = 0;
438   }
439   eat_opt_white( &ctx->cur );
440   if (*ctx->cur != ']') {
441      report_error( ctx, "Expected `]'" );
442      return FALSE;
443   }
444   ctx->cur++;
445   return TRUE;
446}
447
448/* Parse register declaration.
449 *    <register_dcl> ::= <register_file_bracket_index> `]' |
450 *                       <register_file_bracket_index> `..' <index> `]'
451 */
452static boolean
453parse_register_dcl(
454   struct translate_ctx *ctx,
455   uint *file,
456   int *first,
457   int *last )
458{
459   if (!parse_register_file_bracket_index( ctx, file, first ))
460      return FALSE;
461   eat_opt_white( &ctx->cur );
462   if (ctx->cur[0] == '.' && ctx->cur[1] == '.') {
463      uint uindex;
464
465      ctx->cur += 2;
466      eat_opt_white( &ctx->cur );
467      if (!parse_uint( &ctx->cur, &uindex )) {
468         report_error( ctx, "Expected literal integer" );
469         return FALSE;
470      }
471      *last = (int) uindex;
472      eat_opt_white( &ctx->cur );
473   }
474   else {
475      *last = *first;
476   }
477   if (*ctx->cur != ']') {
478      report_error( ctx, "Expected `]' or `..'" );
479      return FALSE;
480   }
481   ctx->cur++;
482   return TRUE;
483}
484
485
486static boolean
487parse_dst_operand(
488   struct translate_ctx *ctx,
489   struct tgsi_full_dst_register *dst )
490{
491   uint file;
492   int index;
493   uint writemask;
494   const char *cur;
495
496   if (!parse_register_dst( ctx, &file, &index ))
497      return FALSE;
498
499   cur = ctx->cur;
500   eat_opt_white( &cur );
501
502   if (!parse_opt_writemask( ctx, &writemask ))
503      return FALSE;
504
505   dst->Register.File = file;
506   dst->Register.Index = index;
507   dst->Register.WriteMask = writemask;
508   return TRUE;
509}
510
511static boolean
512parse_optional_swizzle(
513   struct translate_ctx *ctx,
514   uint swizzle[4],
515   boolean *parsed_swizzle )
516{
517   const char *cur = ctx->cur;
518
519   *parsed_swizzle = FALSE;
520
521   eat_opt_white( &cur );
522   if (*cur == '.') {
523      uint i;
524
525      cur++;
526      eat_opt_white( &cur );
527      for (i = 0; i < 4; i++) {
528         if (uprcase( *cur ) == 'X')
529            swizzle[i] = TGSI_SWIZZLE_X;
530         else if (uprcase( *cur ) == 'Y')
531            swizzle[i] = TGSI_SWIZZLE_Y;
532         else if (uprcase( *cur ) == 'Z')
533            swizzle[i] = TGSI_SWIZZLE_Z;
534         else if (uprcase( *cur ) == 'W')
535            swizzle[i] = TGSI_SWIZZLE_W;
536         else {
537	    report_error( ctx, "Expected register swizzle component `x', `y', `z', `w', `0' or `1'" );
538	    return FALSE;
539         }
540         cur++;
541      }
542      *parsed_swizzle = TRUE;
543      ctx->cur = cur;
544   }
545   return TRUE;
546}
547
548static boolean
549parse_src_operand(
550   struct translate_ctx *ctx,
551   struct tgsi_full_src_register *src )
552{
553   uint file;
554   int index;
555   uint ind_file;
556   int ind_index;
557   uint ind_comp;
558   uint swizzle[4];
559   boolean parsed_swizzle;
560
561   if (*ctx->cur == '-') {
562      ctx->cur++;
563      eat_opt_white( &ctx->cur );
564      src->Register.Negate = 1;
565   }
566
567   if (*ctx->cur == '|') {
568      ctx->cur++;
569      eat_opt_white( &ctx->cur );
570      src->Register.Absolute = 1;
571   }
572
573   if (!parse_register_src(ctx, &file, &index, &ind_file, &ind_index, &ind_comp))
574      return FALSE;
575   src->Register.File = file;
576   src->Register.Index = index;
577   if (ind_file != TGSI_FILE_NULL) {
578      src->Register.Indirect = 1;
579      src->Indirect.File = ind_file;
580      src->Indirect.Index = ind_index;
581      src->Indirect.SwizzleX = ind_comp;
582      src->Indirect.SwizzleY = ind_comp;
583      src->Indirect.SwizzleZ = ind_comp;
584      src->Indirect.SwizzleW = ind_comp;
585   }
586
587   /* Parse optional swizzle.
588    */
589   if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle )) {
590      if (parsed_swizzle) {
591         src->Register.SwizzleX = swizzle[0];
592         src->Register.SwizzleY = swizzle[1];
593         src->Register.SwizzleZ = swizzle[2];
594         src->Register.SwizzleW = swizzle[3];
595      }
596   }
597
598   if (src->Register.Absolute) {
599      eat_opt_white( &ctx->cur );
600      if (*ctx->cur != '|') {
601         report_error( ctx, "Expected `|'" );
602         return FALSE;
603      }
604      ctx->cur++;
605   }
606
607
608   return TRUE;
609}
610
611static const char *texture_names[TGSI_TEXTURE_COUNT] =
612{
613   "UNKNOWN",
614   "1D",
615   "2D",
616   "3D",
617   "CUBE",
618   "RECT",
619   "SHADOW1D",
620   "SHADOW2D",
621   "SHADOWRECT"
622};
623
624static boolean
625match_inst_mnemonic(const char **pcur,
626                    const struct tgsi_opcode_info *info)
627{
628   if (str_match_no_case(pcur, info->mnemonic)) {
629      return TRUE;
630   }
631   return FALSE;
632}
633
634static boolean
635parse_instruction(
636   struct translate_ctx *ctx,
637   boolean has_label )
638{
639   uint i;
640   uint saturate = TGSI_SAT_NONE;
641   const struct tgsi_opcode_info *info;
642   struct tgsi_full_instruction inst;
643   uint advance;
644
645   /* Parse instruction name.
646    */
647   eat_opt_white( &ctx->cur );
648   for (i = 0; i < TGSI_OPCODE_LAST; i++) {
649      const char *cur = ctx->cur;
650
651      info = tgsi_get_opcode_info( i );
652      if (match_inst_mnemonic(&cur, info)) {
653         if (str_match_no_case( &cur, "_SATNV" ))
654            saturate = TGSI_SAT_MINUS_PLUS_ONE;
655         else if (str_match_no_case( &cur, "_SAT" ))
656            saturate = TGSI_SAT_ZERO_ONE;
657
658         if (info->num_dst + info->num_src + info->is_tex == 0) {
659            if (!is_digit_alpha_underscore( cur )) {
660               ctx->cur = cur;
661               break;
662            }
663         }
664         else if (*cur == '\0' || eat_white( &cur )) {
665            ctx->cur = cur;
666            break;
667         }
668      }
669   }
670   if (i == TGSI_OPCODE_LAST) {
671      if (has_label)
672         report_error( ctx, "Unknown opcode" );
673      else
674         report_error( ctx, "Expected `DCL', `IMM' or a label" );
675      return FALSE;
676   }
677
678   inst = tgsi_default_full_instruction();
679   inst.Instruction.Opcode = i;
680   inst.Instruction.Saturate = saturate;
681   inst.Instruction.NumDstRegs = info->num_dst;
682   inst.Instruction.NumSrcRegs = info->num_src;
683
684   /* Parse instruction operands.
685    */
686   for (i = 0; i < info->num_dst + info->num_src + info->is_tex; i++) {
687      if (i > 0) {
688         eat_opt_white( &ctx->cur );
689         if (*ctx->cur != ',') {
690            report_error( ctx, "Expected `,'" );
691            return FALSE;
692         }
693         ctx->cur++;
694         eat_opt_white( &ctx->cur );
695      }
696
697      if (i < info->num_dst) {
698         if (!parse_dst_operand( ctx, &inst.Dst[i] ))
699            return FALSE;
700      }
701      else if (i < info->num_dst + info->num_src) {
702         if (!parse_src_operand( ctx, &inst.Src[i - info->num_dst] ))
703            return FALSE;
704      }
705      else {
706         uint j;
707
708         for (j = 0; j < TGSI_TEXTURE_COUNT; j++) {
709            if (str_match_no_case( &ctx->cur, texture_names[j] )) {
710               if (!is_digit_alpha_underscore( ctx->cur )) {
711                  inst.Instruction.Texture = 1;
712                  inst.Texture.Texture = j;
713                  break;
714               }
715            }
716         }
717         if (j == TGSI_TEXTURE_COUNT) {
718            report_error( ctx, "Expected texture target" );
719            return FALSE;
720         }
721      }
722   }
723
724   if (info->is_branch) {
725      uint target;
726
727      eat_opt_white( &ctx->cur );
728      if (*ctx->cur != ':') {
729         report_error( ctx, "Expected `:'" );
730         return FALSE;
731      }
732      ctx->cur++;
733      eat_opt_white( &ctx->cur );
734      if (!parse_uint( &ctx->cur, &target )) {
735         report_error( ctx, "Expected a label" );
736         return FALSE;
737      }
738      inst.Instruction.Label = 1;
739      inst.Label.Label = target;
740   }
741
742   advance = tgsi_build_full_instruction(
743      &inst,
744      ctx->tokens_cur,
745      ctx->header,
746      (uint) (ctx->tokens_end - ctx->tokens_cur) );
747   if (advance == 0)
748      return FALSE;
749   ctx->tokens_cur += advance;
750
751   return TRUE;
752}
753
754static const char *semantic_names[TGSI_SEMANTIC_COUNT] =
755{
756   "POSITION",
757   "COLOR",
758   "BCOLOR",
759   "FOG",
760   "PSIZE",
761   "GENERIC",
762   "NORMAL",
763   "FACE"
764};
765
766static const char *interpolate_names[TGSI_INTERPOLATE_COUNT] =
767{
768   "CONSTANT",
769   "LINEAR",
770   "PERSPECTIVE"
771};
772
773static boolean parse_declaration( struct translate_ctx *ctx )
774{
775   struct tgsi_full_declaration decl;
776   uint file;
777   int first;
778   int last;
779   uint writemask;
780   const char *cur;
781   uint advance;
782
783   assert(Elements(semantic_names) == TGSI_SEMANTIC_COUNT);
784   assert(Elements(interpolate_names) == TGSI_INTERPOLATE_COUNT);
785
786   if (!eat_white( &ctx->cur )) {
787      report_error( ctx, "Syntax error" );
788      return FALSE;
789   }
790   if (!parse_register_dcl( ctx, &file, &first, &last ))
791      return FALSE;
792   if (!parse_opt_writemask( ctx, &writemask ))
793      return FALSE;
794
795   decl = tgsi_default_full_declaration();
796   decl.Declaration.File = file;
797   decl.Declaration.UsageMask = writemask;
798   decl.Range.First = first;
799   decl.Range.Last = last;
800
801   cur = ctx->cur;
802   eat_opt_white( &cur );
803   if (*cur == ',') {
804      uint i;
805
806      cur++;
807      eat_opt_white( &cur );
808      for (i = 0; i < TGSI_SEMANTIC_COUNT; i++) {
809         if (str_match_no_case( &cur, semantic_names[i] )) {
810            const char *cur2 = cur;
811            uint index;
812
813            if (is_digit_alpha_underscore( cur ))
814               continue;
815            eat_opt_white( &cur2 );
816            if (*cur2 == '[') {
817               cur2++;
818               eat_opt_white( &cur2 );
819               if (!parse_uint( &cur2, &index )) {
820                  report_error( ctx, "Expected literal integer" );
821                  return FALSE;
822               }
823               eat_opt_white( &cur2 );
824               if (*cur2 != ']') {
825                  report_error( ctx, "Expected `]'" );
826                  return FALSE;
827               }
828               cur2++;
829
830               decl.Semantic.Index = index;
831
832               cur = cur2;
833            }
834
835            decl.Declaration.Semantic = 1;
836            decl.Semantic.Name = i;
837
838            ctx->cur = cur;
839            break;
840         }
841      }
842   }
843
844   cur = ctx->cur;
845   eat_opt_white( &cur );
846   if (*cur == ',') {
847      uint i;
848
849      cur++;
850      eat_opt_white( &cur );
851      for (i = 0; i < TGSI_INTERPOLATE_COUNT; i++) {
852         if (str_match_no_case( &cur, interpolate_names[i] )) {
853            if (is_digit_alpha_underscore( cur ))
854               continue;
855            decl.Declaration.Interpolate = i;
856
857            ctx->cur = cur;
858            break;
859         }
860      }
861      if (i == TGSI_INTERPOLATE_COUNT) {
862         report_error( ctx, "Expected semantic or interpolate attribute" );
863         return FALSE;
864      }
865   }
866
867   advance = tgsi_build_full_declaration(
868      &decl,
869      ctx->tokens_cur,
870      ctx->header,
871      (uint) (ctx->tokens_end - ctx->tokens_cur) );
872   if (advance == 0)
873      return FALSE;
874   ctx->tokens_cur += advance;
875
876   return TRUE;
877}
878
879static boolean parse_immediate( struct translate_ctx *ctx )
880{
881   struct tgsi_full_immediate imm;
882   uint i;
883   float values[4];
884   uint advance;
885
886   if (!eat_white( &ctx->cur )) {
887      report_error( ctx, "Syntax error" );
888      return FALSE;
889   }
890   if (!str_match_no_case( &ctx->cur, "FLT32" ) || is_digit_alpha_underscore( ctx->cur )) {
891      report_error( ctx, "Expected `FLT32'" );
892      return FALSE;
893   }
894   eat_opt_white( &ctx->cur );
895   if (*ctx->cur != '{') {
896      report_error( ctx, "Expected `{'" );
897      return FALSE;
898   }
899   ctx->cur++;
900   for (i = 0; i < 4; i++) {
901      eat_opt_white( &ctx->cur );
902      if (i > 0) {
903         if (*ctx->cur != ',') {
904            report_error( ctx, "Expected `,'" );
905            return FALSE;
906         }
907         ctx->cur++;
908         eat_opt_white( &ctx->cur );
909      }
910      if (!parse_float( &ctx->cur, &values[i] )) {
911         report_error( ctx, "Expected literal floating point" );
912         return FALSE;
913      }
914   }
915   eat_opt_white( &ctx->cur );
916   if (*ctx->cur != '}') {
917      report_error( ctx, "Expected `}'" );
918      return FALSE;
919   }
920   ctx->cur++;
921
922   imm = tgsi_default_full_immediate();
923   imm.Immediate.NrTokens += 4;
924   imm.Immediate.DataType = TGSI_IMM_FLOAT32;
925   imm.u[0].Float = values[0];
926   imm.u[1].Float = values[1];
927   imm.u[2].Float = values[2];
928   imm.u[3].Float = values[3];
929
930   advance = tgsi_build_full_immediate(
931      &imm,
932      ctx->tokens_cur,
933      ctx->header,
934      (uint) (ctx->tokens_end - ctx->tokens_cur) );
935   if (advance == 0)
936      return FALSE;
937   ctx->tokens_cur += advance;
938
939   return TRUE;
940}
941
942static boolean translate( struct translate_ctx *ctx )
943{
944   eat_opt_white( &ctx->cur );
945   if (!parse_header( ctx ))
946      return FALSE;
947
948   while (*ctx->cur != '\0') {
949      uint label_val = 0;
950
951      if (!eat_white( &ctx->cur )) {
952         report_error( ctx, "Syntax error" );
953         return FALSE;
954      }
955
956      if (*ctx->cur == '\0')
957         break;
958
959      if (parse_label( ctx, &label_val )) {
960         if (!parse_instruction( ctx, TRUE ))
961            return FALSE;
962      }
963      else if (str_match_no_case( &ctx->cur, "DCL" )) {
964         if (!parse_declaration( ctx ))
965            return FALSE;
966      }
967      else if (str_match_no_case( &ctx->cur, "IMM" )) {
968         if (!parse_immediate( ctx ))
969            return FALSE;
970      }
971      else if (!parse_instruction( ctx, FALSE )) {
972         return FALSE;
973      }
974   }
975
976   return TRUE;
977}
978
979boolean
980tgsi_text_translate(
981   const char *text,
982   struct tgsi_token *tokens,
983   uint num_tokens )
984{
985   struct translate_ctx ctx;
986
987   ctx.text = text;
988   ctx.cur = text;
989   ctx.tokens = tokens;
990   ctx.tokens_cur = tokens;
991   ctx.tokens_end = tokens + num_tokens;
992
993   if (!translate( &ctx ))
994      return FALSE;
995
996   return tgsi_sanity_check( tokens );
997}
998