| /* | 
 | // Copyright 2016 The SwiftShader Authors. All Rights Reserved. | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //    http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | This file contains the Yacc grammar for GLSL ES. | 
 | Based on ANSI C Yacc grammar: | 
 | http://www.lysator.liu.se/c/ANSI-C-grammar-y.html | 
 |  | 
 | IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh, | 
 | WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). | 
 | */ | 
 |  | 
 | %{ | 
 | // Copyright 2016 The SwiftShader Authors. All Rights Reserved. | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //    http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | // This file is auto-generated by generate_parser.sh. DO NOT EDIT! | 
 |  | 
 | // Ignore errors in auto-generated code. | 
 | #if defined(__GNUC__) | 
 | #pragma GCC diagnostic ignored "-Wunused-function" | 
 | #pragma GCC diagnostic ignored "-Wunused-variable" | 
 | #pragma GCC diagnostic ignored "-Wswitch-enum" | 
 | #elif defined(_MSC_VER) | 
 | #pragma warning(disable: 4065) | 
 | #pragma warning(disable: 4189) | 
 | #pragma warning(disable: 4505) | 
 | #pragma warning(disable: 4701) | 
 | #endif | 
 |  | 
 | #include "SymbolTable.h" | 
 | #include "ParseHelper.h" | 
 |  | 
 | #define YYENABLE_NLS 0 | 
 | %} | 
 |  | 
 | %expect 1 /* One shift reduce conflict because of if | else */ | 
 | %pure-parser | 
 | %parse-param {TParseContext* context} | 
 | %param {void* yyscanner} | 
 |  | 
 | %code requires { | 
 | #define YYLTYPE TSourceLoc | 
 | #define YYLTYPE_IS_DECLARED 1 | 
 | } | 
 |  | 
 | %union { | 
 |     struct { | 
 |         union { | 
 |             TString *string; | 
 |             float f; | 
 |             int i; | 
 |             unsigned int u; | 
 |             bool b; | 
 |         }; | 
 |         TSymbol* symbol; | 
 |     } lex; | 
 |     struct { | 
 |         TOperator op; | 
 |         union { | 
 |             TIntermNode* intermNode; | 
 |             TIntermNodePair nodePair; | 
 |             TIntermTyped* intermTypedNode; | 
 |             TIntermAggregate* intermAggregate; | 
 |             TIntermSwitch* intermSwitch; | 
 |             TIntermCase* intermCase; | 
 |         }; | 
 |         union { | 
 |             TPublicType type; | 
 |             TPrecision precision; | 
 |             TLayoutQualifier layoutQualifier; | 
 |             TQualifier qualifier; | 
 |             TFunction* function; | 
 |             TParameter param; | 
 |             TField* field; | 
 |             TFieldList* fieldList; | 
 |         }; | 
 |     } interm; | 
 | } | 
 |  | 
 | %{ | 
 | extern int yylex(YYSTYPE* yylval, YYLTYPE* yylloc, void* yyscanner); | 
 | extern void yyerror(YYLTYPE* lloc, TParseContext* context, void* scanner, const char* reason); | 
 |  | 
 | #define YYLLOC_DEFAULT(Current, Rhs, N)                      \ | 
 |   do {                                                       \ | 
 |       if (N) {                                         \ | 
 |         (Current).first_file = YYRHSLOC(Rhs, 1).first_file;  \ | 
 |         (Current).first_line = YYRHSLOC(Rhs, 1).first_line;  \ | 
 |         (Current).last_file = YYRHSLOC(Rhs, N).last_file;    \ | 
 |         (Current).last_line = YYRHSLOC(Rhs, N).last_line;    \ | 
 |       }                                                      \ | 
 |       else {                                                 \ | 
 |         (Current).first_file = YYRHSLOC(Rhs, 0).last_file;   \ | 
 |         (Current).first_line = YYRHSLOC(Rhs, 0).last_line;   \ | 
 |         (Current).last_file = YYRHSLOC(Rhs, 0).last_file;    \ | 
 |         (Current).last_line = YYRHSLOC(Rhs, 0).last_line;    \ | 
 |       }                                                      \ | 
 |   } while (0) | 
 |  | 
 | #define FRAG_VERT_ONLY(S, L) {  \ | 
 |     if (context->getShaderType() != GL_FRAGMENT_SHADER &&  \ | 
 |         context->getShaderType() != GL_VERTEX_SHADER) {  \ | 
 |         context->error(L, " supported in vertex/fragment shaders only ", S);  \ | 
 |         context->recover();  \ | 
 |     }  \ | 
 | } | 
 |  | 
 | #define VERTEX_ONLY(S, L) {  \ | 
 |     if (context->getShaderType() != GL_VERTEX_SHADER) {  \ | 
 |         context->error(L, " supported in vertex shaders only ", S);  \ | 
 |         context->recover();  \ | 
 |     }  \ | 
 | } | 
 |  | 
 | #define FRAG_ONLY(S, L) {  \ | 
 |     if (context->getShaderType() != GL_FRAGMENT_SHADER) {  \ | 
 |         context->error(L, " supported in fragment shaders only ", S);  \ | 
 |         context->recover();  \ | 
 |     }  \ | 
 | } | 
 |  | 
 | #define ES2_ONLY(S, L) {  \ | 
 |     if (context->getShaderVersion() != 100) {  \ | 
 |         context->error(L, " supported in GLSL ES 1.00 only ", S);  \ | 
 |         context->recover();  \ | 
 |     }  \ | 
 | } | 
 |  | 
 | #define ES3_ONLY(TOKEN, LINE, REASON) {  \ | 
 |     if (context->getShaderVersion() != 300) {  \ | 
 |         context->error(LINE, REASON " supported in GLSL ES 3.00 only ", TOKEN);  \ | 
 |         context->recover();  \ | 
 |     }  \ | 
 | } | 
 | %} | 
 |  | 
 | %token <lex> INVARIANT HIGH_PRECISION MEDIUM_PRECISION LOW_PRECISION PRECISION | 
 | %token <lex> ATTRIBUTE CONST_QUAL BOOL_TYPE FLOAT_TYPE INT_TYPE UINT_TYPE | 
 | %token <lex> BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN SWITCH CASE DEFAULT | 
 | %token <lex> BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 VEC2 VEC3 VEC4 UVEC2 UVEC3 UVEC4 | 
 | %token <lex> MATRIX2 MATRIX3 MATRIX4 IN_QUAL OUT_QUAL INOUT_QUAL UNIFORM VARYING | 
 | %token <lex> MATRIX2x3 MATRIX3x2 MATRIX2x4 MATRIX4x2 MATRIX3x4 MATRIX4x3 | 
 | %token <lex> CENTROID FLAT SMOOTH | 
 | %token <lex> STRUCT VOID_TYPE WHILE | 
 | %token <lex> SAMPLER2D SAMPLERCUBE SAMPLER_EXTERNAL_OES SAMPLER2DRECT SAMPLER2DARRAY | 
 | %token <lex> ISAMPLER2D ISAMPLER3D ISAMPLERCUBE ISAMPLER2DARRAY | 
 | %token <lex> USAMPLER2D USAMPLER3D USAMPLERCUBE USAMPLER2DARRAY | 
 | %token <lex> SAMPLER3D SAMPLER3DRECT SAMPLER2DSHADOW SAMPLERCUBESHADOW SAMPLER2DARRAYSHADOW | 
 | %token <lex> LAYOUT | 
 |  | 
 | %token <lex> IDENTIFIER TYPE_NAME FLOATCONSTANT INTCONSTANT UINTCONSTANT BOOLCONSTANT | 
 | %token <lex> FIELD_SELECTION | 
 | %token <lex> LEFT_OP RIGHT_OP | 
 | %token <lex> INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP | 
 | %token <lex> AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN | 
 | %token <lex> MOD_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN | 
 | %token <lex> SUB_ASSIGN | 
 |  | 
 | %token <lex> LEFT_PAREN RIGHT_PAREN LEFT_BRACKET RIGHT_BRACKET LEFT_BRACE RIGHT_BRACE DOT | 
 | %token <lex> COMMA COLON EQUAL SEMICOLON BANG DASH TILDE PLUS STAR SLASH PERCENT | 
 | %token <lex> LEFT_ANGLE RIGHT_ANGLE VERTICAL_BAR CARET AMPERSAND QUESTION | 
 |  | 
 | %type <interm> assignment_operator unary_operator | 
 | %type <interm.intermTypedNode> variable_identifier primary_expression postfix_expression | 
 | %type <interm.intermTypedNode> expression integer_expression assignment_expression | 
 | %type <interm.intermTypedNode> unary_expression multiplicative_expression additive_expression | 
 | %type <interm.intermTypedNode> relational_expression equality_expression | 
 | %type <interm.intermTypedNode> conditional_expression constant_expression | 
 | %type <interm.intermTypedNode> logical_or_expression logical_xor_expression logical_and_expression | 
 | %type <interm.intermTypedNode> shift_expression and_expression exclusive_or_expression inclusive_or_expression | 
 | %type <interm.intermTypedNode> function_call initializer condition conditionopt | 
 |  | 
 | %type <interm.intermNode> translation_unit function_definition | 
 | %type <interm.intermNode> statement simple_statement | 
 | %type <interm.intermAggregate>  statement_list compound_statement compound_statement_no_new_scope | 
 | %type <interm.intermNode> declaration_statement selection_statement expression_statement | 
 | %type <interm.intermNode> declaration external_declaration | 
 | %type <interm.intermNode> for_init_statement | 
 | %type <interm.nodePair> selection_rest_statement for_rest_statement | 
 | %type <interm.intermSwitch> switch_statement | 
 | %type <interm.intermCase> case_label | 
 | %type <interm.intermNode> iteration_statement jump_statement statement_no_new_scope statement_with_scope | 
 | %type <interm> single_declaration init_declarator_list | 
 |  | 
 | %type <interm> parameter_declaration parameter_declarator parameter_type_specifier | 
 | %type <interm.qualifier> parameter_qualifier parameter_type_qualifier | 
 | %type <interm.layoutQualifier> layout_qualifier layout_qualifier_id_list layout_qualifier_id | 
 |  | 
 | %type <interm.precision> precision_qualifier | 
 | %type <interm.type> type_qualifier fully_specified_type type_specifier storage_qualifier interpolation_qualifier | 
 | %type <interm.type> type_specifier_no_prec type_specifier_nonarray | 
 | %type <interm.type> struct_specifier | 
 | %type <interm.field> struct_declarator | 
 | %type <interm.fieldList> struct_declarator_list struct_declaration struct_declaration_list | 
 | %type <interm.function> function_header function_declarator function_identifier | 
 | %type <interm.function> function_header_with_parameters function_call_header | 
 | %type <interm> function_call_header_with_parameters function_call_header_no_parameters function_call_generic function_prototype | 
 | %type <interm> function_call_or_method | 
 |  | 
 | %type <lex> enter_struct | 
 |  | 
 | %start translation_unit | 
 | %% | 
 |  | 
 | variable_identifier | 
 |     : IDENTIFIER { | 
 |         // The symbol table search was done in the lexical phase | 
 |         const TVariable *variable = context->getNamedVariable(@1, $1.string, $1.symbol); | 
 |  | 
 |         // don't delete $1.string, it's used by error recovery, and the pool | 
 |         // pop will reclaim the memory | 
 |  | 
 |         ConstantUnion *constArray = variable->getConstPointer(); | 
 |         if (constArray) { | 
 |             TType t(variable->getType()); | 
 |             $$ = context->intermediate.addConstantUnion(constArray, t, @1); | 
 |         } else | 
 |             $$ = context->intermediate.addSymbol(variable->getUniqueId(), | 
 |                                                      variable->getName(), | 
 |                                                      variable->getType(), @1); | 
 |     } | 
 |     ; | 
 |  | 
 | primary_expression | 
 |     : variable_identifier { | 
 |         $$ = $1; | 
 |     } | 
 |     | INTCONSTANT { | 
 |         ConstantUnion *unionArray = new ConstantUnion[1]; | 
 |         unionArray->setIConst($1.i); | 
 |         $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConstExpr), @1); | 
 |     } | 
 |     | UINTCONSTANT { | 
 |         ConstantUnion *unionArray = new ConstantUnion[1]; | 
 |         unionArray->setUConst($1.u); | 
 |         $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtUInt, EbpUndefined, EvqConstExpr), @1); | 
 |     } | 
 |     | FLOATCONSTANT { | 
 |         ConstantUnion *unionArray = new ConstantUnion[1]; | 
 |         unionArray->setFConst($1.f); | 
 |         $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConstExpr), @1); | 
 |     } | 
 |     | BOOLCONSTANT { | 
 |         ConstantUnion *unionArray = new ConstantUnion[1]; | 
 |         unionArray->setBConst($1.b); | 
 |         $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConstExpr), @1); | 
 |     } | 
 |     | LEFT_PAREN expression RIGHT_PAREN { | 
 |         $$ = $2; | 
 |     } | 
 |     ; | 
 |  | 
 | postfix_expression | 
 |     : primary_expression { | 
 |         $$ = $1; | 
 |     } | 
 |     | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET { | 
 |         $$ = context->addIndexExpression($1, @2, $3); | 
 |     } | 
 |     | function_call { | 
 |         $$ = $1; | 
 |     } | 
 |     | postfix_expression DOT FIELD_SELECTION { | 
 |         $$ = context->addFieldSelectionExpression($1, @2, *$3.string, @3); | 
 |     } | 
 |     | postfix_expression INC_OP { | 
 |         $$ = context->addUnaryMathLValue(EOpPostIncrement, $1, @2); | 
 |     } | 
 |     | postfix_expression DEC_OP { | 
 |         $$ = context->addUnaryMathLValue(EOpPostDecrement, $1, @2); | 
 |     } | 
 |     ; | 
 |  | 
 | integer_expression | 
 |     : expression { | 
 |         if (context->integerErrorCheck($1, "[]")) | 
 |             context->recover(); | 
 |         $$ = $1; | 
 |     } | 
 |     ; | 
 |  | 
 | function_call | 
 |     : function_call_or_method { | 
 |         bool fatalError = false; | 
 |         $$ = context->addFunctionCallOrMethod($1.function, $1.nodePair.node1, $1.nodePair.node2, @1, &fatalError); | 
 |         if (fatalError) | 
 |         { | 
 |             YYERROR; | 
 |         } | 
 |     } | 
 |     ; | 
 |  | 
 | function_call_or_method | 
 |     : function_call_generic { | 
 |         $$ = $1; | 
 |         $$.nodePair.node2 = nullptr; | 
 |     } | 
 |     | postfix_expression DOT function_call_generic { | 
 |         ES3_ONLY("", @3, "methods"); | 
 |         $$ = $3; | 
 |         $$.nodePair.node2 = $1; | 
 |     } | 
 |     ; | 
 |  | 
 | function_call_generic | 
 |     : function_call_header_with_parameters RIGHT_PAREN { | 
 |         $$ = $1; | 
 |     } | 
 |     | function_call_header_no_parameters RIGHT_PAREN { | 
 |         $$ = $1; | 
 |     } | 
 |     ; | 
 |  | 
 | function_call_header_no_parameters | 
 |     : function_call_header VOID_TYPE { | 
 |         $$.function = $1; | 
 |         $$.nodePair.node1 = nullptr; | 
 |     } | 
 |     | function_call_header { | 
 |         $$.function = $1; | 
 |         $$.nodePair.node1 = nullptr; | 
 |     } | 
 |     ; | 
 |  | 
 | function_call_header_with_parameters | 
 |     : function_call_header assignment_expression { | 
 |         TParameter param = { 0, new TType($2->getType()) }; | 
 |         $1->addParameter(param); | 
 |         $$.function = $1; | 
 |         $$.nodePair.node1 = $2; | 
 |     } | 
 |     | function_call_header_with_parameters COMMA assignment_expression { | 
 |         TParameter param = { 0, new TType($3->getType()) }; | 
 |         $1.function->addParameter(param); | 
 |         $$.function = $1.function; | 
 |         $$.nodePair.node1 = context->intermediate.growAggregate($1.intermNode, $3, @2); | 
 |     } | 
 |     ; | 
 |  | 
 | function_call_header | 
 |     : function_identifier LEFT_PAREN { | 
 |         $$ = $1; | 
 |     } | 
 |     ; | 
 |  | 
 | // Grammar Note:  Constructors look like functions, but are recognized as types. | 
 |  | 
 | function_identifier | 
 |     : type_specifier_no_prec { | 
 |         if ($1.array) { | 
 |             ES3_ONLY("[]", @1, "array constructor"); | 
 |         } | 
 |         $$ = context->addConstructorFunc($1); | 
 |     } | 
 |     | IDENTIFIER { | 
 |         if (context->reservedErrorCheck(@1, *$1.string)) | 
 |             context->recover(); | 
 |         TType type(EbtVoid, EbpUndefined); | 
 |         TFunction *function = new TFunction($1.string, type); | 
 |         $$ = function; | 
 |     } | 
 |     | FIELD_SELECTION { | 
 |         if (context->reservedErrorCheck(@1, *$1.string)) | 
 |             context->recover(); | 
 |         TType type(EbtVoid, EbpUndefined); | 
 |         TFunction *function = new TFunction($1.string, type); | 
 |         $$ = function; | 
 |     } | 
 |     ; | 
 |  | 
 | unary_expression | 
 |     : postfix_expression { | 
 |         $$ = $1; | 
 |     } | 
 |     | INC_OP unary_expression { | 
 |         $$ = context->addUnaryMathLValue(EOpPreIncrement, $2, @1); | 
 |     } | 
 |     | DEC_OP unary_expression { | 
 |         $$ = context->addUnaryMathLValue(EOpPreDecrement, $2, @1); | 
 |     } | 
 |     | unary_operator unary_expression { | 
 |         if ($1.op != EOpNull) { | 
 |             $$ = context->addUnaryMath($1.op, $2, @1); | 
 |         } else | 
 |             $$ = $2; | 
 |     } | 
 |     ; | 
 | // Grammar Note:  No traditional style type casts. | 
 |  | 
 | unary_operator | 
 |     : PLUS  { $$.op = EOpNull; } | 
 |     | DASH  { $$.op = EOpNegative; } | 
 |     | BANG  { $$.op = EOpLogicalNot; } | 
 |     | TILDE { | 
 |         ES3_ONLY("~", @1, "bit-wise operator"); | 
 |         $$.op = EOpBitwiseNot; | 
 |     } | 
 |     ; | 
 | // Grammar Note:  No '*' or '&' unary ops.  Pointers are not supported. | 
 |  | 
 | multiplicative_expression | 
 |     : unary_expression { $$ = $1; } | 
 |     | multiplicative_expression STAR unary_expression { | 
 |         FRAG_VERT_ONLY("*", @2); | 
 |         $$ = context->addBinaryMath(EOpMul, $1, $3, @2); | 
 |     } | 
 |     | multiplicative_expression SLASH unary_expression { | 
 |         FRAG_VERT_ONLY("/", @2); | 
 |         $$ = context->addBinaryMath(EOpDiv, $1, $3, @2); | 
 |     } | 
 |     | multiplicative_expression PERCENT unary_expression { | 
 |         FRAG_VERT_ONLY("%", @2); | 
 |         ES3_ONLY("%", @2, "integer modulus operator"); | 
 |         $$ = context->addBinaryMath(EOpIMod, $1, $3, @2); | 
 |     } | 
 |     ; | 
 |  | 
 | additive_expression | 
 |     : multiplicative_expression { $$ = $1; } | 
 |     | additive_expression PLUS multiplicative_expression { | 
 |         $$ = context->addBinaryMath(EOpAdd, $1, $3, @2); | 
 |     } | 
 |     | additive_expression DASH multiplicative_expression { | 
 |         $$ = context->addBinaryMath(EOpSub, $1, $3, @2); | 
 |     } | 
 |     ; | 
 |  | 
 | shift_expression | 
 |     : additive_expression { $$ = $1; } | 
 |     | shift_expression LEFT_OP additive_expression { | 
 |         ES3_ONLY("<<", @2, "bit-wise operator"); | 
 |         $$ = context->addBinaryMath(EOpBitShiftLeft, $1, $3, @2); | 
 |     } | 
 |     | shift_expression RIGHT_OP additive_expression { | 
 |         ES3_ONLY(">>", @2, "bit-wise operator"); | 
 |         $$ = context->addBinaryMath(EOpBitShiftRight, $1, $3, @2); | 
 |     } | 
 |     ; | 
 |  | 
 | relational_expression | 
 |     : shift_expression { $$ = $1; } | 
 |     | relational_expression LEFT_ANGLE shift_expression { | 
 |         $$ = context->addBinaryMathBooleanResult(EOpLessThan, $1, $3, @2); | 
 |     } | 
 |     | relational_expression RIGHT_ANGLE shift_expression  { | 
 |         $$ = context->addBinaryMathBooleanResult(EOpGreaterThan, $1, $3, @2); | 
 |     } | 
 |     | relational_expression LE_OP shift_expression  { | 
 |         $$ = context->addBinaryMathBooleanResult(EOpLessThanEqual, $1, $3, @2); | 
 |     } | 
 |     | relational_expression GE_OP shift_expression  { | 
 |         $$ = context->addBinaryMathBooleanResult(EOpGreaterThanEqual, $1, $3, @2); | 
 |     } | 
 |     ; | 
 |  | 
 | equality_expression | 
 |     : relational_expression { $$ = $1; } | 
 |     | equality_expression EQ_OP relational_expression  { | 
 |         $$ = context->addBinaryMathBooleanResult(EOpEqual, $1, $3, @2); | 
 |     } | 
 |     | equality_expression NE_OP relational_expression { | 
 |         $$ = context->addBinaryMathBooleanResult(EOpNotEqual, $1, $3, @2); | 
 |     } | 
 |     ; | 
 |  | 
 | and_expression | 
 |     : equality_expression { $$ = $1; } | 
 |     | and_expression AMPERSAND equality_expression { | 
 |         ES3_ONLY("&", @2, "bit-wise operator"); | 
 |         $$ = context->addBinaryMath(EOpBitwiseAnd, $1, $3, @2); | 
 |     } | 
 |     ; | 
 |  | 
 | exclusive_or_expression | 
 |     : and_expression { $$ = $1; } | 
 |     | exclusive_or_expression CARET and_expression { | 
 |         ES3_ONLY("^", @2, "bit-wise operator"); | 
 |         $$ = context->addBinaryMath(EOpBitwiseXor, $1, $3, @2); | 
 |     } | 
 |     ; | 
 |  | 
 | inclusive_or_expression | 
 |     : exclusive_or_expression { $$ = $1; } | 
 |     | inclusive_or_expression VERTICAL_BAR exclusive_or_expression { | 
 |         ES3_ONLY("|", @2, "bit-wise operator"); | 
 |         $$ = context->addBinaryMath(EOpBitwiseOr, $1, $3, @2); | 
 |     } | 
 |     ; | 
 |  | 
 | logical_and_expression | 
 |     : inclusive_or_expression { $$ = $1; } | 
 |     | logical_and_expression AND_OP inclusive_or_expression { | 
 |         $$ = context->addBinaryMathBooleanResult(EOpLogicalAnd, $1, $3, @2); | 
 |     } | 
 |     ; | 
 |  | 
 | logical_xor_expression | 
 |     : logical_and_expression { $$ = $1; } | 
 |     | logical_xor_expression XOR_OP logical_and_expression  { | 
 |         $$ = context->addBinaryMathBooleanResult(EOpLogicalXor, $1, $3, @2); | 
 |     } | 
 |     ; | 
 |  | 
 | logical_or_expression | 
 |     : logical_xor_expression { $$ = $1; } | 
 |     | logical_or_expression OR_OP logical_xor_expression  { | 
 |         $$ = context->addBinaryMathBooleanResult(EOpLogicalOr, $1, $3, @2); | 
 |     } | 
 |     ; | 
 |  | 
 | conditional_expression | 
 |     : logical_or_expression { $$ = $1; } | 
 |     | logical_or_expression QUESTION expression COLON assignment_expression { | 
 |         $$ = context->addTernarySelection($1, $3, $5, @2); | 
 |     } | 
 |     ; | 
 |  | 
 | assignment_expression | 
 |     : conditional_expression { $$ = $1; } | 
 |     | unary_expression assignment_operator assignment_expression { | 
 |         if (context->lValueErrorCheck(@2, "assign", $1)) | 
 |             context->recover(); | 
 |         $$ = context->addAssign($2.op, $1, $3, @2); | 
 |     } | 
 |     ; | 
 |  | 
 | assignment_operator | 
 |     : EQUAL        {                           $$.op = EOpAssign; } | 
 |     | MUL_ASSIGN   { FRAG_VERT_ONLY("*=", @1); $$.op = EOpMulAssign; } | 
 |     | DIV_ASSIGN   { FRAG_VERT_ONLY("/=", @1); $$.op = EOpDivAssign; } | 
 |     | MOD_ASSIGN   { ES3_ONLY("%=", @1, "integer modulus operator"); | 
 |                      FRAG_VERT_ONLY("%=", @1); $$.op = EOpIModAssign; } | 
 |     | ADD_ASSIGN   {                           $$.op = EOpAddAssign; } | 
 |     | SUB_ASSIGN   {                           $$.op = EOpSubAssign; } | 
 |     | LEFT_ASSIGN  { ES3_ONLY("<<=", @1, "bit-wise operator"); | 
 |                      FRAG_VERT_ONLY("<<=", @1); | 
 |                      $$.op = EOpBitShiftLeftAssign; } | 
 |     | RIGHT_ASSIGN { ES3_ONLY(">>=", @1, "bit-wise operator"); | 
 |                      FRAG_VERT_ONLY(">>=", @1); | 
 |                      $$.op = EOpBitShiftRightAssign; } | 
 |     | AND_ASSIGN   { ES3_ONLY("&=", @1, "bit-wise operator"); | 
 |                      FRAG_VERT_ONLY("&=", @1); | 
 |                      $$.op = EOpBitwiseAndAssign; } | 
 |     | XOR_ASSIGN   { ES3_ONLY("^=", @1, "bit-wise operator"); | 
 |                      FRAG_VERT_ONLY("^=", @1); | 
 |                      $$.op = EOpBitwiseXorAssign; } | 
 |     | OR_ASSIGN    { ES3_ONLY("|=", @1, "bit-wise operator"); | 
 |                      FRAG_VERT_ONLY("|=", @1); | 
 |                      $$.op = EOpBitwiseOrAssign; } | 
 |     ; | 
 |  | 
 | expression | 
 |     : assignment_expression { | 
 |         $$ = $1; | 
 |     } | 
 |     | expression COMMA assignment_expression { | 
 |         $$ = context->intermediate.addComma($1, $3, @2); | 
 |         if ($$ == 0) { | 
 |             context->binaryOpError(@2, ",", $1->getCompleteString(), $3->getCompleteString()); | 
 |             context->recover(); | 
 |             $$ = $3; | 
 |         } | 
 |     } | 
 |     ; | 
 |  | 
 | constant_expression | 
 |     : conditional_expression { | 
 |         if (context->constErrorCheck($1)) | 
 |             context->recover(); | 
 |         $$ = $1; | 
 |     } | 
 |     ; | 
 |  | 
 | enter_struct | 
 |     : IDENTIFIER LEFT_BRACE { | 
 |         if (context->enterStructDeclaration(@1, *$1.string)) | 
 |             context->recover(); | 
 |         $$ = $1; | 
 |     } | 
 |     ; | 
 |  | 
 | declaration | 
 |     : function_prototype SEMICOLON { | 
 |         $$ = context->addFunctionPrototypeDeclaration(*($1.function), @1); | 
 |     } | 
 |     | init_declarator_list SEMICOLON { | 
 |         TIntermAggregate *aggNode = $1.intermAggregate; | 
 |         if (aggNode && aggNode->getOp() == EOpNull) | 
 |             aggNode->setOp(EOpDeclaration); | 
 |         $$ = aggNode; | 
 |     } | 
 |     | PRECISION precision_qualifier type_specifier_no_prec SEMICOLON { | 
 |         if (!context->symbolTable.setDefaultPrecision( $3, $2 )) { | 
 |             context->error(@1, "illegal type argument for default precision qualifier", getBasicString($3.type)); | 
 |             context->recover(); | 
 |         } | 
 |         $$ = 0; | 
 |     } | 
 |     | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE SEMICOLON { | 
 |         ES3_ONLY(getQualifierString($1.qualifier), @1, "interface blocks"); | 
 |         $$ = context->addInterfaceBlock($1, @2, *$2.string, $3, NULL, @1, NULL, @1); | 
 |     } | 
 |     | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER SEMICOLON { | 
 |         ES3_ONLY(getQualifierString($1.qualifier), @1, "interface blocks"); | 
 |         $$ = context->addInterfaceBlock($1, @2, *$2.string, $3, $5.string, @5, NULL, @1); | 
 |     } | 
 |     | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET SEMICOLON { | 
 |         ES3_ONLY(getQualifierString($1.qualifier), @1, "interface blocks"); | 
 |         $$ = context->addInterfaceBlock($1, @2, *$2.string, $3, $5.string, @5, $7, @6); | 
 |     } | 
 |     | type_qualifier SEMICOLON { | 
 |         context->parseGlobalLayoutQualifier($1); | 
 |         $$ = 0; | 
 |     } | 
 |     ; | 
 |  | 
 | function_prototype | 
 |     : function_declarator RIGHT_PAREN  { | 
 |         $$.function = context->parseFunctionDeclarator(@2, $1); | 
 |     } | 
 |     ; | 
 |  | 
 | function_declarator | 
 |     : function_header { | 
 |         $$ = $1; | 
 |     } | 
 |     | function_header_with_parameters { | 
 |         $$ = $1; | 
 |     } | 
 |     ; | 
 |  | 
 |  | 
 | function_header_with_parameters | 
 |     : function_header parameter_declaration { | 
 |         // Add the parameter | 
 |         $$ = $1; | 
 |         if ($2.param.type->getBasicType() != EbtVoid) | 
 |             $1->addParameter($2.param); | 
 |         else | 
 |             delete $2.param.type; | 
 |     } | 
 |     | function_header_with_parameters COMMA parameter_declaration { | 
 |         // | 
 |         // Only first parameter of one-parameter functions can be void | 
 |         // The check for named parameters not being void is done in parameter_declarator | 
 |         // | 
 |         if ($3.param.type->getBasicType() == EbtVoid) { | 
 |             // | 
 |             // This parameter > first is void | 
 |             // | 
 |             context->error(@2, "cannot be an argument type except for '(void)'", "void"); | 
 |             context->recover(); | 
 |             delete $3.param.type; | 
 |         } else { | 
 |             // Add the parameter | 
 |             $$ = $1; | 
 |             $1->addParameter($3.param); | 
 |         } | 
 |     } | 
 |     ; | 
 |  | 
 | function_header | 
 |     : fully_specified_type IDENTIFIER LEFT_PAREN { | 
 |         if ($1.qualifier != EvqGlobal && $1.qualifier != EvqTemporary) { | 
 |             context->error(@2, "no qualifiers allowed for function return", getQualifierString($1.qualifier)); | 
 |             context->recover(); | 
 |         } | 
 |         if (!$1.layoutQualifier.isEmpty()) | 
 |         { | 
 |             context->error(@2, "no qualifiers allowed for function return", "layout"); | 
 |             context->recover(); | 
 |         } | 
 |         // make sure a sampler is not involved as well... | 
 |         if (context->samplerErrorCheck(@2, $1, "samplers can't be function return values")) | 
 |             context->recover(); | 
 |  | 
 |         // Add the function as a prototype after parsing it (we do not support recursion) | 
 |         TFunction *function; | 
 |         TType type($1); | 
 |         function = new TFunction($2.string, type); | 
 |         $$ = function; | 
 |  | 
 |         context->symbolTable.push(); | 
 |     } | 
 |     ; | 
 |  | 
 | parameter_declarator | 
 |     // Type + name | 
 |     : type_specifier IDENTIFIER { | 
 |         if ($1.type == EbtVoid) { | 
 |             context->error(@2, "illegal use of type 'void'", $2.string->c_str()); | 
 |             context->recover(); | 
 |         } | 
 |         if (context->reservedErrorCheck(@2, *$2.string)) | 
 |             context->recover(); | 
 |         TParameter param = {$2.string, new TType($1)}; | 
 |         $$.param = param; | 
 |     } | 
 |     | type_specifier IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET { | 
 |         // Check that we can make an array out of this type | 
 |         if (context->arrayTypeErrorCheck(@3, $1)) | 
 |             context->recover(); | 
 |  | 
 |         if (context->reservedErrorCheck(@2, *$2.string)) | 
 |             context->recover(); | 
 |  | 
 |         int size; | 
 |         if (context->arraySizeErrorCheck(@3, $4, size)) | 
 |             context->recover(); | 
 |         $1.setArray(true, size); | 
 |  | 
 |         TType* type = new TType($1); | 
 |         TParameter param = { $2.string, type }; | 
 |         $$.param = param; | 
 |     } | 
 |     ; | 
 |  | 
 | parameter_declaration | 
 |     // | 
 |     // The only parameter qualifier a parameter can have are | 
 |     // IN_QUAL, OUT_QUAL, INOUT_QUAL, or CONST. | 
 |     // | 
 |  | 
 |     // | 
 |     // Type + name | 
 |     // | 
 |     : parameter_type_qualifier parameter_qualifier parameter_declarator { | 
 |         $$ = $3; | 
 |         if (context->paramErrorCheck(@3, $1, $2, $$.param.type)) | 
 |             context->recover(); | 
 |     } | 
 |     | parameter_qualifier parameter_declarator { | 
 |         $$ = $2; | 
 |         if (context->parameterSamplerErrorCheck(@2, $1, *$2.param.type)) | 
 |             context->recover(); | 
 |         if (context->paramErrorCheck(@2, EvqTemporary, $1, $$.param.type)) | 
 |             context->recover(); | 
 |     } | 
 |     // | 
 |     // Only type | 
 |     // | 
 |     | parameter_type_qualifier parameter_qualifier parameter_type_specifier { | 
 |         $$ = $3; | 
 |         if (context->paramErrorCheck(@3, $1, $2, $$.param.type)) | 
 |             context->recover(); | 
 |     } | 
 |     | parameter_qualifier parameter_type_specifier { | 
 |         $$ = $2; | 
 |         if (context->parameterSamplerErrorCheck(@2, $1, *$2.param.type)) | 
 |             context->recover(); | 
 |         if (context->paramErrorCheck(@2, EvqTemporary, $1, $$.param.type)) | 
 |             context->recover(); | 
 |     } | 
 |     ; | 
 |  | 
 | parameter_qualifier | 
 |     : /* empty */ { | 
 |         $$ = EvqIn; | 
 |     } | 
 |     | IN_QUAL { | 
 |         $$ = EvqIn; | 
 |     } | 
 |     | OUT_QUAL { | 
 |         $$ = EvqOut; | 
 |     } | 
 |     | INOUT_QUAL { | 
 |         $$ = EvqInOut; | 
 |     } | 
 |     ; | 
 |  | 
 | parameter_type_specifier | 
 |     : type_specifier { | 
 |         TParameter param = { 0, new TType($1) }; | 
 |         $$.param = param; | 
 |     } | 
 |     ; | 
 |  | 
 | init_declarator_list | 
 |     : single_declaration { | 
 |         $$ = $1; | 
 |     } | 
 |     | init_declarator_list COMMA IDENTIFIER { | 
 |         $$ = $1; | 
 |         $$.intermAggregate = context->parseDeclarator($$.type, $1.intermAggregate, @3, *$3.string); | 
 |     } | 
 |     | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET { | 
 |         $$ = $1; | 
 |         $$.intermAggregate = context->parseArrayDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, $5); | 
 |     } | 
 |     | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET RIGHT_BRACKET EQUAL initializer { | 
 |         ES3_ONLY("[]", @3, "implicitly sized array"); | 
 |         $$ = $1; | 
 |         $$.intermAggregate = context->parseArrayInitDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, nullptr, @6, $7); | 
 |     } | 
 |     | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer { | 
 |         ES3_ONLY("=", @7, "first-class arrays (array initializer)"); | 
 |         $$ = $1; | 
 |         $$.intermAggregate = context->parseArrayInitDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, $5, @7, $8); | 
 |     } | 
 |     | init_declarator_list COMMA IDENTIFIER EQUAL initializer { | 
 |         $$ = $1; | 
 |         $$.intermAggregate = context->parseInitDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, $5); | 
 |     } | 
 |     ; | 
 |  | 
 | single_declaration | 
 |     : fully_specified_type { | 
 |         $$.type = $1; | 
 |         $$.intermAggregate = context->parseSingleDeclaration($$.type, @1, ""); | 
 |     } | 
 |     | fully_specified_type IDENTIFIER { | 
 |         $$.type = $1; | 
 |         $$.intermAggregate = context->parseSingleDeclaration($$.type, @2, *$2.string); | 
 |     } | 
 |     | fully_specified_type IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET { | 
 |         $$.type = $1; | 
 |         $$.intermAggregate = context->parseSingleArrayDeclaration($$.type, @2, *$2.string, @3, $4); | 
 |     } | 
 |     | fully_specified_type IDENTIFIER LEFT_BRACKET RIGHT_BRACKET EQUAL initializer { | 
 |         ES3_ONLY("[]", @3, "implicitly sized array"); | 
 |         $$.type = $1; | 
 |         $$.intermAggregate = context->parseSingleArrayInitDeclaration($$.type, @2, *$2.string, @3, nullptr, @5, $6); | 
 |     } | 
 |     | fully_specified_type IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer { | 
 |         ES3_ONLY("=", @6, "first-class arrays (array initializer)"); | 
 |         $$.type = $1; | 
 |         $$.intermAggregate = context->parseSingleArrayInitDeclaration($$.type, @2, *$2.string, @3, $4, @6, $7); | 
 |     } | 
 |     | fully_specified_type IDENTIFIER EQUAL initializer { | 
 |         $$.type = $1; | 
 |         $$.intermAggregate = context->parseSingleInitDeclaration($$.type, @2, *$2.string, @3, $4); | 
 |     } | 
 |     | INVARIANT IDENTIFIER { | 
 |         // $$.type is not used in invariant declarations. | 
 |         $$.intermAggregate = context->parseInvariantDeclaration(@1, @2, $2.string, $2.symbol); | 
 |     } | 
 |     ; | 
 |  | 
 | fully_specified_type | 
 |     : type_specifier { | 
 |         $$ = $1; | 
 |  | 
 |         if ($1.array) { | 
 |             ES3_ONLY("[]", @1, "first-class-array"); | 
 |             if (context->getShaderVersion() != 300) { | 
 |                 $1.clearArrayness(); | 
 |             } | 
 |         } | 
 |     } | 
 |     | type_qualifier type_specifier  { | 
 |         $$ = context->addFullySpecifiedType($1.qualifier, $1.invariant, $1.layoutQualifier, $2); | 
 |     } | 
 |     ; | 
 |  | 
 | interpolation_qualifier | 
 |     : SMOOTH { | 
 |         $$.qualifier = EvqSmooth; | 
 |     } | 
 |     | FLAT { | 
 |         $$.qualifier = EvqFlat; | 
 |     } | 
 |     ; | 
 |  | 
 | parameter_type_qualifier | 
 |     : CONST_QUAL { | 
 |         $$ = EvqConstReadOnly; | 
 |     } | 
 |     ; | 
 |  | 
 | type_qualifier | 
 |     : ATTRIBUTE { | 
 |         VERTEX_ONLY("attribute", @1); | 
 |         ES2_ONLY("attribute", @1); | 
 |         if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "attribute")) | 
 |             context->recover(); | 
 |         $$.setBasic(EbtVoid, EvqAttribute, @1); | 
 |     } | 
 |     | VARYING { | 
 |         ES2_ONLY("varying", @1); | 
 |         if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "varying")) | 
 |             context->recover(); | 
 |         if (context->getShaderType() == GL_VERTEX_SHADER) | 
 |             $$.setBasic(EbtVoid, EvqVaryingOut, @1); | 
 |         else | 
 |             $$.setBasic(EbtVoid, EvqVaryingIn, @1); | 
 |     } | 
 |     | INVARIANT VARYING { | 
 |         ES2_ONLY("varying", @1); | 
 |         if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "invariant varying")) | 
 |             context->recover(); | 
 |         if (context->getShaderType() == GL_VERTEX_SHADER) | 
 |             $$.setBasic(EbtVoid, EvqInvariantVaryingOut, @1); | 
 |         else | 
 |             $$.setBasic(EbtVoid, EvqInvariantVaryingIn, @1); | 
 |     } | 
 |     | storage_qualifier { | 
 |         if ($1.qualifier != EvqConstExpr && !context->symbolTable.atGlobalLevel()) | 
 |         { | 
 |             context->error(@1, "Local variables can only use the const storage qualifier.", getQualifierString($1.qualifier)); | 
 |             context->recover(); | 
 |         } | 
 |         $$.setBasic(EbtVoid, $1.qualifier, @1); | 
 |     } | 
 | 	| interpolation_qualifier storage_qualifier { | 
 |         $$ = context->joinInterpolationQualifiers(@1, $1.qualifier, @2, $2.qualifier); | 
 |     } | 
 |     | interpolation_qualifier { | 
 |         context->error(@1, "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier", getQualifierString($1.qualifier)); | 
 |         context->recover(); | 
 |  | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtVoid, qual, @1); | 
 |     } | 
 | 	| layout_qualifier { | 
 |         $$.qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.layoutQualifier = $1; | 
 |     } | 
 |     | layout_qualifier storage_qualifier { | 
 |         $$.setBasic(EbtVoid, $2.qualifier, @2); | 
 |         $$.layoutQualifier = $1; | 
 |     } | 
 |     | INVARIANT storage_qualifier { | 
 |         context->es3InvariantErrorCheck($2.qualifier, @1); | 
 |         $$.setBasic(EbtVoid, $2.qualifier, @2); | 
 |         $$.invariant = true; | 
 |     } | 
 |     | INVARIANT interpolation_qualifier storage_qualifier { | 
 |         context->es3InvariantErrorCheck($3.qualifier, @1); | 
 |         $$ = context->joinInterpolationQualifiers(@2, $2.qualifier, @3, $3.qualifier); | 
 |         $$.invariant = true; | 
 |     } | 
 |     ; | 
 |  | 
 | storage_qualifier | 
 |     : CONST_QUAL { | 
 |         $$.qualifier = EvqConstExpr; | 
 |     } | 
 |     | IN_QUAL { | 
 |         ES3_ONLY("in", @1, "storage qualifier"); | 
 |         $$.qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqFragmentIn : EvqVertexIn; | 
 |     } | 
 |     | OUT_QUAL { | 
 |         ES3_ONLY("out", @1, "storage qualifier"); | 
 |         $$.qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqVertexOut; | 
 |     } | 
 |     | CENTROID IN_QUAL { | 
 |         ES3_ONLY("centroid in", @1, "storage qualifier"); | 
 |         if (context->getShaderType() == GL_VERTEX_SHADER) | 
 |         { | 
 |             context->error(@1, "invalid storage qualifier", "it is an error to use 'centroid in' in the vertex shader"); | 
 |             context->recover(); | 
 |         } | 
 |         $$.qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqCentroidIn : EvqVertexIn; | 
 |     } | 
 |     | CENTROID OUT_QUAL { | 
 |         ES3_ONLY("centroid out", @1, "storage qualifier"); | 
 |         if (context->getShaderType() == GL_FRAGMENT_SHADER) | 
 |         { | 
 |             context->error(@1, "invalid storage qualifier", "it is an error to use 'centroid out' in the fragment shader"); | 
 |             context->recover(); | 
 |         } | 
 |         $$.qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqCentroidOut; | 
 |     } | 
 |     | UNIFORM { | 
 |         if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "uniform")) | 
 |             context->recover(); | 
 |         $$.qualifier = EvqUniform; | 
 |     } | 
 |     ; | 
 |  | 
 | type_specifier | 
 |     : type_specifier_no_prec { | 
 |         $$ = $1; | 
 |  | 
 |         if ($$.precision == EbpUndefined) { | 
 |             $$.precision = context->symbolTable.getDefaultPrecision($1.type); | 
 |             if (context->precisionErrorCheck(@1, $$.precision, $1.type)) { | 
 |                 context->recover(); | 
 |             } | 
 |         } | 
 |     } | 
 |     | precision_qualifier type_specifier_no_prec { | 
 |         $$ = $2; | 
 |         $$.precision = $1; | 
 |  | 
 |         if (!SupportsPrecision($2.type)) { | 
 |             context->error(@1, "illegal type for precision qualifier", getBasicString($2.type)); | 
 |             context->recover(); | 
 |         } | 
 |     } | 
 |     ; | 
 |  | 
 | precision_qualifier | 
 |     : HIGH_PRECISION { | 
 |         $$ = EbpHigh; | 
 |     } | 
 |     | MEDIUM_PRECISION { | 
 |         $$ = EbpMedium; | 
 |     } | 
 |     | LOW_PRECISION  { | 
 |         $$ = EbpLow; | 
 |     } | 
 |     ; | 
 |  | 
 | layout_qualifier | 
 |     : LAYOUT LEFT_PAREN layout_qualifier_id_list RIGHT_PAREN { | 
 |         ES3_ONLY("layout", @1, "qualifier"); | 
 |         $$ = $3; | 
 |     } | 
 |     ; | 
 |  | 
 | layout_qualifier_id_list | 
 |     : layout_qualifier_id { | 
 |         $$ = $1; | 
 |     } | 
 |     | layout_qualifier_id_list COMMA layout_qualifier_id { | 
 |         $$ = context->joinLayoutQualifiers($1, $3); | 
 |     } | 
 |     ; | 
 |  | 
 | layout_qualifier_id | 
 |     : IDENTIFIER { | 
 |         $$ = context->parseLayoutQualifier(*$1.string, @1); | 
 |     } | 
 |     | IDENTIFIER EQUAL INTCONSTANT { | 
 |         $$ = context->parseLayoutQualifier(*$1.string, @1, *$3.string, $3.i, @3); | 
 |     } | 
 |     | IDENTIFIER EQUAL UINTCONSTANT { | 
 |         $$ = context->parseLayoutQualifier(*$1.string, @1, *$3.string, $3.i, @3); | 
 |     } | 
 |     ; | 
 |  | 
 | type_specifier_no_prec | 
 |     : type_specifier_nonarray { | 
 |         $$ = $1; | 
 |     } | 
 |     | type_specifier_nonarray LEFT_BRACKET RIGHT_BRACKET { | 
 |         ES3_ONLY("[]", @2, "implicitly sized array"); | 
 |         $$ = $1; | 
 |         $$.setArray(true, 0); | 
 |     } | 
 |     | type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET { | 
 |         $$ = $1; | 
 |  | 
 |         if (context->arrayTypeErrorCheck(@2, $1)) | 
 |             context->recover(); | 
 |         else { | 
 |             int size; | 
 |             if (context->arraySizeErrorCheck(@2, $3, size)) | 
 |                 context->recover(); | 
 |             $$.setArray(true, size); | 
 |         } | 
 |     } | 
 |     ; | 
 |  | 
 | type_specifier_nonarray | 
 |     : VOID_TYPE { | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtVoid, qual, @1); | 
 |     } | 
 |     | FLOAT_TYPE { | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtFloat, qual, @1); | 
 |     } | 
 |     | INT_TYPE { | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtInt, qual, @1); | 
 |     } | 
 |     | UINT_TYPE { | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtUInt, qual, @1); | 
 |     } | 
 |     | BOOL_TYPE { | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtBool, qual, @1); | 
 |     } | 
 |     | VEC2 { | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtFloat, qual, @1); | 
 |         $$.setAggregate(2); | 
 |     } | 
 |     | VEC3 { | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtFloat, qual, @1); | 
 |         $$.setAggregate(3); | 
 |     } | 
 |     | VEC4 { | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtFloat, qual, @1); | 
 |         $$.setAggregate(4); | 
 |     } | 
 |     | BVEC2 { | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtBool, qual, @1); | 
 |         $$.setAggregate(2); | 
 |     } | 
 |     | BVEC3 { | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtBool, qual, @1); | 
 |         $$.setAggregate(3); | 
 |     } | 
 |     | BVEC4 { | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtBool, qual, @1); | 
 |         $$.setAggregate(4); | 
 |     } | 
 |     | IVEC2 { | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtInt, qual, @1); | 
 |         $$.setAggregate(2); | 
 |     } | 
 |     | IVEC3 { | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtInt, qual, @1); | 
 |         $$.setAggregate(3); | 
 |     } | 
 |     | IVEC4 { | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtInt, qual, @1); | 
 |         $$.setAggregate(4); | 
 |     } | 
 |     | UVEC2 { | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtUInt, qual, @1); | 
 |         $$.setAggregate(2); | 
 |     } | 
 |     | UVEC3 { | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtUInt, qual, @1); | 
 |         $$.setAggregate(3); | 
 |     } | 
 |     | UVEC4 { | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtUInt, qual, @1); | 
 |         $$.setAggregate(4); | 
 |     } | 
 |     | MATRIX2 { | 
 |         FRAG_VERT_ONLY("mat2", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtFloat, qual, @1); | 
 |         $$.setMatrix(2, 2); | 
 |     } | 
 |     | MATRIX3 { | 
 |         FRAG_VERT_ONLY("mat3", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtFloat, qual, @1); | 
 |         $$.setMatrix(3, 3); | 
 |     } | 
 |     | MATRIX4 { | 
 |         FRAG_VERT_ONLY("mat4", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtFloat, qual, @1); | 
 |         $$.setMatrix(4, 4); | 
 |     } | 
 |     | MATRIX2x3 { | 
 |         FRAG_VERT_ONLY("mat2x3", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtFloat, qual, @1); | 
 |         $$.setMatrix(2, 3); | 
 |     } | 
 |     | MATRIX3x2 { | 
 |         FRAG_VERT_ONLY("mat3x2", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtFloat, qual, @1); | 
 |         $$.setMatrix(3, 2); | 
 |     } | 
 |     | MATRIX2x4 { | 
 |         FRAG_VERT_ONLY("mat2x4", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtFloat, qual, @1); | 
 |         $$.setMatrix(2, 4); | 
 |     } | 
 |     | MATRIX4x2 { | 
 |         FRAG_VERT_ONLY("mat4x2", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtFloat, qual, @1); | 
 |         $$.setMatrix(4, 2); | 
 |     } | 
 |     | MATRIX3x4 { | 
 |         FRAG_VERT_ONLY("mat3x4", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtFloat, qual, @1); | 
 |         $$.setMatrix(3, 4); | 
 |     } | 
 |     | MATRIX4x3 { | 
 |         FRAG_VERT_ONLY("mat4x3", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtFloat, qual, @1); | 
 |         $$.setMatrix(4, 3); | 
 |     } | 
 |     | SAMPLER2D { | 
 |         FRAG_VERT_ONLY("sampler2D", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtSampler2D, qual, @1); | 
 |     } | 
 |     | SAMPLERCUBE { | 
 |         FRAG_VERT_ONLY("samplerCube", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtSamplerCube, qual, @1); | 
 |     } | 
 | 	| SAMPLER_EXTERNAL_OES { | 
 |         if (!context->supportsExtension("GL_OES_EGL_image_external")) { | 
 |             context->error(@1, "unsupported type", "samplerExternalOES", ""); | 
 |             context->recover(); | 
 |         } | 
 |         FRAG_VERT_ONLY("samplerExternalOES", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtSamplerExternalOES, qual, @1); | 
 |     } | 
 |     | SAMPLER3D { | 
 |         FRAG_VERT_ONLY("sampler3D", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtSampler3D, qual, @1); | 
 |     } | 
 |     | SAMPLER2DARRAY { | 
 |         FRAG_VERT_ONLY("sampler2DArray", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtSampler2DArray, qual, @1); | 
 |     } | 
 |     | ISAMPLER2D { | 
 |         FRAG_VERT_ONLY("isampler2D", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtISampler2D, qual, @1); | 
 |     } | 
 |     | ISAMPLER3D { | 
 |         FRAG_VERT_ONLY("isampler3D", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtISampler3D, qual, @1); | 
 |     } | 
 |     | ISAMPLERCUBE { | 
 |         FRAG_VERT_ONLY("isamplerCube", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtISamplerCube, qual, @1); | 
 |     } | 
 |     | ISAMPLER2DARRAY { | 
 |         FRAG_VERT_ONLY("isampler2DArray", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtISampler2DArray, qual, @1); | 
 |     } | 
 |     | USAMPLER2D { | 
 |         FRAG_VERT_ONLY("usampler2D", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtUSampler2D, qual, @1); | 
 |     } | 
 |     | USAMPLER3D { | 
 |         FRAG_VERT_ONLY("usampler3D", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtUSampler3D, qual, @1); | 
 |     } | 
 |     | USAMPLERCUBE { | 
 |         FRAG_VERT_ONLY("usamplerCube", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtUSamplerCube, qual, @1); | 
 |     } | 
 |     | USAMPLER2DARRAY { | 
 |         FRAG_VERT_ONLY("usampler2DArray", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtUSampler2DArray, qual, @1); | 
 |     } | 
 |     | SAMPLER2DSHADOW { | 
 |         FRAG_VERT_ONLY("sampler2DShadow", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtSampler2DShadow, qual, @1); | 
 |     } | 
 |     | SAMPLERCUBESHADOW { | 
 |         FRAG_VERT_ONLY("samplerCubeShadow", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtSamplerCubeShadow, qual, @1); | 
 |     } | 
 |     | SAMPLER2DARRAYSHADOW { | 
 |         FRAG_VERT_ONLY("sampler2DArrayShadow", @1); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtSampler2DArrayShadow, qual, @1); | 
 |     } | 
 |     | struct_specifier { | 
 |         FRAG_VERT_ONLY("struct", @1); | 
 |         $$ = $1; | 
 |         $$.qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |     } | 
 |     | TYPE_NAME { | 
 |         // | 
 |         // This is for user defined type names.  The lexical phase looked up the | 
 |         // type. | 
 |         // | 
 |         TType& structure = static_cast<TVariable*>($1.symbol)->getType(); | 
 |         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; | 
 |         $$.setBasic(EbtStruct, qual, @1); | 
 |         $$.userDef = &structure; | 
 |     } | 
 |     ; | 
 |  | 
 | struct_specifier | 
 |     : STRUCT IDENTIFIER LEFT_BRACE { if (context->enterStructDeclaration(@2, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE { | 
 |         $$ = context->addStructure(@1, @2, $2.string, $5); | 
 |     } | 
 |     | STRUCT LEFT_BRACE { if (context->enterStructDeclaration(@2, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE { | 
 |         $$ = context->addStructure(@1, @1, NewPoolTString(""), $4); | 
 |     } | 
 |     ; | 
 |  | 
 | struct_declaration_list | 
 |     : struct_declaration { | 
 |         $$ = $1; | 
 |     } | 
 |     | struct_declaration_list struct_declaration { | 
 |         $$ = $1; | 
 |         for (unsigned int i = 0; i < $2->size(); ++i) { | 
 |             TField* field = (*$2)[i]; | 
 |             for (unsigned int j = 0; j < $$->size(); ++j) { | 
 |                 if ((*$$)[j]->name() == field->name()) { | 
 |                     context->error((*$2)[i]->line(), "duplicate field name in structure:", "struct", field->name().c_str()); | 
 |                     context->recover(); | 
 |                 } | 
 |             } | 
 |             $$->push_back((*$2)[i]); | 
 |         } | 
 |     } | 
 |     ; | 
 |  | 
 | struct_declaration | 
 |     : type_specifier struct_declarator_list SEMICOLON { | 
 |         $$ = context->addStructDeclaratorList($1, $2); | 
 |     } | 
 |     | type_qualifier type_specifier struct_declarator_list SEMICOLON { | 
 |         // ES3 Only, but errors should be handled elsewhere | 
 |         $2.qualifier = $1.qualifier; | 
 |         $2.layoutQualifier = $1.layoutQualifier; | 
 |         $$ = context->addStructDeclaratorList($2, $3); | 
 |     } | 
 |     ; | 
 |  | 
 | struct_declarator_list | 
 |     : struct_declarator { | 
 |         $$ = NewPoolTFieldList(); | 
 |         $$->push_back($1); | 
 |     } | 
 |     | struct_declarator_list COMMA struct_declarator { | 
 |         $$->push_back($3); | 
 |     } | 
 |     ; | 
 |  | 
 | struct_declarator | 
 |     : IDENTIFIER { | 
 |         if (context->reservedErrorCheck(@1, *$1.string)) | 
 |             context->recover(); | 
 |  | 
 |         TType* type = new TType(EbtVoid, EbpUndefined); | 
 |         $$ = new TField(type, $1.string, @1); | 
 |     } | 
 |     | IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET { | 
 |         if (context->reservedErrorCheck(@1, *$1.string)) | 
 |             context->recover(); | 
 |  | 
 |         TType* type = new TType(EbtVoid, EbpUndefined); | 
 |         int size; | 
 |         if (context->arraySizeErrorCheck($3->getLine(), $3, size)) | 
 |             context->recover(); | 
 |         type->setArraySize(size); | 
 |  | 
 |         $$ = new TField(type, $1.string, @1); | 
 |     } | 
 |     ; | 
 |  | 
 | initializer | 
 |     : assignment_expression { $$ = $1; } | 
 |     ; | 
 |  | 
 | declaration_statement | 
 |     : declaration { $$ = $1; } | 
 |     ; | 
 |  | 
 | statement | 
 |     : compound_statement  { $$ = $1; } | 
 |     | simple_statement    { $$ = $1; } | 
 |     ; | 
 |  | 
 | // Grammar Note:  Labeled statements for SWITCH only; 'goto' is not supported. | 
 |  | 
 | simple_statement | 
 |     : declaration_statement { $$ = $1; } | 
 |     | expression_statement  { $$ = $1; } | 
 |     | selection_statement   { $$ = $1; } | 
 |     | switch_statement      { $$ = $1; } | 
 |     | case_label            { $$ = $1; } | 
 |     | iteration_statement   { $$ = $1; } | 
 |     | jump_statement        { $$ = $1; } | 
 |     ; | 
 |  | 
 | compound_statement | 
 |     : LEFT_BRACE RIGHT_BRACE { $$ = 0; } | 
 |     | LEFT_BRACE { context->symbolTable.push(); } statement_list { context->symbolTable.pop(); } RIGHT_BRACE { | 
 |         if ($3 != 0) { | 
 |             $3->setOp(EOpSequence); | 
 |             $3->setEndLine(@5); | 
 |         } | 
 |         $$ = $3; | 
 |     } | 
 |     ; | 
 |  | 
 | statement_no_new_scope | 
 |     : compound_statement_no_new_scope { $$ = $1; } | 
 |     | simple_statement                { $$ = $1; } | 
 |     ; | 
 |  | 
 | statement_with_scope | 
 |     : { context->symbolTable.push(); } compound_statement_no_new_scope { context->symbolTable.pop(); $$ = $2; } | 
 |     | { context->symbolTable.push(); } simple_statement                { context->symbolTable.pop(); $$ = $2; } | 
 |     ; | 
 |  | 
 | compound_statement_no_new_scope | 
 |     // Statement that doesn't create a new scope, for selection_statement, iteration_statement | 
 |     : LEFT_BRACE RIGHT_BRACE { | 
 |         $$ = 0; | 
 |     } | 
 |     | LEFT_BRACE statement_list RIGHT_BRACE { | 
 |         if ($2) { | 
 |             $2->setOp(EOpSequence); | 
 |             $2->setEndLine(@3); | 
 |         } | 
 |         $$ = $2; | 
 |     } | 
 |     ; | 
 |  | 
 | statement_list | 
 |     : statement { | 
 |         $$ = context->intermediate.makeAggregate($1, @$); | 
 |     } | 
 |     | statement_list statement { | 
 |         $$ = context->intermediate.growAggregate($1, $2, @$); | 
 |     } | 
 |     ; | 
 |  | 
 | expression_statement | 
 |     : SEMICOLON  { $$ = 0; } | 
 |     | expression SEMICOLON  { $$ = static_cast<TIntermNode*>($1); } | 
 |     ; | 
 |  | 
 | selection_statement | 
 |     : IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement { | 
 |         if (context->boolErrorCheck(@1, $3)) | 
 |             context->recover(); | 
 |         $$ = context->intermediate.addSelection($3, $5, @1); | 
 |     } | 
 |     ; | 
 |  | 
 | selection_rest_statement | 
 |     : statement_with_scope ELSE statement_with_scope { | 
 |         $$.node1 = $1; | 
 |         $$.node2 = $3; | 
 |     } | 
 |     | statement_with_scope { | 
 |         $$.node1 = $1; | 
 |         $$.node2 = 0; | 
 |     } | 
 |     ; | 
 |  | 
 | switch_statement | 
 |     : SWITCH LEFT_PAREN expression RIGHT_PAREN { context->incrSwitchNestingLevel(); } compound_statement { | 
 |         $$ = context->addSwitch($3, $6, @1); | 
 |         context->decrSwitchNestingLevel(); | 
 |     } | 
 |     ; | 
 |  | 
 | case_label | 
 |     : CASE constant_expression COLON { | 
 |         $$ = context->addCase($2, @1); | 
 |     } | 
 |     | DEFAULT COLON { | 
 |         $$ = context->addDefault(@1); | 
 |     } | 
 |     ; | 
 |  | 
 | condition | 
 |     // In 1996 c++ draft, conditions can include single declarations | 
 |     : expression { | 
 |         $$ = $1; | 
 |         if (context->boolErrorCheck($1->getLine(), $1)) | 
 |             context->recover(); | 
 |     } | 
 |     | fully_specified_type IDENTIFIER EQUAL initializer { | 
 |         TIntermNode *intermNode; | 
 |         if (context->boolErrorCheck(@2, $1)) | 
 |             context->recover(); | 
 |  | 
 |         if (!context->executeInitializer(@2, *$2.string, $1, $4, &intermNode)) | 
 |             $$ = $4; | 
 |         else { | 
 |             context->recover(); | 
 |             $$ = 0; | 
 |         } | 
 |     } | 
 |     ; | 
 |  | 
 | iteration_statement | 
 |     : WHILE LEFT_PAREN { context->symbolTable.push(); context->incrLoopNestingLevel(); } condition RIGHT_PAREN statement_no_new_scope { | 
 |         context->symbolTable.pop(); | 
 |         $$ = context->intermediate.addLoop(ELoopWhile, 0, $4, 0, $6, @1); | 
 |         context->decrLoopNestingLevel(); | 
 |     } | 
 |     | DO { context->incrLoopNestingLevel(); } statement_with_scope WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON { | 
 |         if (context->boolErrorCheck(@8, $6)) | 
 |             context->recover(); | 
 |  | 
 |         $$ = context->intermediate.addLoop(ELoopDoWhile, 0, $6, 0, $3, @4); | 
 |         context->decrLoopNestingLevel(); | 
 |     } | 
 |     | FOR LEFT_PAREN { context->symbolTable.push(); context->incrLoopNestingLevel(); } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope { | 
 |         context->symbolTable.pop(); | 
 |         $$ = context->intermediate.addLoop(ELoopFor, $4, reinterpret_cast<TIntermTyped*>($5.node1), reinterpret_cast<TIntermTyped*>($5.node2), $7, @1); | 
 |         context->decrLoopNestingLevel(); | 
 |     } | 
 |     ; | 
 |  | 
 | for_init_statement | 
 |     : expression_statement { | 
 |         $$ = $1; | 
 |     } | 
 |     | declaration_statement { | 
 |         $$ = $1; | 
 |     } | 
 |     ; | 
 |  | 
 | conditionopt | 
 |     : condition { | 
 |         $$ = $1; | 
 |     } | 
 |     | /* May be null */ { | 
 |         $$ = 0; | 
 |     } | 
 |     ; | 
 |  | 
 | for_rest_statement | 
 |     : conditionopt SEMICOLON { | 
 |         $$.node1 = $1; | 
 |         $$.node2 = 0; | 
 |     } | 
 |     | conditionopt SEMICOLON expression  { | 
 |         $$.node1 = $1; | 
 |         $$.node2 = $3; | 
 |     } | 
 |     ; | 
 |  | 
 | jump_statement | 
 |     : CONTINUE SEMICOLON { | 
 |         $$ = context->addBranch(EOpContinue, @1); | 
 |     } | 
 |     | BREAK SEMICOLON { | 
 |         $$ = context->addBranch(EOpBreak, @1); | 
 |     } | 
 |     | RETURN SEMICOLON { | 
 |         $$ = context->addBranch(EOpReturn, @1); | 
 |     } | 
 |     | RETURN expression SEMICOLON { | 
 |         $$ = context->addBranch(EOpReturn, $2, @1); | 
 |     } | 
 |     | DISCARD SEMICOLON { | 
 |         FRAG_ONLY("discard", @1); | 
 |         $$ = context->addBranch(EOpKill, @1); | 
 |     } | 
 |     ; | 
 |  | 
 | // Grammar Note:  No 'goto'.  Gotos are not supported. | 
 |  | 
 | translation_unit | 
 |     : external_declaration { | 
 |         $$ = $1; | 
 |         context->setTreeRoot($$); | 
 |     } | 
 |     | translation_unit external_declaration { | 
 |         $$ = context->intermediate.growAggregate($1, $2, @$); | 
 |         context->setTreeRoot($$); | 
 |     } | 
 |     ; | 
 |  | 
 | external_declaration | 
 |     : function_definition { | 
 |         $$ = $1; | 
 |     } | 
 |     | declaration { | 
 |         $$ = $1; | 
 |     } | 
 |     ; | 
 |  | 
 | function_definition | 
 |     : function_prototype { | 
 |         context->parseFunctionPrototype(@1, $1.function, &$1.intermAggregate); | 
 |     } | 
 |     compound_statement_no_new_scope { | 
 |         $$ = context->addFunctionDefinition(*($1.function), $1.intermAggregate, $3, @1); | 
 |     } | 
 |     ; | 
 |  | 
 | %% | 
 |  | 
 | int glslang_parse(TParseContext* context) { | 
 |     return yyparse(context, context->getScanner()); | 
 | } |