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