glsl: Eliminate reduce/reduce conflicts in glsl grammar
[mesa.git] / src / glsl / glsl_parser.ypp
index 3813d7a4e2072f3b76d51517ae2cff1e3467e62e..dd23279aaae2e9a273bee2ce784d82ddae400525 100644 (file)
@@ -93,7 +93,8 @@
 %token ISAMPLER1DARRAY ISAMPLER2DARRAY USAMPLER1D USAMPLER2D USAMPLER3D
 %token USAMPLERCUBE USAMPLER1DARRAY USAMPLER2DARRAY
 %token STRUCT VOID_TOK WHILE
-%token <identifier> IDENTIFIER
+%token <identifier> IDENTIFIER TYPE_IDENTIFIER NEW_IDENTIFIER
+%type <identifier> any_identifier
 %token <real> FLOATCONSTANT
 %token <n> INTCONSTANT UINTCONSTANT BOOLCONSTANT
 %token <identifier> FIELD_SELECTION
 %token VERSION EXTENSION LINE COLON EOL INTERFACE OUTPUT
 %token PRAGMA_DEBUG_ON PRAGMA_DEBUG_OFF
 %token PRAGMA_OPTIMIZE_ON PRAGMA_OPTIMIZE_OFF
+%token PRAGMA_INVARIANT_ALL
 %token LAYOUT_TOK
 
    /* Reserved words that are not actually used in the grammar.
 %token IIMAGE1D IIMAGE2D IIMAGE3D IIMAGECUBE IIMAGE1DARRAY IIMAGE2DARRAY
 %token UIMAGE1D UIMAGE2D UIMAGE3D UIMAGECUBE UIMAGE1DARRAY UIMAGE2DARRAY
 %token IMAGE1DSHADOW IMAGE2DSHADOW IMAGEBUFFER IIMAGEBUFFER UIMAGEBUFFER
+%token IMAGE1DARRAYSHADOW IMAGE2DARRAYSHADOW
 %token ROW_MAJOR
 
 %type <identifier> variable_identifier
 %type <expression> function_call_generic
 %type <expression> function_call_or_method
 %type <expression> function_call
+%type <expression> method_call_generic
+%type <expression> method_call_header_with_parameters
+%type <expression> method_call_header_no_parameters
+%type <expression> method_call_header
 %type <n> assignment_operator
 %type <n> unary_operator
 %type <expression> function_identifier
@@ -218,20 +225,40 @@ version_statement:
        /* blank - no #version specified: defaults are already set */
        | VERSION INTCONSTANT EOL
        {
+          bool supported = false;
+
           switch ($2) {
           case 100:
              state->es_shader = true;
+             supported = state->Const.GLSL_100ES;
+             break;
           case 110:
+             supported = state->Const.GLSL_110;
+             break;
           case 120:
+             supported = state->Const.GLSL_120;
+             break;
           case 130:
-             /* FINISHME: Check against implementation support versions. */
-             state->language_version = $2;
+             supported = state->Const.GLSL_130;
              break;
           default:
-             _mesa_glsl_error(& @2, state, "Shading language version"
-                              "%u is not supported\n", $2);
+             supported = false;
              break;
           }
+
+          state->language_version = $2;
+          state->version_string =
+             ralloc_asprintf(state, "GLSL%s %d.%02d",
+                             state->es_shader ? " ES" : "",
+                             state->language_version / 100,
+                             state->language_version % 100);
+
+          if (!supported) {
+             _mesa_glsl_error(& @2, state, "%s is not supported. "
+                              "Supported versions are: %s\n",
+                              state->version_string,
+                              state->supported_version_string);
+          }
        }
        ;
 
@@ -240,6 +267,16 @@ pragma_statement:
        | PRAGMA_DEBUG_OFF EOL
        | PRAGMA_OPTIMIZE_ON EOL
        | PRAGMA_OPTIMIZE_OFF EOL
+       | PRAGMA_INVARIANT_ALL EOL
+       {
+          if (state->language_version < 120) {
+             _mesa_glsl_warning(& @1, state,
+                                "pragma `invariant(all)' not supported in %s",
+                                state->version_string);
+          } else {
+             state->all_invariant = true;
+          }
+       }
        ;
 
 extension_statement_list:
@@ -247,8 +284,14 @@ extension_statement_list:
        | extension_statement_list extension_statement
        ;
 
+any_identifier:
+       IDENTIFIER
+       | TYPE_IDENTIFIER
+       | NEW_IDENTIFIER
+       ;
+
 extension_statement:
-       EXTENSION IDENTIFIER COLON IDENTIFIER EOL
+       EXTENSION any_identifier COLON any_identifier EOL
        {
           if (!_mesa_glsl_process_extension($2, & @2, $4, & @4, state)) {
              YYERROR;
@@ -259,16 +302,16 @@ extension_statement:
 external_declaration_list:
        external_declaration
        {
-          /* FINISHME: The NULL test is only required because 'precision'
-           * FINISHME: statements are not yet supported.
+          /* FINISHME: The NULL test is required because pragmas are set to
+           * FINISHME: NULL. (See production rule for external_declaration.)
            */
           if ($1 != NULL)
              state->translation_unit.push_tail(& $1->link);
        }
        | external_declaration_list external_declaration
        {
-          /* FINISHME: The NULL test is only required because 'precision'
-           * FINISHME: statements are not yet supported.
+          /* FINISHME: The NULL test is required because pragmas are set to
+           * FINISHME: NULL. (See production rule for external_declaration.)
            */
           if ($2 != NULL)
              state->translation_unit.push_tail(& $2->link);
@@ -277,6 +320,7 @@ external_declaration_list:
 
 variable_identifier:
        IDENTIFIER
+       | NEW_IDENTIFIER
        ;
 
 primary_expression:
@@ -333,7 +377,7 @@ postfix_expression:
        {
           $$ = $1;
        }
-       | postfix_expression '.' IDENTIFIER
+       | postfix_expression '.' any_identifier
        {
           void *ctx = state;
           $$ = new(ctx) ast_expression(ast_field_selection, $1, NULL, NULL);
@@ -364,7 +408,7 @@ function_call:
 
 function_call_or_method:
        function_call_generic
-       | postfix_expression '.' function_call_generic
+       | postfix_expression '.' method_call_generic
        {
           void *ctx = state;
           $$ = new(ctx) ast_expression(ast_field_selection, $1, $3, NULL);
@@ -411,7 +455,7 @@ function_identifier:
           $$ = new(ctx) ast_function_expression($1);
           $$->set_location(yylloc);
        }
-       | IDENTIFIER
+       | variable_identifier
        {
           void *ctx = state;
           ast_expression *callee = new(ctx) ast_expression($1);
@@ -427,6 +471,44 @@ function_identifier:
        }
        ;
 
+method_call_generic:
+       method_call_header_with_parameters ')'
+       | method_call_header_no_parameters ')'
+       ;
+
+method_call_header_no_parameters:
+       method_call_header VOID_TOK
+       | method_call_header
+       ;
+
+method_call_header_with_parameters:
+       method_call_header assignment_expression
+       {
+          $$ = $1;
+          $$->set_location(yylloc);
+          $$->expressions.push_tail(& $2->link);
+       }
+       | method_call_header_with_parameters ',' assignment_expression
+       {
+          $$ = $1;
+          $$->set_location(yylloc);
+          $$->expressions.push_tail(& $3->link);
+       }
+       ;
+
+       // Grammar Note: Constructors look like methods, but lexical 
+       // analysis recognized most of them as keywords. They are now
+       // recognized through "type_specifier".
+method_call_header:
+       variable_identifier '('
+       {
+          void *ctx = state;
+          ast_expression *callee = new(ctx) ast_expression($1);
+          $$ = new(ctx) ast_function_expression(callee);
+          $$->set_location(yylloc);
+       }
+       ;
+
        // Grammar Note: No traditional style type casts.
 unary_expression:
        postfix_expression
@@ -685,14 +767,9 @@ declaration:
        }
        | PRECISION precision_qualifier type_specifier_no_prec ';'
        {
-          if (($3->type_specifier != ast_float)
-              && ($3->type_specifier != ast_int)) {
-             _mesa_glsl_error(& @3, state, "global precision qualifier can "
-                              "only be applied to `int' or `float'\n");
-             YYERROR;
-          }
-
-          $$ = NULL; /* FINISHME */
+          $3->precision = $2;
+          $3->is_precision_statement = true;
+          $$ = $3;
        }
        ;
 
@@ -719,7 +796,7 @@ function_header_with_parameters:
        ;
 
 function_header:
-       fully_specified_type IDENTIFIER '('
+       fully_specified_type variable_identifier '('
        {
           void *ctx = state;
           $$ = new(ctx) ast_function();
@@ -730,7 +807,7 @@ function_header:
        ;
 
 parameter_declarator:
-       type_specifier IDENTIFIER
+       type_specifier any_identifier
        {
           void *ctx = state;
           $$ = new(ctx) ast_parameter_declarator();
@@ -740,7 +817,7 @@ parameter_declarator:
           $$->type->specifier = $1;
           $$->identifier = $2;
        }
-       | type_specifier IDENTIFIER '[' constant_expression ']'
+       | type_specifier any_identifier '[' constant_expression ']'
        {
           void *ctx = state;
           $$ = new(ctx) ast_parameter_declarator();
@@ -818,7 +895,7 @@ parameter_type_specifier:
 
 init_declarator_list:
        single_declaration
-       | init_declarator_list ',' IDENTIFIER
+       | init_declarator_list ',' any_identifier
        {
           void *ctx = state;
           ast_declaration *decl = new(ctx) ast_declaration($3, false, NULL, NULL);
@@ -827,7 +904,7 @@ init_declarator_list:
           $$ = $1;
           $$->declarations.push_tail(&decl->link);
        }
-       | init_declarator_list ',' IDENTIFIER '[' ']'
+       | init_declarator_list ',' any_identifier '[' ']'
        {
           void *ctx = state;
           ast_declaration *decl = new(ctx) ast_declaration($3, true, NULL, NULL);
@@ -836,7 +913,7 @@ init_declarator_list:
           $$ = $1;
           $$->declarations.push_tail(&decl->link);
        }
-       | init_declarator_list ',' IDENTIFIER '[' constant_expression ']'
+       | init_declarator_list ',' any_identifier '[' constant_expression ']'
        {
           void *ctx = state;
           ast_declaration *decl = new(ctx) ast_declaration($3, true, $5, NULL);
@@ -845,7 +922,7 @@ init_declarator_list:
           $$ = $1;
           $$->declarations.push_tail(&decl->link);
        }
-       | init_declarator_list ',' IDENTIFIER '[' ']' '=' initializer
+       | init_declarator_list ',' any_identifier '[' ']' '=' initializer
        {
           void *ctx = state;
           ast_declaration *decl = new(ctx) ast_declaration($3, true, NULL, $7);
@@ -854,7 +931,7 @@ init_declarator_list:
           $$ = $1;
           $$->declarations.push_tail(&decl->link);
        }
-       | init_declarator_list ',' IDENTIFIER '[' constant_expression ']' '=' initializer
+       | init_declarator_list ',' any_identifier '[' constant_expression ']' '=' initializer
        {
           void *ctx = state;
           ast_declaration *decl = new(ctx) ast_declaration($3, true, $5, $8);
@@ -863,7 +940,7 @@ init_declarator_list:
           $$ = $1;
           $$->declarations.push_tail(&decl->link);
        }
-       | init_declarator_list ',' IDENTIFIER '=' initializer
+       | init_declarator_list ',' any_identifier '=' initializer
        {
           void *ctx = state;
           ast_declaration *decl = new(ctx) ast_declaration($3, false, NULL, $5);
@@ -887,7 +964,7 @@ single_declaration:
              $$->set_location(yylloc);
           }
        }
-       | fully_specified_type IDENTIFIER
+       | fully_specified_type any_identifier
        {
           void *ctx = state;
           ast_declaration *decl = new(ctx) ast_declaration($2, false, NULL, NULL);
@@ -896,7 +973,7 @@ single_declaration:
           $$->set_location(yylloc);
           $$->declarations.push_tail(&decl->link);
        }
-       | fully_specified_type IDENTIFIER '[' ']'
+       | fully_specified_type any_identifier '[' ']'
        {
           void *ctx = state;
           ast_declaration *decl = new(ctx) ast_declaration($2, true, NULL, NULL);
@@ -905,7 +982,7 @@ single_declaration:
           $$->set_location(yylloc);
           $$->declarations.push_tail(&decl->link);
        }
-       | fully_specified_type IDENTIFIER '[' constant_expression ']'
+       | fully_specified_type any_identifier '[' constant_expression ']'
        {
           void *ctx = state;
           ast_declaration *decl = new(ctx) ast_declaration($2, true, $4, NULL);
@@ -914,7 +991,7 @@ single_declaration:
           $$->set_location(yylloc);
           $$->declarations.push_tail(&decl->link);
        }
-       | fully_specified_type IDENTIFIER '[' ']' '=' initializer
+       | fully_specified_type any_identifier '[' ']' '=' initializer
        {
           void *ctx = state;
           ast_declaration *decl = new(ctx) ast_declaration($2, true, NULL, $6);
@@ -923,7 +1000,7 @@ single_declaration:
           $$->set_location(yylloc);
           $$->declarations.push_tail(&decl->link);
        }
-       | fully_specified_type IDENTIFIER '[' constant_expression ']' '=' initializer
+       | fully_specified_type any_identifier '[' constant_expression ']' '=' initializer
        {
           void *ctx = state;
           ast_declaration *decl = new(ctx) ast_declaration($2, true, $4, $7);
@@ -932,7 +1009,7 @@ single_declaration:
           $$->set_location(yylloc);
           $$->declarations.push_tail(&decl->link);
        }
-       | fully_specified_type IDENTIFIER '=' initializer
+       | fully_specified_type any_identifier '=' initializer
        {
           void *ctx = state;
           ast_declaration *decl = new(ctx) ast_declaration($2, false, NULL, $4);
@@ -1006,7 +1083,8 @@ layout_qualifier_id:
 
           memset(& $$, 0, sizeof($$));
 
-          if (state->ARB_fragment_coord_conventions_enable) {
+          /* Layout qualifiers for ARB_fragment_coord_conventions. */
+          if (!got_one && state->ARB_fragment_coord_conventions_enable) {
              if (strcmp($1, "origin_upper_left") == 0) {
                 got_one = true;
                 $$.flags.q.origin_upper_left = 1;
@@ -1014,19 +1092,41 @@ layout_qualifier_id:
                 got_one = true;
                 $$.flags.q.pixel_center_integer = 1;
              }
+
+             if (got_one && state->ARB_fragment_coord_conventions_warn) {
+                _mesa_glsl_warning(& @1, state,
+                                   "GL_ARB_fragment_coord_conventions layout "
+                                   "identifier `%s' used\n", $1);
+             }
+          }
+
+          /* Layout qualifiers for AMD_conservative_depth. */
+          if (!got_one && state->AMD_conservative_depth_enable) {
+             if (strcmp($1, "depth_any") == 0) {
+                got_one = true;
+                $$.flags.q.depth_any = 1;
+             } else if (strcmp($1, "depth_greater") == 0) {
+                got_one = true;
+                $$.flags.q.depth_greater = 1;
+             } else if (strcmp($1, "depth_less") == 0) {
+                got_one = true;
+                $$.flags.q.depth_less = 1;
+             } else if (strcmp($1, "depth_unchanged") == 0) {
+                got_one = true;
+                $$.flags.q.depth_unchanged = 1;
+             }
+       
+             if (got_one && state->AMD_conservative_depth_warn) {
+                _mesa_glsl_warning(& @1, state,
+                                   "GL_AMD_conservative_depth "
+                                   "layout qualifier `%s' is used\n", $1);
+             }
           }
 
-          /* If the identifier didn't match any known layout identifiers,
-           * emit an error.
-           */
           if (!got_one) {
              _mesa_glsl_error(& @1, state, "unrecognized layout identifier "
                               "`%s'\n", $1);
              YYERROR;
-          } else if (state->ARB_fragment_coord_conventions_warn) {
-             _mesa_glsl_warning(& @1, state,
-                                "GL_ARB_fragment_coord_conventions layout "
-                                "identifier `%s' used\n", $1);
           }
        }
        | IDENTIFIER '=' INTCONSTANT
@@ -1178,6 +1278,9 @@ storage_qualifier:
 
 type_specifier:
        type_specifier_no_prec
+       {
+          $$ = $1;
+       }
        | precision_qualifier type_specifier_no_prec
        {
           $$ = $2;
@@ -1214,7 +1317,7 @@ type_specifier_nonarray:
           $$ = new(ctx) ast_type_specifier($1);
           $$->set_location(yylloc);
        }
-       | IDENTIFIER
+       | TYPE_IDENTIFIER
        {
           void *ctx = state;
           $$ = new(ctx) ast_type_specifier($1);
@@ -1281,10 +1384,9 @@ precision_qualifier:
                     if (!state->es_shader && state->language_version < 130)
                        _mesa_glsl_error(& @1, state,
                                         "precision qualifier forbidden "
-                                        "in GLSL %d.%d (1.30 or later "
+                                        "in %s (1.30 or later "
                                         "required)\n",
-                                        state->language_version / 100,
-                                        state->language_version % 100);
+                                        state->version_string);
 
                     $$ = ast_precision_high;
                  }
@@ -1292,10 +1394,9 @@ precision_qualifier:
                     if (!state->es_shader && state->language_version < 130)
                        _mesa_glsl_error(& @1, state,
                                         "precision qualifier forbidden "
-                                        "in GLSL %d.%d (1.30 or later "
+                                        "in %s (1.30 or later "
                                         "required)\n",
-                                        state->language_version / 100,
-                                        state->language_version % 100);
+                                        state->version_string);
 
                     $$ = ast_precision_medium;
                  }
@@ -1303,10 +1404,9 @@ precision_qualifier:
                     if (!state->es_shader && state->language_version < 130)
                        _mesa_glsl_error(& @1, state,
                                         "precision qualifier forbidden "
-                                        "in GLSL %d.%d (1.30 or later "
+                                        "in %s (1.30 or later "
                                         "required)\n",
-                                        state->language_version / 100,
-                                        state->language_version % 100);
+                                        state->version_string);
 
                     $$ = ast_precision_low;
                  }