Remove the pack/unpack languages and bring grammar up from 1.1 to 4.2 and fix the...
authorJohn Kessenich <cepheus@frii.com>
Wed, 12 Dec 2012 21:23:55 +0000 (21:23 +0000)
committerJohn Kessenich <cepheus@frii.com>
Wed, 12 Dec 2012 21:23:55 +0000 (21:23 +0000)
For 4.2, largely, it is only the grammar that is working.  Productions and semantics are mostly missing.  Lexical analysis is mostly done, but not in the preprocessor, which still can't handle uint and double literals.

The grammar and token names are reorganized to match the specification, to allow easier comparison between the specification and the working grammar.

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@19946 e7fa87d3-cd2b-0410-9028-fcbf551c1848

13 files changed:
StandAlone/StandAlone.cpp
glslang/Include/BaseTypes.h
glslang/Include/intermediate.h
glslang/MachineIndependent/Initialize.cpp
glslang/MachineIndependent/IntermTraverse.cpp
glslang/MachineIndependent/Intermediate.cpp
glslang/MachineIndependent/ParseHelper.cpp
glslang/MachineIndependent/ParseHelper.h
glslang/MachineIndependent/glslang.l
glslang/MachineIndependent/glslang.y
glslang/MachineIndependent/intermOut.cpp
glslang/MachineIndependent/localintermediate.h
glslang/Public/ShaderLang.h

index 1fc0872..3620f60 100644 (file)
@@ -212,8 +212,6 @@ int C_DECL main(int argc, char* argv[])
 //
 //   .frag*    = fragment programs
 //   .vert*    = vertex programs
-//   .pack*    = pack programs
-//   .unpa*    = unpack pragrams
 //
 static EShLanguage FindLanguage(char *name)
 {
@@ -228,8 +226,6 @@ static EShLanguage FindLanguage(char *name)
     if (ext = strrchr(name, '.')) {
         if (strncmp(ext, ".frag", 4) == 0) return EShLangFragment;
         if (strncmp(ext, ".vert", 4) == 0) return EShLangVertex;
-        if (strncmp(ext, ".pack", 4) == 0) return EShLangPack;
-        if (strncmp(ext, ".unpa", 4) == 0) return EShLangUnpack;
     }
 
     return EShLangFragment;
index 1249cde..da27303 100644 (file)
@@ -77,10 +77,6 @@ enum TQualifier {
     EvqVaryingOut,    // vertex shaders only  read/write
     EvqUniform,       // Readonly, vertex and fragment
 
-    // pack/unpack input and output
-    EvqInput,
-    EvqOutput,
-
     // parameters
     EvqIn,
     EvqOut,
@@ -113,16 +109,14 @@ __inline const char* getQualifierString(TQualifier q)
     case EvqTemporary:      return "Temporary";      break;
     case EvqGlobal:         return "Global";         break;
     case EvqConst:          return "const";          break;
-    case EvqConstReadOnly:  return "const";          break;
+    case EvqConstReadOnly:  return "const (read only)"; break;
     case EvqAttribute:      return "attribute";      break;
-    case EvqVaryingIn:      return "varying";        break;
-    case EvqVaryingOut:     return "varying";        break;
+    case EvqVaryingIn:      return "varying in";     break;
+    case EvqVaryingOut:     return "varying out";    break;
     case EvqUniform:        return "uniform";        break;
     case EvqIn:             return "in";             break;
     case EvqOut:            return "out";            break;
     case EvqInOut:          return "inout";          break;
-    case EvqInput:          return "input";          break;
-    case EvqOutput:         return "output";         break;
     case EvqPosition:       return "Position";       break;
     case EvqPointSize:      return "PointSize";      break;
     case EvqClipVertex:     return "ClipVertex";     break;
index 336e43c..f0c2cbd 100644 (file)
@@ -118,6 +118,8 @@ enum TOperator {
 
     EOpVectorSwizzle,
 
+    EOpMethod,
+
     //
     // Built-in functions potentially mapped to operators
     //
@@ -168,17 +170,7 @@ enum TOperator {
 
     EOpAny,
     EOpAll,
-    
-    EOpItof,         // pack/unpack only
-    EOpFtoi,         // pack/unpack only    
-    EOpSkipPixels,   // pack/unpack only
-    EOpReadInput,    // unpack only
-    EOpWritePixel,   // unpack only
-    EOpBitmapLsb,    // unpack only
-    EOpBitmapMsb,    // unpack only
-    EOpWriteOutput,  // pack only
-    EOpReadPixel,    // pack only
-    
+
     //
     // Branch
     //
@@ -242,6 +234,7 @@ class TIntermBinary;
 class TIntermConstantUnion;
 class TIntermSelection;
 class TIntermTyped;
+class TIntermMethod;
 class TIntermSymbol;
 class TInfoSink;
 
@@ -261,6 +254,7 @@ public:
     virtual TIntermAggregate* getAsAggregate()     { return 0; }
     virtual TIntermBinary*    getAsBinaryNode()    { return 0; }
     virtual TIntermSelection* getAsSelectionNode() { return 0; }
+    virtual TIntermMethod*    getAsMethodNode()    { return 0; }
     virtual TIntermSymbol*    getAsSymbolNode()    { return 0; }
     virtual ~TIntermNode() { }
 protected:
@@ -343,6 +337,23 @@ protected:
 };
 
 //
+// Represent method names before seeing their calling signature
+// or resolving them to operations.  Just an expression as the base object
+// and a textural name.
+//
+class TIntermMethod : public TIntermTyped {
+public:
+    TIntermMethod(TIntermTyped* o, const TType& t, const TString& m) : TIntermTyped(t), object(o), method(m) { }
+    virtual TIntermMethod* getAsMethodNode() { return this; }
+    virtual const TString& getMethodName() const { return method; }
+    virtual TIntermTyped* getObject() const { return object; }
+    virtual void traverse(TIntermTraverser*);
+protected:
+    TIntermTyped* object;
+    TString method;
+};
+
+//
 // Nodes that correspond to symbols or constants in the source code.
 //
 class TIntermSymbol : public TIntermTyped {
index b978af8..96f307a 100644 (file)
@@ -918,18 +918,6 @@ void IdentifyBuiltIns(EShLanguage language, TSymbolTable& symbolTable)
 
         break;
 
-    case EShLangPack:
-    case EShLangUnpack:
-        symbolTable.relateToOperator("itof",         EOpItof);
-        symbolTable.relateToOperator("ftoi",         EOpFtoi);
-        symbolTable.relateToOperator("skipPixels",   EOpSkipPixels);
-        symbolTable.relateToOperator("readInput",    EOpReadInput);
-        symbolTable.relateToOperator("writePixel",   EOpWritePixel);
-        symbolTable.relateToOperator("bitmapLSB",    EOpBitmapLsb);
-        symbolTable.relateToOperator("bitmapMSB",    EOpBitmapMsb);
-        symbolTable.relateToOperator("writeOutput",  EOpWriteOutput);
-        symbolTable.relateToOperator("readPixel",    EOpReadPixel);
-        break;
        default: assert(false && "Language not supported");
     }
 }
index 8b379db..eb87bf6 100644 (file)
 //
 // Traversal functions for terminals are straighforward....
 //
+void TIntermMethod::traverse(TIntermTraverser* it)
+{
+    // TODO: current tree should always resolve all methods as constants
+    // 4.3 will leave some length methods as methods
+}
+
 void TIntermSymbol::traverse(TIntermTraverser* it)
 {
     if (it->visitSymbol)
index 96c9074..6dc3ca8 100644 (file)
@@ -554,6 +554,14 @@ TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, T
     }
 }
 
+TIntermTyped* TIntermediate::addMethod(TIntermTyped* object, TType& type, const TString* name, TSourceLoc line)
+{
+    TIntermMethod* method = new TIntermMethod(object, type, *name);
+    method->setLine(line);
+
+    return method;
+}
+
 //
 // For "?:" test nodes.  There are three children; a condition,
 // a true path, and a false path.  The two paths are specified
index ee95d71..70df00b 100644 (file)
@@ -252,6 +252,30 @@ void TParseContext::binaryOpError(int line, char* op, TString left, TString righ
 }
 
 //
+// A basic type of EbtVoid is a key that the name string was seen in the source, but
+// it was not found as a variable in the symbol table.  If so, give the error
+// message and insert a dummy variable in the symbol table to prevent future errors.
+//
+void TParseContext::variableErrorCheck(TIntermTyped*& nodePtr) 
+{
+    TIntermSymbol* symbol = nodePtr->getAsSymbolNode();
+    if (symbol && symbol->getType().getBasicType() == EbtVoid) {
+        error(symbol->getLine(), "undeclared identifier", symbol->getSymbol().c_str(), "");
+        recover();
+
+        // Add to symbol table to prevent future error messages on the same name
+            
+        TVariable* fakeVariable = new TVariable(&symbol->getSymbol(), TType(EbtFloat));
+        symbolTable.insert(*fakeVariable);
+
+        // substitute a symbol node for this new variable
+        nodePtr = intermediate.addSymbol(fakeVariable->getUniqueId(), 
+                                         fakeVariable->getName(), 
+                                         fakeVariable->getType(), symbol->getLine());
+    }
+}
+
+//
 // Both test and if necessary, spit out an error, to see if the node is really
 // an l-value that can be operated on this way.
 //
@@ -311,7 +335,6 @@ bool TParseContext::lValueErrorCheck(int line, char* op, TIntermTyped* node)
     case EvqAttribute:      message = "can't modify an attribute";   break;
     case EvqUniform:        message = "can't modify a uniform";      break;
     case EvqVaryingIn:      message = "can't modify a varying";      break;
-    case EvqInput:          message = "can't modify an input";       break;
     case EvqFace:           message = "can't modify gl_FrontFace";   break;
     case EvqFragCoord:      message = "can't modify gl_FragCoord";   break;
     default:
@@ -596,6 +619,24 @@ bool TParseContext::samplerErrorCheck(int line, const TPublicType& pType, const
     return false;
 }
 
+bool TParseContext::globalQualifierFixAndErrorCheck(int line, TQualifier& qualifier)
+{
+    switch (qualifier) {
+    case EvqIn:
+        qualifier = EvqVaryingIn;
+        return false;
+    case EvqOut:
+        qualifier = EvqVaryingOut;
+        return false;
+    case EvqInOut:
+        qualifier = EvqVaryingIn;
+        error(line, "cannot use both 'in' and 'out' at global scope", "", "");
+        return true;
+    }
+
+    return false;
+}
+
 bool TParseContext::structQualifierErrorCheck(int line, const TPublicType& pType)
 {
     if ((pType.qualifier == EvqVaryingIn || pType.qualifier == EvqVaryingOut || pType.qualifier == EvqAttribute) &&
@@ -885,23 +926,26 @@ bool TParseContext::nonInitErrorCheck(int line, TString& identifier, TPublicType
     return false;
 }
 
-bool TParseContext::paramErrorCheck(int line, TQualifier qualifier, TQualifier paramQualifier, TType* type)
-{    
-    if (qualifier != EvqConst && qualifier != EvqTemporary) {
+bool TParseContext::paramErrorCheck(int line, TQualifier qualifier, TType* type)
+{
+    switch (qualifier) {
+    case EvqConst:
+    case EvqConstReadOnly:
+        type->changeQualifier(EvqConstReadOnly);
+        return false;
+    case EvqIn:
+    case EvqOut:
+    case EvqInOut:
+        type->changeQualifier(qualifier);
+        return false;
+    case EvqTemporary:
+        type->changeQualifier(EvqIn);
+        return false;
+    default:
+        type->changeQualifier(EvqIn);
         error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier), "");
         return true;
     }
-    if (qualifier == EvqConst && paramQualifier != EvqIn) {
-        error(line, "qualifier not allowed with ", getQualifierString(qualifier), getQualifierString(paramQualifier));
-        return true;
-    }
-
-    if (qualifier == EvqConst)
-        type->changeQualifier(EvqConstReadOnly);
-    else
-        type->changeQualifier(paramQualifier);
-
-    return false;
 }
 
 bool TParseContext::extensionErrorCheck(int line, const char* extension)
index ca153ae..99e2ded 100644 (file)
@@ -66,17 +66,19 @@ struct TPragma {
 struct TParseContext {
     TParseContext(TSymbolTable& symt, TIntermediate& interm, EShLanguage L, TInfoSink& is) : 
             intermediate(interm), symbolTable(symt), infoSink(is), language(L), treeRoot(0),
-            recoveredFromError(false), numErrors(0), lexAfterType(false), loopNestingLevel(0), 
+            recoveredFromError(false), numErrors(0), lexAfterType(false), loopNestingLevel(0),
+            switchNestingLevel(0),
             inTypeParen(false), contextPragma(true, false) {  }
     TIntermediate& intermediate; // to hold and build a parse tree
     TSymbolTable& symbolTable;   // symbol table that goes with the language currently being parsed
     TInfoSink& infoSink;
-    EShLanguage language;        // vertex or fragment language (future: pack or unpack)
+    EShLanguage language;        // vertex or fragment language
     TIntermNode* treeRoot;       // root of parse tree being created
     bool recoveredFromError;     // true if a parse error has occurred, but we continue to parse
     int numErrors;
     bool lexAfterType;           // true if we've recognized a type, so can only be looking for an identifier
     int loopNestingLevel;        // 0 if outside all loops
+    int switchNestingLevel;      // 0 if outside all switch statements
     bool inTypeParen;            // true if in parentheses, looking only for an identifier
     const TType* currentFunctionType;  // the return type of the function that's currently being parsed
     bool functionReturnsValue;   // true if a non-void function has a return
@@ -93,6 +95,7 @@ struct TParseContext {
     void assignError(int line, const char* op, TString left, TString right);
     void unaryOpError(int line, char* op, TString operand);
     void binaryOpError(int line, char* op, TString left, TString right);
+    void variableErrorCheck(TIntermTyped*& nodePtr);
     bool lValueErrorCheck(int line, char* op, TIntermTyped*);
     bool constErrorCheck(TIntermTyped* node);
     bool integerErrorCheck(TIntermTyped* node, char* token);
@@ -107,12 +110,13 @@ struct TParseContext {
     bool boolErrorCheck(int, const TIntermTyped*);
     bool boolErrorCheck(int, const TPublicType&);
     bool samplerErrorCheck(int line, const TPublicType& pType, const char* reason);
+    bool globalQualifierFixAndErrorCheck(int line, TQualifier&);
     bool structQualifierErrorCheck(int line, const TPublicType& pType);
     bool parameterSamplerErrorCheck(int line, TQualifier qualifier, const TType& type);
     bool containsSampler(TType& type);
     bool nonInitConstErrorCheck(int line, TString& identifier, TPublicType& type);
     bool nonInitErrorCheck(int line, TString& identifier, TPublicType& type);
-    bool paramErrorCheck(int line, TQualifier qualifier, TQualifier paramQualifier, TType* type);
+    bool paramErrorCheck(int line, TQualifier qualifier, TType* type);
     bool extensionErrorCheck(int line, const char*);
     const TFunction* findFunction(int line, TFunction* pfnCall, bool *builtIn = 0);
     bool executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType, 
index 190ee6a..4186968 100644 (file)
@@ -53,6 +53,10 @@ L           [a-zA-Z_]
 H           [a-fA-F0-9]
 E           [Ee][+-]?{D}+
 O           [0-7]
+U           [uU]
+
+/* TODO: double literals, which will likely require pre-processor rework */
+/* TODO: unsigned int literals, which will likely require pre-processor rework */
 
 %option nounput 
 %{
@@ -92,36 +96,85 @@ TSourceLoc yylineno;
 <*>"//"[^\n]*"\n"     { /* ?? carriage and/or line-feed? */ };
 
 "attribute"    {  pyylval->lex.line = yylineno; return(ATTRIBUTE); }
-"const"        {  pyylval->lex.line = yylineno; return(CONST_QUAL); }
+"const"        {  pyylval->lex.line = yylineno; return(CONST); }
+"patch"        {  pyylval->lex.line = yylineno; return(PATCH); }
+"sample"       {  pyylval->lex.line = yylineno; return(SAMPLE); }
 "uniform"      {  pyylval->lex.line = yylineno; return(UNIFORM); }
+"coherent"     {  pyylval->lex.line = yylineno; return(COHERENT); }
+"volatile"     {  pyylval->lex.line = yylineno; return(VOLATILE); }
+"restrict"     {  pyylval->lex.line = yylineno; return(RESTRICT); }
+"readonly"     {  pyylval->lex.line = yylineno; return(READONLY); }
+"writeonly"    {  pyylval->lex.line = yylineno; return(WRITEONLY); }
 "varying"      {  pyylval->lex.line = yylineno; return(VARYING); }
+"layout"       {  pyylval->lex.line = yylineno; return(LAYOUT); }
 
 "break"        {  pyylval->lex.line = yylineno; return(BREAK); }
 "continue"     {  pyylval->lex.line = yylineno; return(CONTINUE); }
 "do"           {  pyylval->lex.line = yylineno; return(DO); }
 "for"          {  pyylval->lex.line = yylineno; return(FOR); }
 "while"        {  pyylval->lex.line = yylineno; return(WHILE); }
+"switch"       {  pyylval->lex.line = yylineno; return(SWITCH); }
+"case"         {  pyylval->lex.line = yylineno; return(CASE); }
+"default"      {  pyylval->lex.line = yylineno; return(DEFAULT); }
 
 "if"           {  pyylval->lex.line = yylineno; return(IF); }
 "else"         {  pyylval->lex.line = yylineno; return(ELSE); }
 
-"in"           {  pyylval->lex.line = yylineno; return(IN_QUAL); }
-"out"          {  pyylval->lex.line = yylineno; return(OUT_QUAL); }
-"inout"        {  pyylval->lex.line = yylineno; return(INOUT_QUAL); }
-
-"float"        {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(FLOAT_TYPE); }
-"int"          {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(INT_TYPE); }
-"void"         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(VOID_TYPE); }
-"bool"         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(BOOL_TYPE); }
+"in"           {  pyylval->lex.line = yylineno; return(IN); }
+"out"          {  pyylval->lex.line = yylineno; return(OUT); }
+"inout"        {  pyylval->lex.line = yylineno; return(INOUT); }
+"centroid"      {  pyylval->lex.line = yylineno; return(CENTROID); }
+"noperspective" {  pyylval->lex.line = yylineno; return(NOPERSPECTIVE); }
+"flat"          {  pyylval->lex.line = yylineno; return(FLAT); }
+"smooth"        {  pyylval->lex.line = yylineno; return(SMOOTH); }
+
+"precise"      {  pyylval->lex.line = yylineno; return(PRECISE); }
+"invariant"    {  pyylval->lex.line = yylineno; return(INVARIANT); }
+
+"precision"    {  pyylval->lex.line = yylineno; return(PRECISION); }
+"highp"        {  pyylval->lex.line = yylineno; return(HIGH_PRECISION); }
+"mediump"      {  pyylval->lex.line = yylineno; return(MEDIUM_PRECISION); }
+"lowp"         {  pyylval->lex.line = yylineno; return(LOW_PRECISION); }
+
+"float"        {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(FLOAT); }
+"double"       {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(DOUBLE); }
+"int"          {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(INT); }
+"uint"         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UINT); }
+"void"         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(VOID); }
+"bool"         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(BOOL); }
 "true"         {  pyylval->lex.line = yylineno; pyylval->lex.b = true;  return(BOOLCONSTANT); }
 "false"        {  pyylval->lex.line = yylineno; pyylval->lex.b = false; return(BOOLCONSTANT); }
 
 "discard"      {  pyylval->lex.line = yylineno; return(DISCARD); }
 "return"       {  pyylval->lex.line = yylineno; return(RETURN); }
-
-"mat2"         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MATRIX2); }
-"mat3"         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MATRIX3); }
-"mat4"         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MATRIX4); }
+"subroutine"   {  pyylval->lex.line = yylineno; return(SUBROUTINE); }
+
+"mat2"         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MAT2); }
+"mat3"         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MAT3); }
+"mat4"         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MAT4); }
+\r
+"mat2x2"       { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MAT2X2); }\r
+"mat2x3"       { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MAT2X3); }\r
+"mat2x4"       { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MAT2X4); }\r
+"mat3x2"       { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MAT3X2); }\r
+"mat3x3"       { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MAT3X3); }\r
+"mat3x4"       { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MAT3X4); }\r
+"mat4x2"       { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MAT4X2); }\r
+"mat4x3"       { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MAT4X3); }\r
+"mat4x4"       { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MAT4X4); }\r
+"dmat2"        { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(DMAT2); }\r
+"dmat3"        { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(DMAT3); }\r
+"dmat4"        { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(DMAT4); }\r
+"dmat2x2"      { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(DMAT2X2); }\r
+"dmat2x3"      { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(DMAT2X3); }\r
+"dmat2x4"      { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(DMAT2X4); }\r
+"dmat3x2"      { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(DMAT3X2); }\r
+"dmat3x3"      { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(DMAT3X3); }\r
+"dmat3x4"      { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(DMAT3X4); }\r
+"dmat4x2"      { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(DMAT4X2); }\r
+"dmat4x3"      { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(DMAT4X3); }\r
+"dmat4x4"      { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(DMAT4X4); }\r
+"atomic_uint"  { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(ATOMIC_UINT); }\r
 
 "vec2"         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (VEC2); }
 "vec3"         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (VEC3); }
@@ -129,6 +182,9 @@ TSourceLoc yylineno;
 "ivec2"        {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (IVEC2); }
 "ivec3"        {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (IVEC3); }
 "ivec4"        {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (IVEC4); }
+"uvec2"        {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (UVEC2); }
+"uvec3"        {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (UVEC3); }
+"uvec4"        {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (UVEC4); }
 "bvec2"        {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (BVEC2); }
 "bvec3"        {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (BVEC3); }
 "bvec4"        {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (BVEC4); }
@@ -140,8 +196,71 @@ TSourceLoc yylineno;
 "sampler1DShadow" {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLER1DSHADOW; }
 "sampler2DShadow" {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLER2DSHADOW; }
 
-"sampler2DRect"        { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLERRECTARB; /* ARB_texture_rectangle */ }
-"sampler2DRectShadow"  { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLERRECTSHADOWARB; /* ARB_texture_rectangle */ }
+"sampler2DRect"        { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLER2DRECT; }
+"isampler2DRect"       { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return ISAMPLER2DRECT; }
+"usampler2DRect"       { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return USAMPLER2DRECT; }
+"sampler2DRectShadow"  { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLER2DRECTSHADOW; }
+
+"samplerCubeShadow"    { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLERCUBESHADOW; }
+"sampler1DArray"       { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLER1DARRAY; }
+"sampler2DArray"       { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLER2DARRAY; }
+"sampler1DArrayShadow" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLER1DARRAYSHADOW; }
+"sampler2DArrayShadow" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLER2DARRAYSHADOW; }
+"isampler1D"           { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return ISAMPLER1D; }
+"isampler2D"           { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return ISAMPLER2D; }
+"isampler3D"           { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return ISAMPLER3D; }
+"isamplerCube"         { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return ISAMPLERCUBE; }
+"isampler1DArray"      { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return ISAMPLER1DARRAY; }
+"isampler2DArray"      { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return ISAMPLER2DARRAY; }
+"usampler1D"           { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return USAMPLER1D; }
+"usampler2D"           { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return USAMPLER2D; }
+"usampler3D"           { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return USAMPLER3D; }
+"usamplerCube"         { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return USAMPLERCUBE; }
+"usampler1DArray"      { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return USAMPLER1DARRAY; }
+"usampler2DArray"      { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return USAMPLER2DARRAY; }
+\r
+"samplerBuffer"        { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(SAMPLERBUFFER); }\r
+"isamplerBuffer"       { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(ISAMPLERBUFFER); }\r
+"usamplerBuffer"       { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(USAMPLERBUFFER); }\r
+"sampler2DMS"          { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(SAMPLER2DMS); }\r
+"isampler2DMS"         { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(ISAMPLER2DMS); }\r
+"usampler2DMS"         { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(USAMPLER2DMS); }\r
+"sampler2DMSarray"     { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(SAMPLER2DMSARRAY); }\r
+"isampler2DMSarray"    { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(ISAMPLER2DMSARRAY); }\r
+"usampler2DMSarray"    { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(USAMPLER2DMSARRAY); }\r
+"image1D"              { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGE1D); }\r
+"iimage1D"             { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGE1D); }\r
+"uimage1D"             { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGE1D); }\r
+"image2D"              { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGE2D); }\r
+"iimage2D"             { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGE2D); }\r
+"uimage2D"             { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGE2D); }\r
+"image3D"              { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGE3D); }\r
+"iimage3D"             { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGE3D); }\r
+"uimage3D"             { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGE3D); }\r
+"image2Drect"          { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGE2DRECT); }\r
+"iimage2Drect"         { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGE2DRECT); }\r
+"uimage2Drect"         { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGE2DRECT); }\r
+"imageCube"            { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGECUBE); }\r
+"iimageCube"           { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGECUBE); }\r
+"uimageCube"           { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGECUBE); }\r
+"imageBuffer"          { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGEBUFFER); }\r
+"iimageBuffer"         { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGEBUFFER); }\r
+"uimageBuffer"         { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGEBUFFER); }\r
+"image1Darray"         { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGE1DARRAY); }\r
+"iimage1Darray"        { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGE1DARRAY); }\r
+"uimage1Darray"        { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGE1DARRAY); }\r
+"image2Darray"         { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGE2DARRAY); }\r
+"iimage2Darray"        { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGE2DARRAY); }\r
+"uimage2Darray"        { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGE2DARRAY); }\r
+"imageCubearray"       { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGECUBEARRAY); }\r
+"iimageCubearray"      { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGECUBEARRAY); }\r
+"uimageCubearray"      { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGECUBEARRAY); }\r
+"image2DMS"            { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGE2DMS); }\r
+"iimage2DMS"           { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGE2DMS); }\r
+"uimage2DMS"           { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGE2DMS); }\r
+"image2DMSarray"       { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGE2DMSARRAY); }\r
+"iimage2DMSarray"      { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGE2DMSARRAY); }\r
+"uimage2DMSarray"      { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGE2DMSARRAY); }\r
 
 "struct"       {  pyylval->lex.line = yylineno; return(STRUCT); }
 
@@ -156,12 +275,9 @@ TSourceLoc yylineno;
 "packed"       {  PaReservedWord(); return 0; }
 
 "goto"         {  PaReservedWord(); return 0; }
-"switch"       {  PaReservedWord(); return 0; }
-"default"      {  PaReservedWord(); return 0; }
 
 "inline"       {  PaReservedWord(); return 0; }
 "noinline"     {  PaReservedWord(); return 0; }
-"volatile"     {  PaReservedWord(); return 0; }
 "public"       {  PaReservedWord(); return 0; }
 "static"       {  PaReservedWord(); return 0; }
 "extern"       {  PaReservedWord(); return 0; }
@@ -170,7 +286,6 @@ TSourceLoc yylineno;
 
 "long"         {  PaReservedWord(); return 0; }
 "short"        {  PaReservedWord(); return 0; }
-"double"       {  PaReservedWord(); return 0; }
 "half"         {  PaReservedWord(); return 0; }
 "fixed"        {  PaReservedWord(); return 0; }
 "unsigned"     {  PaReservedWord(); return 0; }
@@ -207,6 +322,11 @@ TSourceLoc yylineno;
 0{D}+             { pyylval->lex.line = yylineno; parseContext.error(yylineno, "Invalid Octal number.", yytext, "", ""); parseContext.recover(); return 0;}
 {D}+              { pyylval->lex.line = yylineno; pyylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); }
 
+0[xX]{H}+{U}      { pyylval->lex.line = yylineno; pyylval->lex.i = strtol(yytext, 0, 0); return(UINTCONSTANT); }
+0{O}+{U}          { pyylval->lex.line = yylineno; pyylval->lex.i = strtol(yytext, 0, 0); return(UINTCONSTANT); }
+0{D}+{U}          { pyylval->lex.line = yylineno; parseContext.error(yylineno, "Invalid Octal number.", yytext, "", ""); parseContext.recover(); return 0;}
+{D}+{U}           { pyylval->lex.line = yylineno; pyylval->lex.i = strtol(yytext, 0, 0); return(UINTCONSTANT); }
+
 {D}+{E}           { pyylval->lex.line = yylineno; pyylval->lex.f = static_cast<float>(atof(yytext)); return(FLOATCONSTANT); }
 {D}+"."{D}*({E})? { pyylval->lex.line = yylineno; pyylval->lex.f = static_cast<float>(atof(yytext)); return(FLOATCONSTANT); }
 "."{D}+({E})?     { pyylval->lex.line = yylineno; pyylval->lex.f = static_cast<float>(atof(yytext)); return(FLOATCONSTANT); }
index c3fe427..0c26dda 100644 (file)
-//
-//Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
-//All rights reserved.
-//
-//Redistribution and use in source and binary forms, with or without
-//modification, are permitted provided that the following conditions
-//are met:
-//
-//    Redistributions of source code must retain the above copyright
-//    notice, this list of conditions and the following disclaimer.
-//
-//    Redistributions in binary form must reproduce the above
-//    copyright notice, this list of conditions and the following
-//    disclaimer in the documentation and/or other materials provided
-//    with the distribution.
-//
-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
-//    contributors may be used to endorse or promote products derived
-//    from this software without specific prior written permission.
-//
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-//POSSIBILITY OF SUCH DAMAGE.
-//
-
-/**
- * This is bison grammar and production code for parsing the OpenGL 2.0 shading
- * languages.
- */
-%{
-
-/* Based on:
-ANSI C Yacc grammar
-
-In 1985, Jeff Lee published his Yacc grammar (which is accompanied by a 
-matching Lex specification) for the April 30, 1985 draft version of the 
-ANSI C standard.  Tom Stockfisch reposted it to net.sources in 1987; that
-original, as mentioned in the answer to question 17.25 of the comp.lang.c
-FAQ, can be ftp'ed from ftp.uu.net, file usenet/net.sources/ansi.c.grammar.Z.
-I intend to keep this version as close to the current C Standard grammar as 
-possible; please let me know if you discover discrepancies. 
-
-Jutta Degener, 1995 
-*/
-
-#include "SymbolTable.h"
-#include "ParseHelper.h"
-#include "../Public/ShaderLang.h"
-
-#ifdef _WIN32
-    #define YYPARSE_PARAM parseContext
-    #define YYPARSE_PARAM_DECL TParseContext&
-    #define YY_DECL int yylex(YYSTYPE* pyylval, TParseContext& parseContext)
-    #define YYLEX_PARAM parseContext
-#else
-    #define YYPARSE_PARAM parseContextLocal
-    #define parseContext (*((TParseContext*)(parseContextLocal)))
-    #define YY_DECL int yylex(YYSTYPE* pyylval, void* parseContextLocal)
-    #define YYLEX_PARAM (void*)(parseContextLocal)
-    extern void yyerror(char*);    
-#endif
-
-#define FRAG_VERT_ONLY(S, L) {                                                  \
-    if (parseContext.language != EShLangFragment &&                             \
-        parseContext.language != EShLangVertex) {                               \
-        parseContext.error(L, " supported in vertex/fragment shaders only ", S, "", "");   \
-        parseContext.recover();                                                            \
-    }                                                                           \
-}
-
-#define VERTEX_ONLY(S, L) {                                                     \
-    if (parseContext.language != EShLangVertex) {                               \
-        parseContext.error(L, " supported in vertex shaders only ", S, "", "");            \
-        parseContext.recover();                                                            \
-    }                                                                           \
-}
-
-#define FRAG_ONLY(S, L) {                                                       \
-    if (parseContext.language != EShLangFragment) {                             \
-        parseContext.error(L, " supported in fragment shaders only ", S, "", "");          \
-        parseContext.recover();                                                            \
-    }                                                                           \
-}
-
-#define PACK_ONLY(S, L) {                                                       \
-    if (parseContext.language != EShLangPack) {                                 \
-        parseContext.error(L, " supported in pack shaders only ", S, "", "");              \
-        parseContext.recover();                                                            \
-    }                                                                           \
-}
-
-#define UNPACK_ONLY(S, L) {                                                     \
-    if (parseContext.language != EShLangUnpack) {                               \
-        parseContext.error(L, " supported in unpack shaders only ", S, "", "");            \
-        parseContext.recover();                                                            \
-    }                                                                           \
-}
-
-#define PACK_UNPACK_ONLY(S, L) {                                                \
-    if (parseContext.language != EShLangUnpack &&                               \
-        parseContext.language != EShLangPack) {                                 \
-        parseContext.error(L, " supported in pack/unpack shaders only ", S, "", "");       \
-        parseContext.recover();                                                            \
-    }                                                                           \
-}
-%}
-%union {
-    struct {
-        TSourceLoc line;
-        union {
-            TString *string;
-            float f;
-            int i;
-            bool b;
-        };
-        TSymbol* symbol;
-    } lex;
-    struct {
-        TSourceLoc line;
-        TOperator op;
-        union {
-            TIntermNode* intermNode;
-            TIntermNodePair nodePair;
-            TIntermTyped* intermTypedNode;
-            TIntermAggregate* intermAggregate;
-        };
-        union {
-            TPublicType type;
-            TQualifier qualifier;
-            TFunction* function;
-            TParameter param;
-            TTypeLine typeLine;
-            TTypeList* typeList;
-        };
-    } interm;
-}
-
-%{
-#ifndef _WIN32
-    extern int yylex(YYSTYPE*, void*);
-#endif
-%}
-
-%pure_parser /* Just in case is called from multiple threads */
-%expect 1 /* One shift reduce conflict because of if | else */
-%token <lex> ATTRIBUTE CONST_QUAL BOOL_TYPE FLOAT_TYPE INT_TYPE
-%token <lex> BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN
-%token <lex> BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 VEC2 VEC3 VEC4
-%token <lex> MATRIX2 MATRIX3 MATRIX4 IN_QUAL OUT_QUAL INOUT_QUAL UNIFORM VARYING
-%token <lex> STRUCT VOID_TYPE WHILE
-%token <lex> SAMPLER1D SAMPLER2D SAMPLER3D SAMPLERCUBE SAMPLER1DSHADOW SAMPLER2DSHADOW
-
-%token <lex> SAMPLERRECTARB SAMPLERRECTSHADOWARB // ARB_texture_rectangle
-
-%token <lex> IDENTIFIER TYPE_NAME FLOATCONSTANT INTCONSTANT 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 
-%type <interm.intermNode> declaration_statement selection_statement expression_statement
-%type <interm.intermNode> declaration external_declaration
-%type <interm.intermNode> for_init_statement compound_statement_no_new_scope
-%type <interm.nodePair> selection_rest_statement for_rest_statement
-%type <interm.intermNode> iteration_statement jump_statement statement_no_new_scope
-%type <interm> single_declaration init_declarator_list
-
-%type <interm> parameter_declaration parameter_declarator parameter_type_specifier
-%type <interm.qualifier> parameter_qualifier
-
-%type <interm.type> type_qualifier fully_specified_type type_specifier 
-%type <interm.type> type_specifier_nonarray
-%type <interm.type> struct_specifier 
-%type <interm.typeLine> struct_declarator 
-%type <interm.typeList> 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
-
-%start translation_unit 
-%%
-
-variable_identifier 
-    : IDENTIFIER {
-        // The symbol table search was done in the lexical phase
-        const TSymbol* symbol = $1.symbol;
-        const TVariable* variable;
-        if (symbol == 0) {
-            parseContext.error($1.line, "undeclared identifier", $1.string->c_str(), "");
-            parseContext.recover();
-            TType type(EbtFloat);
-            TVariable* fakeVariable = new TVariable($1.string, type);
-            parseContext.symbolTable.insert(*fakeVariable);
-            variable = fakeVariable;
-        } else {
-            // This identifier can only be a variable type symbol 
-            if (! symbol->isVariable()) {
-                parseContext.error($1.line, "variable expected", $1.string->c_str(), "");
-                parseContext.recover();
-            }
-            variable = static_cast<const TVariable*>(symbol);
-        }
-
-        // don't delete $1.string, it's used by error recovery, and the pool
-        // pop will reclaim the memory
-
-        if (variable->getType().getQualifier() == EvqConst ) {
-            constUnion* constArray = variable->getConstPointer();
-            TType t(variable->getType());
-            $$ = parseContext.intermediate.addConstantUnion(constArray, t, $1.line);        
-        } else
-            $$ = parseContext.intermediate.addSymbol(variable->getUniqueId(), 
-                                                     variable->getName(), 
-                                                     variable->getType(), $1.line);
-    }
-    ;
-
-primary_expression
-    : variable_identifier {
-        $$ = $1;
-    }
-    | INTCONSTANT {
-        //
-        // INT_TYPE is only 16-bit plus sign bit for vertex/fragment shaders, 
-        // check for overflow for constants
-        //
-        if (abs($1.i) >= (1 << 16)) {
-            parseContext.error($1.line, " integer constant overflow", "", "");
-            parseContext.recover();
-        }
-        constUnion *unionArray = new constUnion[1];
-        unionArray->setIConst($1.i);
-        $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $1.line);
-    }
-    | FLOATCONSTANT {
-        constUnion *unionArray = new constUnion[1];
-        unionArray->setFConst($1.f);
-        $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), $1.line);
-    }
-    | BOOLCONSTANT {
-        constUnion *unionArray = new constUnion[1];
-        unionArray->setBConst($1.b);
-        $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $1.line);
-    }
-    | LEFT_PAREN expression RIGHT_PAREN {
-        $$ = $2;
-    }
-    ;
-
-postfix_expression
-    : primary_expression { 
-        $$ = $1;
-    } 
-    | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET {
-        if (!$1->isArray() && !$1->isMatrix() && !$1->isVector()) {
-            if ($1->getAsSymbolNode())
-                parseContext.error($2.line, " left of '[' is not of type array, matrix, or vector ", $1->getAsSymbolNode()->getSymbol().c_str(), "");
-            else
-                parseContext.error($2.line, " left of '[' is not of type array, matrix, or vector ", "expression", "");
-            parseContext.recover();
-        }
-        if ($1->getType().getQualifier() == EvqConst && $3->getQualifier() == EvqConst) {
-            if ($1->isArray()) { // constant folding for arrays
-                $$ = parseContext.addConstArrayNode($3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), $1, $2.line);
-            } else if ($1->isVector()) {  // constant folding for vectors
-                TVectorFields fields;                
-                fields.num = 1;
-                fields.offsets[0] = $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(); // need to do it this way because v.xy sends fields integer array
-                $$ = parseContext.addConstVectorNode(fields, $1, $2.line);
-            } else if ($1->isMatrix()) { // constant folding for matrices
-                $$ = parseContext.addConstMatrixNode($3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), $1, $2.line);
-            } 
-        } else {
-            if ($3->getQualifier() == EvqConst) {
-                if (($1->isVector() || $1->isMatrix()) && $1->getType().getNominalSize() <= $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() && !$1->isArray() ) {
-                    parseContext.error($2.line, "", "[", "field selection out of range '%d'", $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst());
-                    parseContext.recover();
-                } else {
-                    if ($1->isArray()) {
-                        if ($1->getType().getArraySize() == 0) {
-                            if ($1->getType().getMaxArraySize() <= $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst()) {
-                                if (parseContext.arraySetMaxSize($1->getAsSymbolNode(), $1->getTypePointer(), $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), true, $2.line))
-                                    parseContext.recover(); 
-                            } else {
-                                if (parseContext.arraySetMaxSize($1->getAsSymbolNode(), $1->getTypePointer(), 0, false, $2.line))
-                                    parseContext.recover(); 
-                            }
-                        } else if ( $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() >= $1->getType().getArraySize()) {
-                            parseContext.error($2.line, "", "[", "array index out of range '%d'", $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst());
-                            parseContext.recover();
-                        }
-                    }
-                    $$ = parseContext.intermediate.addIndex(EOpIndexDirect, $1, $3, $2.line);
-                }
-            } else {
-                if ($1->isArray() && $1->getType().getArraySize() == 0) {
-                    parseContext.error($2.line, "", "[", "array must be redeclared with a size before being indexed with a variable");
-                    parseContext.recover();
-                }
-                
-                $$ = parseContext.intermediate.addIndex(EOpIndexIndirect, $1, $3, $2.line);
-            }
-        } 
-        if ($$ == 0) {
-            constUnion *unionArray = new constUnion[1];
-            unionArray->setFConst(0.0f);
-            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), $2.line);
-        } else if ($1->isArray()) {
-            if ($1->getType().getStruct())
-                $$->setType(TType($1->getType().getStruct(), $1->getType().getTypeName()));
-            else
-                $$->setType(TType($1->getBasicType(), EvqTemporary, $1->getNominalSize(), $1->isMatrix()));
-                
-            if ($1->getType().getQualifier() == EvqConst)
-                $$->getTypePointer()->changeQualifier(EvqConst);
-        } else if ($1->isMatrix() && $1->getType().getQualifier() == EvqConst)         
-            $$->setType(TType($1->getBasicType(), EvqConst, $1->getNominalSize()));     
-        else if ($1->isMatrix())            
-            $$->setType(TType($1->getBasicType(), EvqTemporary, $1->getNominalSize()));     
-        else if ($1->isVector() && $1->getType().getQualifier() == EvqConst)          
-            $$->setType(TType($1->getBasicType(), EvqConst));     
-        else if ($1->isVector())       
-            $$->setType(TType($1->getBasicType(), EvqTemporary));
-        else
-            $$->setType($1->getType()); 
-    }
-    | function_call {
-        $$ = $1;
-    }
-    | postfix_expression DOT FIELD_SELECTION {        
-        if ($1->isArray()) {
-            parseContext.error($3.line, "cannot apply dot operator to an array", ".", "");
-            parseContext.recover();
-        }
-
-        if ($1->isVector()) {
-            TVectorFields fields;
-            if (! parseContext.parseVectorFields(*$3.string, $1->getNominalSize(), fields, $3.line)) {
-                fields.num = 1;
-                fields.offsets[0] = 0;
-                parseContext.recover();
-            }
-
-            if ($1->getType().getQualifier() == EvqConst) { // constant folding for vector fields
-                $$ = parseContext.addConstVectorNode(fields, $1, $3.line);
-                if ($$ == 0) {
-                    parseContext.recover();
-                    $$ = $1;
-                }
-                else
-                    $$->setType(TType($1->getBasicType(), EvqConst, (int) (*$3.string).size()));
-            } else {
-                if (fields.num == 1) {
-                    constUnion *unionArray = new constUnion[1];
-                    unionArray->setIConst(fields.offsets[0]);
-                    TIntermTyped* index = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $3.line);
-                    $$ = parseContext.intermediate.addIndex(EOpIndexDirect, $1, index, $2.line);
-                    $$->setType(TType($1->getBasicType()));
-                } else {
-                    TString vectorString = *$3.string;
-                    TIntermTyped* index = parseContext.intermediate.addSwizzle(fields, $3.line);                
-                    $$ = parseContext.intermediate.addIndex(EOpVectorSwizzle, $1, index, $2.line);
-                    $$->setType(TType($1->getBasicType(),EvqTemporary, (int) vectorString.size()));  
-                }
-            }
-        } else if ($1->isMatrix()) {
-            TMatrixFields fields;
-            if (! parseContext.parseMatrixFields(*$3.string, $1->getNominalSize(), fields, $3.line)) {
-                fields.wholeRow = false;
-                fields.wholeCol = false;
-                fields.row = 0;
-                fields.col = 0;
-                parseContext.recover();
-            }
-
-            if (fields.wholeRow || fields.wholeCol) {
-                parseContext.error($2.line, " non-scalar fields not implemented yet", ".", "");
-                parseContext.recover();
-                constUnion *unionArray = new constUnion[1];
-                unionArray->setIConst(0);
-                TIntermTyped* index = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $3.line);
-                $$ = parseContext.intermediate.addIndex(EOpIndexDirect, $1, index, $2.line);                
-                $$->setType(TType($1->getBasicType(), EvqTemporary, $1->getNominalSize()));
-            } else {
-                constUnion *unionArray = new constUnion[1];
-                unionArray->setIConst(fields.col * $1->getNominalSize() + fields.row);
-                TIntermTyped* index = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $3.line);
-                $$ = parseContext.intermediate.addIndex(EOpIndexDirect, $1, index, $2.line);                
-                $$->setType(TType($1->getBasicType()));
-            }
-        } else if ($1->getBasicType() == EbtStruct) {
-            bool fieldFound = false;
-            TTypeList* fields = $1->getType().getStruct();
-            if (fields == 0) {
-                parseContext.error($2.line, "structure has no fields", "Internal Error", "");
-                parseContext.recover();
-                $$ = $1;
-            } else {
-                unsigned int i;
-                for (i = 0; i < fields->size(); ++i) {
-                    if ((*fields)[i].type->getFieldName() == *$3.string) {
-                        fieldFound = true;
-                        break;
-                    }                
-                }
-                if (fieldFound) {
-                    if ($1->getType().getQualifier() == EvqConst) {
-                        $$ = parseContext.addConstStruct(*$3.string, $1, $2.line);
-                        if ($$ == 0) {
-                            parseContext.recover();
-                            $$ = $1;
-                        }
-                        else {
-                            $$->setType(*(*fields)[i].type);
-                            // change the qualifier of the return type, not of the structure field
-                            // as the structure definition is shared between various structures.
-                            $$->getTypePointer()->changeQualifier(EvqConst);
-                        }
-                    } else {
-                        constUnion *unionArray = new constUnion[1];
-                        unionArray->setIConst(i);
-                        TIntermTyped* index = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $3.line);
-                        $$ = parseContext.intermediate.addIndex(EOpIndexDirectStruct, $1, index, $2.line);                
-                        $$->setType(*(*fields)[i].type);
-                    }
-                } else {
-                    parseContext.error($2.line, " no such field in structure", $3.string->c_str(), "");
-                    parseContext.recover();
-                    $$ = $1;
-                }
-            }
-        } else {
-            parseContext.error($2.line, " field selection requires structure, vector, or matrix on left hand side", $3.string->c_str(), "");
-            parseContext.recover();
-            $$ = $1;
-        }
-        // don't delete $3.string, it's from the pool
-    }
-    | postfix_expression INC_OP {
-        if (parseContext.lValueErrorCheck($2.line, "++", $1))
-            parseContext.recover();
-        $$ = parseContext.intermediate.addUnaryMath(EOpPostIncrement, $1, $2.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.unaryOpError($2.line, "++", $1->getCompleteString());
-            parseContext.recover();
-            $$ = $1;
-        }
-    }
-    | postfix_expression DEC_OP {
-        if (parseContext.lValueErrorCheck($2.line, "--", $1))
-            parseContext.recover();
-        $$ = parseContext.intermediate.addUnaryMath(EOpPostDecrement, $1, $2.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.unaryOpError($2.line, "--", $1->getCompleteString());
-            parseContext.recover();
-            $$ = $1;
-        }
-    }
-    ;
-
-integer_expression 
-    : expression {
-        if (parseContext.integerErrorCheck($1, "[]"))
-            parseContext.recover();
-        $$ = $1; 
-    }
-    ;
-
-function_call 
-    : function_call_or_method {
-        TFunction* fnCall = $1.function;
-        TOperator op = fnCall->getBuiltInOp();
-        
-        if (op == EOpArrayLength) {
-            if ($1.intermNode->getAsTyped() == 0 || $1.intermNode->getAsTyped()->getType().getArraySize() == 0) {
-                parseContext.error($1.line, "", fnCall->getName().c_str(), "array must be declared with a size before using this method");
-                parseContext.recover();
-            }
-
-            constUnion *unionArray = new constUnion[1];
-            unionArray->setIConst($1.intermNode->getAsTyped()->getType().getArraySize());
-            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $1.line);
-        } else if (op != EOpNull) {
-            //
-            // Then this should be a constructor.
-            // Don't go through the symbol table for constructors.  
-            // Their parameters will be verified algorithmically.
-            //
-            TType type(EbtVoid);  // use this to get the type back
-            if (parseContext.constructorErrorCheck($1.line, $1.intermNode, *fnCall, op, &type)) {
-                $$ = 0;
-            } else {
-                //
-                // It's a constructor, of type 'type'.
-                //
-                $$ = parseContext.addConstructor($1.intermNode, &type, op, fnCall, $1.line);
-            }
-            
-            if ($$ == 0) {        
-                parseContext.recover();
-                $$ = parseContext.intermediate.setAggregateOperator(0, op, $1.line);
-            }
-            $$->setType(type);
-        } else {
-            //
-            // Not a constructor.  Find it in the symbol table.
-            //
-            const TFunction* fnCandidate;
-            bool builtIn;
-            fnCandidate = parseContext.findFunction($1.line, fnCall, &builtIn);
-            if (fnCandidate) {
-                //
-                // A declared function.  But, it might still map to a built-in
-                // operation.
-                //
-                op = fnCandidate->getBuiltInOp();
-                if (builtIn && op != EOpNull) {
-                    //
-                    // A function call mapped to a built-in operation.
-                    //
-                    if (fnCandidate->getParamCount() == 1) {
-                        //
-                        // Treat it like a built-in unary operator.
-                        //
-                        $$ = parseContext.intermediate.addUnaryMath(op, $1.intermNode, 0, parseContext.symbolTable);
-                        if ($$ == 0)  {
-                            parseContext.error($1.intermNode->getLine(), " wrong operand type", "Internal Error", 
-                                "built in unary operator function.  Type: %s",
-                                static_cast<TIntermTyped*>($1.intermNode)->getCompleteString().c_str());
-                            YYERROR;
-                        }
-                    } else {
-                        $$ = parseContext.intermediate.setAggregateOperator($1.intermAggregate, op, $1.line);
-                    }
-                } else {
-                    // This is a real function call
-                    
-                    $$ = parseContext.intermediate.setAggregateOperator($1.intermAggregate, EOpFunctionCall, $1.line);
-                    $$->setType(fnCandidate->getReturnType());                   
-                    
-                    // this is how we know whether the given function is a builtIn function or a user defined function
-                    // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also
-                    // if builtIn == true, it's definitely a builtIn function with EOpNull
-                    if (!builtIn) 
-                        $$->getAsAggregate()->setUserDefined(); 
-                    $$->getAsAggregate()->setName(fnCandidate->getMangledName());
-
-                    TQualifier qual;
-                    TQualifierList& qualifierList = $$->getAsAggregate()->getQualifier();
-                    for (int i = 0; i < fnCandidate->getParamCount(); ++i) {
-                        qual = (*fnCandidate)[i].type->getQualifier();
-                        if (qual == EvqOut || qual == EvqInOut) {
-                            if (parseContext.lValueErrorCheck($$->getLine(), "assign", $$->getAsAggregate()->getSequence()[i]->getAsTyped())) {
-                                parseContext.error($1.intermNode->getLine(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error", "");
-                                parseContext.recover();
-                            }
-                        }
-                        qualifierList.push_back(qual);
-                    }
-                }
-                $$->setType(fnCandidate->getReturnType());
-            } else {
-                // error message was put out by PaFindFunction()
-                // Put on a dummy node for error recovery
-                constUnion *unionArray = new constUnion[1];
-                unionArray->setFConst(0.0f);
-                $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), $1.line);
-                parseContext.recover();
-            }
-        }
-        delete fnCall;
-    }
-    ;
-
-function_call_or_method
-    : function_call_generic {
-        $$ = $1;
-    }
-    | postfix_expression DOT function_call_generic {
-        if ($1->isArray() && $3.function->getName() == "length") {
-            //
-            // implement array.length()
-            //
-            if (parseContext.extensionErrorCheck($3.line, "GL_3DL_array_objects")) {
-                parseContext.recover();
-                $$ = $3;
-            } else {
-                $$ = $3;
-                $$.intermNode = $1;
-                $$.function->relateToOperator(EOpArrayLength);
-            }
-        } else {
-            parseContext.error($3.line, "methods are not supported", "", "");
-            parseContext.recover();
-            $$ = $3;
-        }
-    }
-    ;
-
-function_call_generic
-    : function_call_header_with_parameters RIGHT_PAREN {
-        $$ = $1;
-        $$.line = $2.line;
-    }
-    | function_call_header_no_parameters RIGHT_PAREN {
-        $$ = $1;
-        $$.line = $2.line;
-    }
-    ;
-    
-function_call_header_no_parameters 
-    : function_call_header VOID_TYPE {
-        $$.function = $1;
-        $$.intermNode = 0;
-    }
-    | function_call_header {
-        $$.function = $1;
-        $$.intermNode = 0;
-    }
-    ;
-
-function_call_header_with_parameters
-    : function_call_header assignment_expression {
-        TParameter param = { 0, new TType($2->getType()) };
-        $1->addParameter(param);
-        $$.function = $1;
-        $$.intermNode = $2;
-    }
-    | function_call_header_with_parameters COMMA assignment_expression {
-        TParameter param = { 0, new TType($3->getType()) };
-        $1.function->addParameter(param);
-        $$.function = $1.function;
-        $$.intermNode = parseContext.intermediate.growAggregate($1.intermNode, $3, $2.line);
-    }
-    ;
-
-function_call_header 
-    : function_identifier LEFT_PAREN {
-        $$ = $1;
-    }
-    ;
-
-// Grammar Note:  Constructors look like functions, but are recognized as types.
-    
-function_identifier
-    : type_specifier {
-        //
-        // Constructor
-        //
-        if ($1.array) {
-            if (parseContext.extensionErrorCheck($1.line, "GL_3DL_array_objects")) {
-                parseContext.recover();
-                $1.setArray(false);
-            }
-        }
-
-        if ($1.userDef) {
-            TString tempString = "";
-            TType type($1);
-            TFunction *function = new TFunction(&tempString, type, EOpConstructStruct);
-            $$ = function;
-        } else {
-            TOperator op = EOpNull;
-            switch ($1.type) {
-            case EbtFloat:
-                if ($1.matrix) {
-                    switch($1.size) {
-                    case 2:                                     op = EOpConstructMat2;  break;
-                    case 3:                                     op = EOpConstructMat3;  break;
-                    case 4:                                     op = EOpConstructMat4;  break;
-                    }         
-                } else {      
-                    switch($1.size) {
-                    case 1:                                     op = EOpConstructFloat; break;
-                    case 2:                                     op = EOpConstructVec2;  break;
-                    case 3:                                     op = EOpConstructVec3;  break;
-                    case 4:                                     op = EOpConstructVec4;  break;
-                    }       
-                }  
-                break;               
-            case EbtInt:
-                switch($1.size) {
-                case 1:                                         op = EOpConstructInt;   break;
-                case 2:       FRAG_VERT_ONLY("ivec2", $1.line); op = EOpConstructIVec2; break;
-                case 3:       FRAG_VERT_ONLY("ivec3", $1.line); op = EOpConstructIVec3; break;
-                case 4:       FRAG_VERT_ONLY("ivec4", $1.line); op = EOpConstructIVec4; break;
-                }         
-                break;    
-            case EbtBool:
-                switch($1.size) {
-                case 1:                                         op = EOpConstructBool;  break;
-                case 2:       FRAG_VERT_ONLY("bvec2", $1.line); op = EOpConstructBVec2; break;
-                case 3:       FRAG_VERT_ONLY("bvec3", $1.line); op = EOpConstructBVec3; break;
-                case 4:       FRAG_VERT_ONLY("bvec4", $1.line); op = EOpConstructBVec4; break;
-                }         
-                break;
-            }
-            if (op == EOpNull) {                    
-                parseContext.error($1.line, "cannot construct this type", TType::getBasicString($1.type), "");
-                parseContext.recover();
-                $1.type = EbtFloat;
-                op = EOpConstructFloat;
-            }            
-            TString tempString = "";
-            TType type($1);
-            TFunction *function = new TFunction(&tempString, type, op);
-            $$ = function;
-        }
-    }
-    | IDENTIFIER {
-        if (parseContext.reservedErrorCheck($1.line, *$1.string)) 
-            parseContext.recover();
-        TType type(EbtVoid);
-        TFunction *function = new TFunction($1.string, type);
-        $$ = function;
-    }
-    | FIELD_SELECTION {
-        if (parseContext.reservedErrorCheck($1.line, *$1.string)) 
-            parseContext.recover();
-        TType type(EbtVoid);
-        TFunction *function = new TFunction($1.string, type);
-        $$ = function;
-    }
-    ;
-
-unary_expression
-    : postfix_expression {
-        $$ = $1;
-    }
-    | INC_OP unary_expression {
-        if (parseContext.lValueErrorCheck($1.line, "++", $2))
-            parseContext.recover();
-        $$ = parseContext.intermediate.addUnaryMath(EOpPreIncrement, $2, $1.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.unaryOpError($1.line, "++", $2->getCompleteString());
-            parseContext.recover();
-            $$ = $2;
-        }
-    }
-    | DEC_OP unary_expression {
-        if (parseContext.lValueErrorCheck($1.line, "--", $2))
-            parseContext.recover();
-        $$ = parseContext.intermediate.addUnaryMath(EOpPreDecrement, $2, $1.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.unaryOpError($1.line, "--", $2->getCompleteString());
-            parseContext.recover();
-            $$ = $2;
-        }
-    }
-    | unary_operator unary_expression {
-        if ($1.op != EOpNull) {
-            $$ = parseContext.intermediate.addUnaryMath($1.op, $2, $1.line, parseContext.symbolTable);
-            if ($$ == 0) {
-                char* errorOp = "";
-                switch($1.op) {
-                case EOpNegative:   errorOp = "-"; break;
-                case EOpLogicalNot: errorOp = "!"; break;
-                case EOpBitwiseNot: errorOp = "~"; break;
-                               default: break;
-                }
-                parseContext.unaryOpError($1.line, errorOp, $2->getCompleteString());
-                parseContext.recover();
-                $$ = $2;
-            }
-        } else
-            $$ = $2;
-    }
-    ;
-// Grammar Note:  No traditional style type casts.
-
-unary_operator
-    : PLUS  { $$.line = $1.line; $$.op = EOpNull; }
-    | DASH  { $$.line = $1.line; $$.op = EOpNegative; }
-    | BANG  { $$.line = $1.line; $$.op = EOpLogicalNot; }
-    | TILDE { PACK_UNPACK_ONLY("~", $1.line);  
-              $$.line = $1.line; $$.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.line);
-        $$ = parseContext.intermediate.addBinaryMath(EOpMul, $1, $3, $2.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.binaryOpError($2.line, "*", $1->getCompleteString(), $3->getCompleteString());
-            parseContext.recover();
-            $$ = $1;
-        }
-    }
-    | multiplicative_expression SLASH unary_expression {
-        FRAG_VERT_ONLY("/", $2.line); 
-        $$ = parseContext.intermediate.addBinaryMath(EOpDiv, $1, $3, $2.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.binaryOpError($2.line, "/", $1->getCompleteString(), $3->getCompleteString());
-            parseContext.recover();
-            $$ = $1;
-        }
-    }
-    | multiplicative_expression PERCENT unary_expression {
-        PACK_UNPACK_ONLY("%", $2.line);
-        $$ = parseContext.intermediate.addBinaryMath(EOpMod, $1, $3, $2.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.binaryOpError($2.line, "%", $1->getCompleteString(), $3->getCompleteString());
-            parseContext.recover();
-            $$ = $1;
-        }
-    }
-    ;
-
-additive_expression
-    : multiplicative_expression { $$ = $1; }
-    | additive_expression PLUS multiplicative_expression {  
-        $$ = parseContext.intermediate.addBinaryMath(EOpAdd, $1, $3, $2.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.binaryOpError($2.line, "+", $1->getCompleteString(), $3->getCompleteString());
-            parseContext.recover();
-            $$ = $1;
-        }
-    }
-    | additive_expression DASH multiplicative_expression {
-        $$ = parseContext.intermediate.addBinaryMath(EOpSub, $1, $3, $2.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.binaryOpError($2.line, "-", $1->getCompleteString(), $3->getCompleteString());
-            parseContext.recover();
-            $$ = $1;
-        } 
-    }
-    ;
-
-shift_expression
-    : additive_expression { $$ = $1; }
-    | shift_expression LEFT_OP additive_expression {
-        PACK_UNPACK_ONLY("<<", $2.line);
-        $$ = parseContext.intermediate.addBinaryMath(EOpLeftShift, $1, $3, $2.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.binaryOpError($2.line, "<<", $1->getCompleteString(), $3->getCompleteString());
-            parseContext.recover();
-            $$ = $1;
-        }
-    }
-    | shift_expression RIGHT_OP additive_expression {
-        PACK_UNPACK_ONLY(">>", $2.line);
-        $$ = parseContext.intermediate.addBinaryMath(EOpRightShift, $1, $3, $2.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.binaryOpError($2.line, ">>", $1->getCompleteString(), $3->getCompleteString());
-            parseContext.recover();
-            $$ = $1;
-        }
-    }
-    ;
-
-relational_expression
-    : shift_expression { $$ = $1; }
-    | relational_expression LEFT_ANGLE shift_expression { 
-        $$ = parseContext.intermediate.addBinaryMath(EOpLessThan, $1, $3, $2.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.binaryOpError($2.line, "<", $1->getCompleteString(), $3->getCompleteString());
-            parseContext.recover();
-            constUnion *unionArray = new constUnion[1];
-            unionArray->setBConst(false);
-            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line);
-        }
-    }
-    | relational_expression RIGHT_ANGLE shift_expression  { 
-        $$ = parseContext.intermediate.addBinaryMath(EOpGreaterThan, $1, $3, $2.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.binaryOpError($2.line, ">", $1->getCompleteString(), $3->getCompleteString());
-            parseContext.recover();
-            constUnion *unionArray = new constUnion[1];
-            unionArray->setBConst(false);
-            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line);
-        }
-    }
-    | relational_expression LE_OP shift_expression  { 
-        $$ = parseContext.intermediate.addBinaryMath(EOpLessThanEqual, $1, $3, $2.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.binaryOpError($2.line, "<=", $1->getCompleteString(), $3->getCompleteString());
-            parseContext.recover();
-            constUnion *unionArray = new constUnion[1];
-            unionArray->setBConst(false);
-            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line);
-        }
-    }
-    | relational_expression GE_OP shift_expression  { 
-        $$ = parseContext.intermediate.addBinaryMath(EOpGreaterThanEqual, $1, $3, $2.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.binaryOpError($2.line, ">=", $1->getCompleteString(), $3->getCompleteString());
-            parseContext.recover();
-            constUnion *unionArray = new constUnion[1];
-            unionArray->setBConst(false);
-            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line);
-        }
-    }
-    ;
-
-equality_expression
-    : relational_expression { $$ = $1; }
-    | equality_expression EQ_OP relational_expression  {
-        $$ = parseContext.intermediate.addBinaryMath(EOpEqual, $1, $3, $2.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.binaryOpError($2.line, "==", $1->getCompleteString(), $3->getCompleteString());
-            parseContext.recover();
-            constUnion *unionArray = new constUnion[1];
-            unionArray->setBConst(false);
-            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line);
-        } else if (($1->isArray() || $3->isArray()) && parseContext.extensionErrorCheck($2.line, "GL_3DL_array_objects"))
-            parseContext.recover();
-    }
-    | equality_expression NE_OP relational_expression { 
-        $$ = parseContext.intermediate.addBinaryMath(EOpNotEqual, $1, $3, $2.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.binaryOpError($2.line, "!=", $1->getCompleteString(), $3->getCompleteString());
-            parseContext.recover();
-            constUnion *unionArray = new constUnion[1];
-            unionArray->setBConst(false);
-            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line);
-        } else if (($1->isArray() || $3->isArray()) && parseContext.extensionErrorCheck($2.line, "GL_3DL_array_objects"))
-            parseContext.recover();
-    }
-    ;
-
-and_expression
-    : equality_expression { $$ = $1; }
-    | and_expression AMPERSAND equality_expression {
-        PACK_UNPACK_ONLY("&", $2.line);
-        $$ = parseContext.intermediate.addBinaryMath(EOpAnd, $1, $3, $2.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.binaryOpError($2.line, "&", $1->getCompleteString(), $3->getCompleteString());
-            parseContext.recover();
-            $$ = $1;
-        }
-    }
-    ;
-
-exclusive_or_expression
-    : and_expression { $$ = $1; }
-    | exclusive_or_expression CARET and_expression {
-        PACK_UNPACK_ONLY("^", $2.line);
-        $$ = parseContext.intermediate.addBinaryMath(EOpExclusiveOr, $1, $3, $2.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.binaryOpError($2.line, "^", $1->getCompleteString(), $3->getCompleteString());
-            parseContext.recover();
-            $$ = $1;
-        }
-    }
-    ;
-
-inclusive_or_expression
-    : exclusive_or_expression { $$ = $1; }
-    | inclusive_or_expression VERTICAL_BAR exclusive_or_expression {
-        PACK_UNPACK_ONLY("|", $2.line);
-        $$ = parseContext.intermediate.addBinaryMath(EOpInclusiveOr, $1, $3, $2.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.binaryOpError($2.line, "|", $1->getCompleteString(), $3->getCompleteString());
-            parseContext.recover();
-            $$ = $1;
-        }
-    }
-    ;
-
-logical_and_expression
-    : inclusive_or_expression { $$ = $1; }
-    | logical_and_expression AND_OP inclusive_or_expression {
-        $$ = parseContext.intermediate.addBinaryMath(EOpLogicalAnd, $1, $3, $2.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.binaryOpError($2.line, "&&", $1->getCompleteString(), $3->getCompleteString());
-            parseContext.recover();
-            constUnion *unionArray = new constUnion[1];
-            unionArray->setBConst(false);
-            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line);
-        }
-    }
-    ;
-
-logical_xor_expression
-    : logical_and_expression { $$ = $1; }
-    | logical_xor_expression XOR_OP logical_and_expression  { 
-        $$ = parseContext.intermediate.addBinaryMath(EOpLogicalXor, $1, $3, $2.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.binaryOpError($2.line, "^^", $1->getCompleteString(), $3->getCompleteString());
-            parseContext.recover();
-            constUnion *unionArray = new constUnion[1];
-            unionArray->setBConst(false);
-            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line);
-        }
-    }
-    ;
-
-logical_or_expression
-    : logical_xor_expression { $$ = $1; }
-    | logical_or_expression OR_OP logical_xor_expression  { 
-        $$ = parseContext.intermediate.addBinaryMath(EOpLogicalOr, $1, $3, $2.line, parseContext.symbolTable);
-        if ($$ == 0) {
-            parseContext.binaryOpError($2.line, "||", $1->getCompleteString(), $3->getCompleteString());
-            parseContext.recover();
-            constUnion *unionArray = new constUnion[1];
-            unionArray->setBConst(false);
-            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line);
-        }
-    }
-    ;
-
-conditional_expression
-    : logical_or_expression { $$ = $1; }
-    | logical_or_expression QUESTION expression COLON assignment_expression {
-       if (parseContext.boolErrorCheck($2.line, $1))
-            parseContext.recover();
-       
-        $$ = parseContext.intermediate.addSelection($1, $3, $5, $2.line);
-        if ($3->getType() != $5->getType())
-            $$ = 0;
-            
-        if ($$ == 0) {
-            parseContext.binaryOpError($2.line, ":", $3->getCompleteString(), $5->getCompleteString());
-            parseContext.recover();
-            $$ = $5;
-        }
-    }
-    ;
-
-assignment_expression
-    : conditional_expression { $$ = $1; }
-    | unary_expression assignment_operator assignment_expression {        
-        if (parseContext.lValueErrorCheck($2.line, "assign", $1))
-            parseContext.recover();
-        $$ = parseContext.intermediate.addAssign($2.op, $1, $3, $2.line);
-        if ($$ == 0) {
-            parseContext.assignError($2.line, "assign", $1->getCompleteString(), $3->getCompleteString());
-            parseContext.recover();
-            $$ = $1;
-        } else if (($1->isArray() || $3->isArray()) && parseContext.extensionErrorCheck($2.line, "GL_3DL_array_objects"))
-            parseContext.recover();
-    }
-    ;
-
-assignment_operator
-    : EQUAL        {                                    $$.line = $1.line; $$.op = EOpAssign; }
-    | MUL_ASSIGN   { FRAG_VERT_ONLY("*=", $1.line);     $$.line = $1.line; $$.op = EOpMulAssign; }
-    | DIV_ASSIGN   { FRAG_VERT_ONLY("/=", $1.line);     $$.line = $1.line; $$.op = EOpDivAssign; }
-    | MOD_ASSIGN   { PACK_UNPACK_ONLY("%=", $1.line);   $$.line = $1.line; $$.op = EOpModAssign; }
-    | ADD_ASSIGN   {                                    $$.line = $1.line; $$.op = EOpAddAssign; }
-    | SUB_ASSIGN   {                                    $$.line = $1.line; $$.op = EOpSubAssign; }
-    | LEFT_ASSIGN  { PACK_UNPACK_ONLY("<<=", $1.line);  $$.line = $1.line; $$.op = EOpLeftShiftAssign; }
-    | RIGHT_ASSIGN { PACK_UNPACK_ONLY("<<=", $1.line);  $$.line = $1.line; $$.op = EOpRightShiftAssign; }
-    | AND_ASSIGN   { PACK_UNPACK_ONLY("&=",  $1.line);  $$.line = $1.line; $$.op = EOpAndAssign; }
-    | XOR_ASSIGN   { PACK_UNPACK_ONLY("^=",  $1.line);  $$.line = $1.line; $$.op = EOpExclusiveOrAssign; }
-    | OR_ASSIGN    { PACK_UNPACK_ONLY("|=",  $1.line);  $$.line = $1.line; $$.op = EOpInclusiveOrAssign; }
-    ;
-
-expression
-    : assignment_expression {
-        $$ = $1;
-    }
-    | expression COMMA assignment_expression {
-        $$ = parseContext.intermediate.addComma($1, $3, $2.line);
-        if ($$ == 0) {
-            parseContext.binaryOpError($2.line, ",", $1->getCompleteString(), $3->getCompleteString());
-            parseContext.recover();
-            $$ = $3;
-        }
-    }
-    ;
-
-constant_expression
-    : conditional_expression {
-        if (parseContext.constErrorCheck($1))
-            parseContext.recover();
-        $$ = $1;
-    }
-    ;
-
-declaration
-    : function_prototype SEMICOLON   { $$ = 0; }
-    | init_declarator_list SEMICOLON { 
-        if ($1.intermAggregate)
-            $1.intermAggregate->setOperator(EOpSequence); 
-        $$ = $1.intermAggregate; 
-    }
-    ;
-
-function_prototype 
-    : function_declarator RIGHT_PAREN  {
-        //
-        // Multiple declarations of the same function are allowed.
-        //
-        // If this is a definition, the definition production code will check for redefinitions 
-        // (we don't know at this point if it's a definition or not).
-        //
-        // Redeclarations are allowed.  But, return types and parameter qualifiers must match.
-        //        
-        TFunction* prevDec = static_cast<TFunction*>(parseContext.symbolTable.find($1->getMangledName()));
-        if (prevDec) {
-            if (prevDec->getReturnType() != $1->getReturnType()) {
-                parseContext.error($2.line, "overloaded functions must have the same return type", $1->getReturnType().getBasicString(), "");
-                parseContext.recover();
-            }
-            for (int i = 0; i < prevDec->getParamCount(); ++i) {
-                if ((*prevDec)[i].type->getQualifier() != (*$1)[i].type->getQualifier()) {
-                    parseContext.error($2.line, "overloaded functions must have the same parameter qualifiers", (*$1)[i].type->getQualifierString(), "");
-                    parseContext.recover();
-                }
-            }
-        }
-        
-        //
-        // If this is a redeclaration, it could also be a definition,
-        // in which case, we want to use the variable names from this one, and not the one that's
-        // being redeclared.  So, pass back up this declaration, not the one in the symbol table.
-        //
-        $$.function = $1;
-        $$.line = $2.line;
-
-        parseContext.symbolTable.insert(*$$.function);
-    }
-    ;
-
-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
-            //
-            parseContext.error($2.line, "cannot be an argument type except for '(void)'", "void", "");
-            parseContext.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) {
-            parseContext.error($2.line, "no qualifiers allowed for function return", getQualifierString($1.qualifier), "");
-            parseContext.recover();
-        }
-        // make sure a sampler is not involved as well...
-        if (parseContext.structQualifierErrorCheck($2.line, $1))
-            parseContext.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;
-    }
-    ;
-
-parameter_declarator
-    // Type + name 
-    : type_specifier IDENTIFIER {
-        if ($1.type == EbtVoid) {
-            parseContext.error($2.line, "illegal use of type 'void'", $2.string->c_str(), "");
-            parseContext.recover();
-        }
-        if (parseContext.reservedErrorCheck($2.line, *$2.string))
-            parseContext.recover();
-        TParameter param = {$2.string, new TType($1)};
-        $$.line = $2.line;
-        $$.param = param;
-    }
-    | type_specifier IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET {
-        // Check that we can make an array out of this type
-        if (parseContext.arrayTypeErrorCheck($3.line, $1))
-            parseContext.recover();
-            
-        if (parseContext.reservedErrorCheck($2.line, *$2.string))
-            parseContext.recover();
-            
-        int size;
-        if (parseContext.arraySizeErrorCheck($3.line, $4, size))
-            parseContext.recover();
-        $1.setArray(true, size);
-             
-        TType* type = new TType($1);
-        TParameter param = { $2.string, type };
-        $$.line = $2.line;
-        $$.param = param;
-    }
-    ;
-
-parameter_declaration 
-    // 
-    // The only parameter qualifier a parameter can have are 
-    // IN_QUAL, OUT_QUAL, INOUT_QUAL, or CONST.
-    //
-    
-    //
-    // Type + name 
-    //
-    : type_qualifier parameter_qualifier parameter_declarator {
-        $$ = $3;
-        if (parseContext.paramErrorCheck($3.line, $1.qualifier, $2, $$.param.type))
-            parseContext.recover();
-    }
-    | parameter_qualifier parameter_declarator {
-        $$ = $2;
-        if (parseContext.parameterSamplerErrorCheck($2.line, $1, *$2.param.type))
-            parseContext.recover();
-        if (parseContext.paramErrorCheck($2.line, EvqTemporary, $1, $$.param.type))
-            parseContext.recover();
-    }
-    //
-    // Only type 
-    //
-    | type_qualifier parameter_qualifier parameter_type_specifier {
-        $$ = $3;
-        if (parseContext.paramErrorCheck($3.line, $1.qualifier, $2, $$.param.type))
-            parseContext.recover();
-    }
-    | parameter_qualifier parameter_type_specifier {
-        $$ = $2;
-        if (parseContext.parameterSamplerErrorCheck($2.line, $1, *$2.param.type))
-            parseContext.recover();
-        if (parseContext.paramErrorCheck($2.line, EvqTemporary, $1, $$.param.type))
-            parseContext.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;
-        if (parseContext.structQualifierErrorCheck($3.line, $$.type))
-            parseContext.recover();
-        
-        if (parseContext.nonInitConstErrorCheck($3.line, *$3.string, $$.type))
-            parseContext.recover();
-
-        if (parseContext.nonInitErrorCheck($3.line, *$3.string, $$.type))
-            parseContext.recover();
-    }
-    | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET RIGHT_BRACKET {
-        if (parseContext.structQualifierErrorCheck($3.line, $1.type))
-            parseContext.recover();
-            
-        if (parseContext.nonInitConstErrorCheck($3.line, *$3.string, $1.type))
-            parseContext.recover();
-
-        $$ = $1;
-        
-        if (parseContext.arrayTypeErrorCheck($4.line, $1.type) || parseContext.arrayQualifierErrorCheck($4.line, $1.type))
-            parseContext.recover();
-        else {
-            $1.type.setArray(true);
-            TVariable* variable;
-            if (parseContext.arrayErrorCheck($4.line, *$3.string, $1.type, variable))
-                parseContext.recover();
-        }
-    }
-    | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET {
-        if (parseContext.structQualifierErrorCheck($3.line, $1.type))
-            parseContext.recover();
-            
-        if (parseContext.nonInitConstErrorCheck($3.line, *$3.string, $1.type))
-            parseContext.recover();
-        
-        $$ = $1;
-
-        if (parseContext.arrayTypeErrorCheck($4.line, $1.type) || parseContext.arrayQualifierErrorCheck($4.line, $1.type))
-            parseContext.recover();
-        else {
-            int size;
-            if (parseContext.arraySizeErrorCheck($4.line, $5, size))
-                parseContext.recover();
-            $1.type.setArray(true, size);        
-            TVariable* variable;
-            if (parseContext.arrayErrorCheck($4.line, *$3.string, $1.type, variable))
-                parseContext.recover();
-        }
-    }
-    | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET RIGHT_BRACKET EQUAL initializer {
-        if (parseContext.structQualifierErrorCheck($3.line, $1.type))
-            parseContext.recover();
-            
-        $$ = $1;
-            
-        TVariable* variable = 0;
-        if (parseContext.arrayTypeErrorCheck($4.line, $1.type) || parseContext.arrayQualifierErrorCheck($4.line, $1.type))
-            parseContext.recover();
-        else {
-                       $1.type.setArray(true, $7->getType().getArraySize());
-            if (parseContext.arrayErrorCheck($4.line, *$3.string, $1.type, variable))
-                parseContext.recover();
-        }
-
-        if (parseContext.extensionErrorCheck($$.line, "GL_3DL_array_objects"))
-            parseContext.recover();
-        else {
-            TIntermNode* intermNode;
-            if (!parseContext.executeInitializer($3.line, *$3.string, $1.type, $7, intermNode, variable)) {
-                //
-                // build the intermediate representation
-                //
-                if (intermNode)
-                    $$.intermAggregate = parseContext.intermediate.growAggregate($1.intermNode, intermNode, $6.line);
-                else
-                    $$.intermAggregate = $1.intermAggregate;
-            } else {
-                parseContext.recover();
-                $$.intermAggregate = 0;
-            }
-        }
-    }
-    | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer {
-        if (parseContext.structQualifierErrorCheck($3.line, $1.type))
-            parseContext.recover();
-            
-        $$ = $1;
-            
-        TVariable* variable = 0;
-        if (parseContext.arrayTypeErrorCheck($4.line, $1.type) || parseContext.arrayQualifierErrorCheck($4.line, $1.type))
-            parseContext.recover();
-        else {
-            int size;
-            if (parseContext.arraySizeErrorCheck($4.line, $5, size))
-                parseContext.recover();
-            $1.type.setArray(true, size);
-            if (parseContext.arrayErrorCheck($4.line, *$3.string, $1.type, variable))
-                parseContext.recover();
-        }
-
-        if (parseContext.extensionErrorCheck($$.line, "GL_3DL_array_objects"))
-            parseContext.recover();
-        else {
-            TIntermNode* intermNode;
-            if (!parseContext.executeInitializer($3.line, *$3.string, $1.type, $8, intermNode, variable)) {
-                //
-                // build the intermediate representation
-                //
-                if (intermNode)
-                    $$.intermAggregate = parseContext.intermediate.growAggregate($1.intermNode, intermNode, $7.line);
-                else
-                    $$.intermAggregate = $1.intermAggregate;
-            } else {
-                parseContext.recover();
-                $$.intermAggregate = 0;
-            }
-        }
-    }
-    | init_declarator_list COMMA IDENTIFIER EQUAL initializer {
-        if (parseContext.structQualifierErrorCheck($3.line, $1.type))
-            parseContext.recover();
-        
-        $$ = $1;
-        
-        TIntermNode* intermNode;
-        if (!parseContext.executeInitializer($3.line, *$3.string, $1.type, $5, intermNode)) {
-            //
-            // build the intermediate representation
-            //
-            if (intermNode)
-                $$.intermAggregate = parseContext.intermediate.growAggregate($1.intermNode, intermNode, $4.line);
-            else
-                $$.intermAggregate = $1.intermAggregate;
-        } else {
-            parseContext.recover();
-            $$.intermAggregate = 0;
-        }
-    }
-    ;
-
-single_declaration 
-    : fully_specified_type {
-        $$.type = $1;
-        $$.intermAggregate = 0;
-    }    
-    | fully_specified_type IDENTIFIER {
-        $$.intermAggregate = 0;
-        $$.type = $1;
-
-        if (parseContext.structQualifierErrorCheck($2.line, $$.type))
-            parseContext.recover();
-        
-        if (parseContext.nonInitConstErrorCheck($2.line, *$2.string, $$.type))
-            parseContext.recover();
-
-        if (parseContext.nonInitErrorCheck($2.line, *$2.string, $$.type))
-            parseContext.recover();
-    }
-    | fully_specified_type IDENTIFIER LEFT_BRACKET RIGHT_BRACKET {
-        $$.intermAggregate = 0;
-        if (parseContext.structQualifierErrorCheck($2.line, $1))
-            parseContext.recover();
-
-        if (parseContext.nonInitConstErrorCheck($2.line, *$2.string, $1))
-            parseContext.recover();
-
-        $$.type = $1;
-
-        if (parseContext.arrayTypeErrorCheck($3.line, $1) || parseContext.arrayQualifierErrorCheck($3.line, $1))
-            parseContext.recover();
-        else {
-            $1.setArray(true);        
-            TVariable* variable;
-            if (parseContext.arrayErrorCheck($3.line, *$2.string, $1, variable))
-                parseContext.recover();
-        }
-    }
-    | fully_specified_type IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET {
-        $$.intermAggregate = 0;
-        if (parseContext.structQualifierErrorCheck($2.line, $1))
-            parseContext.recover();
-
-        if (parseContext.nonInitConstErrorCheck($2.line, *$2.string, $1))
-            parseContext.recover();
-            
-        $$.type = $1;
-
-        if (parseContext.arrayTypeErrorCheck($3.line, $1) || parseContext.arrayQualifierErrorCheck($3.line, $1))
-            parseContext.recover();
-        else {
-            int size;
-            if (parseContext.arraySizeErrorCheck($3.line, $4, size))
-                parseContext.recover();
-            
-            $1.setArray(true, size);
-            TVariable* variable;
-            if (parseContext.arrayErrorCheck($3.line, *$2.string, $1, variable))
-                parseContext.recover();
-        }
-    }
-    | fully_specified_type IDENTIFIER LEFT_BRACKET RIGHT_BRACKET EQUAL initializer {
-        $$.intermAggregate = 0;
-
-        if (parseContext.structQualifierErrorCheck($2.line, $1))
-            parseContext.recover();
-
-        $$.type = $1;
-
-        TVariable* variable = 0;
-        if (parseContext.arrayTypeErrorCheck($3.line, $1) || parseContext.arrayQualifierErrorCheck($3.line, $1))
-            parseContext.recover();
-        else {
-            $1.setArray(true, $6->getType().getArraySize());
-            if (parseContext.arrayErrorCheck($3.line, *$2.string, $1, variable))
-                parseContext.recover();
-        }
-
-        if (parseContext.extensionErrorCheck($$.line, "GL_3DL_array_objects"))
-            parseContext.recover();
-        else {        
-            TIntermNode* intermNode;
-            if (!parseContext.executeInitializer($2.line, *$2.string, $1, $6, intermNode, variable)) {
-                //
-                // Build intermediate representation
-                //
-                if (intermNode)
-                    $$.intermAggregate = parseContext.intermediate.makeAggregate(intermNode, $5.line);
-                else
-                    $$.intermAggregate = 0;
-            } else {
-                parseContext.recover();
-                $$.intermAggregate = 0;
-            }
-        }
-    }
-    | fully_specified_type IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer {
-        $$.intermAggregate = 0;
-
-        if (parseContext.structQualifierErrorCheck($2.line, $1))
-            parseContext.recover();
-
-        $$.type = $1;
-
-        TVariable* variable = 0;
-        if (parseContext.arrayTypeErrorCheck($3.line, $1) || parseContext.arrayQualifierErrorCheck($3.line, $1))
-            parseContext.recover();
-        else {
-            int size;
-            if (parseContext.arraySizeErrorCheck($3.line, $4, size))
-                parseContext.recover();
-            
-            $1.setArray(true, size);
-            if (parseContext.arrayErrorCheck($3.line, *$2.string, $1, variable))
-                parseContext.recover();
-        }
-
-        if (parseContext.extensionErrorCheck($$.line, "GL_3DL_array_objects"))
-            parseContext.recover();
-        else {        
-            TIntermNode* intermNode;
-            if (!parseContext.executeInitializer($2.line, *$2.string, $1, $7, intermNode, variable)) {
-                //
-                // Build intermediate representation
-                //
-                if (intermNode)
-                    $$.intermAggregate = parseContext.intermediate.makeAggregate(intermNode, $6.line);
-                else
-                    $$.intermAggregate = 0;
-            } else {
-                parseContext.recover();
-                $$.intermAggregate = 0;
-            }
-        }        
-    }
-    | fully_specified_type IDENTIFIER EQUAL initializer {
-        if (parseContext.structQualifierErrorCheck($2.line, $1))
-            parseContext.recover();
-
-        $$.type = $1;
-
-        TIntermNode* intermNode;
-        if (!parseContext.executeInitializer($2.line, *$2.string, $1, $4, intermNode)) {
-            //
-            // Build intermediate representation
-            //
-            if (intermNode)
-                $$.intermAggregate = parseContext.intermediate.makeAggregate(intermNode, $3.line);
-            else
-                $$.intermAggregate = 0;
-        } else {
-            parseContext.recover();
-            $$.intermAggregate = 0;
-        }
-    }
-    
-//
-// Place holder for the pack/unpack languages.
-//
-//    | buffer_specifier {
-//        $$.intermAggregate = 0;
-//    }
-    ;
-
-// Grammar Note:  No 'enum', or 'typedef'.
-
-//
-// Place holder for the pack/unpack languages.
-//
-//%type <interm> buffer_declaration
-//%type <interm.type> buffer_specifier input_or_output buffer_declaration_list 
-//buffer_specifier
-//    : input_or_output LEFT_BRACE buffer_declaration_list RIGHT_BRACE {
-//    }
-//    ;
-//
-//input_or_output
-//    : INPUT {
-//        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "input"))
-//            parseContext.recover();
-//        UNPACK_ONLY("input", $1.line);
-//        $$.qualifier = EvqInput;        
-//    }
-//    | OUTPUT {
-//        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "output"))
-//            parseContext.recover();
-//        PACK_ONLY("output", $1.line);
-//        $$.qualifier = EvqOutput;
-//    }
-//    ;
-
-//
-// Place holder for the pack/unpack languages.
-//
-//buffer_declaration_list
-//    : buffer_declaration {
-//    }
-//    | buffer_declaration_list buffer_declaration {
-//    }
-//    ;
-
-//
-// Input/output semantics:
-//   float must be 16 or 32 bits
-//   float alignment restrictions?
-//   check for only one input and only one output
-//   sum of bitfields has to be multiple of 32
-//
-
-//
-// Place holder for the pack/unpack languages.
-//
-//buffer_declaration
-//    : type_specifier IDENTIFIER COLON constant_expression SEMICOLON {
-//        if (parseContext.reservedErrorCheck($2.line, *$2.string, parseContext))
-//            parseContext.recover();
-//        $$.variable = new TVariable($2.string, $1);
-//        if (! parseContext.symbolTable.insert(*$$.variable)) {
-//            parseContext.error($2.line, "redefinition", $$.variable->getName().c_str(), "");
-//            parseContext.recover();
-//            // don't have to delete $$.variable, the pool pop will take care of it
-//        }
-//    }
-//    ;
-
-fully_specified_type
-    : type_specifier {
-        $$ = $1;
-                
-        if ($1.array) {
-            if (parseContext.extensionErrorCheck($1.line, "GL_3DL_array_objects")) {
-                parseContext.recover();
-                $1.setArray(false);
-            }
-        }
-    }
-    | type_qualifier type_specifier  {        
-        if ($2.array && parseContext.extensionErrorCheck($2.line, "GL_3DL_array_objects")) {
-            parseContext.recover();
-            $2.setArray(false);
-        }
-        if ($2.array && parseContext.arrayQualifierErrorCheck($2.line, $1)) {
-            parseContext.recover();
-            $2.setArray(false);
-        }
-        
-        if ($1.qualifier == EvqAttribute &&
-            ($2.type == EbtBool || $2.type == EbtInt)) {
-            parseContext.error($2.line, "cannot be bool or int", getQualifierString($1.qualifier), "");
-            parseContext.recover();
-        }
-        if (($1.qualifier == EvqVaryingIn || $1.qualifier == EvqVaryingOut) &&
-            ($2.type == EbtBool || $2.type == EbtInt)) {
-            parseContext.error($2.line, "cannot be bool or int", getQualifierString($1.qualifier), "");
-            parseContext.recover();
-        }
-        $$ = $2; 
-        $$.qualifier = $1.qualifier;
-    }
-    ;
-
-type_qualifier
-    : CONST_QUAL {
-        $$.setBasic(EbtVoid, EvqConst, $1.line);
-    }
-    | ATTRIBUTE { 
-        VERTEX_ONLY("attribute", $1.line);
-        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "attribute"))
-            parseContext.recover();
-        $$.setBasic(EbtVoid, EvqAttribute, $1.line);
-    }
-    | VARYING {
-        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "varying"))
-            parseContext.recover();
-        if (parseContext.language == EShLangVertex)
-            $$.setBasic(EbtVoid, EvqVaryingOut, $1.line);
-        else
-            $$.setBasic(EbtVoid, EvqVaryingIn, $1.line);
-    }
-    | UNIFORM {
-        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "uniform"))
-            parseContext.recover();
-        $$.setBasic(EbtVoid, EvqUniform, $1.line);
-    }
-    ;
-
-type_specifier
-    : type_specifier_nonarray {
-        $$ = $1;
-    }
-    | type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET {
-        $$ = $1;
-        
-        if (parseContext.arrayTypeErrorCheck($2.line, $1))
-            parseContext.recover();
-        else {
-            int size;
-            if (parseContext.arraySizeErrorCheck($2.line, $3, size))
-                parseContext.recover();
-            $$.setArray(true, size);
-        }
-    }
-    ;
-
-type_specifier_nonarray
-    : VOID_TYPE {
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtVoid, qual, $1.line); 
-    }
-    | FLOAT_TYPE {
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtFloat, qual, $1.line);
-    }
-    | INT_TYPE {
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtInt, qual, $1.line);
-    }
-    | BOOL_TYPE {
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtBool, qual, $1.line);
-    }
-//    | UNSIGNED INT_TYPE { 
-//        PACK_UNPACK_ONLY("unsigned", $1.line); 
-//        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-//        $$.setBasic(EbtInt, qual, $1.line); 
-//    }
-    | VEC2 {
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtFloat, qual, $1.line);
-        $$.setAggregate(2);
-    }
-    | VEC3 {
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtFloat, qual, $1.line);
-        $$.setAggregate(3);
-    }
-    | VEC4 {
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtFloat, qual, $1.line);
-        $$.setAggregate(4);
-    }
-    | BVEC2 {
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtBool, qual, $1.line);
-        $$.setAggregate(2);
-    }
-    | BVEC3 {
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtBool, qual, $1.line);
-        $$.setAggregate(3);
-    }
-    | BVEC4 {
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtBool, qual, $1.line);
-        $$.setAggregate(4);
-    }
-    | IVEC2 {
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtInt, qual, $1.line);
-        $$.setAggregate(2);
-    }
-    | IVEC3 {
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtInt, qual, $1.line);
-        $$.setAggregate(3);
-    }
-    | IVEC4 {
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtInt, qual, $1.line);
-        $$.setAggregate(4);
-    }
-    | MATRIX2 {
-        FRAG_VERT_ONLY("mat2", $1.line); 
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtFloat, qual, $1.line);
-        $$.setAggregate(2, true);
-    }
-    | MATRIX3 { 
-        FRAG_VERT_ONLY("mat3", $1.line); 
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtFloat, qual, $1.line);
-        $$.setAggregate(3, true);
-    }
-    | MATRIX4 { 
-        FRAG_VERT_ONLY("mat4", $1.line);
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtFloat, qual, $1.line);
-        $$.setAggregate(4, true);
-    } 
-    | SAMPLER1D {
-        FRAG_VERT_ONLY("sampler1D", $1.line);
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtSampler1D, qual, $1.line);
-    } 
-    | SAMPLER2D {
-        FRAG_VERT_ONLY("sampler2D", $1.line);
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtSampler2D, qual, $1.line);
-    } 
-    | SAMPLER3D {
-        FRAG_VERT_ONLY("sampler3D", $1.line);
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtSampler3D, qual, $1.line);
-    } 
-    | SAMPLERCUBE {
-        FRAG_VERT_ONLY("samplerCube", $1.line);
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtSamplerCube, qual, $1.line);
-    } 
-    | SAMPLER1DSHADOW {
-        FRAG_VERT_ONLY("sampler1DShadow", $1.line);
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtSampler1DShadow, qual, $1.line);
-    } 
-    | SAMPLER2DSHADOW {
-        FRAG_VERT_ONLY("sampler2DShadow", $1.line);
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtSampler2DShadow, qual, $1.line);
-    } 
-    | SAMPLERRECTARB {
-        // ARB_texture_rectangle
-
-        FRAG_VERT_ONLY("samplerRectARB", $1.line);
-        if (parseContext.extensionErrorCheck($1.line, "GL_ARB_texture_rectangle"))
-            parseContext.recover();
-        
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtSamplerRect, qual, $1.line);
-    }
-    | SAMPLERRECTSHADOWARB {
-        // ARB_texture_rectangle
-
-        FRAG_VERT_ONLY("samplerRectShadowARB", $1.line);
-        if (parseContext.extensionErrorCheck($1.line, "GL_ARB_texture_rectangle"))
-            parseContext.recover();
-
-        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtSamplerRectShadow, qual, $1.line);
-    }
-    | struct_specifier {
-        FRAG_VERT_ONLY("struct", $1.line);
-        $$ = $1;
-        $$.qualifier = parseContext.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 = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
-        $$.setBasic(EbtStruct, qual, $1.line);
-        $$.userDef = &structure;
-    }
-    ;
-
-struct_specifier
-    : STRUCT IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE {
-        TType* structure = new TType($4, *$2.string);
-        TVariable* userTypeDef = new TVariable($2.string, *structure, true);
-        if (! parseContext.symbolTable.insert(*userTypeDef)) {
-            parseContext.error($2.line, "redefinition", $2.string->c_str(), "struct");
-            parseContext.recover();
-        }
-        $$.setBasic(EbtStruct, EvqTemporary, $1.line);
-        $$.userDef = structure;
-    }
-    | STRUCT LEFT_BRACE struct_declaration_list RIGHT_BRACE {
-        TType* structure = new TType($3, TString(""));
-        $$.setBasic(EbtStruct, EvqTemporary, $1.line);
-        $$.userDef = structure;
-    }
-    ;
-    
-struct_declaration_list
-    : struct_declaration {
-        $$ = $1;
-    }
-    | struct_declaration_list struct_declaration {
-        $$ = $1;
-        for (unsigned int i = 0; i < $2->size(); ++i) {
-            for (unsigned int j = 0; j < $$->size(); ++j) {
-                if ((*$$)[j].type->getFieldName() == (*$2)[i].type->getFieldName()) {
-                    parseContext.error((*$2)[i].line, "duplicate field name in structure:", "struct", (*$2)[i].type->getFieldName().c_str());
-                    parseContext.recover();
-                }
-            }
-            $$->push_back((*$2)[i]);
-        }
-    }
-    ;
-    
-struct_declaration
-    : type_specifier struct_declarator_list SEMICOLON {
-        $$ = $2;
-        
-        if (parseContext.voidErrorCheck($1.line, (*$2)[0].type->getFieldName(), $1)) {
-            parseContext.recover();
-        }
-        for (unsigned int i = 0; i < $$->size(); ++i) {
-            //
-            // Careful not to replace already know aspects of type, like array-ness
-            //
-            (*$$)[i].type->setType($1.type, $1.size, $1.matrix, $1.userDef);
-
-            // don't allow arrays of arrays
-            if ((*$$)[i].type->isArray()) {
-                if (parseContext.arrayTypeErrorCheck($1.line, $1))
-                    parseContext.recover();
-            }
-            if ($1.array)
-                (*$$)[i].type->setArraySize($1.arraySize);
-            if ($1.userDef)
-                (*$$)[i].type->setTypeName($1.userDef->getTypeName());
-        }
-    }
-    ;
-        
-struct_declarator_list
-    : struct_declarator {
-        $$ = NewPoolTTypeList();
-        $$->push_back($1);
-    }
-    | struct_declarator_list COMMA struct_declarator {
-        $$->push_back($3);
-    }
-    ;
-    
-struct_declarator
-    : IDENTIFIER {
-        $$.type = new TType(EbtVoid);
-        $$.line = $1.line;
-        $$.type->setFieldName(*$1.string);
-    }
-    | IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET {
-        $$.type = new TType(EbtVoid);
-        $$.line = $1.line;
-        $$.type->setFieldName(*$1.string);
-        
-        int size;
-        if (parseContext.arraySizeErrorCheck($2.line, $3, size))
-            parseContext.recover();
-        $$.type->setArraySize(size);
-    }
-    ;
-
-initializer
-    : assignment_expression { $$ = $1; }
-    ;
-
-declaration_statement 
-    : declaration { $$ = $1; }
-    ;
-
-statement
-    : compound_statement  { $$ = $1; }
-    | simple_statement    { $$ = $1; }
-    ;
-
-// Grammar Note:  No labeled statements; 'goto' is not supported.
-
-simple_statement 
-    : declaration_statement { $$ = $1; }
-    | expression_statement  { $$ = $1; } 
-    | selection_statement   { $$ = $1; }
-    | iteration_statement   { $$ = $1; }
-    | jump_statement        { $$ = $1; }
-    ;
-
-compound_statement
-    : LEFT_BRACE RIGHT_BRACE { $$ = 0; }
-    | LEFT_BRACE { parseContext.symbolTable.push(); } statement_list { parseContext.symbolTable.pop(); } RIGHT_BRACE {
-        if ($3 != 0)            
-            $3->setOperator(EOpSequence); 
-        $$ = $3;
-    }
-    ;
-
-statement_no_new_scope 
-    : compound_statement_no_new_scope { $$ = $1; }
-    | simple_statement                { $$ = $1; }
-    ;
-
-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->setOperator(EOpSequence); 
-        $$ = $2; 
-    }
-    ;
-
-statement_list
-    : statement {
-        $$ = parseContext.intermediate.makeAggregate($1, 0); 
-    }
-    | statement_list statement { 
-        $$ = parseContext.intermediate.growAggregate($1, $2, 0);
-    }
-    ;
-
-expression_statement
-    : SEMICOLON  { $$ = 0; }
-    | expression SEMICOLON  { $$ = static_cast<TIntermNode*>($1); }
-    ;
-
-selection_statement
-    : IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement { 
-        if (parseContext.boolErrorCheck($1.line, $3))
-            parseContext.recover();
-        $$ = parseContext.intermediate.addSelection($3, $5, $1.line);
-    }
-    ;
-
-selection_rest_statement 
-    : statement ELSE statement {
-        $$.node1 = $1;
-        $$.node2 = $3;
-    }
-    | statement { 
-        $$.node1 = $1;
-        $$.node2 = 0;
-    }
-    ;
-
-// Grammar Note:  No 'switch'.  Switch statements not supported.
-
-condition
-    // In 1996 c++ draft, conditions can include single declarations 
-    : expression {
-        $$ = $1;
-        if (parseContext.boolErrorCheck($1->getLine(), $1))
-            parseContext.recover();          
-    }
-    | fully_specified_type IDENTIFIER EQUAL initializer {
-        TIntermNode* intermNode;
-        if (parseContext.structQualifierErrorCheck($2.line, $1))
-            parseContext.recover();
-        if (parseContext.boolErrorCheck($2.line, $1))
-            parseContext.recover();
-        
-        if (!parseContext.executeInitializer($2.line, *$2.string, $1, $4, intermNode))
-            $$ = $4;
-        else {
-            parseContext.recover();
-            $$ = 0;
-        }
-    }
-    ;
-
-iteration_statement
-    : WHILE LEFT_PAREN { parseContext.symbolTable.push(); ++parseContext.loopNestingLevel; } condition RIGHT_PAREN statement_no_new_scope { 
-        parseContext.symbolTable.pop();
-        $$ = parseContext.intermediate.addLoop($6, $4, 0, true, $1.line);
-        --parseContext.loopNestingLevel;
-    }
-    | DO { ++parseContext.loopNestingLevel; } statement WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON {
-        if (parseContext.boolErrorCheck($8.line, $6))
-            parseContext.recover();
-                    
-        $$ = parseContext.intermediate.addLoop($3, $6, 0, false, $4.line);
-        --parseContext.loopNestingLevel;
-    }
-    | FOR LEFT_PAREN { parseContext.symbolTable.push(); ++parseContext.loopNestingLevel; } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope {
-        parseContext.symbolTable.pop();
-        $$ = parseContext.intermediate.makeAggregate($4, $2.line);
-        $$ = parseContext.intermediate.growAggregate(
-                $$,
-                parseContext.intermediate.addLoop($7, reinterpret_cast<TIntermTyped*>($5.node1), reinterpret_cast<TIntermTyped*>($5.node2), true, $1.line),
-                $1.line);
-        $$->getAsAggregate()->setOperator(EOpSequence);
-        --parseContext.loopNestingLevel;
-    }
-    ;
-
-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 {
-        if (parseContext.loopNestingLevel <= 0) {
-            parseContext.error($1.line, "continue statement only allowed in loops", "", "");
-            parseContext.recover();
-        }        
-        $$ = parseContext.intermediate.addBranch(EOpContinue, $1.line);
-    }
-    | BREAK SEMICOLON {
-        if (parseContext.loopNestingLevel <= 0) {
-            parseContext.error($1.line, "break statement only allowed in loops", "", "");
-            parseContext.recover();
-        }        
-        $$ = parseContext.intermediate.addBranch(EOpBreak, $1.line);
-    }
-    | RETURN SEMICOLON {
-        $$ = parseContext.intermediate.addBranch(EOpReturn, $1.line);
-        if (parseContext.currentFunctionType->getBasicType() != EbtVoid) {
-            parseContext.error($1.line, "non-void function must return a value", "return", "");
-            parseContext.recover();
-        }
-    }
-    | RETURN expression SEMICOLON {        
-        $$ = parseContext.intermediate.addBranch(EOpReturn, $2, $1.line);
-        parseContext.functionReturnsValue = true;
-        if (parseContext.currentFunctionType->getBasicType() == EbtVoid) {
-            parseContext.error($1.line, "void function cannot return a value", "return", "");
-            parseContext.recover();
-        } else if (*(parseContext.currentFunctionType) != $2->getType()) {
-            parseContext.error($1.line, "function return is not matching type:", "return", "");
-            parseContext.recover();
-        }
-    }
-    | DISCARD SEMICOLON {
-        FRAG_ONLY("discard", $1.line);
-        $$ = parseContext.intermediate.addBranch(EOpKill, $1.line);
-    }        
-    ;
-
-// Grammar Note:  No 'goto'.  Gotos are not supported.
-
-translation_unit
-    : external_declaration { 
-        $$ = $1; 
-        parseContext.treeRoot = $$; 
-    }
-    | translation_unit external_declaration {
-        $$ = parseContext.intermediate.growAggregate($1, $2, 0);
-        parseContext.treeRoot = $$;
-    }
-    ;
-
-external_declaration
-    : function_definition { 
-        $$ = $1; 
-    }
-    | declaration { 
-        $$ = $1; 
-    }
-    ;
-
-function_definition
-    : function_prototype {
-        TFunction& function = *($1.function);
-        TFunction* prevDec = static_cast<TFunction*>(parseContext.symbolTable.find(function.getMangledName()));
-        //
-        // Note:  'prevDec' could be 'function' if this is the first time we've seen function
-        // as it would have just been put in the symbol table.  Otherwise, we're looking up
-        // an earlier occurance.
-        //
-        if (prevDec->isDefined()) {
-            //
-            // Then this function already has a body.
-            //
-            parseContext.error($1.line, "function already has a body", function.getName().c_str(), "");
-            parseContext.recover();
-        }
-        prevDec->setDefined();
-        
-        //
-        // Raise error message if main function takes any parameters or return anything other than void
-        //
-        if (function.getName() == "main") {
-            if (function.getParamCount() > 0) {
-                parseContext.error($1.line, "function cannot take any parameter(s)", function.getName().c_str(), "");
-                parseContext.recover();
-            }
-            if (function.getReturnType().getBasicType() != EbtVoid) {
-                parseContext.error($1.line, "", function.getReturnType().getBasicString(), "main function cannot return a value");
-                parseContext.recover();
-            }            
-        }
-   
-        //
-        // New symbol table scope for body of function plus its arguments
-        //
-        parseContext.symbolTable.push();
-        
-        //
-        // Remember the return type for later checking for RETURN statements.
-        //
-        parseContext.currentFunctionType = &(prevDec->getReturnType());
-        parseContext.functionReturnsValue = false;
-        
-        // 
-        // Insert parameters into the symbol table.
-        // If the parameter has no name, it's not an error, just don't insert it 
-        // (could be used for unused args).
-        //
-        // Also, accumulate the list of parameters into the HIL, so lower level code
-        // knows where to find parameters.
-        //
-        TIntermAggregate* paramNodes = new TIntermAggregate;
-        for (int i = 0; i < function.getParamCount(); i++) {
-            TParameter& param = function[i];
-            if (param.name != 0) {
-                TVariable *variable = new TVariable(param.name, *param.type);
-                // 
-                // Insert the parameters with name in the symbol table.
-                //
-                if (! parseContext.symbolTable.insert(*variable)) {
-                    parseContext.error($1.line, "redefinition", variable->getName().c_str(), "");
-                    parseContext.recover();
-                    delete variable;
-                }
-                //
-                // Transfer ownership of name pointer to symbol table.
-                //
-                param.name = 0;
-                
-                //
-                // Add the parameter to the HIL
-                //                
-                paramNodes = parseContext.intermediate.growAggregate(
-                                               paramNodes, 
-                                               parseContext.intermediate.addSymbol(variable->getUniqueId(),
-                                                                       variable->getName(),
-                                                                       variable->getType(), $1.line), 
-                                               $1.line);
-            } else {
-                paramNodes = parseContext.intermediate.growAggregate(paramNodes, parseContext.intermediate.addSymbol(0, "", *param.type, $1.line), $1.line);
-            }
-        }
-        parseContext.intermediate.setAggregateOperator(paramNodes, EOpParameters, $1.line);
-        $1.intermAggregate = paramNodes;
-        parseContext.loopNestingLevel = 0;
-    }
-    compound_statement_no_new_scope {
-        //?? Check that all paths return a value if return type != void ?
-        //   May be best done as post process phase on intermediate code
-        if (parseContext.currentFunctionType->getBasicType() != EbtVoid && ! parseContext.functionReturnsValue) {
-            parseContext.error($1.line, "function does not return a value:", "", $1.function->getName().c_str());
-            parseContext.recover();
-        }
-        parseContext.symbolTable.pop();
-        $$ = parseContext.intermediate.growAggregate($1.intermAggregate, $3, 0);
-        parseContext.intermediate.setAggregateOperator($$, EOpFunction, $1.line);
-        $$->getAsAggregate()->setName($1.function->getMangledName().c_str());
-        $$->getAsAggregate()->setType($1.function->getReturnType());
-        
-        // store the pragma information for debug and optimize and other vendor specific 
-        // information. This information can be queried from the parse tree
-        $$->getAsAggregate()->setOptimize(parseContext.contextPragma.optimize);
-        $$->getAsAggregate()->setDebug(parseContext.contextPragma.debug);
-        $$->getAsAggregate()->addToPragmaTable(parseContext.contextPragma.pragmaTable);
-    }
-    ;
-
-%%
+//\r
+//Copyright (C) 2002-2005  3Dlabs Inc. Ltd.\r
+//All rights reserved.\r
+//\r
+//Redistribution and use in source and binary forms, with or without\r
+//modification, are permitted provided that the following conditions\r
+//are met:\r
+//\r
+//    Redistributions of source code must retain the above copyright\r
+//    notice, this list of conditions and the following disclaimer.\r
+//\r
+//    Redistributions in binary form must reproduce the above\r
+//    copyright notice, this list of conditions and the following\r
+//    disclaimer in the documentation and/or other materials provided\r
+//    with the distribution.\r
+//\r
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
+//    contributors may be used to endorse or promote products derived\r
+//    from this software without specific prior written permission.\r
+//\r
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+//POSSIBILITY OF SUCH DAMAGE.\r
+//\r
+\r
+/**\r
+ * This is bison grammar and production code for parsing the OpenGL 2.0 shading\r
+ * languages.\r
+ */\r
+%{\r
+\r
+/* Based on:\r
+ANSI C Yacc grammar\r
+\r
+In 1985, Jeff Lee published his Yacc grammar (which is accompanied by a\r
+matching Lex specification) for the April 30, 1985 draft version of the\r
+ANSI C standard.  Tom Stockfisch reposted it to net.sources in 1987; that\r
+original, as mentioned in the answer to question 17.25 of the comp.lang.c\r
+FAQ, can be ftp'ed from ftp.uu.net, file usenet/net.sources/ansi.c.grammar.Z.\r
+\r
+I intend to keep this version as close to the current C Standard grammar as\r
+possible; please let me know if you discover discrepancies.\r
+\r
+Jutta Degener, 1995\r
+*/\r
+\r
+#include "SymbolTable.h"\r
+#include "ParseHelper.h"\r
+#include "../Public/ShaderLang.h"\r
+\r
+#ifdef _WIN32\r
+    #define YYPARSE_PARAM parseContext\r
+    #define YYPARSE_PARAM_DECL TParseContext&\r
+    #define YY_DECL int yylex(YYSTYPE* pyylval, TParseContext& parseContext)\r
+    #define YYLEX_PARAM parseContext\r
+#else\r
+    #define YYPARSE_PARAM parseContextLocal\r
+    #define parseContext (*((TParseContext*)(parseContextLocal)))\r
+    #define YY_DECL int yylex(YYSTYPE* pyylval, void* parseContextLocal)\r
+    #define YYLEX_PARAM (void*)(parseContextLocal)\r
+    extern void yyerror(char*);\r
+#endif\r
+\r
+#define VERTEX_ONLY(S, L) {                                                     \\r
+    if (parseContext.language != EShLangVertex) {                               \\r
+        parseContext.error(L, " supported in vertex shaders only ", S, "", ""); \\r
+        parseContext.recover();                                                 \\r
+    }                                                                           \\r
+}\r
+\r
+#define FRAG_ONLY(S, L) {                                                        \\r
+    if (parseContext.language != EShLangFragment) {                              \\r
+        parseContext.error(L, " supported in fragment shaders only ", S, "", "");\\r
+        parseContext.recover();                                                  \\r
+    }                                                                            \\r
+}\r
+\r
+%}\r
+%union {\r
+    struct {\r
+        TSourceLoc line;\r
+        union {\r
+            TString *string;\r
+            float f;\r
+            int i;\r
+            bool b;\r
+        };\r
+        TSymbol* symbol;\r
+    } lex;\r
+    struct {\r
+        TSourceLoc line;\r
+        TOperator op;\r
+        union {\r
+            TIntermNode* intermNode;\r
+            TIntermNodePair nodePair;\r
+            TIntermTyped* intermTypedNode;\r
+            TIntermAggregate* intermAggregate;\r
+        };\r
+        union {\r
+            TPublicType type;\r
+            TQualifier qualifier;\r
+            TFunction* function;\r
+            TParameter param;\r
+            TTypeLine typeLine;\r
+            TTypeList* typeList;\r
+        };\r
+    } interm;\r
+}\r
+\r
+%{\r
+#ifndef _WIN32\r
+    extern int yylex(YYSTYPE*, void*);\r
+#endif\r
+%}\r
+\r
+%pure_parser /* Just in case is called from multiple threads */\r
+%expect 1 /* One shift reduce conflict because of if | else */\r
+\r
+%token <lex> ATTRIBUTE VARYING\r
+%token <lex> CONST BOOL FLOAT DOUBLE INT UINT\r
+%token <lex> BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN SWITCH CASE DEFAULT SUBROUTINE\r
+%token <lex> BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 UVEC2 UVEC3 UVEC4 VEC2 VEC3 VEC4\r
+%token <lex> MAT2 MAT3 MAT4 CENTROID IN OUT INOUT \r
+%token <lex> UNIFORM PATCH SAMPLE\r
+%token <lex> COHERENT VOLATILE RESTRICT READONLY WRITEONLY\r
+%token <lex> DVEC2 DVEC3 DVEC4 DMAT2 DMAT3 DMAT4\r
+%token <lex> NOPERSPECTIVE FLAT SMOOTH LAYOUT\r
+\r
+%token <lex> MAT2X2 MAT2X3 MAT2X4\r
+%token <lex> MAT3X2 MAT3X3 MAT3X4\r
+%token <lex> MAT4X2 MAT4X3 MAT4X4\r
+%token <lex> DMAT2X2 DMAT2X3 DMAT2X4\r
+%token <lex> DMAT3X2 DMAT3X3 DMAT3X4\r
+%token <lex> DMAT4X2 DMAT4X3 DMAT4X4\r
+%token <lex> ATOMIC_UINT\r
+\r
+%token <lex> SAMPLER1D SAMPLER2D SAMPLER3D SAMPLERCUBE SAMPLER1DSHADOW SAMPLER2DSHADOW\r
+%token <lex> SAMPLERCUBESHADOW SAMPLER1DARRAY SAMPLER2DARRAY SAMPLER1DARRAYSHADOW\r
+%token <lex> SAMPLER2DARRAYSHADOW ISAMPLER1D ISAMPLER2D ISAMPLER3D ISAMPLERCUBE\r
+%token <lex> ISAMPLER1DARRAY ISAMPLER2DARRAY USAMPLER1D USAMPLER2D USAMPLER3D\r
+%token <lex> USAMPLERCUBE USAMPLER1DARRAY USAMPLER2DARRAY\r
+%token <lex> SAMPLER2DRECT SAMPLER2DRECTSHADOW ISAMPLER2DRECT USAMPLER2DRECT\r
+%token <lex> SAMPLERBUFFER ISAMPLERBUFFER USAMPLERBUFFER\r
+%token <lex> SAMPLERCUBEARRAY SAMPLERCUBEARRAYSHADOW\r
+%token <lex> ISAMPLERCUBEARRAY USAMPLERCUBEARRAY\r
+%token <lex> SAMPLER2DMS ISAMPLER2DMS USAMPLER2DMS\r
+%token <lex> SAMPLER2DMSARRAY ISAMPLER2DMSARRAY USAMPLER2DMSARRAY\r
+\r
+%token <lex> IMAGE1D IIMAGE1D UIMAGE1D IMAGE2D IIMAGE2D \r
+%token <lex> UIMAGE2D IMAGE3D IIMAGE3D UIMAGE3D\r
+%token <lex> IMAGE2DRECT IIMAGE2DRECT UIMAGE2DRECT \r
+%token <lex> IMAGECUBE IIMAGECUBE UIMAGECUBE\r
+%token <lex> IMAGEBUFFER IIMAGEBUFFER UIMAGEBUFFER\r
+%token <lex> IMAGE1DARRAY IIMAGE1DARRAY UIMAGE1DARRAY \r
+%token <lex> IMAGE2DARRAY IIMAGE2DARRAY UIMAGE2DARRAY\r
+%token <lex> IMAGECUBEARRAY IIMAGECUBEARRAY UIMAGECUBEARRAY\r
+%token <lex> IMAGE2DMS IIMAGE2DMS UIMAGE2DMS \r
+%token <lex> IMAGE2DMSARRAY IIMAGE2DMSARRAY UIMAGE2DMSARRAY\r
+\r
+%token <lex> STRUCT VOID WHILE\r
+\r
+%token <lex> IDENTIFIER TYPE_NAME \r
+%token <lex> FLOATCONSTANT DOUBLECONSTANT INTCONSTANT UINTCONSTANT BOOLCONSTANT\r
+%token <lex> FIELD_SELECTION\r
+%token <lex> LEFT_OP RIGHT_OP\r
+%token <lex> INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP\r
+%token <lex> AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN\r
+%token <lex> MOD_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN\r
+%token <lex> SUB_ASSIGN\r
+\r
+%token <lex> LEFT_PAREN RIGHT_PAREN LEFT_BRACKET RIGHT_BRACKET LEFT_BRACE RIGHT_BRACE DOT\r
+%token <lex> COMMA COLON EQUAL SEMICOLON BANG DASH TILDE PLUS STAR SLASH PERCENT\r
+%token <lex> LEFT_ANGLE RIGHT_ANGLE VERTICAL_BAR CARET AMPERSAND QUESTION\r
+\r
+%token <lex> INVARIANT PRECISE\r
+%token <lex> HIGH_PRECISION MEDIUM_PRECISION LOW_PRECISION PRECISION\r
+\r
+%type <interm> assignment_operator unary_operator\r
+%type <interm.intermTypedNode> variable_identifier primary_expression postfix_expression\r
+%type <interm.intermTypedNode> expression integer_expression assignment_expression\r
+%type <interm.intermTypedNode> unary_expression multiplicative_expression additive_expression\r
+%type <interm.intermTypedNode> relational_expression equality_expression\r
+%type <interm.intermTypedNode> conditional_expression constant_expression\r
+%type <interm.intermTypedNode> logical_or_expression logical_xor_expression logical_and_expression\r
+%type <interm.intermTypedNode> shift_expression and_expression exclusive_or_expression inclusive_or_expression\r
+%type <interm.intermTypedNode> function_call initializer initializer_list condition conditionopt\r
+\r
+%type <interm.intermNode> translation_unit function_definition\r
+%type <interm.intermNode> statement simple_statement\r
+%type <interm.intermAggregate>  statement_list compound_statement\r
+%type <interm.intermNode> declaration_statement selection_statement expression_statement\r
+%type <interm.intermNode> switch_statement case_label switch_statement_list\r
+%type <interm.intermNode> declaration external_declaration\r
+%type <interm.intermNode> for_init_statement compound_statement_no_new_scope\r
+%type <interm.nodePair> selection_rest_statement for_rest_statement\r
+%type <interm.intermNode> iteration_statement jump_statement statement_no_new_scope\r
+%type <interm> single_declaration init_declarator_list\r
+\r
+%type <interm> parameter_declaration parameter_declarator parameter_type_specifier\r
+\r
+%type <interm.type> precise_qualifier invariant_qualifier interpolation_qualifier storage_qualifier precision_qualifier\r
+%type <interm.type> layout_qualifier layout_qualifier_id_list\r
+\r
+%type <interm.type> type_qualifier fully_specified_type type_specifier\r
+%type <interm.type> single_type_qualifier\r
+%type <interm.type> type_specifier_nonarray\r
+%type <interm.type> struct_specifier\r
+%type <interm.typeLine> struct_declarator\r
+%type <interm.typeList> struct_declarator_list struct_declaration struct_declaration_list type_name_list\r
+%type <interm.function> function_header function_declarator\r
+%type <interm.function> function_header_with_parameters\r
+%type <interm> function_call_header_with_parameters function_call_header_no_parameters function_call_generic function_prototype\r
+%type <interm> function_call_or_method function_identifier function_call_header\r
+\r
+%start translation_unit\r
+%%\r
+\r
+variable_identifier\r
+    : IDENTIFIER {\r
+        // The symbol table search was done in the lexical phase\r
+        const TSymbol* symbol = $1.symbol;\r
+        const TVariable* variable;\r
+        if (symbol == 0) {\r
+            TVariable* fakeVariable = new TVariable($1.string, TType(EbtVoid));\r
+            variable = fakeVariable;\r
+        } else {\r
+            // This identifier can only be a variable type symbol\r
+            if (! symbol->isVariable()) {\r
+                parseContext.error($1.line, "variable expected", $1.string->c_str(), "");\r
+                parseContext.recover();\r
+            }\r
+            variable = static_cast<const TVariable*>(symbol);\r
+        }\r
+\r
+        // don't delete $1.string, it's used by error recovery, and the pool\r
+        // pop will reclaim the memory\r
+\r
+        if (variable->getType().getQualifier() == EvqConst ) {\r
+            constUnion* constArray = variable->getConstPointer();\r
+            TType t(variable->getType());\r
+            $$ = parseContext.intermediate.addConstantUnion(constArray, t, $1.line);\r
+        } else\r
+            $$ = parseContext.intermediate.addSymbol(variable->getUniqueId(),\r
+                                                     variable->getName(),\r
+                                                     variable->getType(), $1.line);\r
+    }\r
+    ;\r
+\r
+primary_expression\r
+    : variable_identifier {\r
+        $$ = $1;\r
+    }\r
+    | INTCONSTANT {\r
+        constUnion *unionArray = new constUnion[1];\r
+        unionArray->setIConst($1.i);\r
+        $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $1.line);\r
+    }\r
+    | UINTCONSTANT {\r
+        constUnion *unionArray = new constUnion[1];\r
+        unionArray->setIConst($1.i);\r
+        $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $1.line);\r
+    }\r
+    | FLOATCONSTANT {\r
+        constUnion *unionArray = new constUnion[1];\r
+        unionArray->setFConst($1.f);\r
+        $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), $1.line);\r
+    }\r
+    | DOUBLECONSTANT {\r
+        constUnion *unionArray = new constUnion[1];\r
+        unionArray->setFConst($1.f);\r
+        $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), $1.line);\r
+    }\r
+    | BOOLCONSTANT {\r
+        constUnion *unionArray = new constUnion[1];\r
+        unionArray->setBConst($1.b);\r
+        $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $1.line);\r
+    }\r
+    | LEFT_PAREN expression RIGHT_PAREN {\r
+        $$ = $2;\r
+    }\r
+    ;\r
+\r
+postfix_expression\r
+    : primary_expression {\r
+        $$ = $1;\r
+    }\r
+    | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET {\r
+        parseContext.variableErrorCheck($1);\r
+        if (!$1->isArray() && !$1->isMatrix() && !$1->isVector()) {\r
+            if ($1->getAsSymbolNode())\r
+                parseContext.error($2.line, " left of '[' is not of type array, matrix, or vector ", $1->getAsSymbolNode()->getSymbol().c_str(), "");\r
+            else\r
+                parseContext.error($2.line, " left of '[' is not of type array, matrix, or vector ", "expression", "");\r
+            parseContext.recover();\r
+        }\r
+        if ($1->getType().getQualifier() == EvqConst && $3->getQualifier() == EvqConst) {\r
+            if ($1->isArray()) { // constant folding for arrays\r
+                $$ = parseContext.addConstArrayNode($3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), $1, $2.line);\r
+            } else if ($1->isVector()) {  // constant folding for vectors\r
+                TVectorFields fields;\r
+                fields.num = 1;\r
+                fields.offsets[0] = $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(); // need to do it this way because v.xy sends fields integer array\r
+                $$ = parseContext.addConstVectorNode(fields, $1, $2.line);\r
+            } else if ($1->isMatrix()) { // constant folding for matrices\r
+                $$ = parseContext.addConstMatrixNode($3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), $1, $2.line);\r
+            }\r
+        } else {\r
+            if ($3->getQualifier() == EvqConst) {\r
+                if (($1->isVector() || $1->isMatrix()) && $1->getType().getNominalSize() <= $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() && !$1->isArray() ) {\r
+                    parseContext.error($2.line, "", "[", "field selection out of range '%d'", $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst());\r
+                    parseContext.recover();\r
+                } else {\r
+                    if ($1->isArray()) {\r
+                        if ($1->getType().getArraySize() == 0) {\r
+                            if ($1->getType().getMaxArraySize() <= $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst()) {\r
+                                if (parseContext.arraySetMaxSize($1->getAsSymbolNode(), $1->getTypePointer(), $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), true, $2.line))\r
+                                    parseContext.recover();\r
+                            } else {\r
+                                if (parseContext.arraySetMaxSize($1->getAsSymbolNode(), $1->getTypePointer(), 0, false, $2.line))\r
+                                    parseContext.recover();\r
+                            }\r
+                        } else if ( $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() >= $1->getType().getArraySize()) {\r
+                            parseContext.error($2.line, "", "[", "array index out of range '%d'", $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst());\r
+                            parseContext.recover();\r
+                        }\r
+                    }\r
+                    $$ = parseContext.intermediate.addIndex(EOpIndexDirect, $1, $3, $2.line);\r
+                }\r
+            } else {\r
+                if ($1->isArray() && $1->getType().getArraySize() == 0) {\r
+                    parseContext.error($2.line, "", "[", "array must be redeclared with a size before being indexed with a variable");\r
+                    parseContext.recover();\r
+                }\r
+\r
+                $$ = parseContext.intermediate.addIndex(EOpIndexIndirect, $1, $3, $2.line);\r
+            }\r
+        }\r
+        if ($$ == 0) {\r
+            constUnion *unionArray = new constUnion[1];\r
+            unionArray->setFConst(0.0f);\r
+            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), $2.line);\r
+        } else if ($1->isArray()) {\r
+            if ($1->getType().getStruct())\r
+                $$->setType(TType($1->getType().getStruct(), $1->getType().getTypeName()));\r
+            else\r
+                $$->setType(TType($1->getBasicType(), EvqTemporary, $1->getNominalSize(), $1->isMatrix()));\r
+\r
+            if ($1->getType().getQualifier() == EvqConst)\r
+                $$->getTypePointer()->changeQualifier(EvqConst);\r
+        } else if ($1->isMatrix() && $1->getType().getQualifier() == EvqConst)\r
+            $$->setType(TType($1->getBasicType(), EvqConst, $1->getNominalSize()));\r
+        else if ($1->isMatrix())\r
+            $$->setType(TType($1->getBasicType(), EvqTemporary, $1->getNominalSize()));\r
+        else if ($1->isVector() && $1->getType().getQualifier() == EvqConst)\r
+            $$->setType(TType($1->getBasicType(), EvqConst));\r
+        else if ($1->isVector())\r
+            $$->setType(TType($1->getBasicType(), EvqTemporary));\r
+        else\r
+            $$->setType($1->getType());\r
+    }\r
+    | function_call {\r
+        $$ = $1;\r
+    }\r
+    | postfix_expression DOT FIELD_SELECTION {\r
+        parseContext.variableErrorCheck($1);\r
+        if ($1->isArray()) {\r
+            //\r
+            // It can only be a method (e.g., length), which can't be resolved until\r
+            // we later see the function calling syntax.  Save away the name for now.\r
+            //\r
+\r
+            // TODO: if next token is not "(", then this is an error\r
+\r
+            if (*$3.string == "length") {\r
+                if (parseContext.extensionErrorCheck($3.line, "GL_3DL_array_objects")) {\r
+                    parseContext.recover();\r
+                    $$ = $1;\r
+                } else {\r
+                    $$ = parseContext.intermediate.addMethod($1, TType(EbtInt), $3.string, $2.line);\r
+                }\r
+            } else {\r
+                parseContext.error($3.line, "only the length method is supported for array", $3.string->c_str(), "");\r
+                parseContext.recover();\r
+                $$ = $1;\r
+            }\r
+        } else if ($1->isVector()) {\r
+            TVectorFields fields;\r
+            if (! parseContext.parseVectorFields(*$3.string, $1->getNominalSize(), fields, $3.line)) {\r
+                fields.num = 1;\r
+                fields.offsets[0] = 0;\r
+                parseContext.recover();\r
+            }\r
+\r
+            if ($1->getType().getQualifier() == EvqConst) { // constant folding for vector fields\r
+                $$ = parseContext.addConstVectorNode(fields, $1, $3.line);\r
+                if ($$ == 0) {\r
+                    parseContext.recover();\r
+                    $$ = $1;\r
+                }\r
+                else\r
+                    $$->setType(TType($1->getBasicType(), EvqConst, (int) (*$3.string).size()));\r
+            } else {\r
+                if (fields.num == 1) {\r
+                    constUnion *unionArray = new constUnion[1];\r
+                    unionArray->setIConst(fields.offsets[0]);\r
+                    TIntermTyped* index = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $3.line);\r
+                    $$ = parseContext.intermediate.addIndex(EOpIndexDirect, $1, index, $2.line);\r
+                    $$->setType(TType($1->getBasicType()));\r
+                } else {\r
+                    TString vectorString = *$3.string;\r
+                    TIntermTyped* index = parseContext.intermediate.addSwizzle(fields, $3.line);\r
+                    $$ = parseContext.intermediate.addIndex(EOpVectorSwizzle, $1, index, $2.line);\r
+                    $$->setType(TType($1->getBasicType(),EvqTemporary, (int) vectorString.size()));\r
+                }\r
+            }\r
+        } else if ($1->isMatrix()) {\r
+            TMatrixFields fields;\r
+            if (! parseContext.parseMatrixFields(*$3.string, $1->getNominalSize(), fields, $3.line)) {\r
+                fields.wholeRow = false;\r
+                fields.wholeCol = false;\r
+                fields.row = 0;\r
+                fields.col = 0;\r
+                parseContext.recover();\r
+            }\r
+\r
+            if (fields.wholeRow || fields.wholeCol) {\r
+                parseContext.error($2.line, " non-scalar fields not implemented yet", ".", "");\r
+                parseContext.recover();\r
+                constUnion *unionArray = new constUnion[1];\r
+                unionArray->setIConst(0);\r
+                TIntermTyped* index = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $3.line);\r
+                $$ = parseContext.intermediate.addIndex(EOpIndexDirect, $1, index, $2.line);\r
+                $$->setType(TType($1->getBasicType(), EvqTemporary, $1->getNominalSize()));\r
+            } else {\r
+                constUnion *unionArray = new constUnion[1];\r
+                unionArray->setIConst(fields.col * $1->getNominalSize() + fields.row);\r
+                TIntermTyped* index = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $3.line);\r
+                $$ = parseContext.intermediate.addIndex(EOpIndexDirect, $1, index, $2.line);\r
+                $$->setType(TType($1->getBasicType()));\r
+            }\r
+        } else if ($1->getBasicType() == EbtStruct) {\r
+            bool fieldFound = false;\r
+            TTypeList* fields = $1->getType().getStruct();\r
+            if (fields == 0) {\r
+                parseContext.error($2.line, "structure has no fields", "Internal Error", "");\r
+                parseContext.recover();\r
+                $$ = $1;\r
+            } else {\r
+                unsigned int i;\r
+                for (i = 0; i < fields->size(); ++i) {\r
+                    if ((*fields)[i].type->getFieldName() == *$3.string) {\r
+                        fieldFound = true;\r
+                        break;\r
+                    }\r
+                }\r
+                if (fieldFound) {\r
+                    if ($1->getType().getQualifier() == EvqConst) {\r
+                        $$ = parseContext.addConstStruct(*$3.string, $1, $2.line);\r
+                        if ($$ == 0) {\r
+                            parseContext.recover();\r
+                            $$ = $1;\r
+                        }\r
+                        else {\r
+                            $$->setType(*(*fields)[i].type);\r
+                            // change the qualifier of the return type, not of the structure field\r
+                            // as the structure definition is shared between various structures.\r
+                            $$->getTypePointer()->changeQualifier(EvqConst);\r
+                        }\r
+                    } else {\r
+                        constUnion *unionArray = new constUnion[1];\r
+                        unionArray->setIConst(i);\r
+                        TIntermTyped* index = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $3.line);\r
+                        $$ = parseContext.intermediate.addIndex(EOpIndexDirectStruct, $1, index, $2.line);\r
+                        $$->setType(*(*fields)[i].type);\r
+                    }\r
+                } else {\r
+                    parseContext.error($2.line, " no such field in structure", $3.string->c_str(), "");\r
+                    parseContext.recover();\r
+                    $$ = $1;\r
+                }\r
+            }\r
+        } else {\r
+            parseContext.error($2.line, " field selection requires structure, vector, or matrix on left hand side", $3.string->c_str(), "");\r
+            parseContext.recover();\r
+            $$ = $1;\r
+        }\r
+        // don't delete $3.string, it's from the pool\r
+    }\r
+    | postfix_expression INC_OP {\r
+        parseContext.variableErrorCheck($1);\r
+        if (parseContext.lValueErrorCheck($2.line, "++", $1))\r
+            parseContext.recover();\r
+        $$ = parseContext.intermediate.addUnaryMath(EOpPostIncrement, $1, $2.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.unaryOpError($2.line, "++", $1->getCompleteString());\r
+            parseContext.recover();\r
+            $$ = $1;\r
+        }\r
+    }\r
+    | postfix_expression DEC_OP {\r
+        parseContext.variableErrorCheck($1);\r
+        if (parseContext.lValueErrorCheck($2.line, "--", $1))\r
+            parseContext.recover();\r
+        $$ = parseContext.intermediate.addUnaryMath(EOpPostDecrement, $1, $2.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.unaryOpError($2.line, "--", $1->getCompleteString());\r
+            parseContext.recover();\r
+            $$ = $1;\r
+        }\r
+    }\r
+    ;\r
+\r
+integer_expression\r
+    : expression {\r
+        if (parseContext.integerErrorCheck($1, "[]"))\r
+            parseContext.recover();\r
+        $$ = $1;\r
+    }\r
+    ;\r
+\r
+function_call\r
+    : function_call_or_method {\r
+        TFunction* fnCall = $1.function;\r
+        TOperator op = fnCall->getBuiltInOp();\r
+        if (op == EOpArrayLength) {\r
+            // TODO: check for no arguments to .length()\r
+            if ($1.intermNode->getAsTyped() == 0 || $1.intermNode->getAsTyped()->getType().getArraySize() == 0) {\r
+                parseContext.error($1.line, "", fnCall->getName().c_str(), "array must be declared with a size before using this method");\r
+                parseContext.recover();\r
+            }\r
+\r
+            constUnion *unionArray = new constUnion[1];\r
+            unionArray->setIConst($1.intermNode->getAsTyped()->getType().getArraySize());\r
+            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $1.line);\r
+        } else if (op != EOpNull) {\r
+            //\r
+            // Then this should be a constructor.\r
+            // Don't go through the symbol table for constructors.\r
+            // Their parameters will be verified algorithmically.\r
+            //\r
+            TType type(EbtVoid);  // use this to get the type back\r
+            if (parseContext.constructorErrorCheck($1.line, $1.intermNode, *fnCall, op, &type)) {\r
+                $$ = 0;\r
+            } else {\r
+                //\r
+                // It's a constructor, of type 'type'.\r
+                //\r
+                $$ = parseContext.addConstructor($1.intermNode, &type, op, fnCall, $1.line);\r
+            }\r
+\r
+            if ($$ == 0) {\r
+                parseContext.recover();\r
+                $$ = parseContext.intermediate.setAggregateOperator(0, op, $1.line);\r
+            }\r
+            $$->setType(type);\r
+        } else {\r
+            //\r
+            // Not a constructor.  Find it in the symbol table.\r
+            //\r
+            const TFunction* fnCandidate;\r
+            bool builtIn;\r
+            fnCandidate = parseContext.findFunction($1.line, fnCall, &builtIn);\r
+            if (fnCandidate) {\r
+                //\r
+                // A declared function.  But, it might still map to a built-in\r
+                // operation.\r
+                //\r
+                op = fnCandidate->getBuiltInOp();\r
+                if (builtIn && op != EOpNull) {\r
+                    //\r
+                    // A function call mapped to a built-in operation.\r
+                    //\r
+                    if (fnCandidate->getParamCount() == 1) {\r
+                        //\r
+                        // Treat it like a built-in unary operator.\r
+                        //\r
+                        $$ = parseContext.intermediate.addUnaryMath(op, $1.intermNode, 0, parseContext.symbolTable);\r
+                        if ($$ == 0)  {\r
+                            parseContext.error($1.intermNode->getLine(), " wrong operand type", "Internal Error",\r
+                                "built in unary operator function.  Type: %s",\r
+                                static_cast<TIntermTyped*>($1.intermNode)->getCompleteString().c_str());\r
+                            YYERROR;\r
+                        }\r
+                    } else {\r
+                        $$ = parseContext.intermediate.setAggregateOperator($1.intermAggregate, op, $1.line);\r
+                    }\r
+                } else {\r
+                    // This is a real function call\r
+\r
+                    $$ = parseContext.intermediate.setAggregateOperator($1.intermAggregate, EOpFunctionCall, $1.line);\r
+                    $$->setType(fnCandidate->getReturnType());\r
+\r
+                    // this is how we know whether the given function is a builtIn function or a user defined function\r
+                    // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also\r
+                    // if builtIn == true, it's definitely a builtIn function with EOpNull\r
+                    if (!builtIn)\r
+                        $$->getAsAggregate()->setUserDefined();\r
+                    $$->getAsAggregate()->setName(fnCandidate->getMangledName());\r
+\r
+                    TQualifier qual;\r
+                    TQualifierList& qualifierList = $$->getAsAggregate()->getQualifier();\r
+                    for (int i = 0; i < fnCandidate->getParamCount(); ++i) {\r
+                        qual = (*fnCandidate)[i].type->getQualifier();\r
+                        if (qual == EvqOut || qual == EvqInOut) {\r
+                            if (parseContext.lValueErrorCheck($$->getLine(), "assign", $$->getAsAggregate()->getSequence()[i]->getAsTyped())) {\r
+                                parseContext.error($1.intermNode->getLine(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error", "");\r
+                                parseContext.recover();\r
+                            }\r
+                        }\r
+                        qualifierList.push_back(qual);\r
+                    }\r
+                }\r
+                $$->setType(fnCandidate->getReturnType());\r
+            } else {\r
+                // error message was put out by PaFindFunction()\r
+                // Put on a dummy node for error recovery\r
+                constUnion *unionArray = new constUnion[1];\r
+                unionArray->setFConst(0.0f);\r
+                $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), $1.line);\r
+                parseContext.recover();\r
+            }\r
+        }\r
+        delete fnCall;\r
+    }\r
+    ;\r
+\r
+// TODO: can we eliminate function_call_or_method and function_call_generic?\r
+function_call_or_method\r
+    : function_call_generic {\r
+        $$ = $1;\r
+    }\r
+    ;\r
+\r
+function_call_generic\r
+    : function_call_header_with_parameters RIGHT_PAREN {\r
+        $$ = $1;\r
+        $$.line = $2.line;\r
+    }\r
+    | function_call_header_no_parameters RIGHT_PAREN {\r
+        $$ = $1;\r
+        $$.line = $2.line;\r
+    }\r
+    ;\r
+\r
+function_call_header_no_parameters\r
+    : function_call_header VOID {\r
+        $$ = $1;\r
+    }\r
+    | function_call_header {\r
+        $$ = $1;\r
+    }\r
+    ;\r
+\r
+function_call_header_with_parameters\r
+    : function_call_header assignment_expression {\r
+        TParameter param = { 0, new TType($2->getType()) };\r
+        $1.function->addParameter(param);\r
+        $$.function = $1.function;\r
+        $$.intermNode = $2;\r
+    }\r
+    | function_call_header_with_parameters COMMA assignment_expression {\r
+        TParameter param = { 0, new TType($3->getType()) };\r
+        $1.function->addParameter(param);\r
+        $$.function = $1.function;\r
+        $$.intermNode = parseContext.intermediate.growAggregate($1.intermNode, $3, $2.line);\r
+    }\r
+    ;\r
+\r
+function_call_header\r
+    : function_identifier LEFT_PAREN {\r
+        $$ = $1;\r
+    }\r
+    ;\r
+\r
+// Grammar Note:  Constructors look like functions, but are recognized as types.\r
+\r
+function_identifier\r
+    : type_specifier {\r
+        //\r
+        // Constructor\r
+        //\r
+        $$.function = 0;\r
+        $$.intermNode = 0;\r
+\r
+        if ($1.array) {\r
+            if (parseContext.extensionErrorCheck($1.line, "GL_3DL_array_objects")) {\r
+                parseContext.recover();\r
+                $1.setArray(false);\r
+            }\r
+        }\r
+\r
+        if ($1.userDef) {\r
+            TString tempString = "";\r
+            TType type($1);\r
+            TFunction *function = new TFunction(&tempString, type, EOpConstructStruct);\r
+            $$.function = function;\r
+        } else {\r
+            TOperator op = EOpNull;\r
+            switch ($1.type) {\r
+            case EbtFloat:\r
+                if ($1.matrix) {\r
+                    switch($1.size) {\r
+                    case 2: op = EOpConstructMat2;  break;\r
+                    case 3: op = EOpConstructMat3;  break;\r
+                    case 4: op = EOpConstructMat4;  break;\r
+                    }\r
+                } else {\r
+                    switch($1.size) {\r
+                    case 1: op = EOpConstructFloat; break;\r
+                    case 2: op = EOpConstructVec2;  break;\r
+                    case 3: op = EOpConstructVec3;  break;\r
+                    case 4: op = EOpConstructVec4;  break;\r
+                    }\r
+                }\r
+                break;\r
+            case EbtInt:\r
+                switch($1.size) {\r
+                case 1: op = EOpConstructInt;   break;\r
+                case 2: op = EOpConstructIVec2; break;\r
+                case 3: op = EOpConstructIVec3; break;\r
+                case 4: op = EOpConstructIVec4; break;\r
+                }\r
+                break;\r
+            case EbtBool:\r
+                switch($1.size) {\r
+                case 1:  op = EOpConstructBool;  break;\r
+                case 2:  op = EOpConstructBVec2; break;\r
+                case 3:  op = EOpConstructBVec3; break;\r
+                case 4:  op = EOpConstructBVec4; break;\r
+                }\r
+                break;\r
+            }\r
+            if (op == EOpNull) {\r
+                parseContext.error($1.line, "cannot construct this type", TType::getBasicString($1.type), "");\r
+                parseContext.recover();\r
+                $1.type = EbtFloat;\r
+                op = EOpConstructFloat;\r
+            }\r
+            TString tempString = "";\r
+            TType type($1);\r
+            TFunction *function = new TFunction(&tempString, type, op);\r
+            $$.function = function;\r
+        }\r
+    }\r
+    | postfix_expression {\r
+        //\r
+        // Should be a method or subroutine call, but we don't have arguments yet.\r
+        //\r
+        $$.function = 0;\r
+        $$.intermNode = 0;\r
+\r
+        TIntermMethod* method = $1->getAsMethodNode();\r
+        if (method) {\r
+            if (method->getObject()->isArray()) {\r
+                $$.function = new TFunction(&method->getMethodName(), TType(EbtInt), EOpArrayLength);\r
+                $$.intermNode = method->getObject();\r
+            } else {\r
+                parseContext.error(method->getLine(), "only arrays have methods", "", "");\r
+                parseContext.recover();\r
+            }\r
+        } else {\r
+            TIntermSymbol* symbol = $1->getAsSymbolNode();\r
+            if (symbol) {\r
+                if (parseContext.reservedErrorCheck(symbol->getLine(), symbol->getSymbol()))\r
+                    parseContext.recover();\r
+                TFunction *function = new TFunction(&symbol->getSymbol(), TType(EbtVoid));\r
+                $$.function = function;\r
+            } else {\r
+                parseContext.error($1->getLine(), "function call, method or subroutine call expected", "", "");\r
+                parseContext.recover();\r
+            }\r
+        }\r
+\r
+        if ($$.function == 0) {\r
+            // error recover\r
+            $$.function = new TFunction(&TString(""), TType(EbtVoid), EOpNull);\r
+        }\r
+    }\r
+    ;\r
+\r
+unary_expression\r
+    : postfix_expression {\r
+        parseContext.variableErrorCheck($1);\r
+        $$ = $1;\r
+    }\r
+    | INC_OP unary_expression {\r
+        if (parseContext.lValueErrorCheck($1.line, "++", $2))\r
+            parseContext.recover();\r
+        $$ = parseContext.intermediate.addUnaryMath(EOpPreIncrement, $2, $1.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.unaryOpError($1.line, "++", $2->getCompleteString());\r
+            parseContext.recover();\r
+            $$ = $2;\r
+        }\r
+    }\r
+    | DEC_OP unary_expression {\r
+        if (parseContext.lValueErrorCheck($1.line, "--", $2))\r
+            parseContext.recover();\r
+        $$ = parseContext.intermediate.addUnaryMath(EOpPreDecrement, $2, $1.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.unaryOpError($1.line, "--", $2->getCompleteString());\r
+            parseContext.recover();\r
+            $$ = $2;\r
+        }\r
+    }\r
+    | unary_operator unary_expression {\r
+        if ($1.op != EOpNull) {\r
+            $$ = parseContext.intermediate.addUnaryMath($1.op, $2, $1.line, parseContext.symbolTable);\r
+            if ($$ == 0) {\r
+                char* errorOp = "";\r
+                switch($1.op) {\r
+                case EOpNegative:   errorOp = "-"; break;\r
+                case EOpLogicalNot: errorOp = "!"; break;\r
+                case EOpBitwiseNot: errorOp = "~"; break;\r
+                default: break;\r
+                }\r
+                parseContext.unaryOpError($1.line, errorOp, $2->getCompleteString());\r
+                parseContext.recover();\r
+                $$ = $2;\r
+            }\r
+        } else\r
+            $$ = $2;\r
+    }\r
+    ;\r
+// Grammar Note:  No traditional style type casts.\r
+\r
+unary_operator\r
+    : PLUS  { $$.line = $1.line; $$.op = EOpNull; }\r
+    | DASH  { $$.line = $1.line; $$.op = EOpNegative; }\r
+    | BANG  { $$.line = $1.line; $$.op = EOpLogicalNot; }\r
+    | TILDE { $$.line = $1.line; $$.op = EOpBitwiseNot; }\r
+    ;\r
+// Grammar Note:  No '*' or '&' unary ops.  Pointers are not supported.\r
+\r
+multiplicative_expression\r
+    : unary_expression { $$ = $1; }\r
+    | multiplicative_expression STAR unary_expression {\r
+        $$ = parseContext.intermediate.addBinaryMath(EOpMul, $1, $3, $2.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.binaryOpError($2.line, "*", $1->getCompleteString(), $3->getCompleteString());\r
+            parseContext.recover();\r
+            $$ = $1;\r
+        }\r
+    }\r
+    | multiplicative_expression SLASH unary_expression {\r
+        $$ = parseContext.intermediate.addBinaryMath(EOpDiv, $1, $3, $2.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.binaryOpError($2.line, "/", $1->getCompleteString(), $3->getCompleteString());\r
+            parseContext.recover();\r
+            $$ = $1;\r
+        }\r
+    }\r
+    | multiplicative_expression PERCENT unary_expression {\r
+        $$ = parseContext.intermediate.addBinaryMath(EOpMod, $1, $3, $2.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.binaryOpError($2.line, "%", $1->getCompleteString(), $3->getCompleteString());\r
+            parseContext.recover();\r
+            $$ = $1;\r
+        }\r
+    }\r
+    ;\r
+\r
+additive_expression\r
+    : multiplicative_expression { $$ = $1; }\r
+    | additive_expression PLUS multiplicative_expression {\r
+        $$ = parseContext.intermediate.addBinaryMath(EOpAdd, $1, $3, $2.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.binaryOpError($2.line, "+", $1->getCompleteString(), $3->getCompleteString());\r
+            parseContext.recover();\r
+            $$ = $1;\r
+        }\r
+    }\r
+    | additive_expression DASH multiplicative_expression {\r
+        $$ = parseContext.intermediate.addBinaryMath(EOpSub, $1, $3, $2.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.binaryOpError($2.line, "-", $1->getCompleteString(), $3->getCompleteString());\r
+            parseContext.recover();\r
+            $$ = $1;\r
+        }\r
+    }\r
+    ;\r
+\r
+shift_expression\r
+    : additive_expression { $$ = $1; }\r
+    | shift_expression LEFT_OP additive_expression {\r
+        $$ = parseContext.intermediate.addBinaryMath(EOpLeftShift, $1, $3, $2.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.binaryOpError($2.line, "<<", $1->getCompleteString(), $3->getCompleteString());\r
+            parseContext.recover();\r
+            $$ = $1;\r
+        }\r
+    }\r
+    | shift_expression RIGHT_OP additive_expression {\r
+        $$ = parseContext.intermediate.addBinaryMath(EOpRightShift, $1, $3, $2.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.binaryOpError($2.line, ">>", $1->getCompleteString(), $3->getCompleteString());\r
+            parseContext.recover();\r
+            $$ = $1;\r
+        }\r
+    }\r
+    ;\r
+\r
+relational_expression\r
+    : shift_expression { $$ = $1; }\r
+    | relational_expression LEFT_ANGLE shift_expression {\r
+        $$ = parseContext.intermediate.addBinaryMath(EOpLessThan, $1, $3, $2.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.binaryOpError($2.line, "<", $1->getCompleteString(), $3->getCompleteString());\r
+            parseContext.recover();\r
+            constUnion *unionArray = new constUnion[1];\r
+            unionArray->setBConst(false);\r
+            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line);\r
+        }\r
+    }\r
+    | relational_expression RIGHT_ANGLE shift_expression  {\r
+        $$ = parseContext.intermediate.addBinaryMath(EOpGreaterThan, $1, $3, $2.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.binaryOpError($2.line, ">", $1->getCompleteString(), $3->getCompleteString());\r
+            parseContext.recover();\r
+            constUnion *unionArray = new constUnion[1];\r
+            unionArray->setBConst(false);\r
+            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line);\r
+        }\r
+    }\r
+    | relational_expression LE_OP shift_expression  {\r
+        $$ = parseContext.intermediate.addBinaryMath(EOpLessThanEqual, $1, $3, $2.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.binaryOpError($2.line, "<=", $1->getCompleteString(), $3->getCompleteString());\r
+            parseContext.recover();\r
+            constUnion *unionArray = new constUnion[1];\r
+            unionArray->setBConst(false);\r
+            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line);\r
+        }\r
+    }\r
+    | relational_expression GE_OP shift_expression  {\r
+        $$ = parseContext.intermediate.addBinaryMath(EOpGreaterThanEqual, $1, $3, $2.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.binaryOpError($2.line, ">=", $1->getCompleteString(), $3->getCompleteString());\r
+            parseContext.recover();\r
+            constUnion *unionArray = new constUnion[1];\r
+            unionArray->setBConst(false);\r
+            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line);\r
+        }\r
+    }\r
+    ;\r
+\r
+equality_expression\r
+    : relational_expression { $$ = $1; }\r
+    | equality_expression EQ_OP relational_expression  {\r
+        $$ = parseContext.intermediate.addBinaryMath(EOpEqual, $1, $3, $2.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.binaryOpError($2.line, "==", $1->getCompleteString(), $3->getCompleteString());\r
+            parseContext.recover();\r
+            constUnion *unionArray = new constUnion[1];\r
+            unionArray->setBConst(false);\r
+            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line);\r
+        } else if (($1->isArray() || $3->isArray()) && parseContext.extensionErrorCheck($2.line, "GL_3DL_array_objects"))\r
+            parseContext.recover();\r
+    }\r
+    | equality_expression NE_OP relational_expression {\r
+        $$ = parseContext.intermediate.addBinaryMath(EOpNotEqual, $1, $3, $2.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.binaryOpError($2.line, "!=", $1->getCompleteString(), $3->getCompleteString());\r
+            parseContext.recover();\r
+            constUnion *unionArray = new constUnion[1];\r
+            unionArray->setBConst(false);\r
+            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line);\r
+        } else if (($1->isArray() || $3->isArray()) && parseContext.extensionErrorCheck($2.line, "GL_3DL_array_objects"))\r
+            parseContext.recover();\r
+    }\r
+    ;\r
+\r
+and_expression\r
+    : equality_expression { $$ = $1; }\r
+    | and_expression AMPERSAND equality_expression {\r
+        $$ = parseContext.intermediate.addBinaryMath(EOpAnd, $1, $3, $2.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.binaryOpError($2.line, "&", $1->getCompleteString(), $3->getCompleteString());\r
+            parseContext.recover();\r
+            $$ = $1;\r
+        }\r
+    }\r
+    ;\r
+\r
+exclusive_or_expression\r
+    : and_expression { $$ = $1; }\r
+    | exclusive_or_expression CARET and_expression {\r
+        $$ = parseContext.intermediate.addBinaryMath(EOpExclusiveOr, $1, $3, $2.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.binaryOpError($2.line, "^", $1->getCompleteString(), $3->getCompleteString());\r
+            parseContext.recover();\r
+            $$ = $1;\r
+        }\r
+    }\r
+    ;\r
+\r
+inclusive_or_expression\r
+    : exclusive_or_expression { $$ = $1; }\r
+    | inclusive_or_expression VERTICAL_BAR exclusive_or_expression {\r
+        $$ = parseContext.intermediate.addBinaryMath(EOpInclusiveOr, $1, $3, $2.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.binaryOpError($2.line, "|", $1->getCompleteString(), $3->getCompleteString());\r
+            parseContext.recover();\r
+            $$ = $1;\r
+        }\r
+    }\r
+    ;\r
+\r
+logical_and_expression\r
+    : inclusive_or_expression { $$ = $1; }\r
+    | logical_and_expression AND_OP inclusive_or_expression {\r
+        $$ = parseContext.intermediate.addBinaryMath(EOpLogicalAnd, $1, $3, $2.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.binaryOpError($2.line, "&&", $1->getCompleteString(), $3->getCompleteString());\r
+            parseContext.recover();\r
+            constUnion *unionArray = new constUnion[1];\r
+            unionArray->setBConst(false);\r
+            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line);\r
+        }\r
+    }\r
+    ;\r
+\r
+logical_xor_expression\r
+    : logical_and_expression { $$ = $1; }\r
+    | logical_xor_expression XOR_OP logical_and_expression  {\r
+        $$ = parseContext.intermediate.addBinaryMath(EOpLogicalXor, $1, $3, $2.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.binaryOpError($2.line, "^^", $1->getCompleteString(), $3->getCompleteString());\r
+            parseContext.recover();\r
+            constUnion *unionArray = new constUnion[1];\r
+            unionArray->setBConst(false);\r
+            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line);\r
+        }\r
+    }\r
+    ;\r
+\r
+logical_or_expression\r
+    : logical_xor_expression { $$ = $1; }\r
+    | logical_or_expression OR_OP logical_xor_expression  {\r
+        $$ = parseContext.intermediate.addBinaryMath(EOpLogicalOr, $1, $3, $2.line, parseContext.symbolTable);\r
+        if ($$ == 0) {\r
+            parseContext.binaryOpError($2.line, "||", $1->getCompleteString(), $3->getCompleteString());\r
+            parseContext.recover();\r
+            constUnion *unionArray = new constUnion[1];\r
+            unionArray->setBConst(false);\r
+            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line);\r
+        }\r
+    }\r
+    ;\r
+\r
+conditional_expression\r
+    : logical_or_expression { $$ = $1; }\r
+    | logical_or_expression QUESTION expression COLON assignment_expression {\r
+       if (parseContext.boolErrorCheck($2.line, $1))\r
+            parseContext.recover();\r
+\r
+        $$ = parseContext.intermediate.addSelection($1, $3, $5, $2.line);\r
+        if ($3->getType() != $5->getType())\r
+            $$ = 0;\r
+\r
+        if ($$ == 0) {\r
+            parseContext.binaryOpError($2.line, ":", $3->getCompleteString(), $5->getCompleteString());\r
+            parseContext.recover();\r
+            $$ = $5;\r
+        }\r
+    }\r
+    ;\r
+\r
+assignment_expression\r
+    : conditional_expression { $$ = $1; }\r
+    | unary_expression assignment_operator assignment_expression {\r
+        if (parseContext.lValueErrorCheck($2.line, "assign", $1))\r
+            parseContext.recover();\r
+        $$ = parseContext.intermediate.addAssign($2.op, $1, $3, $2.line);\r
+        if ($$ == 0) {\r
+            parseContext.assignError($2.line, "assign", $1->getCompleteString(), $3->getCompleteString());\r
+            parseContext.recover();\r
+            $$ = $1;\r
+        } else if (($1->isArray() || $3->isArray()) && parseContext.extensionErrorCheck($2.line, "GL_3DL_array_objects"))\r
+            parseContext.recover();\r
+    }\r
+    ;\r
+\r
+assignment_operator\r
+    : EQUAL        { $$.line = $1.line; $$.op = EOpAssign; }\r
+    | MUL_ASSIGN   { $$.line = $1.line; $$.op = EOpMulAssign; }\r
+    | DIV_ASSIGN   { $$.line = $1.line; $$.op = EOpDivAssign; }\r
+    | MOD_ASSIGN   { $$.line = $1.line; $$.op = EOpModAssign; }\r
+    | ADD_ASSIGN   { $$.line = $1.line; $$.op = EOpAddAssign; }\r
+    | SUB_ASSIGN   { $$.line = $1.line; $$.op = EOpSubAssign; }\r
+    | LEFT_ASSIGN  { $$.line = $1.line; $$.op = EOpLeftShiftAssign; }\r
+    | RIGHT_ASSIGN { $$.line = $1.line; $$.op = EOpRightShiftAssign; }\r
+    | AND_ASSIGN   { $$.line = $1.line; $$.op = EOpAndAssign; }\r
+    | XOR_ASSIGN   { $$.line = $1.line; $$.op = EOpExclusiveOrAssign; }\r
+    | OR_ASSIGN    { $$.line = $1.line; $$.op = EOpInclusiveOrAssign; }\r
+    ;\r
+\r
+expression\r
+    : assignment_expression {\r
+        $$ = $1;\r
+    }\r
+    | expression COMMA assignment_expression {\r
+        $$ = parseContext.intermediate.addComma($1, $3, $2.line);\r
+        if ($$ == 0) {\r
+            parseContext.binaryOpError($2.line, ",", $1->getCompleteString(), $3->getCompleteString());\r
+            parseContext.recover();\r
+            $$ = $3;\r
+        }\r
+    }\r
+    ;\r
+\r
+constant_expression\r
+    : conditional_expression {\r
+        if (parseContext.constErrorCheck($1))\r
+            parseContext.recover();\r
+        $$ = $1;\r
+    }\r
+    ;\r
+\r
+declaration\r
+    : function_prototype SEMICOLON {\r
+        $$ = 0;\r
+        // TODO: subroutines: make the identifier a user type for this signature\r
+    }\r
+    | init_declarator_list SEMICOLON {\r
+        if ($1.intermAggregate)\r
+            $1.intermAggregate->setOperator(EOpSequence);\r
+        $$ = $1.intermAggregate;\r
+    }\r
+    | PRECISION precision_qualifier type_specifier SEMICOLON {\r
+        $$ = 0;\r
+    }\r
+    | type_qualifier IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE SEMICOLON {\r
+        // block\r
+        $$ = 0;\r
+    }\r
+    | type_qualifier IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE IDENTIFIER SEMICOLON {\r
+        // block\r
+        $$ = 0;\r
+    }\r
+    | type_qualifier IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE IDENTIFIER LEFT_BRACKET RIGHT_BRACKET SEMICOLON {\r
+        // block\r
+        $$ = 0;\r
+    }\r
+    | type_qualifier IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET SEMICOLON {\r
+        // block\r
+        $$ = 0;\r
+    }\r
+    | type_qualifier SEMICOLON {\r
+        // setting defaults\r
+        $$ = 0;\r
+    }\r
+    | type_qualifier IDENTIFIER SEMICOLON {\r
+        // precise foo;\r
+        // invariant foo;\r
+        $$ = 0;\r
+    }\r
+    | type_qualifier IDENTIFIER identifier_list SEMICOLON {\r
+        // precise foo, bar;\r
+        // invariant foo, bar;\r
+        $$ = 0;\r
+    }\r
+    ;\r
+\r
+identifier_list\r
+    : COMMA IDENTIFIER {\r
+    }\r
+    | identifier_list COMMA IDENTIFIER {\r
+    }\r
+    ;\r
+\r
+function_prototype\r
+    : function_declarator RIGHT_PAREN  {\r
+        //\r
+        // Multiple declarations of the same function are allowed.\r
+        //\r
+        // If this is a definition, the definition production code will check for redefinitions\r
+        // (we don't know at this point if it's a definition or not).\r
+        //\r
+        // Redeclarations are allowed.  But, return types and parameter qualifiers must match.\r
+        //\r
+        TFunction* prevDec = static_cast<TFunction*>(parseContext.symbolTable.find($1->getMangledName()));\r
+        if (prevDec) {\r
+            if (prevDec->getReturnType() != $1->getReturnType()) {\r
+                parseContext.error($2.line, "overloaded functions must have the same return type", $1->getReturnType().getBasicString(), "");\r
+                parseContext.recover();\r
+            }\r
+            for (int i = 0; i < prevDec->getParamCount(); ++i) {\r
+                if ((*prevDec)[i].type->getQualifier() != (*$1)[i].type->getQualifier()) {\r
+                    parseContext.error($2.line, "overloaded functions must have the same parameter qualifiers", (*$1)[i].type->getQualifierString(), "");\r
+                    parseContext.recover();\r
+                }\r
+            }\r
+        }\r
+\r
+        //\r
+        // If this is a redeclaration, it could also be a definition,\r
+        // in which case, we want to use the variable names from this one, and not the one that's\r
+        // being redeclared.  So, pass back up this declaration, not the one in the symbol table.\r
+        //\r
+        $$.function = $1;\r
+        $$.line = $2.line;\r
+\r
+        parseContext.symbolTable.insert(*$$.function);\r
+    }\r
+    ;\r
+\r
+function_declarator\r
+    : function_header {\r
+        $$ = $1;\r
+    }\r
+    | function_header_with_parameters {\r
+        $$ = $1;\r
+    }\r
+    ;\r
+\r
+\r
+function_header_with_parameters\r
+    : function_header parameter_declaration {\r
+        // Add the parameter\r
+        $$ = $1;\r
+        if ($2.param.type->getBasicType() != EbtVoid)\r
+            $1->addParameter($2.param);\r
+        else\r
+            delete $2.param.type;\r
+    }\r
+    | function_header_with_parameters COMMA parameter_declaration {\r
+        //\r
+        // Only first parameter of one-parameter functions can be void\r
+        // The check for named parameters not being void is done in parameter_declarator\r
+        //\r
+        if ($3.param.type->getBasicType() == EbtVoid) {\r
+            //\r
+            // This parameter > first is void\r
+            //\r
+            parseContext.error($2.line, "cannot be an argument type except for '(void)'", "void", "");\r
+            parseContext.recover();\r
+            delete $3.param.type;\r
+        } else {\r
+            // Add the parameter\r
+            $$ = $1;\r
+            $1->addParameter($3.param);\r
+        }\r
+    }\r
+    ;\r
+\r
+function_header\r
+    : fully_specified_type IDENTIFIER LEFT_PAREN {\r
+        if ($1.qualifier != EvqGlobal && $1.qualifier != EvqTemporary) {\r
+            parseContext.error($2.line, "no qualifiers allowed for function return", getQualifierString($1.qualifier), "");\r
+            parseContext.recover();\r
+        }\r
+        // make sure a sampler is not involved as well...\r
+        if (parseContext.structQualifierErrorCheck($2.line, $1))\r
+            parseContext.recover();\r
+\r
+        // Add the function as a prototype after parsing it (we do not support recursion)\r
+        TFunction *function;\r
+        TType type($1);\r
+        function = new TFunction($2.string, type);\r
+        $$ = function;\r
+    }\r
+    ;\r
+\r
+parameter_declarator\r
+    // Type + name\r
+    : type_specifier IDENTIFIER {\r
+        if ($1.type == EbtVoid) {\r
+            parseContext.error($2.line, "illegal use of type 'void'", $2.string->c_str(), "");\r
+            parseContext.recover();\r
+        }\r
+        if (parseContext.reservedErrorCheck($2.line, *$2.string))\r
+            parseContext.recover();\r
+        TParameter param = {$2.string, new TType($1)};\r
+        $$.line = $2.line;\r
+        $$.param = param;\r
+    }\r
+    | type_specifier IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET {\r
+        // Check that we can make an array out of this type\r
+        if (parseContext.arrayTypeErrorCheck($3.line, $1))\r
+            parseContext.recover();\r
+\r
+        if (parseContext.reservedErrorCheck($2.line, *$2.string))\r
+            parseContext.recover();\r
+\r
+        int size;\r
+        if (parseContext.arraySizeErrorCheck($3.line, $4, size))\r
+            parseContext.recover();\r
+        $1.setArray(true, size);\r
+\r
+        TParameter param = { $2.string, new TType($1)};\r
+        $$.line = $2.line;\r
+        $$.param = param;\r
+    }\r
+    ;\r
+\r
+parameter_declaration\r
+    //\r
+    // With name\r
+    //\r
+    : type_qualifier parameter_declarator {\r
+        $$ = $2;\r
+\r
+        if (parseContext.parameterSamplerErrorCheck($2.line, $1.qualifier, *$2.param.type))\r
+            parseContext.recover();\r
+        if (parseContext.paramErrorCheck($1.line, $1.qualifier, $$.param.type))\r
+            parseContext.recover();\r
+    }\r
+    | parameter_declarator {\r
+        $$ = $1;\r
+\r
+        if (parseContext.parameterSamplerErrorCheck($1.line, EvqIn, *$1.param.type))\r
+            parseContext.recover();\r
+        if (parseContext.paramErrorCheck($1.line, EvqTemporary, $$.param.type))\r
+            parseContext.recover();\r
+    }\r
+    //\r
+    // Without name\r
+    //\r
+    | type_qualifier parameter_type_specifier {\r
+        $$ = $2;\r
+        \r
+        if (parseContext.parameterSamplerErrorCheck($2.line, $1.qualifier, *$2.param.type))\r
+            parseContext.recover();\r
+        if (parseContext.paramErrorCheck($1.line, $1.qualifier, $$.param.type))\r
+            parseContext.recover();\r
+    }\r
+    | parameter_type_specifier {\r
+        $$ = $1;\r
+\r
+        if (parseContext.parameterSamplerErrorCheck($1.line, $1.qualifier, *$1.param.type))\r
+            parseContext.recover();\r
+        if (parseContext.paramErrorCheck($1.line, EvqTemporary, $$.param.type))\r
+            parseContext.recover();\r
+    }\r
+    ;\r
+\r
+parameter_type_specifier\r
+    : type_specifier {\r
+        TParameter param = { 0, new TType($1) };\r
+        $$.param = param;\r
+    }\r
+    ;\r
+\r
+init_declarator_list\r
+    : single_declaration {\r
+        $$ = $1;\r
+    }\r
+    | init_declarator_list COMMA IDENTIFIER {\r
+        $$ = $1;\r
+        if (parseContext.structQualifierErrorCheck($3.line, $$.type))\r
+            parseContext.recover();\r
+\r
+        if (parseContext.nonInitConstErrorCheck($3.line, *$3.string, $$.type))\r
+            parseContext.recover();\r
+\r
+        if (parseContext.nonInitErrorCheck($3.line, *$3.string, $$.type))\r
+            parseContext.recover();\r
+    }\r
+    | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET RIGHT_BRACKET {\r
+        if (parseContext.structQualifierErrorCheck($3.line, $1.type))\r
+            parseContext.recover();\r
+\r
+        if (parseContext.nonInitConstErrorCheck($3.line, *$3.string, $1.type))\r
+            parseContext.recover();\r
+\r
+        $$ = $1;\r
+\r
+        if (parseContext.arrayTypeErrorCheck($4.line, $1.type) || parseContext.arrayQualifierErrorCheck($4.line, $1.type))\r
+            parseContext.recover();\r
+        else {\r
+            $1.type.setArray(true);\r
+            TVariable* variable;\r
+            if (parseContext.arrayErrorCheck($4.line, *$3.string, $1.type, variable))\r
+                parseContext.recover();\r
+        }\r
+    }\r
+    | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET {\r
+        if (parseContext.structQualifierErrorCheck($3.line, $1.type))\r
+            parseContext.recover();\r
+\r
+        if (parseContext.nonInitConstErrorCheck($3.line, *$3.string, $1.type))\r
+            parseContext.recover();\r
+\r
+        $$ = $1;\r
+\r
+        if (parseContext.arrayTypeErrorCheck($4.line, $1.type) || parseContext.arrayQualifierErrorCheck($4.line, $1.type))\r
+            parseContext.recover();\r
+        else {\r
+            int size;\r
+            if (parseContext.arraySizeErrorCheck($4.line, $5, size))\r
+                parseContext.recover();\r
+            $1.type.setArray(true, size);\r
+            TVariable* variable;\r
+            if (parseContext.arrayErrorCheck($4.line, *$3.string, $1.type, variable))\r
+                parseContext.recover();\r
+        }\r
+    }\r
+    | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET RIGHT_BRACKET EQUAL initializer {\r
+        if (parseContext.structQualifierErrorCheck($3.line, $1.type))\r
+            parseContext.recover();\r
+\r
+        $$ = $1;\r
+\r
+        TVariable* variable = 0;\r
+        if (parseContext.arrayTypeErrorCheck($4.line, $1.type) || parseContext.arrayQualifierErrorCheck($4.line, $1.type))\r
+            parseContext.recover();\r
+        else {\r
+            $1.type.setArray(true, $7->getType().getArraySize());\r
+            if (parseContext.arrayErrorCheck($4.line, *$3.string, $1.type, variable))\r
+                parseContext.recover();\r
+        }\r
+\r
+        if (parseContext.extensionErrorCheck($$.line, "GL_3DL_array_objects"))\r
+            parseContext.recover();\r
+        else {\r
+            TIntermNode* intermNode;\r
+            if (!parseContext.executeInitializer($3.line, *$3.string, $1.type, $7, intermNode, variable)) {\r
+                //\r
+                // build the intermediate representation\r
+                //\r
+                if (intermNode)\r
+                    $$.intermAggregate = parseContext.intermediate.growAggregate($1.intermNode, intermNode, $6.line);\r
+                else\r
+                    $$.intermAggregate = $1.intermAggregate;\r
+            } else {\r
+                parseContext.recover();\r
+                $$.intermAggregate = 0;\r
+            }\r
+        }\r
+    }\r
+    | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer {\r
+        if (parseContext.structQualifierErrorCheck($3.line, $1.type))\r
+            parseContext.recover();\r
+\r
+        $$ = $1;\r
+\r
+        TVariable* variable = 0;\r
+        if (parseContext.arrayTypeErrorCheck($4.line, $1.type) || parseContext.arrayQualifierErrorCheck($4.line, $1.type))\r
+            parseContext.recover();\r
+        else {\r
+            int size;\r
+            if (parseContext.arraySizeErrorCheck($4.line, $5, size))\r
+                parseContext.recover();\r
+            $1.type.setArray(true, size);\r
+            if (parseContext.arrayErrorCheck($4.line, *$3.string, $1.type, variable))\r
+                parseContext.recover();\r
+        }\r
+\r
+        if (parseContext.extensionErrorCheck($$.line, "GL_3DL_array_objects"))\r
+            parseContext.recover();\r
+        else {\r
+            TIntermNode* intermNode;\r
+            if (!parseContext.executeInitializer($3.line, *$3.string, $1.type, $8, intermNode, variable)) {\r
+                //\r
+                // build the intermediate representation\r
+                //\r
+                if (intermNode)\r
+                    $$.intermAggregate = parseContext.intermediate.growAggregate($1.intermNode, intermNode, $7.line);\r
+                else\r
+                    $$.intermAggregate = $1.intermAggregate;\r
+            } else {\r
+                parseContext.recover();\r
+                $$.intermAggregate = 0;\r
+            }\r
+        }\r
+    }\r
+    | init_declarator_list COMMA IDENTIFIER EQUAL initializer {\r
+        if (parseContext.structQualifierErrorCheck($3.line, $1.type))\r
+            parseContext.recover();\r
+\r
+        $$ = $1;\r
+\r
+        TIntermNode* intermNode;\r
+        if (!parseContext.executeInitializer($3.line, *$3.string, $1.type, $5, intermNode)) {\r
+            //\r
+            // build the intermediate representation\r
+            //\r
+            if (intermNode)\r
+                $$.intermAggregate = parseContext.intermediate.growAggregate($1.intermNode, intermNode, $4.line);\r
+            else\r
+                $$.intermAggregate = $1.intermAggregate;\r
+        } else {\r
+            parseContext.recover();\r
+            $$.intermAggregate = 0;\r
+        }\r
+    }\r
+    ;\r
+\r
+single_declaration\r
+    : fully_specified_type {\r
+        $$.type = $1;\r
+        $$.intermAggregate = 0;\r
+    }\r
+    | fully_specified_type IDENTIFIER {\r
+        $$.intermAggregate = 0;\r
+\r
+        if (parseContext.globalQualifierFixAndErrorCheck($1.line, $1.qualifier))\r
+            parseContext.recover();\r
+\r
+        $$.type = $1;\r
+\r
+        if (parseContext.structQualifierErrorCheck($2.line, $$.type))\r
+            parseContext.recover();\r
+\r
+        if (parseContext.nonInitConstErrorCheck($2.line, *$2.string, $$.type))\r
+            parseContext.recover();\r
+\r
+        if (parseContext.nonInitErrorCheck($2.line, *$2.string, $$.type))\r
+            parseContext.recover();\r
+    }\r
+    | fully_specified_type IDENTIFIER LEFT_BRACKET RIGHT_BRACKET {\r
+        $$.intermAggregate = 0;\r
+        if (parseContext.structQualifierErrorCheck($2.line, $1))\r
+            parseContext.recover();\r
+\r
+        if (parseContext.nonInitConstErrorCheck($2.line, *$2.string, $1))\r
+            parseContext.recover();\r
+\r
+        $$.type = $1;\r
+\r
+        if (parseContext.arrayTypeErrorCheck($3.line, $1) || parseContext.arrayQualifierErrorCheck($3.line, $1))\r
+            parseContext.recover();\r
+        else {\r
+            $1.setArray(true);\r
+            TVariable* variable;\r
+            if (parseContext.arrayErrorCheck($3.line, *$2.string, $1, variable))\r
+                parseContext.recover();\r
+        }\r
+    }\r
+    | fully_specified_type IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET {\r
+        $$.intermAggregate = 0;\r
+        if (parseContext.structQualifierErrorCheck($2.line, $1))\r
+            parseContext.recover();\r
+\r
+        if (parseContext.nonInitConstErrorCheck($2.line, *$2.string, $1))\r
+            parseContext.recover();\r
+\r
+        $$.type = $1;\r
+\r
+        if (parseContext.arrayTypeErrorCheck($3.line, $1) || parseContext.arrayQualifierErrorCheck($3.line, $1))\r
+            parseContext.recover();\r
+        else {\r
+            int size;\r
+            if (parseContext.arraySizeErrorCheck($3.line, $4, size))\r
+                parseContext.recover();\r
+\r
+            $1.setArray(true, size);\r
+            TVariable* variable;\r
+            if (parseContext.arrayErrorCheck($3.line, *$2.string, $1, variable))\r
+                parseContext.recover();\r
+        }\r
+    }\r
+    | fully_specified_type IDENTIFIER LEFT_BRACKET RIGHT_BRACKET EQUAL initializer {\r
+        $$.intermAggregate = 0;\r
+\r
+        if (parseContext.structQualifierErrorCheck($2.line, $1))\r
+            parseContext.recover();\r
+\r
+        $$.type = $1;\r
+\r
+        TVariable* variable = 0;\r
+        if (parseContext.arrayTypeErrorCheck($3.line, $1) || parseContext.arrayQualifierErrorCheck($3.line, $1))\r
+            parseContext.recover();\r
+        else {\r
+            $1.setArray(true, $6->getType().getArraySize());\r
+            if (parseContext.arrayErrorCheck($3.line, *$2.string, $1, variable))\r
+                parseContext.recover();\r
+        }\r
+\r
+        if (parseContext.extensionErrorCheck($$.line, "GL_3DL_array_objects"))\r
+            parseContext.recover();\r
+        else {\r
+            TIntermNode* intermNode;\r
+            if (!parseContext.executeInitializer($2.line, *$2.string, $1, $6, intermNode, variable)) {\r
+                //\r
+                // Build intermediate representation\r
+                //\r
+                if (intermNode)\r
+                    $$.intermAggregate = parseContext.intermediate.makeAggregate(intermNode, $5.line);\r
+                else\r
+                    $$.intermAggregate = 0;\r
+            } else {\r
+                parseContext.recover();\r
+                $$.intermAggregate = 0;\r
+            }\r
+        }\r
+    }\r
+    | fully_specified_type IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer {\r
+        $$.intermAggregate = 0;\r
+\r
+        if (parseContext.structQualifierErrorCheck($2.line, $1))\r
+            parseContext.recover();\r
+\r
+        $$.type = $1;\r
+\r
+        TVariable* variable = 0;\r
+        if (parseContext.arrayTypeErrorCheck($3.line, $1) || parseContext.arrayQualifierErrorCheck($3.line, $1))\r
+            parseContext.recover();\r
+        else {\r
+            int size;\r
+            if (parseContext.arraySizeErrorCheck($3.line, $4, size))\r
+                parseContext.recover();\r
+\r
+            $1.setArray(true, size);\r
+            if (parseContext.arrayErrorCheck($3.line, *$2.string, $1, variable))\r
+                parseContext.recover();\r
+        }\r
+\r
+        if (parseContext.extensionErrorCheck($$.line, "GL_3DL_array_objects"))\r
+            parseContext.recover();\r
+        else {\r
+            TIntermNode* intermNode;\r
+            if (!parseContext.executeInitializer($2.line, *$2.string, $1, $7, intermNode, variable)) {\r
+                //\r
+                // Build intermediate representation\r
+                //\r
+                if (intermNode)\r
+                    $$.intermAggregate = parseContext.intermediate.makeAggregate(intermNode, $6.line);\r
+                else\r
+                    $$.intermAggregate = 0;\r
+            } else {\r
+                parseContext.recover();\r
+                $$.intermAggregate = 0;\r
+            }\r
+        }\r
+    }\r
+    | fully_specified_type IDENTIFIER EQUAL initializer {\r
+        if (parseContext.structQualifierErrorCheck($2.line, $1))\r
+            parseContext.recover();\r
+\r
+        $$.type = $1;\r
+\r
+        TIntermNode* intermNode;\r
+        if (!parseContext.executeInitializer($2.line, *$2.string, $1, $4, intermNode)) {\r
+            //\r
+            // Build intermediate representation\r
+            //\r
+            if (intermNode)\r
+                $$.intermAggregate = parseContext.intermediate.makeAggregate(intermNode, $3.line);\r
+            else\r
+                $$.intermAggregate = 0;\r
+        } else {\r
+            parseContext.recover();\r
+            $$.intermAggregate = 0;\r
+        }\r
+    }\r
+\r
+// Grammar Note:  No 'enum', or 'typedef'.\r
+\r
+fully_specified_type\r
+    : type_specifier {\r
+        $$ = $1;\r
+\r
+        if ($1.array) {\r
+            if (parseContext.extensionErrorCheck($1.line, "GL_3DL_array_objects")) {\r
+                parseContext.recover();\r
+                $1.setArray(false);\r
+            }\r
+        }\r
+    }\r
+    | type_qualifier type_specifier  {\r
+        if ($2.array && parseContext.extensionErrorCheck($2.line, "GL_3DL_array_objects")) {\r
+            parseContext.recover();\r
+            $2.setArray(false);\r
+        }\r
+        if ($2.array && parseContext.arrayQualifierErrorCheck($2.line, $1)) {\r
+            parseContext.recover();\r
+            $2.setArray(false);\r
+        }\r
+\r
+        if ($1.qualifier == EvqAttribute &&\r
+            ($2.type == EbtBool || $2.type == EbtInt)) {\r
+            parseContext.error($2.line, "cannot be bool or int", getQualifierString($1.qualifier), "");\r
+            parseContext.recover();\r
+        }\r
+        if (($1.qualifier == EvqVaryingIn || $1.qualifier == EvqVaryingOut) &&\r
+            ($2.type == EbtBool || $2.type == EbtInt)) {\r
+            parseContext.error($2.line, "cannot be bool or int", getQualifierString($1.qualifier), "");\r
+            parseContext.recover();\r
+        }\r
+        $$ = $2;\r
+        $$.qualifier = $1.qualifier;\r
+    }\r
+    ;\r
+\r
+invariant_qualifier\r
+    : INVARIANT {\r
+    }\r
+    ;\r
+\r
+interpolation_qualifier\r
+    : SMOOTH {\r
+    }\r
+    | FLAT {\r
+    }\r
+    | NOPERSPECTIVE {\r
+    }\r
+    ;\r
+\r
+layout_qualifier\r
+    : LAYOUT LEFT_PAREN layout_qualifier_id_list RIGHT_PAREN {\r
+    }\r
+    ;\r
+\r
+layout_qualifier_id_list\r
+    : layout_qualifier_id {\r
+    }\r
+    | layout_qualifier_id_list COMMA layout_qualifier_id {\r
+    }\r
+\r
+layout_qualifier_id\r
+    : IDENTIFIER {\r
+    }\r
+    | IDENTIFIER EQUAL INTCONSTANT {\r
+    }\r
+    ;\r
+\r
+precise_qualifier\r
+    : PRECISE {\r
+    }\r
+    ;\r
+\r
+type_qualifier\r
+    : single_type_qualifier {\r
+        $$ = $1;\r
+    }\r
+    | type_qualifier single_type_qualifier {\r
+        $$ = $1;\r
+        // TODO: merge qualifiers in $1 and $2 and check for duplication\r
+\r
+        if ($$.type == EbtVoid) {\r
+            $$.type = $2.type;\r
+        }\r
+\r
+        if ($$.qualifier == EvqTemporary) {\r
+            $$.qualifier = $2.qualifier;\r
+        } else if ($$.qualifier == EvqIn  && $2.qualifier == EvqOut ||\r
+                   $$.qualifier == EvqOut && $2.qualifier == EvqIn) {\r
+            $$.qualifier = EvqInOut;\r
+        } else if ($$.qualifier == EvqIn    && $2.qualifier == EvqConst ||\r
+                   $$.qualifier == EvqConst && $2.qualifier == EvqIn) {\r
+            $$.qualifier = EvqConstReadOnly;\r
+        }\r
+    }\r
+    ;\r
+\r
+single_type_qualifier\r
+    : storage_qualifier {\r
+        $$ = $1;\r
+    }\r
+    | layout_qualifier {\r
+        $$ = $1;\r
+    }\r
+    | precision_qualifier {\r
+        $$ = $1;\r
+    }\r
+    | interpolation_qualifier {\r
+        // allow inheritance of storage qualifier from block declaration\r
+        $$ = $1;\r
+    }\r
+    | invariant_qualifier {\r
+        // allow inheritance of storage qualifier from block declaration\r
+        $$ = $1;\r
+    }\r
+    | precise_qualifier {\r
+        // allow inheritance of storage qualifier from block declaration\r
+        $$ = $1;\r
+    }\r
+    ;\r
+\r
+storage_qualifier\r
+    : CONST {\r
+        $$.setBasic(EbtVoid, EvqConst, $1.line);\r
+    }\r
+    | ATTRIBUTE {\r
+        VERTEX_ONLY("attribute", $1.line);\r
+        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "attribute"))\r
+            parseContext.recover();\r
+        $$.setBasic(EbtVoid, EvqAttribute, $1.line);\r
+    }\r
+    | VARYING {\r
+        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "varying"))\r
+            parseContext.recover();\r
+        if (parseContext.language == EShLangVertex)\r
+            $$.setBasic(EbtVoid, EvqVaryingOut, $1.line);\r
+        else\r
+            $$.setBasic(EbtVoid, EvqVaryingIn, $1.line);\r
+    }\r
+    | INOUT {\r
+        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "out"))\r
+            parseContext.recover();\r
+        $$.setBasic(EbtVoid, EvqInOut, $1.line);\r
+    }\r
+    | IN {\r
+        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "in"))\r
+            parseContext.recover();\r
+        $$.setBasic(EbtVoid, EvqIn, $1.line);\r
+    }\r
+    | OUT {\r
+        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "out"))\r
+            parseContext.recover();\r
+        $$.setBasic(EbtVoid, EvqOut, $1.line);\r
+    }\r
+    | CENTROID {\r
+        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "centroid"))\r
+            parseContext.recover();\r
+        $$.setBasic(EbtVoid, EvqVaryingIn, $1.line);\r
+    }\r
+    | PATCH {\r
+        // TODO: implement this qualifier\r
+        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "patch"))\r
+            parseContext.recover();\r
+        $$.setBasic(EbtVoid, EvqUniform, $1.line);\r
+    }\r
+    | SAMPLE {\r
+        // TODO: implement this qualifier\r
+        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "sample"))\r
+            parseContext.recover();\r
+        $$.setBasic(EbtVoid, EvqUniform, $1.line);\r
+    }\r
+    | UNIFORM {\r
+        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "uniform"))\r
+            parseContext.recover();\r
+        $$.setBasic(EbtVoid, EvqUniform, $1.line);\r
+    }\r
+    | COHERENT {\r
+        // TODO: implement this qualifier\r
+        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "coherent"))\r
+            parseContext.recover();\r
+        $$.setBasic(EbtVoid, EvqUniform, $1.line);\r
+    }\r
+    | VOLATILE {\r
+        // TODO: implement this qualifier\r
+        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "volatile"))\r
+            parseContext.recover();\r
+        $$.setBasic(EbtVoid, EvqUniform, $1.line);\r
+    }\r
+    | RESTRICT {\r
+        // TODO: implement this qualifier\r
+        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "restrict"))\r
+            parseContext.recover();\r
+        $$.setBasic(EbtVoid, EvqUniform, $1.line);\r
+    }\r
+    | READONLY {\r
+        // TODO: implement this qualifier\r
+        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "readonly"))\r
+            parseContext.recover();\r
+        $$.setBasic(EbtVoid, EvqUniform, $1.line);\r
+    }\r
+    | WRITEONLY {\r
+        // TODO: implement this qualifier\r
+        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "writeonly"))\r
+            parseContext.recover();\r
+        $$.setBasic(EbtVoid, EvqUniform, $1.line);\r
+    }\r
+    | SUBROUTINE {\r
+        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "subroutine"))\r
+            parseContext.recover();\r
+        $$.setBasic(EbtVoid, EvqUniform, $1.line);\r
+    }\r
+    | SUBROUTINE LEFT_PAREN type_name_list RIGHT_PAREN {\r
+        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "subroutine"))\r
+            parseContext.recover();\r
+        $$.setBasic(EbtVoid, EvqUniform, $1.line);\r
+        // TODO: subroutine semantics\r
+        // 1) make sure each identifier is a type declared earlier with SUBROUTINE\r
+        // 2) save all of the identifiers for future comparison with the declared function\r
+    }\r
+    ;\r
+\r
+type_name_list\r
+    : TYPE_NAME {\r
+        // TODO: add subroutine type to list\r
+    }\r
+    | type_name_list COMMA TYPE_NAME {\r
+        // TODO: add subroutine type to list\r
+    }\r
+    ;\r
+\r
+type_specifier\r
+    : type_specifier_nonarray {\r
+        $$ = $1;\r
+    }\r
+    | type_specifier_nonarray LEFT_BRACKET RIGHT_BRACKET {\r
+        $$ = $1;\r
+    }\r
+    | type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET {\r
+        $$ = $1;\r
+\r
+        if (parseContext.arrayTypeErrorCheck($2.line, $1))\r
+            parseContext.recover();\r
+        else {\r
+            int size;\r
+            if (parseContext.arraySizeErrorCheck($2.line, $3, size))\r
+                parseContext.recover();\r
+            $$.setArray(true, size);\r
+        }\r
+    }\r
+    ;\r
+\r
+type_specifier_nonarray\r
+    : VOID {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtVoid, qual, $1.line);\r
+    }\r
+    | FLOAT {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+    }\r
+    | DOUBLE {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        // TODO: implement EbtDouble, check all float types\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+    }\r
+    | INT {\r
+        // TODO: implement EbtUint, check all int types\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtInt, qual, $1.line);\r
+    }\r
+    | UINT {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtInt, qual, $1.line);\r
+    }\r
+    | BOOL {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtBool, qual, $1.line);\r
+    }\r
+    | VEC2 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(2);\r
+    }\r
+    | VEC3 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(3);\r
+    }\r
+    | VEC4 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4);\r
+    }\r
+    | DVEC2 {\r
+    }\r
+    | DVEC3 {\r
+    }\r
+    | DVEC4 {\r
+    }\r
+    | BVEC2 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtBool, qual, $1.line);\r
+        $$.setAggregate(2);\r
+    }\r
+    | BVEC3 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtBool, qual, $1.line);\r
+        $$.setAggregate(3);\r
+    }\r
+    | BVEC4 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtBool, qual, $1.line);\r
+        $$.setAggregate(4);\r
+    }\r
+    | IVEC2 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtInt, qual, $1.line);\r
+        $$.setAggregate(2);\r
+    }\r
+    | IVEC3 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtInt, qual, $1.line);\r
+        $$.setAggregate(3);\r
+    }\r
+    | IVEC4 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtInt, qual, $1.line);\r
+        $$.setAggregate(4);\r
+    }\r
+    | UVEC2 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtInt, qual, $1.line);\r
+        $$.setAggregate(2);\r
+    }\r
+    | UVEC3 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtInt, qual, $1.line);\r
+        $$.setAggregate(3);\r
+    }\r
+    | UVEC4 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtInt, qual, $1.line);\r
+        $$.setAggregate(4);\r
+    }\r
+    | MAT2 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(2, true);\r
+    }\r
+    | MAT3 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(3, true);\r
+    }\r
+    | MAT4 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4, true);\r
+    }\r
+    | MAT2X2 {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4, true);\r
+    }\r
+    | MAT2X3 {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4, true);\r
+    }\r
+    | MAT2X4 {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4, true);\r
+    }\r
+    | MAT3X2 {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4, true);\r
+    }\r
+    | MAT3X3 {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4, true);\r
+    }\r
+    | MAT3X4 {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4, true);\r
+    }\r
+    | MAT4X2 {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4, true);\r
+    }\r
+    | MAT4X3 {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4, true);\r
+    }\r
+    | MAT4X4 {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4, true);\r
+    }\r
+    | DMAT2 {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4, true);\r
+    }\r
+    | DMAT3 {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4, true);\r
+    }\r
+    | DMAT4 {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4, true);\r
+    }\r
+    | DMAT2X2 {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4, true);\r
+    }\r
+    | DMAT2X3 {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4, true);\r
+    }\r
+    | DMAT2X4 {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4, true);\r
+    }\r
+    | DMAT3X2 {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4, true);\r
+    }\r
+    | DMAT3X3 {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4, true);\r
+    }\r
+    | DMAT3X4 {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4, true);\r
+    }\r
+    | DMAT4X2 {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4, true);\r
+    }\r
+    | DMAT4X3 {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4, true);\r
+    }\r
+    | DMAT4X4 {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtFloat, qual, $1.line);\r
+        $$.setAggregate(4, true);\r
+    }\r
+    | ATOMIC_UINT {\r
+        // TODO: add type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtInt, qual, $1.line);\r
+    }\r
+    | SAMPLER1D {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler1D, qual, $1.line);\r
+    }\r
+    | SAMPLER2D {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | SAMPLER3D {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler3D, qual, $1.line);\r
+    }\r
+    | SAMPLERCUBE {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSamplerCube, qual, $1.line);\r
+    }\r
+    | SAMPLER1DSHADOW {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler1DShadow, qual, $1.line);\r
+    }\r
+    | SAMPLER2DSHADOW {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2DShadow, qual, $1.line);\r
+    }\r
+    | SAMPLERCUBESHADOW {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2DShadow, qual, $1.line);\r
+    }\r
+    | SAMPLER1DARRAY {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2DShadow, qual, $1.line);\r
+    }\r
+    | SAMPLER2DARRAY {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2DShadow, qual, $1.line);\r
+    }\r
+    | SAMPLER1DARRAYSHADOW {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2DShadow, qual, $1.line);\r
+    }\r
+    | SAMPLER2DARRAYSHADOW {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2DShadow, qual, $1.line);\r
+    }\r
+    | SAMPLERCUBEARRAY {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2DShadow, qual, $1.line);\r
+    }\r
+    | SAMPLERCUBEARRAYSHADOW {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2DShadow, qual, $1.line);\r
+    }\r
+    | ISAMPLER1D {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2DShadow, qual, $1.line);\r
+    }\r
+    | ISAMPLER2D {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2DShadow, qual, $1.line);\r
+    }\r
+    | ISAMPLER3D {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2DShadow, qual, $1.line);\r
+    }\r
+    | ISAMPLERCUBE {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2DShadow, qual, $1.line);\r
+    }\r
+    | ISAMPLER1DARRAY {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2DShadow, qual, $1.line);\r
+    }\r
+    | ISAMPLER2DARRAY {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2DShadow, qual, $1.line);\r
+    }\r
+    | ISAMPLERCUBEARRAY {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2DShadow, qual, $1.line);\r
+    }\r
+    | USAMPLER1D {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2DShadow, qual, $1.line);\r
+    }\r
+    | USAMPLER2D {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2DShadow, qual, $1.line);\r
+    }\r
+    | USAMPLER3D {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2DShadow, qual, $1.line);\r
+    }\r
+    | USAMPLERCUBE {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2DShadow, qual, $1.line);\r
+    }\r
+    | USAMPLER1DARRAY {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2DShadow, qual, $1.line);\r
+    }\r
+    | USAMPLER2DARRAY {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2DShadow, qual, $1.line);\r
+    }\r
+    | USAMPLERCUBEARRAY {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2DShadow, qual, $1.line);\r
+    }\r
+    | SAMPLER2DRECT {\r
+        if (parseContext.extensionErrorCheck($1.line, "GL_ARB_texture_rectangle"))\r
+            parseContext.recover();\r
+\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSamplerRect, qual, $1.line);\r
+    }\r
+    | SAMPLER2DRECTSHADOW {\r
+        if (parseContext.extensionErrorCheck($1.line, "GL_ARB_texture_rectangle"))\r
+            parseContext.recover();\r
+\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSamplerRectShadow, qual, $1.line);\r
+    }\r
+    | ISAMPLER2DRECT {\r
+        if (parseContext.extensionErrorCheck($1.line, "GL_ARB_texture_rectangle"))\r
+            parseContext.recover();\r
+\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSamplerRect, qual, $1.line);\r
+    }\r
+    | USAMPLER2DRECT {\r
+        if (parseContext.extensionErrorCheck($1.line, "GL_ARB_texture_rectangle"))\r
+            parseContext.recover();\r
+\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSamplerRect, qual, $1.line);\r
+    }\r
+    | SAMPLERBUFFER {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | ISAMPLERBUFFER {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | USAMPLERBUFFER {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | SAMPLER2DMS {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | ISAMPLER2DMS {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | USAMPLER2DMS {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | SAMPLER2DMSARRAY {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | ISAMPLER2DMSARRAY {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | USAMPLER2DMSARRAY {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | IMAGE1D {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | IIMAGE1D {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | UIMAGE1D {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | IMAGE2D {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | IIMAGE2D {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | UIMAGE2D {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | IMAGE3D {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | IIMAGE3D {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | UIMAGE3D {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | IMAGE2DRECT {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | IIMAGE2DRECT {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | UIMAGE2DRECT {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | IMAGECUBE {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | IIMAGECUBE {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | UIMAGECUBE {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | IMAGEBUFFER {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | IIMAGEBUFFER {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | UIMAGEBUFFER {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | IMAGE1DARRAY {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | IIMAGE1DARRAY {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | UIMAGE1DARRAY {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | IMAGE2DARRAY {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | IIMAGE2DARRAY {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | UIMAGE2DARRAY {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | IMAGECUBEARRAY {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | IIMAGECUBEARRAY {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | UIMAGECUBEARRAY {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | IMAGE2DMS {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | IIMAGE2DMS {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | UIMAGE2DMS {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | IMAGE2DMSARRAY {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | IIMAGE2DMSARRAY {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | UIMAGE2DMSARRAY {\r
+        // TODO: implement this type\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtSampler2D, qual, $1.line);\r
+    }\r
+    | struct_specifier {\r
+        $$ = $1;\r
+        $$.qualifier = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+    }\r
+    | TYPE_NAME {\r
+        //\r
+        // This is for user defined type names.  The lexical phase looked up the\r
+        // type.\r
+        //\r
+        TType& structure = static_cast<TVariable*>($1.symbol)->getType();\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        $$.setBasic(EbtStruct, qual, $1.line);\r
+        $$.userDef = &structure;\r
+    }\r
+    ;\r
+\r
+precision_qualifier\r
+    : HIGH_PRECISION {\r
+    }\r
+    | MEDIUM_PRECISION {\r
+    }\r
+    | LOW_PRECISION {\r
+    }\r
+    ;\r
+\r
+struct_specifier\r
+    : STRUCT IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE {\r
+        TType* structure = new TType($4, *$2.string);\r
+        TVariable* userTypeDef = new TVariable($2.string, *structure, true);\r
+        if (! parseContext.symbolTable.insert(*userTypeDef)) {\r
+            parseContext.error($2.line, "redefinition", $2.string->c_str(), "struct");\r
+            parseContext.recover();\r
+        }\r
+        $$.setBasic(EbtStruct, EvqTemporary, $1.line);\r
+        $$.userDef = structure;\r
+    }\r
+    | STRUCT LEFT_BRACE struct_declaration_list RIGHT_BRACE {\r
+        TType* structure = new TType($3, TString(""));\r
+        $$.setBasic(EbtStruct, EvqTemporary, $1.line);\r
+        $$.userDef = structure;\r
+    }\r
+    ;\r
+\r
+struct_declaration_list\r
+    : struct_declaration {\r
+        $$ = $1;\r
+    }\r
+    | struct_declaration_list struct_declaration {\r
+        $$ = $1;\r
+        for (unsigned int i = 0; i < $2->size(); ++i) {\r
+            for (unsigned int j = 0; j < $$->size(); ++j) {\r
+                if ((*$$)[j].type->getFieldName() == (*$2)[i].type->getFieldName()) {\r
+                    parseContext.error((*$2)[i].line, "duplicate field name in structure:", "struct", (*$2)[i].type->getFieldName().c_str());\r
+                    parseContext.recover();\r
+                }\r
+            }\r
+            $$->push_back((*$2)[i]);\r
+        }\r
+    }\r
+    ;\r
+\r
+struct_declaration\r
+    : type_specifier struct_declarator_list SEMICOLON {\r
+        $$ = $2;\r
+\r
+        if (parseContext.voidErrorCheck($1.line, (*$2)[0].type->getFieldName(), $1)) {\r
+            parseContext.recover();\r
+        }\r
+        for (unsigned int i = 0; i < $$->size(); ++i) {\r
+            //\r
+            // Careful not to replace already know aspects of type, like array-ness\r
+            //\r
+            (*$$)[i].type->setType($1.type, $1.size, $1.matrix, $1.userDef);\r
+\r
+            // don't allow arrays of arrays\r
+            if ((*$$)[i].type->isArray()) {\r
+                if (parseContext.arrayTypeErrorCheck($1.line, $1))\r
+                    parseContext.recover();\r
+            }\r
+            if ($1.array)\r
+                (*$$)[i].type->setArraySize($1.arraySize);\r
+            if ($1.userDef)\r
+                (*$$)[i].type->setTypeName($1.userDef->getTypeName());\r
+        }\r
+    }\r
+    | type_qualifier type_specifier struct_declarator_list SEMICOLON {\r
+        $$ = $3;\r
+\r
+        if (parseContext.voidErrorCheck($2.line, (*$3)[0].type->getFieldName(), $2)) {\r
+            parseContext.recover();\r
+        }\r
+        for (unsigned int i = 0; i < $$->size(); ++i) {\r
+            //\r
+            // Careful not to replace already know aspects of type, like array-ness\r
+            //\r
+            (*$$)[i].type->setType($2.type, $2.size, $2.matrix, $2.userDef);\r
+\r
+            // don't allow arrays of arrays\r
+            if ((*$$)[i].type->isArray()) {\r
+                if (parseContext.arrayTypeErrorCheck($2.line, $2))\r
+                    parseContext.recover();\r
+            }\r
+            if ($2.array)\r
+                (*$$)[i].type->setArraySize($2.arraySize);\r
+            if ($2.userDef)\r
+                (*$$)[i].type->setTypeName($2.userDef->getTypeName());\r
+        }\r
+    }\r
+    ;\r
+\r
+struct_declarator_list\r
+    : struct_declarator {\r
+        $$ = NewPoolTTypeList();\r
+        $$->push_back($1);\r
+    }\r
+    | struct_declarator_list COMMA struct_declarator {\r
+        $$->push_back($3);\r
+    }\r
+    ;\r
+\r
+struct_declarator\r
+    : IDENTIFIER {\r
+        $$.type = new TType(EbtVoid);\r
+        $$.line = $1.line;\r
+        $$.type->setFieldName(*$1.string);\r
+    }\r
+    | IDENTIFIER LEFT_BRACKET RIGHT_BRACKET {\r
+        // allow non-sized arrays in blocks\r
+        $$.type = new TType(EbtVoid);\r
+        $$.line = $1.line;\r
+        $$.type->setFieldName(*$1.string);\r
+    }\r
+    | IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET {\r
+        $$.type = new TType(EbtVoid);\r
+        $$.line = $1.line;\r
+        $$.type->setFieldName(*$1.string);\r
+\r
+        int size;\r
+        if (parseContext.arraySizeErrorCheck($2.line, $3, size))\r
+            parseContext.recover();\r
+        $$.type->setArraySize(size);\r
+    }\r
+    ;\r
+\r
+initializer\r
+    : assignment_expression {\r
+        $$ = $1;\r
+    }\r
+    | LEFT_BRACE initializer_list RIGHT_BRACE { \r
+        $$ = $2;\r
+    }\r
+    | LEFT_BRACE initializer_list COMMA RIGHT_BRACE { \r
+        $$ = $2;\r
+    }\r
+    ;\r
+\r
+initializer_list\r
+    : initializer {\r
+        $$ = $1;\r
+    }\r
+    | initializer_list COMMA initializer {\r
+        // TODO: implement the list\r
+        $$ = $3;\r
+    }\r
+    ;\r
+\r
+declaration_statement\r
+    : declaration { $$ = $1; }\r
+    ;\r
+\r
+statement\r
+    : compound_statement  { $$ = $1; }\r
+    | simple_statement    { $$ = $1; }\r
+    ;\r
+\r
+// Grammar Note:  labeled statements for switch statements only; 'goto' is not supported.\r
+\r
+simple_statement\r
+    : declaration_statement { $$ = $1; }\r
+    | expression_statement  { $$ = $1; }\r
+    | selection_statement   { $$ = $1; }\r
+    | switch_statement      { $$ = $1; }\r
+    | case_label            { $$ = $1; }\r
+    | iteration_statement   { $$ = $1; }\r
+    | jump_statement        { $$ = $1; }\r
+    ;\r
+\r
+compound_statement\r
+    : LEFT_BRACE RIGHT_BRACE { $$ = 0; }\r
+    | LEFT_BRACE { parseContext.symbolTable.push(); } statement_list { parseContext.symbolTable.pop(); } RIGHT_BRACE {\r
+        if ($3 != 0)\r
+            $3->setOperator(EOpSequence);\r
+        $$ = $3;\r
+    }\r
+    ;\r
+\r
+statement_no_new_scope\r
+    : compound_statement_no_new_scope { $$ = $1; }\r
+    | simple_statement                { $$ = $1; }\r
+    ;\r
+\r
+compound_statement_no_new_scope\r
+    // Statement that doesn't create a new scope, for selection_statement, iteration_statement\r
+    : LEFT_BRACE RIGHT_BRACE {\r
+        $$ = 0;\r
+    }\r
+    | LEFT_BRACE statement_list RIGHT_BRACE {\r
+        if ($2)\r
+            $2->setOperator(EOpSequence);\r
+        $$ = $2;\r
+    }\r
+    ;\r
+\r
+statement_list\r
+    : statement {\r
+        $$ = parseContext.intermediate.makeAggregate($1, 0);\r
+    }\r
+    | statement_list statement {\r
+        $$ = parseContext.intermediate.growAggregate($1, $2, 0);\r
+    }\r
+    ;\r
+\r
+expression_statement\r
+    : SEMICOLON  { $$ = 0; }\r
+    | expression SEMICOLON  { $$ = static_cast<TIntermNode*>($1); }\r
+    ;\r
+\r
+selection_statement\r
+    : IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement {\r
+        if (parseContext.boolErrorCheck($1.line, $3))\r
+            parseContext.recover();\r
+        $$ = parseContext.intermediate.addSelection($3, $5, $1.line);\r
+    }\r
+    ;\r
+\r
+selection_rest_statement\r
+    : statement ELSE statement {\r
+        $$.node1 = $1;\r
+        $$.node2 = $3;\r
+    }\r
+    | statement {\r
+        $$.node1 = $1;\r
+        $$.node2 = 0;\r
+    }\r
+    ;\r
+\r
+condition\r
+    // In 1996 c++ draft, conditions can include single declarations\r
+    : expression {\r
+        $$ = $1;\r
+        if (parseContext.boolErrorCheck($1->getLine(), $1))\r
+            parseContext.recover();\r
+    }\r
+    | fully_specified_type IDENTIFIER EQUAL initializer {\r
+        TIntermNode* intermNode;\r
+        if (parseContext.structQualifierErrorCheck($2.line, $1))\r
+            parseContext.recover();\r
+        if (parseContext.boolErrorCheck($2.line, $1))\r
+            parseContext.recover();\r
+\r
+        if (!parseContext.executeInitializer($2.line, *$2.string, $1, $4, intermNode))\r
+            $$ = $4;\r
+        else {\r
+            parseContext.recover();\r
+            $$ = 0;\r
+        }\r
+    }\r
+    ;\r
+\r
+switch_statement\r
+    : SWITCH LEFT_PAREN expression RIGHT_PAREN { ++parseContext.switchNestingLevel; } LEFT_BRACE switch_statement_list RIGHT_BRACE {\r
+        $$ = 0;\r
+        --parseContext.switchNestingLevel;\r
+    }\r
+    ;\r
+\r
+switch_statement_list\r
+    : /* nothing */ {\r
+    }\r
+    | statement_list {\r
+        $$ = $1;\r
+    }\r
+    ;\r
+\r
+case_label\r
+    : CASE expression COLON {\r
+        $$ = 0;\r
+    }\r
+    | DEFAULT COLON {\r
+        $$ = 0;\r
+    }\r
+    ;\r
+\r
+iteration_statement\r
+    : WHILE LEFT_PAREN { parseContext.symbolTable.push(); ++parseContext.loopNestingLevel; } condition RIGHT_PAREN statement_no_new_scope {\r
+        parseContext.symbolTable.pop();\r
+        $$ = parseContext.intermediate.addLoop($6, $4, 0, true, $1.line);\r
+        --parseContext.loopNestingLevel;\r
+    }\r
+    | DO { ++parseContext.loopNestingLevel; } statement WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON {\r
+        if (parseContext.boolErrorCheck($8.line, $6))\r
+            parseContext.recover();\r
+\r
+        $$ = parseContext.intermediate.addLoop($3, $6, 0, false, $4.line);\r
+        --parseContext.loopNestingLevel;\r
+    }\r
+    | FOR LEFT_PAREN { parseContext.symbolTable.push(); ++parseContext.loopNestingLevel; } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope {\r
+        parseContext.symbolTable.pop();\r
+        $$ = parseContext.intermediate.makeAggregate($4, $2.line);\r
+        $$ = parseContext.intermediate.growAggregate(\r
+                $$,\r
+                parseContext.intermediate.addLoop($7, reinterpret_cast<TIntermTyped*>($5.node1), reinterpret_cast<TIntermTyped*>($5.node2), true, $1.line),\r
+                $1.line);\r
+        $$->getAsAggregate()->setOperator(EOpSequence);\r
+        --parseContext.loopNestingLevel;\r
+    }\r
+    ;\r
+\r
+for_init_statement\r
+    : expression_statement {\r
+        $$ = $1;\r
+    }\r
+    | declaration_statement {\r
+        $$ = $1;\r
+    }\r
+    ;\r
+\r
+conditionopt\r
+    : condition {\r
+        $$ = $1;\r
+    }\r
+    | /* May be null */ {\r
+        $$ = 0;\r
+    }\r
+    ;\r
+\r
+for_rest_statement\r
+    : conditionopt SEMICOLON {\r
+        $$.node1 = $1;\r
+        $$.node2 = 0;\r
+    }\r
+    | conditionopt SEMICOLON expression  {\r
+        $$.node1 = $1;\r
+        $$.node2 = $3;\r
+    }\r
+    ;\r
+\r
+jump_statement\r
+    : CONTINUE SEMICOLON {\r
+        if (parseContext.loopNestingLevel <= 0) {\r
+            parseContext.error($1.line, "continue statement only allowed in loops", "", "");\r
+            parseContext.recover();\r
+        }\r
+        $$ = parseContext.intermediate.addBranch(EOpContinue, $1.line);\r
+    }\r
+    | BREAK SEMICOLON {\r
+        if (parseContext.loopNestingLevel + parseContext.switchNestingLevel <= 0) {\r
+            parseContext.error($1.line, "break statement only allowed in switch and loops", "", "");\r
+            parseContext.recover();\r
+        }\r
+        $$ = parseContext.intermediate.addBranch(EOpBreak, $1.line);\r
+    }\r
+    | RETURN SEMICOLON {\r
+        $$ = parseContext.intermediate.addBranch(EOpReturn, $1.line);\r
+        if (parseContext.currentFunctionType->getBasicType() != EbtVoid) {\r
+            parseContext.error($1.line, "non-void function must return a value", "return", "");\r
+            parseContext.recover();\r
+        }\r
+    }\r
+    | RETURN expression SEMICOLON {\r
+        $$ = parseContext.intermediate.addBranch(EOpReturn, $2, $1.line);\r
+        parseContext.functionReturnsValue = true;\r
+        if (parseContext.currentFunctionType->getBasicType() == EbtVoid) {\r
+            parseContext.error($1.line, "void function cannot return a value", "return", "");\r
+            parseContext.recover();\r
+        } else if (*(parseContext.currentFunctionType) != $2->getType()) {\r
+            parseContext.error($1.line, "function return is not matching type:", "return", "");\r
+            parseContext.recover();\r
+        }\r
+    }\r
+    | DISCARD SEMICOLON {\r
+        FRAG_ONLY("discard", $1.line);\r
+        $$ = parseContext.intermediate.addBranch(EOpKill, $1.line);\r
+    }\r
+    ;\r
+\r
+// Grammar Note:  No 'goto'.  Gotos are not supported.\r
+\r
+translation_unit\r
+    : external_declaration {\r
+        $$ = $1;\r
+        parseContext.treeRoot = $$;\r
+    }\r
+    | translation_unit external_declaration {\r
+        $$ = parseContext.intermediate.growAggregate($1, $2, 0);\r
+        parseContext.treeRoot = $$;\r
+    }\r
+    ;\r
+\r
+external_declaration\r
+    : function_definition {\r
+        $$ = $1;\r
+    }\r
+    | declaration {\r
+        $$ = $1;\r
+    }\r
+    ;\r
+\r
+function_definition\r
+    : function_prototype {\r
+        TFunction& function = *($1.function);\r
+        TFunction* prevDec = static_cast<TFunction*>(parseContext.symbolTable.find(function.getMangledName()));\r
+        //\r
+        // Note:  'prevDec' could be 'function' if this is the first time we've seen function\r
+        // as it would have just been put in the symbol table.  Otherwise, we're looking up\r
+        // an earlier occurance.\r
+        //\r
+        if (prevDec->isDefined()) {\r
+            //\r
+            // Then this function already has a body.\r
+            //\r
+            parseContext.error($1.line, "function already has a body", function.getName().c_str(), "");\r
+            parseContext.recover();\r
+        }\r
+        prevDec->setDefined();\r
+\r
+        //\r
+        // Raise error message if main function takes any parameters or return anything other than void\r
+        //\r
+        if (function.getName() == "main") {\r
+            if (function.getParamCount() > 0) {\r
+                parseContext.error($1.line, "function cannot take any parameter(s)", function.getName().c_str(), "");\r
+                parseContext.recover();\r
+            }\r
+            if (function.getReturnType().getBasicType() != EbtVoid) {\r
+                parseContext.error($1.line, "", function.getReturnType().getBasicString(), "main function cannot return a value");\r
+                parseContext.recover();\r
+            }\r
+        }\r
+\r
+        //\r
+        // New symbol table scope for body of function plus its arguments\r
+        //\r
+        parseContext.symbolTable.push();\r
+\r
+        //\r
+        // Remember the return type for later checking for RETURN statements.\r
+        //\r
+        parseContext.currentFunctionType = &(prevDec->getReturnType());\r
+        parseContext.functionReturnsValue = false;\r
+\r
+        //\r
+        // Insert parameters into the symbol table.\r
+        // If the parameter has no name, it's not an error, just don't insert it\r
+        // (could be used for unused args).\r
+        //\r
+        // Also, accumulate the list of parameters into the HIL, so lower level code\r
+        // knows where to find parameters.\r
+        //\r
+        TIntermAggregate* paramNodes = new TIntermAggregate;\r
+        for (int i = 0; i < function.getParamCount(); i++) {\r
+            TParameter& param = function[i];\r
+            if (param.name != 0) {\r
+                TVariable *variable = new TVariable(param.name, *param.type);\r
+                //\r
+                // Insert the parameters with name in the symbol table.\r
+                //\r
+                if (! parseContext.symbolTable.insert(*variable)) {\r
+                    parseContext.error($1.line, "redefinition", variable->getName().c_str(), "");\r
+                    parseContext.recover();\r
+                    delete variable;\r
+                }\r
+                //\r
+                // Transfer ownership of name pointer to symbol table.\r
+                //\r
+                param.name = 0;\r
+\r
+                //\r
+                // Add the parameter to the HIL\r
+                //\r
+                paramNodes = parseContext.intermediate.growAggregate(\r
+                                               paramNodes,\r
+                                               parseContext.intermediate.addSymbol(variable->getUniqueId(),\r
+                                                                       variable->getName(),\r
+                                                                       variable->getType(), $1.line),\r
+                                               $1.line);\r
+            } else {\r
+                paramNodes = parseContext.intermediate.growAggregate(paramNodes, parseContext.intermediate.addSymbol(0, "", *param.type, $1.line), $1.line);\r
+            }\r
+        }\r
+        parseContext.intermediate.setAggregateOperator(paramNodes, EOpParameters, $1.line);\r
+        $1.intermAggregate = paramNodes;\r
+        parseContext.loopNestingLevel = 0;\r
+    }\r
+    compound_statement_no_new_scope {\r
+        //?? Check that all paths return a value if return type != void ?\r
+        //   May be best done as post process phase on intermediate code\r
+        if (parseContext.currentFunctionType->getBasicType() != EbtVoid && ! parseContext.functionReturnsValue) {\r
+            parseContext.error($1.line, "function does not return a value:", "", $1.function->getName().c_str());\r
+            parseContext.recover();\r
+        }\r
+        parseContext.symbolTable.pop();\r
+        $$ = parseContext.intermediate.growAggregate($1.intermAggregate, $3, 0);\r
+        parseContext.intermediate.setAggregateOperator($$, EOpFunction, $1.line);\r
+        $$->getAsAggregate()->setName($1.function->getMangledName().c_str());\r
+        $$->getAsAggregate()->setType($1.function->getReturnType());\r
+\r
+        // store the pragma information for debug and optimize and other vendor specific\r
+        // information. This information can be queried from the parse tree\r
+        $$->getAsAggregate()->setOptimize(parseContext.contextPragma.optimize);\r
+        $$->getAsAggregate()->setDebug(parseContext.contextPragma.debug);\r
+        $$->getAsAggregate()->addToPragmaTable(parseContext.contextPragma.pragmaTable);\r
+    }\r
+    ;\r
+\r
+%%\r
index 78dc850..14fe314 100644 (file)
@@ -306,16 +306,6 @@ bool OutputAggregate(bool /* preVisit */, TIntermAggregate* node, TIntermTravers
     case EOpRefract:       out.debug << "refract";                 break;
     case EOpMul:           out.debug << "component-wise multiply"; break;
 
-    case EOpItof:          out.debug << "itof";        break;
-    case EOpFtoi:          out.debug << "ftoi";        break;
-    case EOpSkipPixels:    out.debug << "skipPixels";  break;
-    case EOpReadInput:     out.debug << "readInput";   break;
-    case EOpWritePixel:    out.debug << "writePixel";  break;
-    case EOpBitmapLsb:     out.debug << "bitmapLSB";   break;
-    case EOpBitmapMsb:     out.debug << "bitmapMSB";   break;
-    case EOpWriteOutput:   out.debug << "writeOutput"; break;
-    case EOpReadPixel:     out.debug << "readPixel";   break;
-
     default: out.debug.message(EPrefixError, "Bad aggregation op");
     }
 
index ae30c73..40471a1 100644 (file)
@@ -65,6 +65,7 @@ public:
     TIntermNode*  addSelection(TIntermTyped* cond, TIntermNodePair code, TSourceLoc);
     TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, TSourceLoc);
     TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc);
+    TIntermTyped* addMethod(TIntermTyped*, TType&, const TString*, TSourceLoc);
     TIntermConstantUnion* addConstantUnion(constUnion*, const TType&, TSourceLoc);
     TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) ;
     bool parseConstTree(TSourceLoc, TIntermNode*, constUnion*, TOperator, TSymbolTable&, TType, bool singleConstantParam = false);        
index 581ad3c..96e35d4 100644 (file)
@@ -72,8 +72,6 @@ SH_IMPORT_EXPORT int __fastcall ShFinalize();
 typedef enum {
        EShLangVertex,
        EShLangFragment,
-       EShLangPack,
-    EShLangUnpack,
     EShLangCount,
 } EShLanguage;
 
@@ -82,8 +80,6 @@ typedef enum {
 //
 typedef enum {
     EShExVertexFragment,
-    EShExPackFragment,
-    EShExUnpackFragment,
     EShExFragment
 } EShExecutable;