tgsi_text.c revision dcf8543ab375dd9c128d1ca772b1e587cebbdc7c
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 "util/u_prim.h"
31#include "pipe/p_defines.h"
32#include "pipe/p_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_util.h"
39
40static boolean is_alpha_underscore( const char *cur )
41{
42   return
43      (*cur >= 'a' && *cur <= 'z') ||
44      (*cur >= 'A' && *cur <= 'Z') ||
45      *cur == '_';
46}
47
48static boolean is_digit( const char *cur )
49{
50   return *cur >= '0' && *cur <= '9';
51}
52
53static boolean is_digit_alpha_underscore( const char *cur )
54{
55   return is_digit( cur ) || is_alpha_underscore( cur );
56}
57
58static boolean uprcase( char c )
59{
60   if (c >= 'a' && c <= 'z')
61      return c += 'A' - 'a';
62   return c;
63}
64
65/*
66 * Ignore case of str1 and assume str1 is already uppercase.
67 * Return TRUE iff str1 and str2 are equal.
68 */
69static int
70streq_nocase_uprcase(const char *str1,
71                     const char *str2)
72{
73   while (*str1 && *str2) {
74      if (*str1 != uprcase(*str2))
75         return FALSE;
76      str1++;
77      str2++;
78   }
79   return TRUE;
80}
81
82static boolean str_match_no_case( const char **pcur, const char *str )
83{
84   const char *cur = *pcur;
85
86   while (*str != '\0' && *str == uprcase( *cur )) {
87      str++;
88      cur++;
89   }
90   if (*str == '\0') {
91      *pcur = cur;
92      return TRUE;
93   }
94   return FALSE;
95}
96
97/* Eat zero or more whitespaces.
98 */
99static void eat_opt_white( const char **pcur )
100{
101   while (**pcur == ' ' || **pcur == '\t' || **pcur == '\n')
102      (*pcur)++;
103}
104
105/* Eat one or more whitespaces.
106 * Return TRUE if at least one whitespace eaten.
107 */
108static boolean eat_white( const char **pcur )
109{
110   const char *cur = *pcur;
111
112   eat_opt_white( pcur );
113   return *pcur > cur;
114}
115
116/* Parse unsigned integer.
117 * No checks for overflow.
118 */
119static boolean parse_uint( const char **pcur, uint *val )
120{
121   const char *cur = *pcur;
122
123   if (is_digit( cur )) {
124      *val = *cur++ - '0';
125      while (is_digit( cur ))
126         *val = *val * 10 + *cur++ - '0';
127      *pcur = cur;
128      return TRUE;
129   }
130   return FALSE;
131}
132
133static boolean parse_identifier( const char **pcur, char *ret )
134{
135   const char *cur = *pcur;
136   int i = 0;
137   if (is_alpha_underscore( cur )) {
138      ret[i++] = *cur++;
139      while (is_alpha_underscore( cur ))
140         ret[i++] = *cur++;
141      *pcur = cur;
142      return TRUE;
143   }
144   return FALSE;
145}
146
147/* Parse floating point.
148 */
149static boolean parse_float( const char **pcur, float *val )
150{
151   const char *cur = *pcur;
152   boolean integral_part = FALSE;
153   boolean fractional_part = FALSE;
154
155   *val = (float) atof( cur );
156
157   if (*cur == '-' || *cur == '+')
158      cur++;
159   if (is_digit( cur )) {
160      cur++;
161      integral_part = TRUE;
162      while (is_digit( cur ))
163         cur++;
164   }
165   if (*cur == '.') {
166      cur++;
167      if (is_digit( cur )) {
168         cur++;
169         fractional_part = TRUE;
170         while (is_digit( cur ))
171            cur++;
172      }
173   }
174   if (!integral_part && !fractional_part)
175      return FALSE;
176   if (uprcase( *cur ) == 'E') {
177      cur++;
178      if (*cur == '-' || *cur == '+')
179         cur++;
180      if (is_digit( cur )) {
181         cur++;
182         while (is_digit( cur ))
183            cur++;
184      }
185      else
186         return FALSE;
187   }
188   *pcur = cur;
189   return TRUE;
190}
191
192struct translate_ctx
193{
194   const char *text;
195   const char *cur;
196   struct tgsi_token *tokens;
197   struct tgsi_token *tokens_cur;
198   struct tgsi_token *tokens_end;
199   struct tgsi_header *header;
200   unsigned processor : 4;
201   int implied_array_size : 5;
202};
203
204static void report_error( struct translate_ctx *ctx, const char *msg )
205{
206   int line = 1;
207   int column = 1;
208   const char *itr = ctx->text;
209
210   while (itr != ctx->cur) {
211      if (*itr == '\n') {
212         column = 1;
213         ++line;
214      }
215      ++column;
216      ++itr;
217   }
218
219   debug_printf( "\nTGSI asm error: %s [%d : %d] \n", msg, line, column );
220}
221
222/* Parse shader header.
223 * Return TRUE for one of the following headers.
224 *    FRAG
225 *    GEOM
226 *    VERT
227 */
228static boolean parse_header( struct translate_ctx *ctx )
229{
230   uint processor;
231
232   if (str_match_no_case( &ctx->cur, "FRAG" ))
233      processor = TGSI_PROCESSOR_FRAGMENT;
234   else if (str_match_no_case( &ctx->cur, "VERT" ))
235      processor = TGSI_PROCESSOR_VERTEX;
236   else if (str_match_no_case( &ctx->cur, "GEOM" ))
237      processor = TGSI_PROCESSOR_GEOMETRY;
238   else {
239      report_error( ctx, "Unknown header" );
240      return FALSE;
241   }
242
243   if (ctx->tokens_cur >= ctx->tokens_end)
244      return FALSE;
245   ctx->header = (struct tgsi_header *) ctx->tokens_cur++;
246   *ctx->header = tgsi_build_header();
247
248   if (ctx->tokens_cur >= ctx->tokens_end)
249      return FALSE;
250   *(struct tgsi_processor *) ctx->tokens_cur++ = tgsi_build_processor( processor, ctx->header );
251   ctx->processor = processor;
252
253   return TRUE;
254}
255
256static boolean parse_label( struct translate_ctx *ctx, uint *val )
257{
258   const char *cur = ctx->cur;
259
260   if (parse_uint( &cur, val )) {
261      eat_opt_white( &cur );
262      if (*cur == ':') {
263         cur++;
264         ctx->cur = cur;
265         return TRUE;
266      }
267   }
268   return FALSE;
269}
270
271static const char *file_names[TGSI_FILE_COUNT] =
272{
273   "NULL",
274   "CONST",
275   "IN",
276   "OUT",
277   "TEMP",
278   "SAMP",
279   "ADDR",
280   "IMM",
281   "LOOP",
282   "PRED",
283   "SV"
284};
285
286static boolean
287parse_file( const char **pcur, uint *file )
288{
289   uint i;
290
291   for (i = 0; i < TGSI_FILE_COUNT; i++) {
292      const char *cur = *pcur;
293
294      if (str_match_no_case( &cur, file_names[i] )) {
295         if (!is_digit_alpha_underscore( cur )) {
296            *pcur = cur;
297            *file = i;
298            return TRUE;
299         }
300      }
301   }
302   return FALSE;
303}
304
305static boolean
306parse_opt_writemask(
307   struct translate_ctx *ctx,
308   uint *writemask )
309{
310   const char *cur;
311
312   cur = ctx->cur;
313   eat_opt_white( &cur );
314   if (*cur == '.') {
315      cur++;
316      *writemask = TGSI_WRITEMASK_NONE;
317      eat_opt_white( &cur );
318      if (uprcase( *cur ) == 'X') {
319         cur++;
320         *writemask |= TGSI_WRITEMASK_X;
321      }
322      if (uprcase( *cur ) == 'Y') {
323         cur++;
324         *writemask |= TGSI_WRITEMASK_Y;
325      }
326      if (uprcase( *cur ) == 'Z') {
327         cur++;
328         *writemask |= TGSI_WRITEMASK_Z;
329      }
330      if (uprcase( *cur ) == 'W') {
331         cur++;
332         *writemask |= TGSI_WRITEMASK_W;
333      }
334
335      if (*writemask == TGSI_WRITEMASK_NONE) {
336         report_error( ctx, "Writemask expected" );
337         return FALSE;
338      }
339
340      ctx->cur = cur;
341   }
342   else {
343      *writemask = TGSI_WRITEMASK_XYZW;
344   }
345   return TRUE;
346}
347
348static boolean
349parse_register_dst( struct translate_ctx *ctx,
350                    uint *file,
351                    int *index );
352
353struct parsed_src_bracket {
354   int index;
355
356   uint ind_file;
357   int ind_index;
358   uint ind_comp;
359};
360
361
362static boolean
363parse_register_src_bracket(
364   struct translate_ctx *ctx,
365   struct parsed_src_bracket *brackets)
366{
367   const char *cur;
368   uint uindex;
369
370   memset(brackets, 0, sizeof(struct parsed_src_bracket));
371
372   eat_opt_white( &ctx->cur );
373
374   cur = ctx->cur;
375   if (parse_file( &cur, &brackets->ind_file )) {
376      if (!parse_register_dst( ctx, &brackets->ind_file,
377                               &brackets->ind_index ))
378         return FALSE;
379      eat_opt_white( &ctx->cur );
380
381      if (*ctx->cur == '.') {
382         ctx->cur++;
383         eat_opt_white(&ctx->cur);
384
385         switch (uprcase(*ctx->cur)) {
386         case 'X':
387            brackets->ind_comp = TGSI_SWIZZLE_X;
388            break;
389         case 'Y':
390            brackets->ind_comp = TGSI_SWIZZLE_Y;
391            break;
392         case 'Z':
393            brackets->ind_comp = TGSI_SWIZZLE_Z;
394            break;
395         case 'W':
396            brackets->ind_comp = TGSI_SWIZZLE_W;
397            break;
398         default:
399            report_error(ctx, "Expected indirect register swizzle component `x', `y', `z' or `w'");
400            return FALSE;
401         }
402         ctx->cur++;
403         eat_opt_white(&ctx->cur);
404      }
405
406      if (*ctx->cur == '+' || *ctx->cur == '-') {
407         boolean negate;
408
409         negate = *ctx->cur == '-';
410         ctx->cur++;
411         eat_opt_white( &ctx->cur );
412         if (!parse_uint( &ctx->cur, &uindex )) {
413            report_error( ctx, "Expected literal unsigned integer" );
414            return FALSE;
415         }
416         if (negate)
417            brackets->index = -(int) uindex;
418         else
419            brackets->index = (int) uindex;
420      }
421      else {
422         brackets->index = 0;
423      }
424   }
425   else {
426      if (!parse_uint( &ctx->cur, &uindex )) {
427         report_error( ctx, "Expected literal unsigned integer" );
428         return FALSE;
429      }
430      brackets->index = (int) uindex;
431      brackets->ind_file = TGSI_FILE_NULL;
432      brackets->ind_index = 0;
433   }
434   eat_opt_white( &ctx->cur );
435   if (*ctx->cur != ']') {
436      report_error( ctx, "Expected `]'" );
437      return FALSE;
438   }
439   ctx->cur++;
440   return TRUE;
441}
442
443static boolean
444parse_opt_register_src_bracket(
445   struct translate_ctx *ctx,
446   struct parsed_src_bracket *brackets,
447   int *parsed_brackets)
448{
449   const char *cur = ctx->cur;
450
451   *parsed_brackets = 0;
452
453   eat_opt_white( &cur );
454   if (cur[0] == '[') {
455      ++cur;
456      ctx->cur = cur;
457
458      if (!parse_register_src_bracket(ctx, brackets))
459         return FALSE;
460
461      *parsed_brackets = 1;
462   }
463
464   return TRUE;
465}
466
467/* <register_file_bracket> ::= <file> `['
468 */
469static boolean
470parse_register_file_bracket(
471   struct translate_ctx *ctx,
472   uint *file )
473{
474   if (!parse_file( &ctx->cur, file )) {
475      report_error( ctx, "Unknown register file" );
476      return FALSE;
477   }
478   eat_opt_white( &ctx->cur );
479   if (*ctx->cur != '[') {
480      report_error( ctx, "Expected `['" );
481      return FALSE;
482   }
483   ctx->cur++;
484   return TRUE;
485}
486
487/* <register_file_bracket_index> ::= <register_file_bracket> <uint>
488 */
489static boolean
490parse_register_file_bracket_index(
491   struct translate_ctx *ctx,
492   uint *file,
493   int *index )
494{
495   uint uindex;
496
497   if (!parse_register_file_bracket( ctx, file ))
498      return FALSE;
499   eat_opt_white( &ctx->cur );
500   if (!parse_uint( &ctx->cur, &uindex )) {
501      report_error( ctx, "Expected literal unsigned integer" );
502      return FALSE;
503   }
504   *index = (int) uindex;
505   return TRUE;
506}
507
508/* Parse source register operand.
509 *    <register_src> ::= <register_file_bracket_index> `]' |
510 *                       <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `]' |
511 *                       <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `+' <uint> `]' |
512 *                       <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `-' <uint> `]'
513 */
514static boolean
515parse_register_src(
516   struct translate_ctx *ctx,
517   uint *file,
518   struct parsed_src_bracket *brackets)
519{
520
521   brackets->ind_comp = TGSI_SWIZZLE_X;
522   if (!parse_register_file_bracket( ctx, file ))
523      return FALSE;
524   if (!parse_register_src_bracket( ctx, brackets ))
525       return FALSE;
526
527   return TRUE;
528}
529
530struct parsed_dcl_bracket {
531   uint first;
532   uint last;
533};
534
535static boolean
536parse_register_dcl_bracket(
537   struct translate_ctx *ctx,
538   struct parsed_dcl_bracket *bracket)
539{
540   uint uindex;
541   memset(bracket, 0, sizeof(struct parsed_dcl_bracket));
542
543   eat_opt_white( &ctx->cur );
544
545   if (!parse_uint( &ctx->cur, &uindex )) {
546      /* it can be an empty bracket [] which means its range
547       * is from 0 to some implied size */
548      if (ctx->cur[0] == ']' && ctx->implied_array_size != 0) {
549         bracket->first = 0;
550         bracket->last = ctx->implied_array_size - 1;
551         goto cleanup;
552      }
553      report_error( ctx, "Expected literal unsigned integer" );
554      return FALSE;
555   }
556   bracket->first = uindex;
557
558   eat_opt_white( &ctx->cur );
559
560   if (ctx->cur[0] == '.' && ctx->cur[1] == '.') {
561      uint uindex;
562
563      ctx->cur += 2;
564      eat_opt_white( &ctx->cur );
565      if (!parse_uint( &ctx->cur, &uindex )) {
566         report_error( ctx, "Expected literal integer" );
567         return FALSE;
568      }
569      bracket->last = (int) uindex;
570      eat_opt_white( &ctx->cur );
571   }
572   else {
573      bracket->last = bracket->first;
574   }
575
576cleanup:
577   if (*ctx->cur != ']') {
578      report_error( ctx, "Expected `]' or `..'" );
579      return FALSE;
580   }
581   ctx->cur++;
582   return TRUE;
583}
584
585/* Parse register declaration.
586 *    <register_dcl> ::= <register_file_bracket_index> `]' |
587 *                       <register_file_bracket_index> `..' <index> `]'
588 */
589static boolean
590parse_register_dcl(
591   struct translate_ctx *ctx,
592   uint *file,
593   struct parsed_dcl_bracket *brackets,
594   int *num_brackets)
595{
596   const char *cur;
597
598   *num_brackets = 0;
599
600   if (!parse_register_file_bracket( ctx, file ))
601      return FALSE;
602   if (!parse_register_dcl_bracket( ctx, &brackets[0] ))
603      return FALSE;
604
605   *num_brackets = 1;
606
607   cur = ctx->cur;
608   eat_opt_white( &cur );
609
610   if (cur[0] == '[') {
611      ++cur;
612      ctx->cur = cur;
613      if (!parse_register_dcl_bracket( ctx, &brackets[1] ))
614         return FALSE;
615      /* for geometry shader we don't really care about
616       * the first brackets it's always the size of the
617       * input primitive. so we want to declare just
618       * the index relevant to the semantics which is in
619       * the second bracket */
620      if (ctx->processor == TGSI_PROCESSOR_GEOMETRY && *file == TGSI_FILE_INPUT) {
621         brackets[0] = brackets[1];
622         *num_brackets = 1;
623      } else {
624         *num_brackets = 2;
625      }
626   }
627
628   return TRUE;
629}
630
631
632/* Parse destination register operand.
633 *    <register_dst> ::= <register_file_bracket_index> `]'
634 */
635static boolean
636parse_register_dst(
637   struct translate_ctx *ctx,
638   uint *file,
639   int *index )
640{
641   if (!parse_register_file_bracket_index( ctx, file, index ))
642      return FALSE;
643   eat_opt_white( &ctx->cur );
644   if (*ctx->cur != ']') {
645      report_error( ctx, "Expected `]'" );
646      return FALSE;
647   }
648   ctx->cur++;
649   return TRUE;
650}
651
652static boolean
653parse_dst_operand(
654   struct translate_ctx *ctx,
655   struct tgsi_full_dst_register *dst )
656{
657   uint file;
658   int index;
659   uint writemask;
660   const char *cur;
661
662   if (!parse_register_dst( ctx, &file, &index ))
663      return FALSE;
664
665   cur = ctx->cur;
666   eat_opt_white( &cur );
667
668   if (!parse_opt_writemask( ctx, &writemask ))
669      return FALSE;
670
671   dst->Register.File = file;
672   dst->Register.Index = index;
673   dst->Register.WriteMask = writemask;
674   return TRUE;
675}
676
677static boolean
678parse_optional_swizzle(
679   struct translate_ctx *ctx,
680   uint swizzle[4],
681   boolean *parsed_swizzle )
682{
683   const char *cur = ctx->cur;
684
685   *parsed_swizzle = FALSE;
686
687   eat_opt_white( &cur );
688   if (*cur == '.') {
689      uint i;
690
691      cur++;
692      eat_opt_white( &cur );
693      for (i = 0; i < 4; i++) {
694         if (uprcase( *cur ) == 'X')
695            swizzle[i] = TGSI_SWIZZLE_X;
696         else if (uprcase( *cur ) == 'Y')
697            swizzle[i] = TGSI_SWIZZLE_Y;
698         else if (uprcase( *cur ) == 'Z')
699            swizzle[i] = TGSI_SWIZZLE_Z;
700         else if (uprcase( *cur ) == 'W')
701            swizzle[i] = TGSI_SWIZZLE_W;
702         else {
703	    report_error( ctx, "Expected register swizzle component `x', `y', `z', `w', `0' or `1'" );
704	    return FALSE;
705         }
706         cur++;
707      }
708      *parsed_swizzle = TRUE;
709      ctx->cur = cur;
710   }
711   return TRUE;
712}
713
714static boolean
715parse_src_operand(
716   struct translate_ctx *ctx,
717   struct tgsi_full_src_register *src )
718{
719   uint file;
720   uint swizzle[4];
721   boolean parsed_swizzle;
722   struct parsed_src_bracket bracket[2];
723   int parsed_opt_brackets;
724
725   if (*ctx->cur == '-') {
726      ctx->cur++;
727      eat_opt_white( &ctx->cur );
728      src->Register.Negate = 1;
729   }
730
731   if (*ctx->cur == '|') {
732      ctx->cur++;
733      eat_opt_white( &ctx->cur );
734      src->Register.Absolute = 1;
735   }
736
737   if (!parse_register_src(ctx, &file, &bracket[0]))
738      return FALSE;
739   if (!parse_opt_register_src_bracket(ctx, &bracket[1], &parsed_opt_brackets))
740      return FALSE;
741
742   src->Register.File = file;
743   if (parsed_opt_brackets) {
744      src->Register.Dimension = 1;
745      src->Dimension.Indirect = 0;
746      src->Dimension.Dimension = 0;
747      src->Dimension.Index = bracket[0].index;
748      bracket[0] = bracket[1];
749   }
750   src->Register.Index = bracket[0].index;
751   if (bracket[0].ind_file != TGSI_FILE_NULL) {
752      src->Register.Indirect = 1;
753      src->Indirect.File = bracket[0].ind_file;
754      src->Indirect.Index = bracket[0].ind_index;
755      src->Indirect.SwizzleX = bracket[0].ind_comp;
756      src->Indirect.SwizzleY = bracket[0].ind_comp;
757      src->Indirect.SwizzleZ = bracket[0].ind_comp;
758      src->Indirect.SwizzleW = bracket[0].ind_comp;
759   }
760
761   /* Parse optional swizzle.
762    */
763   if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle )) {
764      if (parsed_swizzle) {
765         src->Register.SwizzleX = swizzle[0];
766         src->Register.SwizzleY = swizzle[1];
767         src->Register.SwizzleZ = swizzle[2];
768         src->Register.SwizzleW = swizzle[3];
769      }
770   }
771
772   if (src->Register.Absolute) {
773      eat_opt_white( &ctx->cur );
774      if (*ctx->cur != '|') {
775         report_error( ctx, "Expected `|'" );
776         return FALSE;
777      }
778      ctx->cur++;
779   }
780
781
782   return TRUE;
783}
784
785static const char *texture_names[TGSI_TEXTURE_COUNT] =
786{
787   "UNKNOWN",
788   "1D",
789   "2D",
790   "3D",
791   "CUBE",
792   "RECT",
793   "SHADOW1D",
794   "SHADOW2D",
795   "SHADOWRECT"
796};
797
798static boolean
799match_inst_mnemonic(const char **pcur,
800                    const struct tgsi_opcode_info *info)
801{
802   if (str_match_no_case(pcur, info->mnemonic)) {
803      return TRUE;
804   }
805   return FALSE;
806}
807
808static boolean
809parse_instruction(
810   struct translate_ctx *ctx,
811   boolean has_label )
812{
813   uint i;
814   uint saturate = TGSI_SAT_NONE;
815   const struct tgsi_opcode_info *info;
816   struct tgsi_full_instruction inst;
817   uint advance;
818
819   /* Parse instruction name.
820    */
821   eat_opt_white( &ctx->cur );
822   for (i = 0; i < TGSI_OPCODE_LAST; i++) {
823      const char *cur = ctx->cur;
824
825      info = tgsi_get_opcode_info( i );
826      if (match_inst_mnemonic(&cur, info)) {
827         if (str_match_no_case( &cur, "_SATNV" ))
828            saturate = TGSI_SAT_MINUS_PLUS_ONE;
829         else if (str_match_no_case( &cur, "_SAT" ))
830            saturate = TGSI_SAT_ZERO_ONE;
831
832         if (info->num_dst + info->num_src + info->is_tex == 0) {
833            if (!is_digit_alpha_underscore( cur )) {
834               ctx->cur = cur;
835               break;
836            }
837         }
838         else if (*cur == '\0' || eat_white( &cur )) {
839            ctx->cur = cur;
840            break;
841         }
842      }
843   }
844   if (i == TGSI_OPCODE_LAST) {
845      if (has_label)
846         report_error( ctx, "Unknown opcode" );
847      else
848         report_error( ctx, "Expected `DCL', `IMM' or a label" );
849      return FALSE;
850   }
851
852   inst = tgsi_default_full_instruction();
853   inst.Instruction.Opcode = i;
854   inst.Instruction.Saturate = saturate;
855   inst.Instruction.NumDstRegs = info->num_dst;
856   inst.Instruction.NumSrcRegs = info->num_src;
857
858   /* Parse instruction operands.
859    */
860   for (i = 0; i < info->num_dst + info->num_src + info->is_tex; i++) {
861      if (i > 0) {
862         eat_opt_white( &ctx->cur );
863         if (*ctx->cur != ',') {
864            report_error( ctx, "Expected `,'" );
865            return FALSE;
866         }
867         ctx->cur++;
868         eat_opt_white( &ctx->cur );
869      }
870
871      if (i < info->num_dst) {
872         if (!parse_dst_operand( ctx, &inst.Dst[i] ))
873            return FALSE;
874      }
875      else if (i < info->num_dst + info->num_src) {
876         if (!parse_src_operand( ctx, &inst.Src[i - info->num_dst] ))
877            return FALSE;
878      }
879      else {
880         uint j;
881
882         for (j = 0; j < TGSI_TEXTURE_COUNT; j++) {
883            if (str_match_no_case( &ctx->cur, texture_names[j] )) {
884               if (!is_digit_alpha_underscore( ctx->cur )) {
885                  inst.Instruction.Texture = 1;
886                  inst.Texture.Texture = j;
887                  break;
888               }
889            }
890         }
891         if (j == TGSI_TEXTURE_COUNT) {
892            report_error( ctx, "Expected texture target" );
893            return FALSE;
894         }
895      }
896   }
897
898   if (info->is_branch) {
899      uint target;
900
901      eat_opt_white( &ctx->cur );
902      if (*ctx->cur != ':') {
903         report_error( ctx, "Expected `:'" );
904         return FALSE;
905      }
906      ctx->cur++;
907      eat_opt_white( &ctx->cur );
908      if (!parse_uint( &ctx->cur, &target )) {
909         report_error( ctx, "Expected a label" );
910         return FALSE;
911      }
912      inst.Instruction.Label = 1;
913      inst.Label.Label = target;
914   }
915
916   advance = tgsi_build_full_instruction(
917      &inst,
918      ctx->tokens_cur,
919      ctx->header,
920      (uint) (ctx->tokens_end - ctx->tokens_cur) );
921   if (advance == 0)
922      return FALSE;
923   ctx->tokens_cur += advance;
924
925   return TRUE;
926}
927
928static const char *semantic_names[TGSI_SEMANTIC_COUNT] =
929{
930   "POSITION",
931   "COLOR",
932   "BCOLOR",
933   "FOG",
934   "PSIZE",
935   "GENERIC",
936   "NORMAL",
937   "FACE",
938   "EDGEFLAG",
939   "PRIM_ID",
940   "INSTANCEID"
941};
942
943static const char *interpolate_names[TGSI_INTERPOLATE_COUNT] =
944{
945   "CONSTANT",
946   "LINEAR",
947   "PERSPECTIVE"
948};
949
950static boolean parse_declaration( struct translate_ctx *ctx )
951{
952   struct tgsi_full_declaration decl;
953   uint file;
954   struct parsed_dcl_bracket brackets[2];
955   int num_brackets;
956   uint writemask;
957   const char *cur;
958   uint advance;
959
960   assert(Elements(semantic_names) == TGSI_SEMANTIC_COUNT);
961   assert(Elements(interpolate_names) == TGSI_INTERPOLATE_COUNT);
962
963   if (!eat_white( &ctx->cur )) {
964      report_error( ctx, "Syntax error" );
965      return FALSE;
966   }
967   if (!parse_register_dcl( ctx, &file, brackets, &num_brackets))
968      return FALSE;
969   if (!parse_opt_writemask( ctx, &writemask ))
970      return FALSE;
971
972   decl = tgsi_default_full_declaration();
973   decl.Declaration.File = file;
974   decl.Declaration.UsageMask = writemask;
975
976   if (num_brackets == 1) {
977      decl.Range.First = brackets[0].first;
978      decl.Range.Last = brackets[0].last;
979   } else {
980      decl.Range.First = brackets[1].first;
981      decl.Range.Last = brackets[1].last;
982
983      decl.Declaration.Dimension = 1;
984      decl.Dim.Index2D = brackets[0].first;
985   }
986
987   cur = ctx->cur;
988   eat_opt_white( &cur );
989   if (*cur == ',') {
990      uint i;
991
992      cur++;
993      eat_opt_white( &cur );
994      for (i = 0; i < TGSI_SEMANTIC_COUNT; i++) {
995         if (str_match_no_case( &cur, semantic_names[i] )) {
996            const char *cur2 = cur;
997            uint index;
998
999            if (is_digit_alpha_underscore( cur ))
1000               continue;
1001            eat_opt_white( &cur2 );
1002            if (*cur2 == '[') {
1003               cur2++;
1004               eat_opt_white( &cur2 );
1005               if (!parse_uint( &cur2, &index )) {
1006                  report_error( ctx, "Expected literal integer" );
1007                  return FALSE;
1008               }
1009               eat_opt_white( &cur2 );
1010               if (*cur2 != ']') {
1011                  report_error( ctx, "Expected `]'" );
1012                  return FALSE;
1013               }
1014               cur2++;
1015
1016               decl.Semantic.Index = index;
1017
1018               cur = cur2;
1019            }
1020
1021            decl.Declaration.Semantic = 1;
1022            decl.Semantic.Name = i;
1023
1024            ctx->cur = cur;
1025            break;
1026         }
1027      }
1028   }
1029
1030   cur = ctx->cur;
1031   eat_opt_white( &cur );
1032   if (*cur == ',') {
1033      uint i;
1034
1035      cur++;
1036      eat_opt_white( &cur );
1037      for (i = 0; i < TGSI_INTERPOLATE_COUNT; i++) {
1038         if (str_match_no_case( &cur, interpolate_names[i] )) {
1039            if (is_digit_alpha_underscore( cur ))
1040               continue;
1041            decl.Declaration.Interpolate = i;
1042
1043            ctx->cur = cur;
1044            break;
1045         }
1046      }
1047      if (i == TGSI_INTERPOLATE_COUNT) {
1048         report_error( ctx, "Expected semantic or interpolate attribute" );
1049         return FALSE;
1050      }
1051   }
1052
1053   advance = tgsi_build_full_declaration(
1054      &decl,
1055      ctx->tokens_cur,
1056      ctx->header,
1057      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1058   if (advance == 0)
1059      return FALSE;
1060   ctx->tokens_cur += advance;
1061
1062   return TRUE;
1063}
1064
1065static boolean parse_immediate( struct translate_ctx *ctx )
1066{
1067   struct tgsi_full_immediate imm;
1068   uint i;
1069   float values[4];
1070   uint advance;
1071
1072   if (!eat_white( &ctx->cur )) {
1073      report_error( ctx, "Syntax error" );
1074      return FALSE;
1075   }
1076   if (!str_match_no_case( &ctx->cur, "FLT32" ) || is_digit_alpha_underscore( ctx->cur )) {
1077      report_error( ctx, "Expected `FLT32'" );
1078      return FALSE;
1079   }
1080   eat_opt_white( &ctx->cur );
1081   if (*ctx->cur != '{') {
1082      report_error( ctx, "Expected `{'" );
1083      return FALSE;
1084   }
1085   ctx->cur++;
1086   for (i = 0; i < 4; i++) {
1087      eat_opt_white( &ctx->cur );
1088      if (i > 0) {
1089         if (*ctx->cur != ',') {
1090            report_error( ctx, "Expected `,'" );
1091            return FALSE;
1092         }
1093         ctx->cur++;
1094         eat_opt_white( &ctx->cur );
1095      }
1096      if (!parse_float( &ctx->cur, &values[i] )) {
1097         report_error( ctx, "Expected literal floating point" );
1098         return FALSE;
1099      }
1100   }
1101   eat_opt_white( &ctx->cur );
1102   if (*ctx->cur != '}') {
1103      report_error( ctx, "Expected `}'" );
1104      return FALSE;
1105   }
1106   ctx->cur++;
1107
1108   imm = tgsi_default_full_immediate();
1109   imm.Immediate.NrTokens += 4;
1110   imm.Immediate.DataType = TGSI_IMM_FLOAT32;
1111   imm.u[0].Float = values[0];
1112   imm.u[1].Float = values[1];
1113   imm.u[2].Float = values[2];
1114   imm.u[3].Float = values[3];
1115
1116   advance = tgsi_build_full_immediate(
1117      &imm,
1118      ctx->tokens_cur,
1119      ctx->header,
1120      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1121   if (advance == 0)
1122      return FALSE;
1123   ctx->tokens_cur += advance;
1124
1125   return TRUE;
1126}
1127
1128static const char *property_names[] =
1129{
1130   "GS_INPUT_PRIMITIVE",
1131   "GS_OUTPUT_PRIMITIVE",
1132   "GS_MAX_OUTPUT_VERTICES"
1133};
1134
1135static const char *primitive_names[] =
1136{
1137   "POINTS",
1138   "LINES",
1139   "LINE_LOOP",
1140   "LINE_STRIP",
1141   "TRIANGLES",
1142   "TRIANGLE_STRIP",
1143   "TRIANGLE_FAN",
1144   "QUADS",
1145   "QUAD_STRIP",
1146   "POLYGON"
1147};
1148
1149static boolean
1150parse_primitive( const char **pcur, uint *primitive )
1151{
1152   uint i;
1153
1154   for (i = 0; i < PIPE_PRIM_MAX; i++) {
1155      const char *cur = *pcur;
1156
1157      if (str_match_no_case( &cur, primitive_names[i])) {
1158         *primitive = i;
1159         *pcur = cur;
1160         return TRUE;
1161      }
1162   }
1163   return FALSE;
1164}
1165
1166
1167static boolean parse_property( struct translate_ctx *ctx )
1168{
1169   struct tgsi_full_property prop;
1170   uint property_name;
1171   uint values[8];
1172   uint advance;
1173   char id[64];
1174
1175   if (!eat_white( &ctx->cur )) {
1176      report_error( ctx, "Syntax error" );
1177      return FALSE;
1178   }
1179   if (!parse_identifier( &ctx->cur, id )) {
1180      report_error( ctx, "Syntax error" );
1181      return FALSE;
1182   }
1183   for (property_name = 0; property_name < TGSI_PROPERTY_COUNT;
1184        ++property_name) {
1185      if (streq_nocase_uprcase(property_names[property_name], id)) {
1186         break;
1187      }
1188   }
1189   if (property_name >= TGSI_PROPERTY_COUNT) {
1190      debug_printf( "\nError: Unknown property : '%s'", id );
1191      return FALSE;
1192   }
1193
1194   eat_opt_white( &ctx->cur );
1195   switch(property_name) {
1196   case TGSI_PROPERTY_GS_INPUT_PRIM:
1197   case TGSI_PROPERTY_GS_OUTPUT_PRIM:
1198      if (!parse_primitive(&ctx->cur, &values[0] )) {
1199         report_error( ctx, "Unknown primitive name as property!" );
1200         return FALSE;
1201      }
1202      if (property_name == TGSI_PROPERTY_GS_INPUT_PRIM &&
1203          ctx->processor == TGSI_PROCESSOR_GEOMETRY) {
1204         ctx->implied_array_size = u_vertices_per_prim(values[0]);
1205      }
1206      break;
1207   default:
1208      if (!parse_uint(&ctx->cur, &values[0] )) {
1209         report_error( ctx, "Expected unsigned integer as property!" );
1210         return FALSE;
1211      }
1212   }
1213
1214   prop = tgsi_default_full_property();
1215   prop.Property.PropertyName = property_name;
1216   prop.Property.NrTokens += 1;
1217   prop.u[0].Data = values[0];
1218
1219   advance = tgsi_build_full_property(
1220      &prop,
1221      ctx->tokens_cur,
1222      ctx->header,
1223      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1224   if (advance == 0)
1225      return FALSE;
1226   ctx->tokens_cur += advance;
1227
1228   return TRUE;
1229}
1230
1231
1232static boolean translate( struct translate_ctx *ctx )
1233{
1234   eat_opt_white( &ctx->cur );
1235   if (!parse_header( ctx ))
1236      return FALSE;
1237
1238   while (*ctx->cur != '\0') {
1239      uint label_val = 0;
1240      if (!eat_white( &ctx->cur )) {
1241         report_error( ctx, "Syntax error" );
1242         return FALSE;
1243      }
1244
1245      if (*ctx->cur == '\0')
1246         break;
1247      if (parse_label( ctx, &label_val )) {
1248         if (!parse_instruction( ctx, TRUE ))
1249            return FALSE;
1250      }
1251      else if (str_match_no_case( &ctx->cur, "DCL" )) {
1252         if (!parse_declaration( ctx ))
1253            return FALSE;
1254      }
1255      else if (str_match_no_case( &ctx->cur, "IMM" )) {
1256         if (!parse_immediate( ctx ))
1257            return FALSE;
1258      }
1259      else if (str_match_no_case( &ctx->cur, "PROPERTY" )) {
1260         if (!parse_property( ctx ))
1261            return FALSE;
1262      }
1263      else if (!parse_instruction( ctx, FALSE )) {
1264         return FALSE;
1265      }
1266   }
1267
1268   return TRUE;
1269}
1270
1271boolean
1272tgsi_text_translate(
1273   const char *text,
1274   struct tgsi_token *tokens,
1275   uint num_tokens )
1276{
1277   struct translate_ctx ctx;
1278
1279   ctx.text = text;
1280   ctx.cur = text;
1281   ctx.tokens = tokens;
1282   ctx.tokens_cur = tokens;
1283   ctx.tokens_end = tokens + num_tokens;
1284
1285   if (!translate( &ctx ))
1286      return FALSE;
1287
1288   return tgsi_sanity_check( tokens );
1289}
1290