84e863b23759fcfe32e3d9ba3a03d5812c113dae
[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 "VERTICES_IN",
796 "PRIM_ID"
797 };
798
799 static const char *interpolate_names[TGSI_INTERPOLATE_COUNT] =
800 {
801 "CONSTANT",
802 "LINEAR",
803 "PERSPECTIVE"
804 };
805
806 static boolean parse_declaration( struct translate_ctx *ctx )
807 {
808 struct tgsi_full_declaration decl;
809 uint file;
810 int first;
811 int last;
812 uint writemask;
813 const char *cur;
814 uint advance;
815
816 assert(Elements(semantic_names) == TGSI_SEMANTIC_COUNT);
817 assert(Elements(interpolate_names) == TGSI_INTERPOLATE_COUNT);
818
819 if (!eat_white( &ctx->cur )) {
820 report_error( ctx, "Syntax error" );
821 return FALSE;
822 }
823 if (!parse_register_dcl( ctx, &file, &first, &last ))
824 return FALSE;
825 if (!parse_opt_writemask( ctx, &writemask ))
826 return FALSE;
827
828 decl = tgsi_default_full_declaration();
829 decl.Declaration.File = file;
830 decl.Declaration.UsageMask = writemask;
831 decl.Range.First = first;
832 decl.Range.Last = last;
833
834 cur = ctx->cur;
835 eat_opt_white( &cur );
836 if (*cur == ',') {
837 uint i;
838
839 cur++;
840 eat_opt_white( &cur );
841 for (i = 0; i < TGSI_SEMANTIC_COUNT; i++) {
842 if (str_match_no_case( &cur, semantic_names[i] )) {
843 const char *cur2 = cur;
844 uint index;
845
846 if (is_digit_alpha_underscore( cur ))
847 continue;
848 eat_opt_white( &cur2 );
849 if (*cur2 == '[') {
850 cur2++;
851 eat_opt_white( &cur2 );
852 if (!parse_uint( &cur2, &index )) {
853 report_error( ctx, "Expected literal integer" );
854 return FALSE;
855 }
856 eat_opt_white( &cur2 );
857 if (*cur2 != ']') {
858 report_error( ctx, "Expected `]'" );
859 return FALSE;
860 }
861 cur2++;
862
863 decl.Semantic.Index = index;
864
865 cur = cur2;
866 }
867
868 decl.Declaration.Semantic = 1;
869 decl.Semantic.Name = i;
870
871 ctx->cur = cur;
872 break;
873 }
874 }
875 }
876
877 cur = ctx->cur;
878 eat_opt_white( &cur );
879 if (*cur == ',') {
880 uint i;
881
882 cur++;
883 eat_opt_white( &cur );
884 for (i = 0; i < TGSI_INTERPOLATE_COUNT; i++) {
885 if (str_match_no_case( &cur, interpolate_names[i] )) {
886 if (is_digit_alpha_underscore( cur ))
887 continue;
888 decl.Declaration.Interpolate = i;
889
890 ctx->cur = cur;
891 break;
892 }
893 }
894 if (i == TGSI_INTERPOLATE_COUNT) {
895 report_error( ctx, "Expected semantic or interpolate attribute" );
896 return FALSE;
897 }
898 }
899
900 advance = tgsi_build_full_declaration(
901 &decl,
902 ctx->tokens_cur,
903 ctx->header,
904 (uint) (ctx->tokens_end - ctx->tokens_cur) );
905 if (advance == 0)
906 return FALSE;
907 ctx->tokens_cur += advance;
908
909 return TRUE;
910 }
911
912 static boolean parse_immediate( struct translate_ctx *ctx )
913 {
914 struct tgsi_full_immediate imm;
915 uint i;
916 float values[4];
917 uint advance;
918
919 if (!eat_white( &ctx->cur )) {
920 report_error( ctx, "Syntax error" );
921 return FALSE;
922 }
923 if (!str_match_no_case( &ctx->cur, "FLT32" ) || is_digit_alpha_underscore( ctx->cur )) {
924 report_error( ctx, "Expected `FLT32'" );
925 return FALSE;
926 }
927 eat_opt_white( &ctx->cur );
928 if (*ctx->cur != '{') {
929 report_error( ctx, "Expected `{'" );
930 return FALSE;
931 }
932 ctx->cur++;
933 for (i = 0; i < 4; i++) {
934 eat_opt_white( &ctx->cur );
935 if (i > 0) {
936 if (*ctx->cur != ',') {
937 report_error( ctx, "Expected `,'" );
938 return FALSE;
939 }
940 ctx->cur++;
941 eat_opt_white( &ctx->cur );
942 }
943 if (!parse_float( &ctx->cur, &values[i] )) {
944 report_error( ctx, "Expected literal floating point" );
945 return FALSE;
946 }
947 }
948 eat_opt_white( &ctx->cur );
949 if (*ctx->cur != '}') {
950 report_error( ctx, "Expected `}'" );
951 return FALSE;
952 }
953 ctx->cur++;
954
955 imm = tgsi_default_full_immediate();
956 imm.Immediate.NrTokens += 4;
957 imm.Immediate.DataType = TGSI_IMM_FLOAT32;
958 imm.u[0].Float = values[0];
959 imm.u[1].Float = values[1];
960 imm.u[2].Float = values[2];
961 imm.u[3].Float = values[3];
962
963 advance = tgsi_build_full_immediate(
964 &imm,
965 ctx->tokens_cur,
966 ctx->header,
967 (uint) (ctx->tokens_end - ctx->tokens_cur) );
968 if (advance == 0)
969 return FALSE;
970 ctx->tokens_cur += advance;
971
972 return TRUE;
973 }
974
975 static const char *property_names[] =
976 {
977 "GS_INPUT_PRIMITIVE",
978 "GS_OUTPUT_PRIMITIVE",
979 "GS_MAX_OUTPUT_VERTICES"
980 };
981
982 static const char *primitive_names[] =
983 {
984 "POINTS",
985 "LINES",
986 "LINE_LOOP",
987 "LINE_STRIP",
988 "TRIANGLES",
989 "TRIANGLE_STRIP",
990 "TRIANGLE_FAN",
991 "QUADS",
992 "QUAD_STRIP",
993 "POLYGON"
994 };
995
996 static boolean
997 parse_primitive( const char **pcur, uint *primitive )
998 {
999 uint i;
1000
1001 for (i = 0; i < PIPE_PRIM_MAX; i++) {
1002 const char *cur = *pcur;
1003
1004 if (str_match_no_case( &cur, primitive_names[i])) {
1005 *primitive = i;
1006 *pcur = cur;
1007 return TRUE;
1008 }
1009 }
1010 return FALSE;
1011 }
1012
1013
1014 static boolean parse_property( struct translate_ctx *ctx )
1015 {
1016 struct tgsi_full_property prop;
1017 uint property_name;
1018 uint values[8];
1019 uint advance;
1020 char id[64];
1021
1022 if (!eat_white( &ctx->cur )) {
1023 report_error( ctx, "Syntax error" );
1024 return FALSE;
1025 }
1026 if (!parse_identifier( &ctx->cur, id )) {
1027 report_error( ctx, "Syntax error" );
1028 return FALSE;
1029 }
1030 for (property_name = 0; property_name < TGSI_PROPERTY_COUNT;
1031 ++property_name) {
1032 if (streq_nocase_uprcase(id, property_names[property_name])) {
1033 break;
1034 }
1035 }
1036 if (property_name >= TGSI_PROPERTY_COUNT) {
1037 debug_printf( "\nError: Unknown property : '%s'", id );
1038 return FALSE;
1039 }
1040
1041 eat_opt_white( &ctx->cur );
1042 switch(property_name) {
1043 case TGSI_PROPERTY_GS_INPUT_PRIM:
1044 case TGSI_PROPERTY_GS_OUTPUT_PRIM:
1045 if (!parse_primitive(&ctx->cur, &values[0] )) {
1046 report_error( ctx, "Unknown primitive name as property!" );
1047 return FALSE;
1048 }
1049 break;
1050 default:
1051 if (!parse_uint(&ctx->cur, &values[0] )) {
1052 report_error( ctx, "Expected unsigned integer as property!" );
1053 return FALSE;
1054 }
1055 }
1056
1057 prop = tgsi_default_full_property();
1058 prop.Property.PropertyName = property_name;
1059 prop.Property.NrTokens += 1;
1060 prop.u[0].Data = values[0];
1061
1062 advance = tgsi_build_full_property(
1063 &prop,
1064 ctx->tokens_cur,
1065 ctx->header,
1066 (uint) (ctx->tokens_end - ctx->tokens_cur) );
1067 if (advance == 0)
1068 return FALSE;
1069 ctx->tokens_cur += advance;
1070
1071 return TRUE;
1072 }
1073
1074
1075 static boolean translate( struct translate_ctx *ctx )
1076 {
1077 eat_opt_white( &ctx->cur );
1078 if (!parse_header( ctx ))
1079 return FALSE;
1080
1081 while (*ctx->cur != '\0') {
1082 uint label_val = 0;
1083 if (!eat_white( &ctx->cur )) {
1084 report_error( ctx, "Syntax error" );
1085 return FALSE;
1086 }
1087
1088 if (*ctx->cur == '\0')
1089 break;
1090 if (parse_label( ctx, &label_val )) {
1091 if (!parse_instruction( ctx, TRUE ))
1092 return FALSE;
1093 }
1094 else if (str_match_no_case( &ctx->cur, "DCL" )) {
1095 if (!parse_declaration( ctx ))
1096 return FALSE;
1097 }
1098 else if (str_match_no_case( &ctx->cur, "IMM" )) {
1099 if (!parse_immediate( ctx ))
1100 return FALSE;
1101 }
1102 else if (str_match_no_case( &ctx->cur, "PROPERTY" )) {
1103 if (!parse_property( ctx ))
1104 return FALSE;
1105 }
1106 else if (!parse_instruction( ctx, FALSE )) {
1107 return FALSE;
1108 }
1109 }
1110
1111 return TRUE;
1112 }
1113
1114 boolean
1115 tgsi_text_translate(
1116 const char *text,
1117 struct tgsi_token *tokens,
1118 uint num_tokens )
1119 {
1120 struct translate_ctx ctx;
1121
1122 ctx.text = text;
1123 ctx.cur = text;
1124 ctx.tokens = tokens;
1125 ctx.tokens_cur = tokens;
1126 ctx.tokens_end = tokens + num_tokens;
1127
1128 if (!translate( &ctx ))
1129 return FALSE;
1130
1131 return tgsi_sanity_check( tokens );
1132 }