Merge branch 'mesa_7_5_branch'
[mesa.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 "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
37 static boolean is_alpha_underscore( const char *cur )
38 {
39 return
40 (*cur >= 'a' && *cur <= 'z') ||
41 (*cur >= 'A' && *cur <= 'Z') ||
42 *cur == '_';
43 }
44
45 static boolean is_digit( const char *cur )
46 {
47 return *cur >= '0' && *cur <= '9';
48 }
49
50 static boolean is_digit_alpha_underscore( const char *cur )
51 {
52 return is_digit( cur ) || is_alpha_underscore( cur );
53 }
54
55 static boolean uprcase( char c )
56 {
57 if (c >= 'a' && c <= 'z')
58 return c += 'A' - 'a';
59 return c;
60 }
61
62 static 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 */
79 static 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 */
88 static 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 */
99 static 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 */
115 static 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
158 struct 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
168 static 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 * FRAG1.1
176 * GEOM1.1
177 * VERT1.1
178 */
179 static boolean parse_header( struct translate_ctx *ctx )
180 {
181 uint processor;
182
183 if (str_match_no_case( &ctx->cur, "FRAG1.1" ))
184 processor = TGSI_PROCESSOR_FRAGMENT;
185 else if (str_match_no_case( &ctx->cur, "VERT1.1" ))
186 processor = TGSI_PROCESSOR_VERTEX;
187 else if (str_match_no_case( &ctx->cur, "GEOM1.1" ))
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 *(struct tgsi_version *) ctx->tokens_cur++ = tgsi_build_version();
197
198 if (ctx->tokens_cur >= ctx->tokens_end)
199 return FALSE;
200 ctx->header = (struct tgsi_header *) ctx->tokens_cur++;
201 *ctx->header = tgsi_build_header();
202
203 if (ctx->tokens_cur >= ctx->tokens_end)
204 return FALSE;
205 *(struct tgsi_processor *) ctx->tokens_cur++ = tgsi_build_processor( processor, ctx->header );
206
207 return TRUE;
208 }
209
210 static boolean parse_label( struct translate_ctx *ctx, uint *val )
211 {
212 const char *cur = ctx->cur;
213
214 if (parse_uint( &cur, val )) {
215 eat_opt_white( &cur );
216 if (*cur == ':') {
217 cur++;
218 ctx->cur = cur;
219 return TRUE;
220 }
221 }
222 return FALSE;
223 }
224
225 static const char *file_names[TGSI_FILE_COUNT] =
226 {
227 "NULL",
228 "CONST",
229 "IN",
230 "OUT",
231 "TEMP",
232 "SAMP",
233 "ADDR",
234 "IMM"
235 };
236
237 static boolean
238 parse_file( const char **pcur, uint *file )
239 {
240 uint i;
241
242 for (i = 0; i < TGSI_FILE_COUNT; i++) {
243 const char *cur = *pcur;
244
245 if (str_match_no_case( &cur, file_names[i] )) {
246 if (!is_digit_alpha_underscore( cur )) {
247 *pcur = cur;
248 *file = i;
249 return TRUE;
250 }
251 }
252 }
253 return FALSE;
254 }
255
256 static boolean
257 parse_opt_writemask(
258 struct translate_ctx *ctx,
259 uint *writemask )
260 {
261 const char *cur;
262
263 cur = ctx->cur;
264 eat_opt_white( &cur );
265 if (*cur == '.') {
266 cur++;
267 *writemask = TGSI_WRITEMASK_NONE;
268 eat_opt_white( &cur );
269 if (uprcase( *cur ) == 'X') {
270 cur++;
271 *writemask |= TGSI_WRITEMASK_X;
272 }
273 if (uprcase( *cur ) == 'Y') {
274 cur++;
275 *writemask |= TGSI_WRITEMASK_Y;
276 }
277 if (uprcase( *cur ) == 'Z') {
278 cur++;
279 *writemask |= TGSI_WRITEMASK_Z;
280 }
281 if (uprcase( *cur ) == 'W') {
282 cur++;
283 *writemask |= TGSI_WRITEMASK_W;
284 }
285
286 if (*writemask == TGSI_WRITEMASK_NONE) {
287 report_error( ctx, "Writemask expected" );
288 return FALSE;
289 }
290
291 ctx->cur = cur;
292 }
293 else {
294 *writemask = TGSI_WRITEMASK_XYZW;
295 }
296 return TRUE;
297 }
298
299 /* <register_file_bracket> ::= <file> `['
300 */
301 static boolean
302 parse_register_file_bracket(
303 struct translate_ctx *ctx,
304 uint *file )
305 {
306 if (!parse_file( &ctx->cur, file )) {
307 report_error( ctx, "Unknown register file" );
308 return FALSE;
309 }
310 eat_opt_white( &ctx->cur );
311 if (*ctx->cur != '[') {
312 report_error( ctx, "Expected `['" );
313 return FALSE;
314 }
315 ctx->cur++;
316 return TRUE;
317 }
318
319 /* <register_file_bracket_index> ::= <register_file_bracket> <uint>
320 */
321 static boolean
322 parse_register_file_bracket_index(
323 struct translate_ctx *ctx,
324 uint *file,
325 int *index )
326 {
327 uint uindex;
328
329 if (!parse_register_file_bracket( ctx, file ))
330 return FALSE;
331 eat_opt_white( &ctx->cur );
332 if (!parse_uint( &ctx->cur, &uindex )) {
333 report_error( ctx, "Expected literal unsigned integer" );
334 return FALSE;
335 }
336 *index = (int) uindex;
337 return TRUE;
338 }
339
340 /* Parse destination register operand.
341 * <register_dst> ::= <register_file_bracket_index> `]'
342 */
343 static boolean
344 parse_register_dst(
345 struct translate_ctx *ctx,
346 uint *file,
347 int *index )
348 {
349 if (!parse_register_file_bracket_index( ctx, file, index ))
350 return FALSE;
351 eat_opt_white( &ctx->cur );
352 if (*ctx->cur != ']') {
353 report_error( ctx, "Expected `]'" );
354 return FALSE;
355 }
356 ctx->cur++;
357 return TRUE;
358 }
359
360 /* Parse source register operand.
361 * <register_src> ::= <register_file_bracket_index> `]' |
362 * <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `]' |
363 * <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `+' <uint> `]' |
364 * <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `-' <uint> `]'
365 */
366 static boolean
367 parse_register_src(
368 struct translate_ctx *ctx,
369 uint *file,
370 int *index,
371 uint *ind_file,
372 int *ind_index,
373 uint *ind_comp)
374 {
375 const char *cur;
376 uint uindex;
377
378 *ind_comp = TGSI_SWIZZLE_X;
379 if (!parse_register_file_bracket( ctx, file ))
380 return FALSE;
381 eat_opt_white( &ctx->cur );
382 cur = ctx->cur;
383 if (parse_file( &cur, ind_file )) {
384 if (!parse_register_dst( ctx, ind_file, ind_index ))
385 return FALSE;
386 eat_opt_white( &ctx->cur );
387
388 if (*ctx->cur == '.') {
389 ctx->cur++;
390 eat_opt_white(&ctx->cur);
391
392 switch (uprcase(*ctx->cur)) {
393 case 'X':
394 *ind_comp = TGSI_SWIZZLE_X;
395 break;
396 case 'Y':
397 *ind_comp = TGSI_SWIZZLE_Y;
398 break;
399 case 'Z':
400 *ind_comp = TGSI_SWIZZLE_Z;
401 break;
402 case 'W':
403 *ind_comp = TGSI_SWIZZLE_W;
404 break;
405 default:
406 report_error(ctx, "Expected indirect register swizzle component `x', `y', `z' or `w'");
407 return FALSE;
408 }
409 ctx->cur++;
410 eat_opt_white(&ctx->cur);
411 }
412
413 if (*ctx->cur == '+' || *ctx->cur == '-') {
414 boolean negate;
415
416 negate = *ctx->cur == '-';
417 ctx->cur++;
418 eat_opt_white( &ctx->cur );
419 if (!parse_uint( &ctx->cur, &uindex )) {
420 report_error( ctx, "Expected literal unsigned integer" );
421 return FALSE;
422 }
423 if (negate)
424 *index = -(int) uindex;
425 else
426 *index = (int) uindex;
427 }
428 else {
429 *index = 0;
430 }
431 }
432 else {
433 if (!parse_uint( &ctx->cur, &uindex )) {
434 report_error( ctx, "Expected literal unsigned integer" );
435 return FALSE;
436 }
437 *index = (int) uindex;
438 *ind_file = TGSI_FILE_NULL;
439 *ind_index = 0;
440 }
441 eat_opt_white( &ctx->cur );
442 if (*ctx->cur != ']') {
443 report_error( ctx, "Expected `]'" );
444 return FALSE;
445 }
446 ctx->cur++;
447 return TRUE;
448 }
449
450 /* Parse register declaration.
451 * <register_dcl> ::= <register_file_bracket_index> `]' |
452 * <register_file_bracket_index> `..' <index> `]'
453 */
454 static boolean
455 parse_register_dcl(
456 struct translate_ctx *ctx,
457 uint *file,
458 int *first,
459 int *last )
460 {
461 if (!parse_register_file_bracket_index( ctx, file, first ))
462 return FALSE;
463 eat_opt_white( &ctx->cur );
464 if (ctx->cur[0] == '.' && ctx->cur[1] == '.') {
465 uint uindex;
466
467 ctx->cur += 2;
468 eat_opt_white( &ctx->cur );
469 if (!parse_uint( &ctx->cur, &uindex )) {
470 report_error( ctx, "Expected literal integer" );
471 return FALSE;
472 }
473 *last = (int) uindex;
474 eat_opt_white( &ctx->cur );
475 }
476 else {
477 *last = *first;
478 }
479 if (*ctx->cur != ']') {
480 report_error( ctx, "Expected `]' or `..'" );
481 return FALSE;
482 }
483 ctx->cur++;
484 return TRUE;
485 }
486
487 static const char *modulate_names[TGSI_MODULATE_COUNT] =
488 {
489 "_1X",
490 "_2X",
491 "_4X",
492 "_8X",
493 "_D2",
494 "_D4",
495 "_D8"
496 };
497
498 static boolean
499 parse_dst_operand(
500 struct translate_ctx *ctx,
501 struct tgsi_full_dst_register *dst )
502 {
503 uint file;
504 int index;
505 uint writemask;
506 const char *cur;
507
508 if (!parse_register_dst( ctx, &file, &index ))
509 return FALSE;
510
511 cur = ctx->cur;
512 eat_opt_white( &cur );
513 if (*cur == '_') {
514 uint i;
515
516 for (i = 0; i < TGSI_MODULATE_COUNT; i++) {
517 if (str_match_no_case( &cur, modulate_names[i] )) {
518 if (!is_digit_alpha_underscore( cur )) {
519 dst->DstRegisterExtModulate.Modulate = i;
520 ctx->cur = cur;
521 break;
522 }
523 }
524 }
525 }
526
527 if (!parse_opt_writemask( ctx, &writemask ))
528 return FALSE;
529
530 dst->DstRegister.File = file;
531 dst->DstRegister.Index = index;
532 dst->DstRegister.WriteMask = writemask;
533 return TRUE;
534 }
535
536 static boolean
537 parse_optional_swizzle(
538 struct translate_ctx *ctx,
539 uint swizzle[4],
540 boolean *parsed_swizzle,
541 boolean *parsed_extswizzle )
542 {
543 const char *cur = ctx->cur;
544
545 *parsed_swizzle = FALSE;
546 *parsed_extswizzle = FALSE;
547
548 eat_opt_white( &cur );
549 if (*cur == '.') {
550 uint i;
551
552 cur++;
553 eat_opt_white( &cur );
554 for (i = 0; i < 4; i++) {
555 if (uprcase( *cur ) == 'X')
556 swizzle[i] = TGSI_SWIZZLE_X;
557 else if (uprcase( *cur ) == 'Y')
558 swizzle[i] = TGSI_SWIZZLE_Y;
559 else if (uprcase( *cur ) == 'Z')
560 swizzle[i] = TGSI_SWIZZLE_Z;
561 else if (uprcase( *cur ) == 'W')
562 swizzle[i] = TGSI_SWIZZLE_W;
563 else {
564 if (*cur == '0')
565 swizzle[i] = TGSI_EXTSWIZZLE_ZERO;
566 else if (*cur == '1')
567 swizzle[i] = TGSI_EXTSWIZZLE_ONE;
568 else {
569 report_error( ctx, "Expected register swizzle component `x', `y', `z', `w', `0' or `1'" );
570 return FALSE;
571 }
572 *parsed_extswizzle = TRUE;
573 }
574 cur++;
575 }
576 *parsed_swizzle = TRUE;
577 ctx->cur = cur;
578 }
579 return TRUE;
580 }
581
582 static boolean
583 parse_src_operand(
584 struct translate_ctx *ctx,
585 struct tgsi_full_src_register *src )
586 {
587 const char *cur;
588 float value;
589 uint file;
590 int index;
591 uint ind_file;
592 int ind_index;
593 uint ind_comp;
594 uint swizzle[4];
595 boolean parsed_ext_negate_paren = FALSE;
596 boolean parsed_swizzle;
597 boolean parsed_extswizzle;
598
599 if (*ctx->cur == '-') {
600 cur = ctx->cur;
601 cur++;
602 eat_opt_white( &cur );
603 if (*cur == '(') {
604 cur++;
605 src->SrcRegisterExtMod.Negate = 1;
606 eat_opt_white( &cur );
607 ctx->cur = cur;
608 parsed_ext_negate_paren = TRUE;
609 }
610 else if (*cur == '|') {
611 cur++;
612 src->SrcRegisterExtMod.Negate = 1;
613 src->SrcRegisterExtMod.Absolute = 1;
614 eat_opt_white(&cur);
615 ctx->cur = cur;
616 }
617 }
618 else if (*ctx->cur == '|') {
619 ctx->cur++;
620 eat_opt_white( &ctx->cur );
621 src->SrcRegisterExtMod.Absolute = 1;
622 }
623
624 if (*ctx->cur == '-') {
625 ctx->cur++;
626 eat_opt_white( &ctx->cur );
627 src->SrcRegister.Negate = 1;
628 }
629
630 cur = ctx->cur;
631 if (parse_float( &cur, &value )) {
632 if (value == 2.0f) {
633 eat_opt_white( &cur );
634 if (*cur != '*') {
635 report_error( ctx, "Expected `*'" );
636 return FALSE;
637 }
638 cur++;
639 if (*cur != '(') {
640 report_error( ctx, "Expected `('" );
641 return FALSE;
642 }
643 cur++;
644 src->SrcRegisterExtMod.Scale2X = 1;
645 eat_opt_white( &cur );
646 ctx->cur = cur;
647 }
648 }
649
650 if (*ctx->cur == '(') {
651 ctx->cur++;
652 eat_opt_white( &ctx->cur );
653 src->SrcRegisterExtMod.Bias = 1;
654 }
655
656 cur = ctx->cur;
657 if (parse_float( &cur, &value )) {
658 if (value == 1.0f) {
659 eat_opt_white( &cur );
660 if (*cur != '-') {
661 report_error( ctx, "Expected `-'" );
662 return FALSE;
663 }
664 cur++;
665 if (*cur != '(') {
666 report_error( ctx, "Expected `('" );
667 return FALSE;
668 }
669 cur++;
670 src->SrcRegisterExtMod.Complement = 1;
671 eat_opt_white( &cur );
672 ctx->cur = cur;
673 }
674 }
675
676 if (!parse_register_src(ctx, &file, &index, &ind_file, &ind_index, &ind_comp))
677 return FALSE;
678 src->SrcRegister.File = file;
679 src->SrcRegister.Index = index;
680 if (ind_file != TGSI_FILE_NULL) {
681 src->SrcRegister.Indirect = 1;
682 src->SrcRegisterInd.File = ind_file;
683 src->SrcRegisterInd.Index = ind_index;
684 src->SrcRegisterInd.SwizzleX = ind_comp;
685 src->SrcRegisterInd.SwizzleY = ind_comp;
686 src->SrcRegisterInd.SwizzleZ = ind_comp;
687 src->SrcRegisterInd.SwizzleW = ind_comp;
688 }
689
690 /* Parse optional swizzle.
691 */
692 if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle, &parsed_extswizzle )) {
693 if (parsed_extswizzle) {
694 assert( parsed_swizzle );
695
696 src->SrcRegisterExtSwz.ExtSwizzleX = swizzle[0];
697 src->SrcRegisterExtSwz.ExtSwizzleY = swizzle[1];
698 src->SrcRegisterExtSwz.ExtSwizzleZ = swizzle[2];
699 src->SrcRegisterExtSwz.ExtSwizzleW = swizzle[3];
700 }
701 else if (parsed_swizzle) {
702 src->SrcRegister.SwizzleX = swizzle[0];
703 src->SrcRegister.SwizzleY = swizzle[1];
704 src->SrcRegister.SwizzleZ = swizzle[2];
705 src->SrcRegister.SwizzleW = swizzle[3];
706 }
707 }
708
709 if (src->SrcRegisterExtMod.Complement) {
710 eat_opt_white( &ctx->cur );
711 if (*ctx->cur != ')') {
712 report_error( ctx, "Expected `)'" );
713 return FALSE;
714 }
715 ctx->cur++;
716 }
717
718 if (src->SrcRegisterExtMod.Bias) {
719 eat_opt_white( &ctx->cur );
720 if (*ctx->cur != ')') {
721 report_error( ctx, "Expected `)'" );
722 return FALSE;
723 }
724 ctx->cur++;
725 eat_opt_white( &ctx->cur );
726 if (*ctx->cur != '-') {
727 report_error( ctx, "Expected `-'" );
728 return FALSE;
729 }
730 ctx->cur++;
731 eat_opt_white( &ctx->cur );
732 if (!parse_float( &ctx->cur, &value )) {
733 report_error( ctx, "Expected literal floating point" );
734 return FALSE;
735 }
736 if (value != 0.5f) {
737 report_error( ctx, "Expected 0.5" );
738 return FALSE;
739 }
740 }
741
742 if (src->SrcRegisterExtMod.Scale2X) {
743 eat_opt_white( &ctx->cur );
744 if (*ctx->cur != ')') {
745 report_error( ctx, "Expected `)'" );
746 return FALSE;
747 }
748 ctx->cur++;
749 }
750
751 if (src->SrcRegisterExtMod.Absolute) {
752 eat_opt_white( &ctx->cur );
753 if (*ctx->cur != '|') {
754 report_error( ctx, "Expected `|'" );
755 return FALSE;
756 }
757 ctx->cur++;
758 }
759
760 if (parsed_ext_negate_paren) {
761 eat_opt_white( &ctx->cur );
762 if (*ctx->cur != ')') {
763 report_error( ctx, "Expected `)'" );
764 return FALSE;
765 }
766 ctx->cur++;
767 }
768
769 return TRUE;
770 }
771
772 static const char *texture_names[TGSI_TEXTURE_COUNT] =
773 {
774 "UNKNOWN",
775 "1D",
776 "2D",
777 "3D",
778 "CUBE",
779 "RECT",
780 "SHADOW1D",
781 "SHADOW2D",
782 "SHADOWRECT"
783 };
784
785 static boolean
786 match_inst_mnemonic(const char **pcur,
787 const struct tgsi_opcode_info *info)
788 {
789 if (str_match_no_case(pcur, info->mnemonic)) {
790 return TRUE;
791 }
792 return FALSE;
793 }
794
795 static boolean
796 parse_instruction(
797 struct translate_ctx *ctx,
798 boolean has_label )
799 {
800 uint i;
801 uint saturate = TGSI_SAT_NONE;
802 const struct tgsi_opcode_info *info;
803 struct tgsi_full_instruction inst;
804 uint advance;
805
806 /* Parse instruction name.
807 */
808 eat_opt_white( &ctx->cur );
809 for (i = 0; i < TGSI_OPCODE_LAST; i++) {
810 const char *cur = ctx->cur;
811
812 info = tgsi_get_opcode_info( i );
813 if (match_inst_mnemonic(&cur, info)) {
814 if (str_match_no_case( &cur, "_SATNV" ))
815 saturate = TGSI_SAT_MINUS_PLUS_ONE;
816 else if (str_match_no_case( &cur, "_SAT" ))
817 saturate = TGSI_SAT_ZERO_ONE;
818
819 if (info->num_dst + info->num_src + info->is_tex == 0) {
820 if (!is_digit_alpha_underscore( cur )) {
821 ctx->cur = cur;
822 break;
823 }
824 }
825 else if (*cur == '\0' || eat_white( &cur )) {
826 ctx->cur = cur;
827 break;
828 }
829 }
830 }
831 if (i == TGSI_OPCODE_LAST) {
832 if (has_label)
833 report_error( ctx, "Unknown opcode" );
834 else
835 report_error( ctx, "Expected `DCL', `IMM' or a label" );
836 return FALSE;
837 }
838
839 inst = tgsi_default_full_instruction();
840 inst.Instruction.Opcode = i;
841 inst.Instruction.Saturate = saturate;
842 inst.Instruction.NumDstRegs = info->num_dst;
843 inst.Instruction.NumSrcRegs = info->num_src;
844
845 /* Parse instruction operands.
846 */
847 for (i = 0; i < info->num_dst + info->num_src + info->is_tex; i++) {
848 if (i > 0) {
849 eat_opt_white( &ctx->cur );
850 if (*ctx->cur != ',') {
851 report_error( ctx, "Expected `,'" );
852 return FALSE;
853 }
854 ctx->cur++;
855 eat_opt_white( &ctx->cur );
856 }
857
858 if (i < info->num_dst) {
859 if (!parse_dst_operand( ctx, &inst.FullDstRegisters[i] ))
860 return FALSE;
861 }
862 else if (i < info->num_dst + info->num_src) {
863 if (!parse_src_operand( ctx, &inst.FullSrcRegisters[i - info->num_dst] ))
864 return FALSE;
865 }
866 else {
867 uint j;
868
869 for (j = 0; j < TGSI_TEXTURE_COUNT; j++) {
870 if (str_match_no_case( &ctx->cur, texture_names[j] )) {
871 if (!is_digit_alpha_underscore( ctx->cur )) {
872 inst.InstructionExtTexture.Texture = j;
873 break;
874 }
875 }
876 }
877 if (j == TGSI_TEXTURE_COUNT) {
878 report_error( ctx, "Expected texture target" );
879 return FALSE;
880 }
881 }
882 }
883
884 if (info->is_branch) {
885 uint target;
886
887 eat_opt_white( &ctx->cur );
888 if (*ctx->cur != ':') {
889 report_error( ctx, "Expected `:'" );
890 return FALSE;
891 }
892 ctx->cur++;
893 eat_opt_white( &ctx->cur );
894 if (!parse_uint( &ctx->cur, &target )) {
895 report_error( ctx, "Expected a label" );
896 return FALSE;
897 }
898 inst.InstructionExtLabel.Label = target;
899 }
900
901 advance = tgsi_build_full_instruction(
902 &inst,
903 ctx->tokens_cur,
904 ctx->header,
905 (uint) (ctx->tokens_end - ctx->tokens_cur) );
906 if (advance == 0)
907 return FALSE;
908 ctx->tokens_cur += advance;
909
910 return TRUE;
911 }
912
913 static const char *semantic_names[TGSI_SEMANTIC_COUNT] =
914 {
915 "POSITION",
916 "COLOR",
917 "BCOLOR",
918 "FOG",
919 "PSIZE",
920 "GENERIC",
921 "NORMAL",
922 "FACE"
923 };
924
925 static const char *interpolate_names[TGSI_INTERPOLATE_COUNT] =
926 {
927 "CONSTANT",
928 "LINEAR",
929 "PERSPECTIVE"
930 };
931
932 static boolean parse_declaration( struct translate_ctx *ctx )
933 {
934 struct tgsi_full_declaration decl;
935 uint file;
936 int first;
937 int last;
938 uint writemask;
939 const char *cur;
940 uint advance;
941
942 assert(Elements(semantic_names) == TGSI_SEMANTIC_COUNT);
943 assert(Elements(interpolate_names) == TGSI_INTERPOLATE_COUNT);
944
945 if (!eat_white( &ctx->cur )) {
946 report_error( ctx, "Syntax error" );
947 return FALSE;
948 }
949 if (!parse_register_dcl( ctx, &file, &first, &last ))
950 return FALSE;
951 if (!parse_opt_writemask( ctx, &writemask ))
952 return FALSE;
953
954 decl = tgsi_default_full_declaration();
955 decl.Declaration.File = file;
956 decl.Declaration.UsageMask = writemask;
957 decl.DeclarationRange.First = first;
958 decl.DeclarationRange.Last = last;
959
960 cur = ctx->cur;
961 eat_opt_white( &cur );
962 if (*cur == ',') {
963 uint i;
964
965 cur++;
966 eat_opt_white( &cur );
967 for (i = 0; i < TGSI_SEMANTIC_COUNT; i++) {
968 if (str_match_no_case( &cur, semantic_names[i] )) {
969 const char *cur2 = cur;
970 uint index;
971
972 if (is_digit_alpha_underscore( cur ))
973 continue;
974 eat_opt_white( &cur2 );
975 if (*cur2 == '[') {
976 cur2++;
977 eat_opt_white( &cur2 );
978 if (!parse_uint( &cur2, &index )) {
979 report_error( ctx, "Expected literal integer" );
980 return FALSE;
981 }
982 eat_opt_white( &cur2 );
983 if (*cur2 != ']') {
984 report_error( ctx, "Expected `]'" );
985 return FALSE;
986 }
987 cur2++;
988
989 decl.Semantic.SemanticIndex = index;
990
991 cur = cur2;
992 }
993
994 decl.Declaration.Semantic = 1;
995 decl.Semantic.SemanticName = i;
996
997 ctx->cur = cur;
998 break;
999 }
1000 }
1001 }
1002
1003 cur = ctx->cur;
1004 eat_opt_white( &cur );
1005 if (*cur == ',') {
1006 uint i;
1007
1008 cur++;
1009 eat_opt_white( &cur );
1010 for (i = 0; i < TGSI_INTERPOLATE_COUNT; i++) {
1011 if (str_match_no_case( &cur, interpolate_names[i] )) {
1012 if (is_digit_alpha_underscore( cur ))
1013 continue;
1014 decl.Declaration.Interpolate = i;
1015
1016 ctx->cur = cur;
1017 break;
1018 }
1019 }
1020 if (i == TGSI_INTERPOLATE_COUNT) {
1021 report_error( ctx, "Expected semantic or interpolate attribute" );
1022 return FALSE;
1023 }
1024 }
1025
1026 advance = tgsi_build_full_declaration(
1027 &decl,
1028 ctx->tokens_cur,
1029 ctx->header,
1030 (uint) (ctx->tokens_end - ctx->tokens_cur) );
1031 if (advance == 0)
1032 return FALSE;
1033 ctx->tokens_cur += advance;
1034
1035 return TRUE;
1036 }
1037
1038 static boolean parse_immediate( struct translate_ctx *ctx )
1039 {
1040 struct tgsi_full_immediate imm;
1041 uint i;
1042 float values[4];
1043 uint advance;
1044
1045 if (!eat_white( &ctx->cur )) {
1046 report_error( ctx, "Syntax error" );
1047 return FALSE;
1048 }
1049 if (!str_match_no_case( &ctx->cur, "FLT32" ) || is_digit_alpha_underscore( ctx->cur )) {
1050 report_error( ctx, "Expected `FLT32'" );
1051 return FALSE;
1052 }
1053 eat_opt_white( &ctx->cur );
1054 if (*ctx->cur != '{') {
1055 report_error( ctx, "Expected `{'" );
1056 return FALSE;
1057 }
1058 ctx->cur++;
1059 for (i = 0; i < 4; i++) {
1060 eat_opt_white( &ctx->cur );
1061 if (i > 0) {
1062 if (*ctx->cur != ',') {
1063 report_error( ctx, "Expected `,'" );
1064 return FALSE;
1065 }
1066 ctx->cur++;
1067 eat_opt_white( &ctx->cur );
1068 }
1069 if (!parse_float( &ctx->cur, &values[i] )) {
1070 report_error( ctx, "Expected literal floating point" );
1071 return FALSE;
1072 }
1073 }
1074 eat_opt_white( &ctx->cur );
1075 if (*ctx->cur != '}') {
1076 report_error( ctx, "Expected `}'" );
1077 return FALSE;
1078 }
1079 ctx->cur++;
1080
1081 imm = tgsi_default_full_immediate();
1082 imm.Immediate.NrTokens += 4;
1083 imm.Immediate.DataType = TGSI_IMM_FLOAT32;
1084 imm.u[0].Float = values[0];
1085 imm.u[1].Float = values[1];
1086 imm.u[2].Float = values[2];
1087 imm.u[3].Float = values[3];
1088
1089 advance = tgsi_build_full_immediate(
1090 &imm,
1091 ctx->tokens_cur,
1092 ctx->header,
1093 (uint) (ctx->tokens_end - ctx->tokens_cur) );
1094 if (advance == 0)
1095 return FALSE;
1096 ctx->tokens_cur += advance;
1097
1098 return TRUE;
1099 }
1100
1101 static boolean translate( struct translate_ctx *ctx )
1102 {
1103 eat_opt_white( &ctx->cur );
1104 if (!parse_header( ctx ))
1105 return FALSE;
1106
1107 while (*ctx->cur != '\0') {
1108 uint label_val = 0;
1109
1110 if (!eat_white( &ctx->cur )) {
1111 report_error( ctx, "Syntax error" );
1112 return FALSE;
1113 }
1114
1115 if (*ctx->cur == '\0')
1116 break;
1117
1118 if (parse_label( ctx, &label_val )) {
1119 if (!parse_instruction( ctx, TRUE ))
1120 return FALSE;
1121 }
1122 else if (str_match_no_case( &ctx->cur, "DCL" )) {
1123 if (!parse_declaration( ctx ))
1124 return FALSE;
1125 }
1126 else if (str_match_no_case( &ctx->cur, "IMM" )) {
1127 if (!parse_immediate( ctx ))
1128 return FALSE;
1129 }
1130 else if (!parse_instruction( ctx, FALSE )) {
1131 return FALSE;
1132 }
1133 }
1134
1135 return TRUE;
1136 }
1137
1138 boolean
1139 tgsi_text_translate(
1140 const char *text,
1141 struct tgsi_token *tokens,
1142 uint num_tokens )
1143 {
1144 struct translate_ctx ctx;
1145
1146 ctx.text = text;
1147 ctx.cur = text;
1148 ctx.tokens = tokens;
1149 ctx.tokens_cur = tokens;
1150 ctx.tokens_end = tokens + num_tokens;
1151
1152 if (!translate( &ctx ))
1153 return FALSE;
1154
1155 return tgsi_sanity_check( tokens );
1156 }