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