Home | History | Annotate | Download | only in tgsi
      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 "util/u_prim.h"
     31 #include "pipe/p_defines.h"
     32 #include "util/u_inlines.h"
     33 #include "tgsi_text.h"
     34 #include "tgsi_build.h"
     35 #include "tgsi_info.h"
     36 #include "tgsi_parse.h"
     37 #include "tgsi_sanity.h"
     38 #include "tgsi_strings.h"
     39 #include "tgsi_util.h"
     40 #include "tgsi_dump.h"
     41 
     42 static boolean is_alpha_underscore( const char *cur )
     43 {
     44    return
     45       (*cur >= 'a' && *cur <= 'z') ||
     46       (*cur >= 'A' && *cur <= 'Z') ||
     47       *cur == '_';
     48 }
     49 
     50 static boolean is_digit( const char *cur )
     51 {
     52    return *cur >= '0' && *cur <= '9';
     53 }
     54 
     55 static boolean is_digit_alpha_underscore( const char *cur )
     56 {
     57    return is_digit( cur ) || is_alpha_underscore( cur );
     58 }
     59 
     60 static char uprcase( char c )
     61 {
     62    if (c >= 'a' && c <= 'z')
     63       return c + 'A' - 'a';
     64    return c;
     65 }
     66 
     67 /*
     68  * Ignore case of str1 and assume str1 is already uppercase.
     69  * Return TRUE iff str1 and str2 are equal.
     70  */
     71 static int
     72 streq_nocase_uprcase(const char *str1,
     73                      const char *str2)
     74 {
     75    while (*str1 && *str2) {
     76       if (*str1 != uprcase(*str2))
     77          return FALSE;
     78       str1++;
     79       str2++;
     80    }
     81    return *str1 == 0 && *str2 == 0;
     82 }
     83 
     84 /* Return TRUE if both strings match.
     85  * The second string is terminated by zero.
     86  * The pointer to the first string is moved at end of the read word
     87  * on success.
     88  */
     89 static boolean str_match_no_case( const char **pcur, const char *str )
     90 {
     91    const char *cur = *pcur;
     92 
     93    while (*str != '\0' && *str == uprcase( *cur )) {
     94       str++;
     95       cur++;
     96    }
     97    if (*str == '\0') {
     98       *pcur = cur;
     99       return TRUE;
    100    }
    101    return FALSE;
    102 }
    103 
    104 /* Return TRUE if both strings match.
    105  * The first string is be terminated by a non-digit non-letter non-underscore
    106  * character, the second string is terminated by zero.
    107  * The pointer to the first string is moved at end of the read word
    108  * on success.
    109  */
    110 static boolean str_match_nocase_whole( const char **pcur, const char *str )
    111 {
    112    const char *cur = *pcur;
    113 
    114    if (str_match_no_case(&cur, str) &&
    115        !is_digit_alpha_underscore(cur)) {
    116       *pcur = cur;
    117       return TRUE;
    118    }
    119    return FALSE;
    120 }
    121 
    122 /* Eat zero or more whitespaces.
    123  */
    124 static void eat_opt_white( const char **pcur )
    125 {
    126    while (**pcur == ' ' || **pcur == '\t' || **pcur == '\n')
    127       (*pcur)++;
    128 }
    129 
    130 /* Eat one or more whitespaces.
    131  * Return TRUE if at least one whitespace eaten.
    132  */
    133 static boolean eat_white( const char **pcur )
    134 {
    135    const char *cur = *pcur;
    136 
    137    eat_opt_white( pcur );
    138    return *pcur > cur;
    139 }
    140 
    141 /* Parse unsigned integer.
    142  * No checks for overflow.
    143  */
    144 static boolean parse_uint( const char **pcur, uint *val )
    145 {
    146    const char *cur = *pcur;
    147 
    148    if (is_digit( cur )) {
    149       *val = *cur++ - '0';
    150       while (is_digit( cur ))
    151          *val = *val * 10 + *cur++ - '0';
    152       *pcur = cur;
    153       return TRUE;
    154    }
    155    return FALSE;
    156 }
    157 
    158 static boolean parse_int( const char **pcur, int *val )
    159 {
    160    const char *cur = *pcur;
    161    int sign = (*cur == '-' ? -1 : 1);
    162 
    163    if (*cur == '+' || *cur == '-')
    164       cur++;
    165 
    166    if (parse_uint(&cur, (uint *)val)) {
    167       *val *= sign;
    168       *pcur = cur;
    169       return TRUE;
    170    }
    171 
    172    return FALSE;
    173 }
    174 
    175 static boolean parse_identifier( const char **pcur, char *ret )
    176 {
    177    const char *cur = *pcur;
    178    int i = 0;
    179    if (is_alpha_underscore( cur )) {
    180       ret[i++] = *cur++;
    181       while (is_alpha_underscore( cur ) || is_digit( cur ))
    182          ret[i++] = *cur++;
    183       ret[i++] = '\0';
    184       *pcur = cur;
    185       return TRUE;
    186    }
    187    return FALSE;
    188 }
    189 
    190 /* Parse floating point.
    191  */
    192 static boolean parse_float( const char **pcur, float *val )
    193 {
    194    const char *cur = *pcur;
    195    boolean integral_part = FALSE;
    196    boolean fractional_part = FALSE;
    197 
    198    *val = (float) atof( cur );
    199 
    200    if (*cur == '-' || *cur == '+')
    201       cur++;
    202    if (is_digit( cur )) {
    203       cur++;
    204       integral_part = TRUE;
    205       while (is_digit( cur ))
    206          cur++;
    207    }
    208    if (*cur == '.') {
    209       cur++;
    210       if (is_digit( cur )) {
    211          cur++;
    212          fractional_part = TRUE;
    213          while (is_digit( cur ))
    214             cur++;
    215       }
    216    }
    217    if (!integral_part && !fractional_part)
    218       return FALSE;
    219    if (uprcase( *cur ) == 'E') {
    220       cur++;
    221       if (*cur == '-' || *cur == '+')
    222          cur++;
    223       if (is_digit( cur )) {
    224          cur++;
    225          while (is_digit( cur ))
    226             cur++;
    227       }
    228       else
    229          return FALSE;
    230    }
    231    *pcur = cur;
    232    return TRUE;
    233 }
    234 
    235 struct translate_ctx
    236 {
    237    const char *text;
    238    const char *cur;
    239    struct tgsi_token *tokens;
    240    struct tgsi_token *tokens_cur;
    241    struct tgsi_token *tokens_end;
    242    struct tgsi_header *header;
    243    unsigned processor : 4;
    244    int implied_array_size : 5;
    245 };
    246 
    247 static void report_error( struct translate_ctx *ctx, const char *msg )
    248 {
    249    int line = 1;
    250    int column = 1;
    251    const char *itr = ctx->text;
    252 
    253    while (itr != ctx->cur) {
    254       if (*itr == '\n') {
    255          column = 1;
    256          ++line;
    257       }
    258       ++column;
    259       ++itr;
    260    }
    261 
    262    debug_printf( "\nTGSI asm error: %s [%d : %d] \n", msg, line, column );
    263 }
    264 
    265 /* Parse shader header.
    266  * Return TRUE for one of the following headers.
    267  *    FRAG
    268  *    GEOM
    269  *    VERT
    270  */
    271 static boolean parse_header( struct translate_ctx *ctx )
    272 {
    273    uint processor;
    274 
    275    if (str_match_nocase_whole( &ctx->cur, "FRAG" ))
    276       processor = TGSI_PROCESSOR_FRAGMENT;
    277    else if (str_match_nocase_whole( &ctx->cur, "VERT" ))
    278       processor = TGSI_PROCESSOR_VERTEX;
    279    else if (str_match_nocase_whole( &ctx->cur, "GEOM" ))
    280       processor = TGSI_PROCESSOR_GEOMETRY;
    281    else if (str_match_nocase_whole( &ctx->cur, "COMP" ))
    282       processor = TGSI_PROCESSOR_COMPUTE;
    283    else {
    284       report_error( ctx, "Unknown header" );
    285       return FALSE;
    286    }
    287 
    288    if (ctx->tokens_cur >= ctx->tokens_end)
    289       return FALSE;
    290    ctx->header = (struct tgsi_header *) ctx->tokens_cur++;
    291    *ctx->header = tgsi_build_header();
    292 
    293    if (ctx->tokens_cur >= ctx->tokens_end)
    294       return FALSE;
    295    *(struct tgsi_processor *) ctx->tokens_cur++ = tgsi_build_processor( processor, ctx->header );
    296    ctx->processor = processor;
    297 
    298    return TRUE;
    299 }
    300 
    301 static boolean parse_label( struct translate_ctx *ctx, uint *val )
    302 {
    303    const char *cur = ctx->cur;
    304 
    305    if (parse_uint( &cur, val )) {
    306       eat_opt_white( &cur );
    307       if (*cur == ':') {
    308          cur++;
    309          ctx->cur = cur;
    310          return TRUE;
    311       }
    312    }
    313    return FALSE;
    314 }
    315 
    316 static boolean
    317 parse_file( const char **pcur, uint *file )
    318 {
    319    uint i;
    320 
    321    for (i = 0; i < TGSI_FILE_COUNT; i++) {
    322       const char *cur = *pcur;
    323 
    324       if (str_match_nocase_whole( &cur, tgsi_file_names[i] )) {
    325          *pcur = cur;
    326          *file = i;
    327          return TRUE;
    328       }
    329    }
    330    return FALSE;
    331 }
    332 
    333 static boolean
    334 parse_opt_writemask(
    335    struct translate_ctx *ctx,
    336    uint *writemask )
    337 {
    338    const char *cur;
    339 
    340    cur = ctx->cur;
    341    eat_opt_white( &cur );
    342    if (*cur == '.') {
    343       cur++;
    344       *writemask = TGSI_WRITEMASK_NONE;
    345       eat_opt_white( &cur );
    346       if (uprcase( *cur ) == 'X') {
    347          cur++;
    348          *writemask |= TGSI_WRITEMASK_X;
    349       }
    350       if (uprcase( *cur ) == 'Y') {
    351          cur++;
    352          *writemask |= TGSI_WRITEMASK_Y;
    353       }
    354       if (uprcase( *cur ) == 'Z') {
    355          cur++;
    356          *writemask |= TGSI_WRITEMASK_Z;
    357       }
    358       if (uprcase( *cur ) == 'W') {
    359          cur++;
    360          *writemask |= TGSI_WRITEMASK_W;
    361       }
    362 
    363       if (*writemask == TGSI_WRITEMASK_NONE) {
    364          report_error( ctx, "Writemask expected" );
    365          return FALSE;
    366       }
    367 
    368       ctx->cur = cur;
    369    }
    370    else {
    371       *writemask = TGSI_WRITEMASK_XYZW;
    372    }
    373    return TRUE;
    374 }
    375 
    376 
    377 /* <register_file_bracket> ::= <file> `['
    378  */
    379 static boolean
    380 parse_register_file_bracket(
    381    struct translate_ctx *ctx,
    382    uint *file )
    383 {
    384    if (!parse_file( &ctx->cur, file )) {
    385       report_error( ctx, "Unknown register file" );
    386       return FALSE;
    387    }
    388    eat_opt_white( &ctx->cur );
    389    if (*ctx->cur != '[') {
    390       report_error( ctx, "Expected `['" );
    391       return FALSE;
    392    }
    393    ctx->cur++;
    394    return TRUE;
    395 }
    396 
    397 /* <register_file_bracket_index> ::= <register_file_bracket> <uint>
    398  */
    399 static boolean
    400 parse_register_file_bracket_index(
    401    struct translate_ctx *ctx,
    402    uint *file,
    403    int *index )
    404 {
    405    uint uindex;
    406 
    407    if (!parse_register_file_bracket( ctx, file ))
    408       return FALSE;
    409    eat_opt_white( &ctx->cur );
    410    if (!parse_uint( &ctx->cur, &uindex )) {
    411       report_error( ctx, "Expected literal unsigned integer" );
    412       return FALSE;
    413    }
    414    *index = (int) uindex;
    415    return TRUE;
    416 }
    417 
    418 /* Parse simple 1d register operand.
    419  *    <register_dst> ::= <register_file_bracket_index> `]'
    420  */
    421 static boolean
    422 parse_register_1d(struct translate_ctx *ctx,
    423                   uint *file,
    424                   int *index )
    425 {
    426    if (!parse_register_file_bracket_index( ctx, file, index ))
    427       return FALSE;
    428    eat_opt_white( &ctx->cur );
    429    if (*ctx->cur != ']') {
    430       report_error( ctx, "Expected `]'" );
    431       return FALSE;
    432    }
    433    ctx->cur++;
    434    return TRUE;
    435 }
    436 
    437 struct parsed_bracket {
    438    int index;
    439 
    440    uint ind_file;
    441    int ind_index;
    442    uint ind_comp;
    443 };
    444 
    445 
    446 static boolean
    447 parse_register_bracket(
    448    struct translate_ctx *ctx,
    449    struct parsed_bracket *brackets)
    450 {
    451    const char *cur;
    452    uint uindex;
    453 
    454    memset(brackets, 0, sizeof(struct parsed_bracket));
    455 
    456    eat_opt_white( &ctx->cur );
    457 
    458    cur = ctx->cur;
    459    if (parse_file( &cur, &brackets->ind_file )) {
    460       if (!parse_register_1d( ctx, &brackets->ind_file,
    461                               &brackets->ind_index ))
    462          return FALSE;
    463       eat_opt_white( &ctx->cur );
    464 
    465       if (*ctx->cur == '.') {
    466          ctx->cur++;
    467          eat_opt_white(&ctx->cur);
    468 
    469          switch (uprcase(*ctx->cur)) {
    470          case 'X':
    471             brackets->ind_comp = TGSI_SWIZZLE_X;
    472             break;
    473          case 'Y':
    474             brackets->ind_comp = TGSI_SWIZZLE_Y;
    475             break;
    476          case 'Z':
    477             brackets->ind_comp = TGSI_SWIZZLE_Z;
    478             break;
    479          case 'W':
    480             brackets->ind_comp = TGSI_SWIZZLE_W;
    481             break;
    482          default:
    483             report_error(ctx, "Expected indirect register swizzle component `x', `y', `z' or `w'");
    484             return FALSE;
    485          }
    486          ctx->cur++;
    487          eat_opt_white(&ctx->cur);
    488       }
    489 
    490       if (*ctx->cur == '+' || *ctx->cur == '-')
    491          parse_int( &ctx->cur, &brackets->index );
    492       else
    493          brackets->index = 0;
    494    }
    495    else {
    496       if (!parse_uint( &ctx->cur, &uindex )) {
    497          report_error( ctx, "Expected literal unsigned integer" );
    498          return FALSE;
    499       }
    500       brackets->index = (int) uindex;
    501       brackets->ind_file = TGSI_FILE_NULL;
    502       brackets->ind_index = 0;
    503    }
    504    eat_opt_white( &ctx->cur );
    505    if (*ctx->cur != ']') {
    506       report_error( ctx, "Expected `]'" );
    507       return FALSE;
    508    }
    509    ctx->cur++;
    510    return TRUE;
    511 }
    512 
    513 static boolean
    514 parse_opt_register_src_bracket(
    515    struct translate_ctx *ctx,
    516    struct parsed_bracket *brackets,
    517    int *parsed_brackets)
    518 {
    519    const char *cur = ctx->cur;
    520 
    521    *parsed_brackets = 0;
    522 
    523    eat_opt_white( &cur );
    524    if (cur[0] == '[') {
    525       ++cur;
    526       ctx->cur = cur;
    527 
    528       if (!parse_register_bracket(ctx, brackets))
    529          return FALSE;
    530 
    531       *parsed_brackets = 1;
    532    }
    533 
    534    return TRUE;
    535 }
    536 
    537 
    538 /* Parse source register operand.
    539  *    <register_src> ::= <register_file_bracket_index> `]' |
    540  *                       <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `]' |
    541  *                       <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `+' <uint> `]' |
    542  *                       <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `-' <uint> `]'
    543  */
    544 static boolean
    545 parse_register_src(
    546    struct translate_ctx *ctx,
    547    uint *file,
    548    struct parsed_bracket *brackets)
    549 {
    550    brackets->ind_comp = TGSI_SWIZZLE_X;
    551    if (!parse_register_file_bracket( ctx, file ))
    552       return FALSE;
    553    if (!parse_register_bracket( ctx, brackets ))
    554        return FALSE;
    555 
    556    return TRUE;
    557 }
    558 
    559 struct parsed_dcl_bracket {
    560    uint first;
    561    uint last;
    562 };
    563 
    564 static boolean
    565 parse_register_dcl_bracket(
    566    struct translate_ctx *ctx,
    567    struct parsed_dcl_bracket *bracket)
    568 {
    569    uint uindex;
    570    memset(bracket, 0, sizeof(struct parsed_dcl_bracket));
    571 
    572    eat_opt_white( &ctx->cur );
    573 
    574    if (!parse_uint( &ctx->cur, &uindex )) {
    575       /* it can be an empty bracket [] which means its range
    576        * is from 0 to some implied size */
    577       if (ctx->cur[0] == ']' && ctx->implied_array_size != 0) {
    578          bracket->first = 0;
    579          bracket->last = ctx->implied_array_size - 1;
    580          goto cleanup;
    581       }
    582       report_error( ctx, "Expected literal unsigned integer" );
    583       return FALSE;
    584    }
    585    bracket->first = uindex;
    586 
    587    eat_opt_white( &ctx->cur );
    588 
    589    if (ctx->cur[0] == '.' && ctx->cur[1] == '.') {
    590       uint uindex;
    591 
    592       ctx->cur += 2;
    593       eat_opt_white( &ctx->cur );
    594       if (!parse_uint( &ctx->cur, &uindex )) {
    595          report_error( ctx, "Expected literal integer" );
    596          return FALSE;
    597       }
    598       bracket->last = (int) uindex;
    599       eat_opt_white( &ctx->cur );
    600    }
    601    else {
    602       bracket->last = bracket->first;
    603    }
    604 
    605 cleanup:
    606    if (*ctx->cur != ']') {
    607       report_error( ctx, "Expected `]' or `..'" );
    608       return FALSE;
    609    }
    610    ctx->cur++;
    611    return TRUE;
    612 }
    613 
    614 /* Parse register declaration.
    615  *    <register_dcl> ::= <register_file_bracket_index> `]' |
    616  *                       <register_file_bracket_index> `..' <index> `]'
    617  */
    618 static boolean
    619 parse_register_dcl(
    620    struct translate_ctx *ctx,
    621    uint *file,
    622    struct parsed_dcl_bracket *brackets,
    623    int *num_brackets)
    624 {
    625    const char *cur;
    626 
    627    *num_brackets = 0;
    628 
    629    if (!parse_register_file_bracket( ctx, file ))
    630       return FALSE;
    631    if (!parse_register_dcl_bracket( ctx, &brackets[0] ))
    632       return FALSE;
    633 
    634    *num_brackets = 1;
    635 
    636    cur = ctx->cur;
    637    eat_opt_white( &cur );
    638 
    639    if (cur[0] == '[') {
    640       ++cur;
    641       ctx->cur = cur;
    642       if (!parse_register_dcl_bracket( ctx, &brackets[1] ))
    643          return FALSE;
    644       /* for geometry shader we don't really care about
    645        * the first brackets it's always the size of the
    646        * input primitive. so we want to declare just
    647        * the index relevant to the semantics which is in
    648        * the second bracket */
    649       if (ctx->processor == TGSI_PROCESSOR_GEOMETRY && *file == TGSI_FILE_INPUT) {
    650          brackets[0] = brackets[1];
    651          *num_brackets = 1;
    652       } else {
    653          *num_brackets = 2;
    654       }
    655    }
    656 
    657    return TRUE;
    658 }
    659 
    660 
    661 /* Parse destination register operand.*/
    662 static boolean
    663 parse_register_dst(
    664    struct translate_ctx *ctx,
    665    uint *file,
    666    struct parsed_bracket *brackets)
    667 {
    668    brackets->ind_comp = TGSI_SWIZZLE_X;
    669    if (!parse_register_file_bracket( ctx, file ))
    670       return FALSE;
    671    if (!parse_register_bracket( ctx, brackets ))
    672        return FALSE;
    673 
    674    return TRUE;
    675 }
    676 
    677 static boolean
    678 parse_dst_operand(
    679    struct translate_ctx *ctx,
    680    struct tgsi_full_dst_register *dst )
    681 {
    682    uint file;
    683    uint writemask;
    684    const char *cur;
    685    struct parsed_bracket bracket[2];
    686    int parsed_opt_brackets;
    687 
    688    if (!parse_register_dst( ctx, &file, &bracket[0] ))
    689       return FALSE;
    690    if (!parse_opt_register_src_bracket(ctx, &bracket[1], &parsed_opt_brackets))
    691       return FALSE;
    692 
    693    cur = ctx->cur;
    694    eat_opt_white( &cur );
    695 
    696    if (!parse_opt_writemask( ctx, &writemask ))
    697       return FALSE;
    698 
    699    dst->Register.File = file;
    700    if (parsed_opt_brackets) {
    701       dst->Register.Dimension = 1;
    702       dst->Dimension.Indirect = 0;
    703       dst->Dimension.Dimension = 0;
    704       dst->Dimension.Index = bracket[0].index;
    705       bracket[0] = bracket[1];
    706    }
    707    dst->Register.Index = bracket[0].index;
    708    dst->Register.WriteMask = writemask;
    709    if (bracket[0].ind_file != TGSI_FILE_NULL) {
    710       dst->Register.Indirect = 1;
    711       dst->Indirect.File = bracket[0].ind_file;
    712       dst->Indirect.Index = bracket[0].ind_index;
    713       dst->Indirect.SwizzleX = bracket[0].ind_comp;
    714       dst->Indirect.SwizzleY = bracket[0].ind_comp;
    715       dst->Indirect.SwizzleZ = bracket[0].ind_comp;
    716       dst->Indirect.SwizzleW = bracket[0].ind_comp;
    717    }
    718    return TRUE;
    719 }
    720 
    721 static boolean
    722 parse_optional_swizzle(
    723    struct translate_ctx *ctx,
    724    uint swizzle[4],
    725    boolean *parsed_swizzle )
    726 {
    727    const char *cur = ctx->cur;
    728 
    729    *parsed_swizzle = FALSE;
    730 
    731    eat_opt_white( &cur );
    732    if (*cur == '.') {
    733       uint i;
    734 
    735       cur++;
    736       eat_opt_white( &cur );
    737       for (i = 0; i < 4; i++) {
    738          if (uprcase( *cur ) == 'X')
    739             swizzle[i] = TGSI_SWIZZLE_X;
    740          else if (uprcase( *cur ) == 'Y')
    741             swizzle[i] = TGSI_SWIZZLE_Y;
    742          else if (uprcase( *cur ) == 'Z')
    743             swizzle[i] = TGSI_SWIZZLE_Z;
    744          else if (uprcase( *cur ) == 'W')
    745             swizzle[i] = TGSI_SWIZZLE_W;
    746          else {
    747 	    report_error( ctx, "Expected register swizzle component `x', `y', `z' or `w'" );
    748 	    return FALSE;
    749          }
    750          cur++;
    751       }
    752       *parsed_swizzle = TRUE;
    753       ctx->cur = cur;
    754    }
    755    return TRUE;
    756 }
    757 
    758 static boolean
    759 parse_src_operand(
    760    struct translate_ctx *ctx,
    761    struct tgsi_full_src_register *src )
    762 {
    763    uint file;
    764    uint swizzle[4];
    765    boolean parsed_swizzle;
    766    struct parsed_bracket bracket[2];
    767    int parsed_opt_brackets;
    768 
    769    if (*ctx->cur == '-') {
    770       ctx->cur++;
    771       eat_opt_white( &ctx->cur );
    772       src->Register.Negate = 1;
    773    }
    774 
    775    if (*ctx->cur == '|') {
    776       ctx->cur++;
    777       eat_opt_white( &ctx->cur );
    778       src->Register.Absolute = 1;
    779    }
    780 
    781    if (!parse_register_src(ctx, &file, &bracket[0]))
    782       return FALSE;
    783    if (!parse_opt_register_src_bracket(ctx, &bracket[1], &parsed_opt_brackets))
    784       return FALSE;
    785 
    786    src->Register.File = file;
    787    if (parsed_opt_brackets) {
    788       src->Register.Dimension = 1;
    789       src->Dimension.Indirect = 0;
    790       src->Dimension.Dimension = 0;
    791       src->Dimension.Index = bracket[0].index;
    792       bracket[0] = bracket[1];
    793    }
    794    src->Register.Index = bracket[0].index;
    795    if (bracket[0].ind_file != TGSI_FILE_NULL) {
    796       src->Register.Indirect = 1;
    797       src->Indirect.File = bracket[0].ind_file;
    798       src->Indirect.Index = bracket[0].ind_index;
    799       src->Indirect.SwizzleX = bracket[0].ind_comp;
    800       src->Indirect.SwizzleY = bracket[0].ind_comp;
    801       src->Indirect.SwizzleZ = bracket[0].ind_comp;
    802       src->Indirect.SwizzleW = bracket[0].ind_comp;
    803    }
    804 
    805    /* Parse optional swizzle.
    806     */
    807    if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle )) {
    808       if (parsed_swizzle) {
    809          src->Register.SwizzleX = swizzle[0];
    810          src->Register.SwizzleY = swizzle[1];
    811          src->Register.SwizzleZ = swizzle[2];
    812          src->Register.SwizzleW = swizzle[3];
    813       }
    814    }
    815 
    816    if (src->Register.Absolute) {
    817       eat_opt_white( &ctx->cur );
    818       if (*ctx->cur != '|') {
    819          report_error( ctx, "Expected `|'" );
    820          return FALSE;
    821       }
    822       ctx->cur++;
    823    }
    824 
    825 
    826    return TRUE;
    827 }
    828 
    829 static boolean
    830 match_inst(const char **pcur,
    831            unsigned *saturate,
    832            const struct tgsi_opcode_info *info)
    833 {
    834    const char *cur = *pcur;
    835 
    836    /* simple case: the whole string matches the instruction name */
    837    if (str_match_nocase_whole(&cur, info->mnemonic)) {
    838       *pcur = cur;
    839       *saturate = TGSI_SAT_NONE;
    840       return TRUE;
    841    }
    842 
    843    if (str_match_no_case(&cur, info->mnemonic)) {
    844       /* the instruction has a suffix, figure it out */
    845       if (str_match_nocase_whole(&cur, "_SAT")) {
    846          *pcur = cur;
    847          *saturate = TGSI_SAT_ZERO_ONE;
    848          return TRUE;
    849       }
    850 
    851       if (str_match_nocase_whole(&cur, "_SATNV")) {
    852          *pcur = cur;
    853          *saturate = TGSI_SAT_MINUS_PLUS_ONE;
    854          return TRUE;
    855       }
    856    }
    857 
    858    return FALSE;
    859 }
    860 
    861 static boolean
    862 parse_instruction(
    863    struct translate_ctx *ctx,
    864    boolean has_label )
    865 {
    866    uint i;
    867    uint saturate = TGSI_SAT_NONE;
    868    const struct tgsi_opcode_info *info;
    869    struct tgsi_full_instruction inst;
    870    const char *cur;
    871    uint advance;
    872 
    873    inst = tgsi_default_full_instruction();
    874 
    875    /* Parse predicate.
    876     */
    877    eat_opt_white( &ctx->cur );
    878    if (*ctx->cur == '(') {
    879       uint file;
    880       int index;
    881       uint swizzle[4];
    882       boolean parsed_swizzle;
    883 
    884       inst.Instruction.Predicate = 1;
    885 
    886       ctx->cur++;
    887       if (*ctx->cur == '!') {
    888          ctx->cur++;
    889          inst.Predicate.Negate = 1;
    890       }
    891 
    892       if (!parse_register_1d( ctx, &file, &index ))
    893          return FALSE;
    894 
    895       if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle )) {
    896          if (parsed_swizzle) {
    897             inst.Predicate.SwizzleX = swizzle[0];
    898             inst.Predicate.SwizzleY = swizzle[1];
    899             inst.Predicate.SwizzleZ = swizzle[2];
    900             inst.Predicate.SwizzleW = swizzle[3];
    901          }
    902       }
    903 
    904       if (*ctx->cur != ')') {
    905          report_error( ctx, "Expected `)'" );
    906          return FALSE;
    907       }
    908 
    909       ctx->cur++;
    910    }
    911 
    912    /* Parse instruction name.
    913     */
    914    eat_opt_white( &ctx->cur );
    915    for (i = 0; i < TGSI_OPCODE_LAST; i++) {
    916       cur = ctx->cur;
    917 
    918       info = tgsi_get_opcode_info( i );
    919       if (match_inst(&cur, &saturate, info)) {
    920          if (info->num_dst + info->num_src + info->is_tex == 0) {
    921             ctx->cur = cur;
    922             break;
    923          }
    924          else if (*cur == '\0' || eat_white( &cur )) {
    925             ctx->cur = cur;
    926             break;
    927          }
    928       }
    929    }
    930    if (i == TGSI_OPCODE_LAST) {
    931       if (has_label)
    932          report_error( ctx, "Unknown opcode" );
    933       else
    934          report_error( ctx, "Expected `DCL', `IMM' or a label" );
    935       return FALSE;
    936    }
    937 
    938    inst.Instruction.Opcode = i;
    939    inst.Instruction.Saturate = saturate;
    940    inst.Instruction.NumDstRegs = info->num_dst;
    941    inst.Instruction.NumSrcRegs = info->num_src;
    942 
    943    /* Parse instruction operands.
    944     */
    945    for (i = 0; i < info->num_dst + info->num_src + info->is_tex; i++) {
    946       if (i > 0) {
    947          eat_opt_white( &ctx->cur );
    948          if (*ctx->cur != ',') {
    949             report_error( ctx, "Expected `,'" );
    950             return FALSE;
    951          }
    952          ctx->cur++;
    953          eat_opt_white( &ctx->cur );
    954       }
    955 
    956       if (i < info->num_dst) {
    957          if (!parse_dst_operand( ctx, &inst.Dst[i] ))
    958             return FALSE;
    959       }
    960       else if (i < info->num_dst + info->num_src) {
    961          if (!parse_src_operand( ctx, &inst.Src[i - info->num_dst] ))
    962             return FALSE;
    963       }
    964       else {
    965          uint j;
    966 
    967          for (j = 0; j < TGSI_TEXTURE_COUNT; j++) {
    968             if (str_match_nocase_whole( &ctx->cur, tgsi_texture_names[j] )) {
    969                inst.Instruction.Texture = 1;
    970                inst.Texture.Texture = j;
    971                break;
    972             }
    973          }
    974          if (j == TGSI_TEXTURE_COUNT) {
    975             report_error( ctx, "Expected texture target" );
    976             return FALSE;
    977          }
    978       }
    979    }
    980 
    981    cur = ctx->cur;
    982    eat_opt_white( &cur );
    983    if (info->is_branch && *cur == ':') {
    984       uint target;
    985 
    986       cur++;
    987       eat_opt_white( &cur );
    988       if (!parse_uint( &cur, &target )) {
    989          report_error( ctx, "Expected a label" );
    990          return FALSE;
    991       }
    992       inst.Instruction.Label = 1;
    993       inst.Label.Label = target;
    994       ctx->cur = cur;
    995    }
    996 
    997    advance = tgsi_build_full_instruction(
    998       &inst,
    999       ctx->tokens_cur,
   1000       ctx->header,
   1001       (uint) (ctx->tokens_end - ctx->tokens_cur) );
   1002    if (advance == 0)
   1003       return FALSE;
   1004    ctx->tokens_cur += advance;
   1005 
   1006    return TRUE;
   1007 }
   1008 
   1009 /* parses a 4-touple of the form {x, y, z, w}
   1010  * where x, y, z, w are numbers */
   1011 static boolean parse_immediate_data(struct translate_ctx *ctx, unsigned type,
   1012                                     union tgsi_immediate_data *values)
   1013 {
   1014    unsigned i;
   1015    int ret;
   1016 
   1017    eat_opt_white( &ctx->cur );
   1018    if (*ctx->cur != '{') {
   1019       report_error( ctx, "Expected `{'" );
   1020       return FALSE;
   1021    }
   1022    ctx->cur++;
   1023    for (i = 0; i < 4; i++) {
   1024       eat_opt_white( &ctx->cur );
   1025       if (i > 0) {
   1026          if (*ctx->cur != ',') {
   1027             report_error( ctx, "Expected `,'" );
   1028             return FALSE;
   1029          }
   1030          ctx->cur++;
   1031          eat_opt_white( &ctx->cur );
   1032       }
   1033 
   1034       switch (type) {
   1035       case TGSI_IMM_FLOAT32:
   1036          ret = parse_float(&ctx->cur, &values[i].Float);
   1037          break;
   1038       case TGSI_IMM_UINT32:
   1039          ret = parse_uint(&ctx->cur, &values[i].Uint);
   1040          break;
   1041       case TGSI_IMM_INT32:
   1042          ret = parse_int(&ctx->cur, &values[i].Int);
   1043          break;
   1044       default:
   1045          assert(0);
   1046          ret = FALSE;
   1047          break;
   1048       }
   1049 
   1050       if (!ret) {
   1051          report_error( ctx, "Expected immediate constant" );
   1052          return FALSE;
   1053       }
   1054    }
   1055    eat_opt_white( &ctx->cur );
   1056    if (*ctx->cur != '}') {
   1057       report_error( ctx, "Expected `}'" );
   1058       return FALSE;
   1059    }
   1060    ctx->cur++;
   1061 
   1062    return TRUE;
   1063 }
   1064 
   1065 static boolean parse_declaration( struct translate_ctx *ctx )
   1066 {
   1067    struct tgsi_full_declaration decl;
   1068    uint file;
   1069    struct parsed_dcl_bracket brackets[2];
   1070    int num_brackets;
   1071    uint writemask;
   1072    const char *cur, *cur2;
   1073    uint advance;
   1074    boolean is_vs_input;
   1075    boolean is_imm_array;
   1076 
   1077    if (!eat_white( &ctx->cur )) {
   1078       report_error( ctx, "Syntax error" );
   1079       return FALSE;
   1080    }
   1081    if (!parse_register_dcl( ctx, &file, brackets, &num_brackets))
   1082       return FALSE;
   1083    if (!parse_opt_writemask( ctx, &writemask ))
   1084       return FALSE;
   1085 
   1086    decl = tgsi_default_full_declaration();
   1087    decl.Declaration.File = file;
   1088    decl.Declaration.UsageMask = writemask;
   1089 
   1090    if (num_brackets == 1) {
   1091       decl.Range.First = brackets[0].first;
   1092       decl.Range.Last = brackets[0].last;
   1093    } else {
   1094       decl.Range.First = brackets[1].first;
   1095       decl.Range.Last = brackets[1].last;
   1096 
   1097       decl.Declaration.Dimension = 1;
   1098       decl.Dim.Index2D = brackets[0].first;
   1099    }
   1100 
   1101    is_vs_input = (file == TGSI_FILE_INPUT &&
   1102                   ctx->processor == TGSI_PROCESSOR_VERTEX);
   1103    is_imm_array = (file == TGSI_FILE_IMMEDIATE_ARRAY);
   1104 
   1105    cur = ctx->cur;
   1106    eat_opt_white( &cur );
   1107    if (*cur == ',' && !is_vs_input) {
   1108       uint i, j;
   1109 
   1110       cur++;
   1111       eat_opt_white( &cur );
   1112       if (file == TGSI_FILE_RESOURCE) {
   1113          for (i = 0; i < TGSI_TEXTURE_COUNT; i++) {
   1114             if (str_match_nocase_whole(&cur, tgsi_texture_names[i])) {
   1115                decl.Resource.Resource = i;
   1116                break;
   1117             }
   1118          }
   1119          if (i == TGSI_TEXTURE_COUNT) {
   1120             report_error(ctx, "Expected texture target");
   1121             return FALSE;
   1122          }
   1123 
   1124          cur2 = cur;
   1125          eat_opt_white(&cur2);
   1126          while (*cur2 == ',') {
   1127             cur2++;
   1128             eat_opt_white(&cur2);
   1129             if (str_match_nocase_whole(&cur2, "RAW")) {
   1130                decl.Resource.Raw = 1;
   1131 
   1132             } else if (str_match_nocase_whole(&cur2, "WR")) {
   1133                decl.Resource.Writable = 1;
   1134 
   1135             } else {
   1136                break;
   1137             }
   1138             cur = cur2;
   1139             eat_opt_white(&cur2);
   1140          }
   1141 
   1142          ctx->cur = cur;
   1143 
   1144       } else if (file == TGSI_FILE_SAMPLER_VIEW) {
   1145          for (i = 0; i < TGSI_TEXTURE_COUNT; i++) {
   1146             if (str_match_nocase_whole(&cur, tgsi_texture_names[i])) {
   1147                decl.SamplerView.Resource = i;
   1148                break;
   1149             }
   1150          }
   1151          if (i == TGSI_TEXTURE_COUNT) {
   1152             report_error(ctx, "Expected texture target");
   1153             return FALSE;
   1154          }
   1155          eat_opt_white( &cur );
   1156          if (*cur != ',') {
   1157             report_error( ctx, "Expected `,'" );
   1158             return FALSE;
   1159          }
   1160          ++cur;
   1161          eat_opt_white( &cur );
   1162          for (j = 0; j < 4; ++j) {
   1163             for (i = 0; i < PIPE_TYPE_COUNT; ++i) {
   1164                if (str_match_nocase_whole(&cur, tgsi_type_names[i])) {
   1165                   switch (j) {
   1166                   case 0:
   1167                      decl.SamplerView.ReturnTypeX = i;
   1168                      break;
   1169                   case 1:
   1170                      decl.SamplerView.ReturnTypeY = i;
   1171                      break;
   1172                   case 2:
   1173                      decl.SamplerView.ReturnTypeZ = i;
   1174                      break;
   1175                   case 3:
   1176                      decl.SamplerView.ReturnTypeW = i;
   1177                      break;
   1178                   default:
   1179                      assert(0);
   1180                   }
   1181                   break;
   1182                }
   1183             }
   1184             if (i == PIPE_TYPE_COUNT) {
   1185                if (j == 0 || j >  2) {
   1186                   report_error(ctx, "Expected type name");
   1187                   return FALSE;
   1188                }
   1189                break;
   1190             } else {
   1191                cur2 = cur;
   1192                eat_opt_white( &cur2 );
   1193                if (*cur2 == ',') {
   1194                   cur2++;
   1195                   eat_opt_white( &cur2 );
   1196                   cur = cur2;
   1197                   continue;
   1198                } else
   1199                   break;
   1200             }
   1201          }
   1202          if (j < 4) {
   1203             decl.SamplerView.ReturnTypeY =
   1204                decl.SamplerView.ReturnTypeZ =
   1205                decl.SamplerView.ReturnTypeW =
   1206                decl.SamplerView.ReturnTypeX;
   1207          }
   1208          ctx->cur = cur;
   1209       } else {
   1210          if (str_match_nocase_whole(&cur, "LOCAL")) {
   1211             decl.Declaration.Local = 1;
   1212             ctx->cur = cur;
   1213          }
   1214 
   1215          cur = ctx->cur;
   1216          eat_opt_white( &cur );
   1217          if (*cur == ',') {
   1218             cur++;
   1219             eat_opt_white( &cur );
   1220 
   1221             for (i = 0; i < TGSI_SEMANTIC_COUNT; i++) {
   1222                if (str_match_nocase_whole(&cur, tgsi_semantic_names[i])) {
   1223                   uint index;
   1224 
   1225                   cur2 = cur;
   1226                   eat_opt_white( &cur2 );
   1227                   if (*cur2 == '[') {
   1228                      cur2++;
   1229                      eat_opt_white( &cur2 );
   1230                      if (!parse_uint( &cur2, &index )) {
   1231                         report_error( ctx, "Expected literal integer" );
   1232                         return FALSE;
   1233                      }
   1234                      eat_opt_white( &cur2 );
   1235                      if (*cur2 != ']') {
   1236                         report_error( ctx, "Expected `]'" );
   1237                         return FALSE;
   1238                      }
   1239                      cur2++;
   1240 
   1241                      decl.Semantic.Index = index;
   1242 
   1243                      cur = cur2;
   1244                   }
   1245 
   1246                   decl.Declaration.Semantic = 1;
   1247                   decl.Semantic.Name = i;
   1248 
   1249                   ctx->cur = cur;
   1250                   break;
   1251                }
   1252             }
   1253          }
   1254       }
   1255    } else if (is_imm_array) {
   1256       unsigned i;
   1257       union tgsi_immediate_data *vals_itr;
   1258       /* we have our immediate data */
   1259       if (*cur != '{') {
   1260          report_error( ctx, "Immediate array without data" );
   1261          return FALSE;
   1262       }
   1263       ++cur;
   1264       ctx->cur = cur;
   1265 
   1266       decl.ImmediateData.u =
   1267          MALLOC(sizeof(union tgsi_immediate_data) * 4 *
   1268                 (decl.Range.Last + 1));
   1269       vals_itr = decl.ImmediateData.u;
   1270       for (i = 0; i <= decl.Range.Last; ++i) {
   1271          if (!parse_immediate_data(ctx, TGSI_IMM_FLOAT32, vals_itr)) {
   1272             FREE(decl.ImmediateData.u);
   1273             return FALSE;
   1274          }
   1275          vals_itr += 4;
   1276          eat_opt_white( &ctx->cur );
   1277          if (*ctx->cur != ',') {
   1278             if (i !=  decl.Range.Last) {
   1279                report_error( ctx, "Not enough data in immediate array!" );
   1280                FREE(decl.ImmediateData.u);
   1281                return FALSE;
   1282             }
   1283          } else
   1284             ++ctx->cur;
   1285       }
   1286       eat_opt_white( &ctx->cur );
   1287       if (*ctx->cur != '}') {
   1288          FREE(decl.ImmediateData.u);
   1289          report_error( ctx, "Immediate array data missing closing '}'" );
   1290          return FALSE;
   1291       }
   1292       ++ctx->cur;
   1293    }
   1294 
   1295    cur = ctx->cur;
   1296    eat_opt_white( &cur );
   1297    if (*cur == ',' && !is_vs_input) {
   1298       uint i;
   1299 
   1300       cur++;
   1301       eat_opt_white( &cur );
   1302       for (i = 0; i < TGSI_INTERPOLATE_COUNT; i++) {
   1303          if (str_match_nocase_whole( &cur, tgsi_interpolate_names[i] )) {
   1304             decl.Declaration.Interpolate = 1;
   1305             decl.Interp.Interpolate = i;
   1306 
   1307             ctx->cur = cur;
   1308             break;
   1309          }
   1310       }
   1311       if (i == TGSI_INTERPOLATE_COUNT) {
   1312          report_error( ctx, "Expected semantic or interpolate attribute" );
   1313          return FALSE;
   1314       }
   1315    }
   1316 
   1317    advance = tgsi_build_full_declaration(
   1318       &decl,
   1319       ctx->tokens_cur,
   1320       ctx->header,
   1321       (uint) (ctx->tokens_end - ctx->tokens_cur) );
   1322 
   1323    if (is_imm_array)
   1324       FREE(decl.ImmediateData.u);
   1325 
   1326    if (advance == 0)
   1327       return FALSE;
   1328    ctx->tokens_cur += advance;
   1329 
   1330    return TRUE;
   1331 }
   1332 
   1333 static boolean parse_immediate( struct translate_ctx *ctx )
   1334 {
   1335    struct tgsi_full_immediate imm;
   1336    uint advance;
   1337    int type;
   1338 
   1339    if (!eat_white( &ctx->cur )) {
   1340       report_error( ctx, "Syntax error" );
   1341       return FALSE;
   1342    }
   1343    for (type = 0; type < Elements(tgsi_immediate_type_names); ++type) {
   1344       if (str_match_nocase_whole(&ctx->cur, tgsi_immediate_type_names[type]))
   1345          break;
   1346    }
   1347    if (type == Elements(tgsi_immediate_type_names)) {
   1348       report_error( ctx, "Expected immediate type" );
   1349       return FALSE;
   1350    }
   1351 
   1352    imm = tgsi_default_full_immediate();
   1353    imm.Immediate.NrTokens += 4;
   1354    imm.Immediate.DataType = type;
   1355    parse_immediate_data(ctx, type, imm.u);
   1356 
   1357    advance = tgsi_build_full_immediate(
   1358       &imm,
   1359       ctx->tokens_cur,
   1360       ctx->header,
   1361       (uint) (ctx->tokens_end - ctx->tokens_cur) );
   1362    if (advance == 0)
   1363       return FALSE;
   1364    ctx->tokens_cur += advance;
   1365 
   1366    return TRUE;
   1367 }
   1368 
   1369 static boolean
   1370 parse_primitive( const char **pcur, uint *primitive )
   1371 {
   1372    uint i;
   1373 
   1374    for (i = 0; i < PIPE_PRIM_MAX; i++) {
   1375       const char *cur = *pcur;
   1376 
   1377       if (str_match_nocase_whole( &cur, tgsi_primitive_names[i])) {
   1378          *primitive = i;
   1379          *pcur = cur;
   1380          return TRUE;
   1381       }
   1382    }
   1383    return FALSE;
   1384 }
   1385 
   1386 static boolean
   1387 parse_fs_coord_origin( const char **pcur, uint *fs_coord_origin )
   1388 {
   1389    uint i;
   1390 
   1391    for (i = 0; i < Elements(tgsi_fs_coord_origin_names); i++) {
   1392       const char *cur = *pcur;
   1393 
   1394       if (str_match_nocase_whole( &cur, tgsi_fs_coord_origin_names[i])) {
   1395          *fs_coord_origin = i;
   1396          *pcur = cur;
   1397          return TRUE;
   1398       }
   1399    }
   1400    return FALSE;
   1401 }
   1402 
   1403 static boolean
   1404 parse_fs_coord_pixel_center( const char **pcur, uint *fs_coord_pixel_center )
   1405 {
   1406    uint i;
   1407 
   1408    for (i = 0; i < Elements(tgsi_fs_coord_pixel_center_names); i++) {
   1409       const char *cur = *pcur;
   1410 
   1411       if (str_match_nocase_whole( &cur, tgsi_fs_coord_pixel_center_names[i])) {
   1412          *fs_coord_pixel_center = i;
   1413          *pcur = cur;
   1414          return TRUE;
   1415       }
   1416    }
   1417    return FALSE;
   1418 }
   1419 
   1420 
   1421 static boolean parse_property( struct translate_ctx *ctx )
   1422 {
   1423    struct tgsi_full_property prop;
   1424    uint property_name;
   1425    uint values[8];
   1426    uint advance;
   1427    char id[64];
   1428 
   1429    if (!eat_white( &ctx->cur )) {
   1430       report_error( ctx, "Syntax error" );
   1431       return FALSE;
   1432    }
   1433    if (!parse_identifier( &ctx->cur, id )) {
   1434       report_error( ctx, "Syntax error" );
   1435       return FALSE;
   1436    }
   1437    for (property_name = 0; property_name < TGSI_PROPERTY_COUNT;
   1438         ++property_name) {
   1439       if (streq_nocase_uprcase(tgsi_property_names[property_name], id)) {
   1440          break;
   1441       }
   1442    }
   1443    if (property_name >= TGSI_PROPERTY_COUNT) {
   1444       debug_printf( "\nError: Unknown property : '%s'", id );
   1445       return FALSE;
   1446    }
   1447 
   1448    eat_opt_white( &ctx->cur );
   1449    switch(property_name) {
   1450    case TGSI_PROPERTY_GS_INPUT_PRIM:
   1451    case TGSI_PROPERTY_GS_OUTPUT_PRIM:
   1452       if (!parse_primitive(&ctx->cur, &values[0] )) {
   1453          report_error( ctx, "Unknown primitive name as property!" );
   1454          return FALSE;
   1455       }
   1456       if (property_name == TGSI_PROPERTY_GS_INPUT_PRIM &&
   1457           ctx->processor == TGSI_PROCESSOR_GEOMETRY) {
   1458          ctx->implied_array_size = u_vertices_per_prim(values[0]);
   1459       }
   1460       break;
   1461    case TGSI_PROPERTY_FS_COORD_ORIGIN:
   1462       if (!parse_fs_coord_origin(&ctx->cur, &values[0] )) {
   1463          report_error( ctx, "Unknown coord origin as property: must be UPPER_LEFT or LOWER_LEFT!" );
   1464          return FALSE;
   1465       }
   1466       break;
   1467    case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER:
   1468       if (!parse_fs_coord_pixel_center(&ctx->cur, &values[0] )) {
   1469          report_error( ctx, "Unknown coord pixel center as property: must be HALF_INTEGER or INTEGER!" );
   1470          return FALSE;
   1471       }
   1472       break;
   1473    case TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS:
   1474    default:
   1475       if (!parse_uint(&ctx->cur, &values[0] )) {
   1476          report_error( ctx, "Expected unsigned integer as property!" );
   1477          return FALSE;
   1478       }
   1479    }
   1480 
   1481    prop = tgsi_default_full_property();
   1482    prop.Property.PropertyName = property_name;
   1483    prop.Property.NrTokens += 1;
   1484    prop.u[0].Data = values[0];
   1485 
   1486    advance = tgsi_build_full_property(
   1487       &prop,
   1488       ctx->tokens_cur,
   1489       ctx->header,
   1490       (uint) (ctx->tokens_end - ctx->tokens_cur) );
   1491    if (advance == 0)
   1492       return FALSE;
   1493    ctx->tokens_cur += advance;
   1494 
   1495    return TRUE;
   1496 }
   1497 
   1498 
   1499 static boolean translate( struct translate_ctx *ctx )
   1500 {
   1501    eat_opt_white( &ctx->cur );
   1502    if (!parse_header( ctx ))
   1503       return FALSE;
   1504 
   1505    while (*ctx->cur != '\0') {
   1506       uint label_val = 0;
   1507       if (!eat_white( &ctx->cur )) {
   1508          report_error( ctx, "Syntax error" );
   1509          return FALSE;
   1510       }
   1511 
   1512       if (*ctx->cur == '\0')
   1513          break;
   1514       if (parse_label( ctx, &label_val )) {
   1515          if (!parse_instruction( ctx, TRUE ))
   1516             return FALSE;
   1517       }
   1518       else if (str_match_nocase_whole( &ctx->cur, "DCL" )) {
   1519          if (!parse_declaration( ctx ))
   1520             return FALSE;
   1521       }
   1522       else if (str_match_nocase_whole( &ctx->cur, "IMM" )) {
   1523          if (!parse_immediate( ctx ))
   1524             return FALSE;
   1525       }
   1526       else if (str_match_nocase_whole( &ctx->cur, "PROPERTY" )) {
   1527          if (!parse_property( ctx ))
   1528             return FALSE;
   1529       }
   1530       else if (!parse_instruction( ctx, FALSE )) {
   1531          return FALSE;
   1532       }
   1533    }
   1534 
   1535    return TRUE;
   1536 }
   1537 
   1538 boolean
   1539 tgsi_text_translate(
   1540    const char *text,
   1541    struct tgsi_token *tokens,
   1542    uint num_tokens )
   1543 {
   1544    struct translate_ctx ctx;
   1545 
   1546    ctx.text = text;
   1547    ctx.cur = text;
   1548    ctx.tokens = tokens;
   1549    ctx.tokens_cur = tokens;
   1550    ctx.tokens_end = tokens + num_tokens;
   1551 
   1552    if (!translate( &ctx ))
   1553       return FALSE;
   1554 
   1555    return tgsi_sanity_check( tokens );
   1556 }
   1557