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