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