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