glslang flex and bison sources:
authorMichal Krol <mjkrol@gmail.org>
Fri, 18 Mar 2005 12:18:00 +0000 (12:18 +0000)
committerMichal Krol <mjkrol@gmail.org>
Fri, 18 Mar 2005 12:18:00 +0000 (12:18 +0000)
flex glslang.l
bison -t -v -d glslang.y
mv glslang.tab.c Gen_glslang_tab.cpp (shouldn't be .c?)
mv glslang.tab.h glslang_tab.h

src/mesa/shader/slang/MachineIndependent/glslang.l [new file with mode: 0644]
src/mesa/shader/slang/MachineIndependent/glslang.y [new file with mode: 0644]

diff --git a/src/mesa/shader/slang/MachineIndependent/glslang.l b/src/mesa/shader/slang/MachineIndependent/glslang.l
new file mode 100644 (file)
index 0000000..f6cd3ca
--- /dev/null
@@ -0,0 +1,614 @@
+/*\r
+//\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
+/* Based on\r
+ANSI C grammar, Lex specification\r
+\r
+In 1985, Jeff Lee published this Lex specification together with a Yacc \r
+grammar for the April 30, 1985 ANSI C draft.  Tom Stockfisch reposted \r
+both to net.sources in 1987; that original, as mentioned in the answer \r
+to question 17.25 of the comp.lang.c FAQ, can be ftp'ed from ftp.uu.net, \r
+file usenet/net.sources/ansi.c.grammar.Z. \r
+\r
+I intend to keep this version as close to the current C Standard grammar \r
+as possible; please let me know if you discover discrepancies. \r
+\r
+Jutta Degener, 1995 \r
+*/\r
+\r
+D           [0-9]\r
+L           [a-zA-Z_]\r
+H           [a-fA-F0-9]\r
+E           [Ee][+-]?{D}+\r
+O           [0-7]\r
+\r
+%option nounput \r
+%{\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include "ParseHelper.h"\r
+#include "glslang_tab.h"\r
+\r
+/* windows only pragma */\r
+#ifdef _MSC_VER\r
+#pragma warning(disable : 4102)\r
+#endif\r
+\r
+int yy_input(char* buf, int max_size);\r
+TSourceLoc yylineno;\r
+\r
+#ifdef _WIN32\r
+    extern int yyparse(TParseContext&);\r
+    #define YY_DECL int yylex(YYSTYPE* pyylval, TParseContext& parseContext)    \r
+#else\r
+    extern int yyparse(void*);\r
+    #define YY_DECL int yylex(YYSTYPE* pyylval, void* parseContextLocal)\r
+    #define parseContext (*((TParseContext*)(parseContextLocal)))\r
+#endif\r
\r
+#define YY_INPUT(buf,result,max_size) (result = yy_input(buf, max_size))\r
+\r
+%}\r
+\r
+%option noyywrap\r
+%option never-interactive\r
+%option outfile="Gen_glslang.cpp"\r
+%x FIELDS\r
+\r
+\r
+%%\r
+<*>"//"[^\n]*"\n"     { /* ?? carriage and/or line-feed? */ };\r
+\r
+"attribute"    {  pyylval->lex.line = yylineno; return(ATTRIBUTE); }\r
+"const"        {  pyylval->lex.line = yylineno; return(CONST_QUAL); }\r
+"uniform"      {  pyylval->lex.line = yylineno; return(UNIFORM); }\r
+"varying"      {  pyylval->lex.line = yylineno; return(VARYING); }\r
+\r
+"break"        {  pyylval->lex.line = yylineno; return(BREAK); }\r
+"continue"     {  pyylval->lex.line = yylineno; return(CONTINUE); }\r
+"do"           {  pyylval->lex.line = yylineno; return(DO); }\r
+"for"          {  pyylval->lex.line = yylineno; return(FOR); }\r
+"while"        {  pyylval->lex.line = yylineno; return(WHILE); }\r
+\r
+"if"           {  pyylval->lex.line = yylineno; return(IF); }\r
+"else"         {  pyylval->lex.line = yylineno; return(ELSE); }\r
+\r
+"in"           {  pyylval->lex.line = yylineno; return(IN_QUAL); }\r
+"out"          {  pyylval->lex.line = yylineno; return(OUT_QUAL); }\r
+"inout"        {  pyylval->lex.line = yylineno; return(INOUT_QUAL); }\r
+\r
+"float"        {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(FLOAT_TYPE); }\r
+"int"          {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(INT_TYPE); }\r
+"void"         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(VOID_TYPE); }\r
+"bool"         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(BOOL_TYPE); }\r
+"true"         {  pyylval->lex.line = yylineno; pyylval->lex.b = true;  return(BOOLCONSTANT); }\r
+"false"        {  pyylval->lex.line = yylineno; pyylval->lex.b = false; return(BOOLCONSTANT); }\r
+\r
+"discard"      {  pyylval->lex.line = yylineno; return(DISCARD); }\r
+"return"       {  pyylval->lex.line = yylineno; return(RETURN); }\r
+\r
+"mat2"         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MATRIX2); }\r
+"mat3"         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MATRIX3); }\r
+"mat4"         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MATRIX4); }\r
+\r
+"vec2"         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (VEC2); }\r
+"vec3"         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (VEC3); }\r
+"vec4"         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (VEC4); }\r
+"ivec2"        {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (IVEC2); }\r
+"ivec3"        {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (IVEC3); }\r
+"ivec4"        {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (IVEC4); }\r
+"bvec2"        {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (BVEC2); }\r
+"bvec3"        {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (BVEC3); }\r
+"bvec4"        {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (BVEC4); }\r
+\r
+"sampler1D"       {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLER1D; }\r
+"sampler2D"       {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLER2D; }\r
+"sampler3D"       {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLER3D; }\r
+"samplerCube"     {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLERCUBE; }\r
+"sampler1DShadow" {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLER1DSHADOW; }\r
+"sampler2DShadow" {  pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLER2DSHADOW; }\r
+\r
+"struct"       {  pyylval->lex.line = yylineno; return(STRUCT); }\r
+\r
+"asm"          {  PaReservedWord(); return 0; }\r
+\r
+"class"        {  PaReservedWord(); return 0; }\r
+"union"        {  PaReservedWord(); return 0; }\r
+"enum"         {  PaReservedWord(); return 0; }\r
+"typedef"      {  PaReservedWord(); return 0; }\r
+"template"     {  PaReservedWord(); return 0; }\r
+"this"         {  PaReservedWord(); return 0; }\r
+"packed"       {  PaReservedWord(); return 0; }\r
+\r
+"goto"         {  PaReservedWord(); return 0; }\r
+"switch"       {  PaReservedWord(); return 0; }\r
+"default"      {  PaReservedWord(); return 0; }\r
+\r
+"inline"       {  PaReservedWord(); return 0; }\r
+"noinline"     {  PaReservedWord(); return 0; }\r
+"volatile"     {  PaReservedWord(); return 0; }\r
+"public"       {  PaReservedWord(); return 0; }\r
+"static"       {  PaReservedWord(); return 0; }\r
+"extern"       {  PaReservedWord(); return 0; }\r
+"external"     {  PaReservedWord(); return 0; }\r
+"interface"    {  PaReservedWord(); return 0; }\r
+\r
+"long"         {  PaReservedWord(); return 0; }\r
+"short"        {  PaReservedWord(); return 0; }\r
+"double"       {  PaReservedWord(); return 0; }\r
+"half"         {  PaReservedWord(); return 0; }\r
+"fixed"        {  PaReservedWord(); return 0; }\r
+"unsigned"     {  PaReservedWord(); return 0; }\r
+\r
+"input"        {  PaReservedWord(); return 0; }\r
+"output"       {  PaReservedWord(); return 0; }\r
+\r
+"hvec2"        {  PaReservedWord(); return 0; }\r
+"hvec3"        {  PaReservedWord(); return 0; }\r
+"hvec4"        {  PaReservedWord(); return 0; }\r
+"fvec2"        {  PaReservedWord(); return 0; }\r
+"fvec3"        {  PaReservedWord(); return 0; }\r
+"fvec4"        {  PaReservedWord(); return 0; }\r
+"dvec2"        {  PaReservedWord(); return 0; }\r
+"dvec3"        {  PaReservedWord(); return 0; }\r
+"dvec4"        {  PaReservedWord(); return 0; }\r
+\r
+"sampler2DRect"        {  PaReservedWord(); return 0; }\r
+"sampler3DRect"        {  PaReservedWord(); return 0; }\r
+"sampler2DRectShadow"  {  PaReservedWord(); return 0; }\r
+\r
+"sizeof"       {  PaReservedWord(); return 0; }\r
+"cast"         {  PaReservedWord(); return 0; }\r
+\r
+"namespace"    {  PaReservedWord(); return 0; }\r
+"using"        {  PaReservedWord(); return 0; }\r
+\r
+{L}({L}|{D})*       {  \r
+   pyylval->lex.line = yylineno; \r
+   pyylval->lex.string = NewPoolTString(yytext); \r
+   return PaIdentOrType(*pyylval->lex.string, parseContext, pyylval->lex.symbol); \r
+}\r
+\r
+0[xX]{H}+         { pyylval->lex.line = yylineno; pyylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); }\r
+0{O}+             { pyylval->lex.line = yylineno; pyylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); }\r
+0{D}+             { pyylval->lex.line = yylineno; parseContext.error(yylineno, "Invalid Octal number.", yytext, "", ""); parseContext.recover(); return 0;}\r
+{D}+              { pyylval->lex.line = yylineno; pyylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); }\r
+\r
+{D}+{E}           { pyylval->lex.line = yylineno; pyylval->lex.f = static_cast<float>(atof(yytext)); return(FLOATCONSTANT); }\r
+{D}+"."{D}*({E})? { pyylval->lex.line = yylineno; pyylval->lex.f = static_cast<float>(atof(yytext)); return(FLOATCONSTANT); }\r
+"."{D}+({E})?     { pyylval->lex.line = yylineno; pyylval->lex.f = static_cast<float>(atof(yytext)); return(FLOATCONSTANT); }\r
+\r
+"/*"            {  int ret = PaParseComment(pyylval->lex.line, parseContext); if (!ret) return ret; }   \r
+\r
+"+="            {  pyylval->lex.line = yylineno; return(ADD_ASSIGN); }\r
+"-="            {  pyylval->lex.line = yylineno; return(SUB_ASSIGN); }\r
+"*="            {  pyylval->lex.line = yylineno; return(MUL_ASSIGN); }\r
+"/="            {  pyylval->lex.line = yylineno; return(DIV_ASSIGN); }\r
+"%="            {  pyylval->lex.line = yylineno; return(MOD_ASSIGN); }\r
+"<<="           {  pyylval->lex.line = yylineno; return(LEFT_ASSIGN); }\r
+">>="           {  pyylval->lex.line = yylineno; return(RIGHT_ASSIGN); }\r
+"&="            {  pyylval->lex.line = yylineno; return(AND_ASSIGN); }\r
+"^="            {  pyylval->lex.line = yylineno; return(XOR_ASSIGN); }\r
+"|="            {  pyylval->lex.line = yylineno; return(OR_ASSIGN); }\r
+\r
+"++"            {  pyylval->lex.line = yylineno; return(INC_OP); }\r
+"--"            {  pyylval->lex.line = yylineno; return(DEC_OP); }\r
+"&&"            {  pyylval->lex.line = yylineno; return(AND_OP); }\r
+"||"            {  pyylval->lex.line = yylineno; return(OR_OP); }\r
+"^^"            {  pyylval->lex.line = yylineno; return(XOR_OP); }\r
+"<="            {  pyylval->lex.line = yylineno; return(LE_OP); }\r
+">="            {  pyylval->lex.line = yylineno; return(GE_OP); }\r
+"=="            {  pyylval->lex.line = yylineno; return(EQ_OP); }\r
+"!="            {  pyylval->lex.line = yylineno; return(NE_OP); }\r
+"<<"            {  pyylval->lex.line = yylineno; return(LEFT_OP); }\r
+">>"            {  pyylval->lex.line = yylineno; return(RIGHT_OP); }\r
+";"         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = false; return(SEMICOLON); }\r
+("{"|"<%")      {  pyylval->lex.line = yylineno; parseContext.lexAfterType = false; return(LEFT_BRACE); }\r
+("}"|"%>")      {  pyylval->lex.line = yylineno; return(RIGHT_BRACE); }\r
+","         {  pyylval->lex.line = yylineno; if (parseContext.inTypeParen) parseContext.lexAfterType = false; return(COMMA); }\r
+":"         {  pyylval->lex.line = yylineno; return(COLON); }\r
+"="         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = false; return(EQUAL); }\r
+"("         {  pyylval->lex.line = yylineno; parseContext.lexAfterType = false; parseContext.inTypeParen = true; return(LEFT_PAREN); }\r
+")"         {  pyylval->lex.line = yylineno; parseContext.inTypeParen = false; return(RIGHT_PAREN); }\r
+("["|"<:")      {  pyylval->lex.line = yylineno; return(LEFT_BRACKET); }\r
+("]"|":>")      {  pyylval->lex.line = yylineno; return(RIGHT_BRACKET); }\r
+"."         { BEGIN(FIELDS);  return(DOT); }\r
+"!"         {  pyylval->lex.line = yylineno; return(BANG); }\r
+"-"         {  pyylval->lex.line = yylineno; return(DASH); }\r
+"~"         {  pyylval->lex.line = yylineno; return(TILDE); }\r
+"+"         {  pyylval->lex.line = yylineno; return(PLUS); }\r
+"*"         {  pyylval->lex.line = yylineno; return(STAR); }\r
+"/"         {  pyylval->lex.line = yylineno; return(SLASH); }\r
+"%"         {  pyylval->lex.line = yylineno; return(PERCENT); }\r
+"<"         {  pyylval->lex.line = yylineno; return(LEFT_ANGLE); }\r
+">"         {  pyylval->lex.line = yylineno; return(RIGHT_ANGLE); }\r
+"|"         {  pyylval->lex.line = yylineno; return(VERTICAL_BAR); }\r
+"^"         {  pyylval->lex.line = yylineno; return(CARET); }\r
+"&"         {  pyylval->lex.line = yylineno; return(AMPERSAND); }\r
+"?"         {  pyylval->lex.line = yylineno; return(QUESTION); }\r
+\r
+<FIELDS>{L}({L}|{D})* { \r
+BEGIN(INITIAL);      \r
+    pyylval->lex.line = yylineno;     \r
+    pyylval->lex.string = NewPoolTString(yytext); \r
+    return FIELD_SELECTION; }\r
+<FIELDS>[ \t\v\f\r] {}\r
+\r
+[ \t\v\n\f\r]   {  }\r
+<*><<EOF>> { (&parseContext)->AfterEOF = true; yy_delete_buffer(YY_CURRENT_BUFFER); yyterminate();}\r
+<*>.    { parseContext.infoSink.info << "FLEX: Unknown char " << yytext << "\n";\r
+          return 0; }\r
+\r
+%%\r
+\r
+\r
+//Including Pre-processor.\r
+extern "C" {\r
+  #include "./preprocessor/preprocess.h"\r
+} \r
+\r
+//\r
+// The YY_INPUT macro just calls this.  Maybe this could be just put into\r
+// the macro directly.\r
+//\r
+\r
+int yy_input(char* buf, int max_size)\r
+{\r
+     char *char_token =NULL;\r
+     int len;\r
+\r
+    if ((len = yylex_CPP(buf, max_size)) == 0)\r
+        return 0;\r
+    if (len >= max_size) \r
+        YY_FATAL_ERROR( "input buffer overflow, can't enlarge buffer because scanner uses REJECT" );\r
+\r
+       buf[len] = ' ';\r
+       return len+1;\r
+}\r
+\r
+\r
+//\r
+// Parse an array of strings using yyparse.  We set up globals used by\r
+// yywrap.\r
+//\r
+// Returns 0 for success, as per yyparse().\r
+//\r
+int PaParseStrings(char* argv[], int strLen[], int argc, TParseContext& parseContextLocal)\r
+{\r
+    int argv0len;\r
+    ScanFromString(argv[0]); \r
+    \r
+    //Storing the Current Compiler Parse context into the cpp structure.\r
+       cpp->pC = (void*)&parseContextLocal;\r
+       \r
+       if (!argv || argc == 0 || !argv[0])\r
+        return 1;\r
+    \r
+    if (!strLen) {\r
+        argv0len = (int) strlen(argv[0]);\r
+        strLen   = &argv0len;\r
+    }\r
+    yyrestart(0);\r
+    (&parseContextLocal)->AfterEOF = false;\r
+    cpp->PaWhichStr = 0;\r
+    cpp->PaArgv     = argv;\r
+    cpp->PaArgc     = argc;\r
+    cpp->PaStrLen   = strLen;\r
+    yylineno   = 1;\r
+   \r
+    if (*cpp->PaStrLen >= 0) {    \r
+        int ret;\r
+        #ifdef _WIN32\r
+            ret = yyparse(parseContextLocal);\r
+        #else\r
+            ret = yyparse((void*)(&parseContextLocal));\r
+        #endif\r
+        if (cpp->CompileError == 1 || parseContextLocal.recoveredFromError || parseContextLocal.numErrors > 0)\r
+             return 1;\r
+        else\r
+             return 0;\r
+    }\r
+    else\r
+        return 0;\r
+}\r
+\r
+void yyerror(char *s) \r
+{\r
+    if (((TParseContext *)cpp->pC)->AfterEOF) {\r
+        if (cpp->tokensBeforeEOF == 1) {\r
+            GlobalParseContext->error(yylineno, "syntax error", "pre-mature EOF", s, "");\r
+            GlobalParseContext->recover();\r
+        }\r
+    } else {\r
+        GlobalParseContext->error(yylineno, "syntax error", yytext, s, "");\r
+        GlobalParseContext->recover();\r
+    }            \r
+}\r
+\r
+void PaReservedWord()\r
+{\r
+    GlobalParseContext->error(yylineno, "Reserved word.", yytext, "", "");\r
+    GlobalParseContext->recover();\r
+}\r
+\r
+int PaIdentOrType(TString& id, TParseContext& parseContextLocal, TSymbol*& symbol)\r
+{\r
+    symbol = parseContextLocal.symbolTable.find(id);\r
+    if (parseContextLocal.lexAfterType == false && symbol && symbol->isVariable()) {\r
+        TVariable* variable = static_cast<TVariable*>(symbol);\r
+        if (variable->isUserType()) {\r
+            parseContextLocal.lexAfterType = true;\r
+            return TYPE_NAME;\r
+        }\r
+    }\r
+    \r
+    return IDENTIFIER;\r
+}\r
+\r
+int PaParseComment(int &lineno, TParseContext& parseContextLocal)\r
+{\r
+    int transitionFlag = 0;\r
+    int nextChar;\r
+    \r
+    while (transitionFlag != 2) {\r
+        nextChar = yyinput();\r
+        if (nextChar == '\n')\r
+             lineno++;\r
+        switch (nextChar) {\r
+        case '*' :\r
+            transitionFlag = 1;\r
+            break;\r
+        case '/' :  /* if star is the previous character, then it is the end of comment */\r
+            if (transitionFlag == 1) {\r
+                return 1 ;\r
+            }\r
+            break;\r
+        case EOF :\r
+            /* Raise error message here */\r
+            parseContextLocal.error(yylineno, "End of shader found before end of comment.", "", "", "");\r
+            GlobalParseContext->recover();\r
+            return YY_NULL; \r
+        default :  /* Any other character will be a part of the comment */\r
+            transitionFlag = 0;\r
+        }\r
+    }\r
+    return 1;\r
+}\r
+\r
+extern "C" {\r
+\r
+void CPPDebugLogMsg(const char *msg)\r
+{\r
+    ((TParseContext *)cpp->pC)->infoSink.debug.message(EPrefixNone, msg);\r
+}\r
+\r
+void CPPWarningToInfoLog(const char *msg)\r
+{\r
+    ((TParseContext *)cpp->pC)->infoSink.info.message(EPrefixWarning, msg, yylineno); \r
+}\r
+\r
+void CPPShInfoLogMsg(const char *msg)\r
+{\r
+    ((TParseContext *)cpp->pC)->error(yylineno,"", "",msg,"");\r
+    GlobalParseContext->recover();\r
+}\r
+\r
+void CPPErrorToInfoLog(char *msg)\r
+{\r
+    ((TParseContext *)cpp->pC)->error(yylineno,"syntax error", "",msg,"");\r
+    GlobalParseContext->recover();\r
+}\r
+\r
+void SetLineNumber(int line)\r
+{\r
+    yylineno &= ~SourceLocLineMask;\r
+    yylineno |= line;\r
+}\r
+\r
+void SetStringNumber(int string)\r
+{\r
+    yylineno = (string << SourceLocStringShift) | (yylineno & SourceLocLineMask);\r
+}\r
+\r
+int GetStringNumber(void)\r
+{\r
+    return yylineno >> 16;\r
+}\r
+\r
+int GetLineNumber(void)\r
+{\r
+    return yylineno & SourceLocLineMask;\r
+}\r
+\r
+void IncLineNumber(void)\r
+{\r
+    if ((yylineno & SourceLocLineMask) <= SourceLocLineMask)\r
+        ++yylineno;\r
+}\r
+\r
+void DecLineNumber(void)\r
+{\r
+    if ((yylineno & SourceLocLineMask) > 0)\r
+        --yylineno;\r
+}\r
+\r
+void HandlePragma(const char **tokens, int numTokens)\r
+{\r
+    if (!strcmp(tokens[0], "optimize")) {\r
+        if (numTokens != 4) {\r
+            CPPShInfoLogMsg("optimize pragma syntax is incorrect");\r
+            return;\r
+        }\r
+        \r
+        if (strcmp(tokens[1], "(")) {\r
+            CPPShInfoLogMsg("\"(\" expected after 'optimize' keyword");\r
+            return;\r
+        }\r
+            \r
+        if (!strcmp(tokens[2], "on"))\r
+            ((TParseContext *)cpp->pC)->contextPragma.optimize = true;\r
+        else if (!strcmp(tokens[2], "off"))\r
+            ((TParseContext *)cpp->pC)->contextPragma.optimize = false;\r
+        else {\r
+            CPPShInfoLogMsg("\"on\" or \"off\" expected after '(' for 'optimize' pragma");\r
+            return;\r
+        }\r
+        \r
+        if (strcmp(tokens[3], ")")) {\r
+            CPPShInfoLogMsg("\")\" expected to end 'optimize' pragma");\r
+            return;\r
+        }\r
+    } else if (!strcmp(tokens[0], "debug")) {\r
+        if (numTokens != 4) {\r
+            CPPShInfoLogMsg("debug pragma syntax is incorrect");\r
+            return;\r
+        }\r
+        \r
+        if (strcmp(tokens[1], "(")) {\r
+            CPPShInfoLogMsg("\"(\" expected after 'debug' keyword");\r
+            return;\r
+        }\r
+            \r
+        if (!strcmp(tokens[2], "on"))\r
+            ((TParseContext *)cpp->pC)->contextPragma.debug = true;\r
+        else if (!strcmp(tokens[2], "off"))\r
+            ((TParseContext *)cpp->pC)->contextPragma.debug = false;\r
+        else {\r
+            CPPShInfoLogMsg("\"on\" or \"off\" expected after '(' for 'debug' pragma");\r
+            return;\r
+        }\r
+        \r
+        if (strcmp(tokens[3], ")")) {\r
+            CPPShInfoLogMsg("\")\" expected to end 'debug' pragma");\r
+            return;\r
+        }\r
+    } else {\r
+        /*\r
+        // implementation specific pragma\r
+        // use ((TParseContext *)cpp->pC)->contextPragma.pragmaTable to store the information about pragma\r
+        // For now, just ignore the pragma that the implementation cannot recognize\r
+        // An Example of one such implementation for a pragma that has a syntax like\r
+        // #pragma pragmaname(pragmavalue)\r
+        // This implementation stores the current pragmavalue against the pragma name in pragmaTable.\r
+        if (numTokens == 4 && !strcmp(tokens[1], "(") && !strcmp(tokens[3], ")")) {              \r
+            TPragmaTable& pragmaTable = ((TParseContext *)cpp->pC)->contextPragma.pragmaTable;\r
+            TPragmaTable::iterator iter;\r
+            iter = pragmaTable.find(TString(tokens[0]));\r
+            if (iter != pragmaTable.end()) {\r
+                iter->second = tokens[2];\r
+            } else {\r
+                pragmaTable[tokens[0]] = tokens[2];\r
+            }        \r
+        }\r
+        */\r
+    }\r
+}\r
+\r
+void StoreStr(char *string)\r
+{\r
+    TString strSrc;\r
+    strSrc = TString(string);\r
+\r
+    ((TParseContext *)cpp->pC)->HashErrMsg = ((TParseContext *)cpp->pC)->HashErrMsg + " " + strSrc;\r
+}\r
+\r
+const char* GetStrfromTStr(void)\r
+{\r
+    cpp->ErrMsg = (((TParseContext *)cpp->pC)->HashErrMsg).c_str();\r
+    return cpp->ErrMsg;\r
+}\r
+\r
+void ResetTString(void)\r
+{\r
+    ((TParseContext *)cpp->pC)->HashErrMsg = "";\r
+}\r
+\r
+TBehavior GetBehavior(const char* behavior)\r
+{\r
+    if (!strcmp("require", behavior))\r
+        return EBhRequire;\r
+    else if (!strcmp("enable", behavior))\r
+        return EBhEnable;\r
+    else if (!strcmp("disable", behavior))\r
+        return EBhDisable;\r
+    else if (!strcmp("warn", behavior))\r
+        return EBhWarn;\r
+    else {\r
+        CPPShInfoLogMsg((TString("behavior '") + behavior + "' is not supported").c_str());\r
+        return EBhDisable;\r
+    }        \r
+}\r
+\r
+void  updateExtensionBehavior(const char* extName, const char* behavior)\r
+{\r
+    TBehavior behaviorVal = GetBehavior(behavior);\r
+    TMap<TString, TBehavior>:: iterator iter;\r
+    TString msg;\r
+    \r
+    // special cased for all extension\r
+    if (!strcmp(extName, "all")) {\r
+        if (behaviorVal == EBhRequire || behaviorVal == EBhEnable) {\r
+            CPPShInfoLogMsg("extension 'all' cannot have 'require' or 'enable' behavior");  \r
+            return;\r
+        } else {\r
+            for (iter =  ((TParseContext *)cpp->pC)->extensionBehavior.begin(); iter != ((TParseContext *)cpp->pC)->extensionBehavior.end(); ++iter)\r
+                iter->second = behaviorVal;\r
+        }        \r
+    } else {\r
+        iter = ((TParseContext *)cpp->pC)->extensionBehavior.find(TString(extName));\r
+        if (iter == ((TParseContext *)cpp->pC)->extensionBehavior.end()) {\r
+            switch (behaviorVal) {\r
+            case EBhRequire:\r
+                CPPShInfoLogMsg((TString("extension '") + extName + "' is not supported").c_str());  \r
+                break;\r
+            case EBhEnable:\r
+            case EBhWarn:\r
+            case EBhDisable:\r
+                msg = TString("extension '") + extName + "' is not supported";\r
+                ((TParseContext *)cpp->pC)->infoSink.info.message(EPrefixWarning, msg.c_str(), yylineno); \r
+                break;\r
+            }\r
+            return;\r
+        } else\r
+            iter->second = behaviorVal;\r
+    }\r
+}\r
+        \r
+}\r
+\r
+void setInitialState()\r
+{\r
+    yy_start = 1;\r
+}\r
diff --git a/src/mesa/shader/slang/MachineIndependent/glslang.y b/src/mesa/shader/slang/MachineIndependent/glslang.y
new file mode 100644 (file)
index 0000000..d2dc1db
--- /dev/null
@@ -0,0 +1,2009 @@
+//\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 FRAG_VERT_ONLY(S, L) {                                                  \\r
+    if (parseContext.language != EShLangFragment &&                             \\r
+        parseContext.language != EShLangVertex) {                               \\r
+        parseContext.error(L, " supported in vertex/fragment shaders only ", S, "", "");   \\r
+        parseContext.recover();                                                            \\r
+    }                                                                           \\r
+}\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
+#define PACK_ONLY(S, L) {                                                       \\r
+    if (parseContext.language != EShLangPack) {                                 \\r
+        parseContext.error(L, " supported in pack shaders only ", S, "", "");              \\r
+        parseContext.recover();                                                            \\r
+    }                                                                           \\r
+}\r
+\r
+#define UNPACK_ONLY(S, L) {                                                     \\r
+    if (parseContext.language != EShLangUnpack) {                               \\r
+        parseContext.error(L, " supported in unpack shaders only ", S, "", "");            \\r
+        parseContext.recover();                                                            \\r
+    }                                                                           \\r
+}\r
+\r
+#define PACK_UNPACK_ONLY(S, L) {                                                \\r
+    if (parseContext.language != EShLangUnpack &&                               \\r
+        parseContext.language != EShLangPack) {                                 \\r
+        parseContext.error(L, " supported in pack/unpack shaders only ", S, "", "");       \\r
+        parseContext.recover();                                                            \\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
+%token <lex> ATTRIBUTE CONST_QUAL BOOL_TYPE FLOAT_TYPE INT_TYPE\r
+%token <lex> BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN\r
+%token <lex> BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 VEC2 VEC3 VEC4\r
+%token <lex> MATRIX2 MATRIX3 MATRIX4 IN_QUAL OUT_QUAL INOUT_QUAL UNIFORM VARYING\r
+%token <lex> STRUCT VOID_TYPE WHILE\r
+%token <lex> SAMPLER1D SAMPLER2D SAMPLER3D SAMPLERCUBE SAMPLER1DSHADOW SAMPLER2DSHADOW\r
+\r
+%token <lex> IDENTIFIER TYPE_NAME FLOATCONSTANT INTCONSTANT 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
+%type <interm> assignment_operator constructor_identifier 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 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> 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
+%type <interm.qualifier> parameter_qualifier\r
+\r
+%type <interm.type> type_qualifier fully_specified_type type_specifier \r
+%type <interm.type> struct_specifier \r
+%type <interm.typeLine> struct_declarator \r
+%type <interm.typeList> struct_declarator_list struct_declaration struct_declaration_list\r
+%type <interm.function> function_header function_declarator function_identifier\r
+%type <interm.function> function_header_with_parameters function_call_header \r
+%type <interm> function_call_header_with_parameters function_call_header_no_parameters function_call_generic function_prototype\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
+            parseContext.error($1.line, "undeclared identifier", $1.string->c_str(), "");\r
+            parseContext.recover();\r
+            TType type(EbtFloat);\r
+            TVariable* fakeVariable = new TVariable($1.string, type);\r
+            parseContext.symbolTable.insert(*fakeVariable);\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
+        //\r
+        // INT_TYPE is only 16-bit plus sign bit for vertex/fragment shaders, \r
+        // check for overflow for constants\r
+        //\r
+        if (abs($1.i) >= (1 << 16)) {\r
+            parseContext.error($1.line, " integer constant overflow", "", "");\r
+            parseContext.recover();\r
+        }\r
+        constUnion *unionArray = new constUnion[1];\r
+        unionArray->iConst = $1.i;\r
+        $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $1.line);\r
+    }\r
+    | FLOATCONSTANT {\r
+        constUnion *unionArray = new constUnion[1];\r
+        unionArray->fConst = $1.f;\r
+        $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), $1.line);\r
+    }\r
+    | BOOLCONSTANT {\r
+        constUnion *unionArray = new constUnion[1];\r
+        unionArray->bConst = $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
+        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 && !$1->isArray() && $3->getQualifier() == EvqConst) {\r
+             if ($1->isVector()) {  // constant folding for vectors\r
+                TVectorFields fields;\r
+                fields.num = 1;\r
+                fields.offsets[0] = $3->getAsConstantUnion()->getUnionArrayPointer()->iConst; // 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()->iConst, $1, $2.line);\r
+            }\r
+        } else {\r
+            if ($3->getQualifier() == EvqConst) {\r
+                if (($1->isVector() || $1->isMatrix()) && $1->getType().getNominalSize() <= $3->getAsConstantUnion()->getUnionArrayPointer()->iConst && !$1->isArray() ) {\r
+                    parseContext.error($2.line, "", "[", "field selection out of range '%d'", $3->getAsConstantUnion()->getUnionArrayPointer()->iConst);\r
+                    parseContext.recover();\r
+                } else {\r
+                    if ($1->isArray()) {\r
+                        if ($1->getType().getArraySize() == 0) {\r
+                            if ($1->getType().getMaxArraySize() <= $3->getAsConstantUnion()->getUnionArrayPointer()->iConst) {\r
+                                if (parseContext.arraySetMaxSize($1->getAsSymbolNode(), $1->getTypePointer(), $3->getAsConstantUnion()->getUnionArrayPointer()->iConst, 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()->iConst >= $1->getType().getArraySize()) {\r
+                            parseContext.error($2.line, "", "[", "array index out of range '%d'", $3->getAsConstantUnion()->getUnionArrayPointer()->iConst);\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->fConst = 0.0;\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
+        } 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
+        if ($1->isArray()) {\r
+            parseContext.error($3.line, "cannot apply dot operator to an array", ".", "");\r
+            parseContext.recover();\r
+        }\r
+\r
+        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->iConst = 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->iConst = 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->iConst = 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->iConst = 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
+        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
+        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_generic {\r
+        TFunction* fnCall = $1.function;\r
+        TOperator op = fnCall->getBuiltInOp();\r
+        \r
+        if (op != EOpNull) {\r
+            //\r
+            // Then this should be a constructor.\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->fConst = 0.0;\r
+                $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), $1.line);\r
+                parseContext.recover();\r
+            }\r
+        }\r
+        delete fnCall;\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_TYPE {\r
+        $$.function = $1;\r
+        $$.intermNode = 0;\r
+    }\r
+    | function_call_header {\r
+        $$.function = $1;\r
+        $$.intermNode = 0;\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->addParameter(param);\r
+        $$.function = $1;\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
+function_identifier\r
+    : constructor_identifier {\r
+        if ($1.op == EOpConstructStruct) {\r
+            TString tempString = "";\r
+            TFunction *function = new TFunction(&tempString, *($1.type.userDef), $1.op);\r
+            $$ = function;\r
+        }\r
+        else {\r
+            TFunction *function = new TFunction($1.op);\r
+            $$ = function;\r
+        }\r
+    }\r
+    | IDENTIFIER {\r
+        if (parseContext.reservedErrorCheck($1.line, *$1.string)) \r
+            parseContext.recover();\r
+        TType type(EbtVoid);\r
+        TFunction *function = new TFunction($1.string, type);\r
+        $$ = function;        \r
+    }\r
+    ;\r
+\r
+// Grammar Note:  Constructors look like functions, but lexical anaylsis recognized most of them as keywords.\r
+\r
+//\r
+// Don't go through the symbol table for constructors.  \r
+// Their parameters will be verified algorithmically.\r
+//\r
+constructor_identifier\r
+    : FLOAT_TYPE {                                   $$.line = $1.line; $$.op = EOpConstructFloat; }\r
+    | INT_TYPE   {                                   $$.line = $1.line; $$.op = EOpConstructInt;   }\r
+    | BOOL_TYPE  {                                   $$.line = $1.line; $$.op = EOpConstructBool;  }\r
+    | VEC2       {                                   $$.line = $1.line; $$.op = EOpConstructVec2;  }\r
+    | VEC3       {                                   $$.line = $1.line; $$.op = EOpConstructVec3;  }\r
+    | VEC4       {                                   $$.line = $1.line; $$.op = EOpConstructVec4;  }\r
+    | BVEC2      { FRAG_VERT_ONLY("bvec2", $1.line); $$.line = $1.line; $$.op = EOpConstructBVec2; }\r
+    | BVEC3      { FRAG_VERT_ONLY("bvec3", $1.line); $$.line = $1.line; $$.op = EOpConstructBVec3; }\r
+    | BVEC4      { FRAG_VERT_ONLY("bvec4", $1.line); $$.line = $1.line; $$.op = EOpConstructBVec4; }\r
+    | IVEC2      { FRAG_VERT_ONLY("ivec2", $1.line); $$.line = $1.line; $$.op = EOpConstructIVec2; }\r
+    | IVEC3      { FRAG_VERT_ONLY("ivec3", $1.line); $$.line = $1.line; $$.op = EOpConstructIVec3; }\r
+    | IVEC4      { FRAG_VERT_ONLY("ivec4", $1.line); $$.line = $1.line; $$.op = EOpConstructIVec4; }\r
+    | MATRIX2    { FRAG_VERT_ONLY("mat2", $1.line);  $$.line = $1.line; $$.op = EOpConstructMat2;  }\r
+    | MATRIX3    { FRAG_VERT_ONLY("mat3", $1.line);  $$.line = $1.line; $$.op = EOpConstructMat3;  }\r
+    | MATRIX4    { FRAG_VERT_ONLY("mat4", $1.line);  $$.line = $1.line; $$.op = EOpConstructMat4;  }\r
+    | TYPE_NAME  {                                   \r
+        TType& structure = static_cast<TVariable*>($1.symbol)->getType();\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtStruct, qual, 1, false, false, &structure, $1.line }; \r
+        $$.type = t;\r
+        $$.line = $1.line; \r
+        $$.op = EOpConstructStruct; \r
+    }    \r
+    ;\r
+\r
+unary_expression\r
+    : postfix_expression {\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 { PACK_UNPACK_ONLY("~", $1.line);  \r
+              $$.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
+        FRAG_VERT_ONLY("*", $2.line);\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
+        FRAG_VERT_ONLY("/", $2.line); \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
+        PACK_UNPACK_ONLY("%", $2.line);\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
+        PACK_UNPACK_ONLY("<<", $2.line);\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
+        PACK_UNPACK_ONLY(">>", $2.line);\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->bConst = 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->bConst = 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->bConst = 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->bConst = 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->bConst = false;\r
+            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line);\r
+        }\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->bConst = false;\r
+            $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line);\r
+        }\r
+    }\r
+    ;\r
+\r
+and_expression\r
+    : equality_expression { $$ = $1; }\r
+    | and_expression AMPERSAND equality_expression {\r
+        PACK_UNPACK_ONLY("&", $2.line);\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
+        PACK_UNPACK_ONLY("^", $2.line);\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
+        PACK_UNPACK_ONLY("|", $2.line);\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->bConst = 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->bConst = 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->bConst = 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
+        }\r
+    }\r
+    ;\r
+\r
+assignment_operator\r
+    : EQUAL        {                                    $$.line = $1.line; $$.op = EOpAssign; }\r
+    | MUL_ASSIGN   { FRAG_VERT_ONLY("*=", $1.line);     $$.line = $1.line; $$.op = EOpMulAssign; }\r
+    | DIV_ASSIGN   { FRAG_VERT_ONLY("/=", $1.line);     $$.line = $1.line; $$.op = EOpDivAssign; }\r
+    | MOD_ASSIGN   { PACK_UNPACK_ONLY("%=", $1.line);   $$.line = $1.line; $$.op = EOpModAssign; }\r
+    | ADD_ASSIGN   {                                    $$.line = $1.line; $$.op = EOpAddAssign; }\r
+    | SUB_ASSIGN   {                                    $$.line = $1.line; $$.op = EOpSubAssign; }\r
+    | LEFT_ASSIGN  { PACK_UNPACK_ONLY("<<=", $1.line);  $$.line = $1.line; $$.op = EOpLeftShiftAssign; }\r
+    | RIGHT_ASSIGN { PACK_UNPACK_ONLY("<<=", $1.line);  $$.line = $1.line; $$.op = EOpRightShiftAssign; }\r
+    | AND_ASSIGN   { PACK_UNPACK_ONLY("&=",  $1.line);  $$.line = $1.line; $$.op = EOpAndAssign; }\r
+    | XOR_ASSIGN   { PACK_UNPACK_ONLY("^=",  $1.line);  $$.line = $1.line; $$.op = EOpExclusiveOrAssign; }\r
+    | OR_ASSIGN    { PACK_UNPACK_ONLY("|=",  $1.line);  $$.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   { $$ = 0; }\r
+    | init_declarator_list SEMICOLON { \r
+        if ($1.intermAggregate)\r
+            $1.intermAggregate->setOperator(EOpSequence); \r
+        $$ = $1.intermAggregate; \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 ($1.array) {\r
+            parseContext.error($3.line, "cannot declare arrays of this type", TType($1).getCompleteString().c_str(), "");\r
+            parseContext.recover();\r
+        }\r
+        if (parseContext.reservedErrorCheck($2.line, *$2.string))\r
+            parseContext.recover();\r
+        $1.array = true;\r
+        TType* type = new TType($1);        \r
+        if ($4->getAsConstantUnion())\r
+            type->setArraySize($4->getAsConstantUnion()->getUnionArrayPointer()->iConst);\r
+        TParameter param = { $2.string, type };\r
+        $$.line = $2.line;\r
+        $$.param = param;\r
+    }\r
+    ;\r
+\r
+parameter_declaration \r
+    // \r
+    // The only parameter qualifier a parameter can have are \r
+    // IN_QUAL, OUT_QUAL, INOUT_QUAL, or CONST.\r
+    //\r
+    \r
+    //\r
+    // Type + name \r
+    //\r
+    : type_qualifier parameter_qualifier parameter_declarator {\r
+        $$ = $3;\r
+        if (parseContext.paramErrorCheck($3.line, $1.qualifier, $2, $$.param.type))\r
+            parseContext.recover();\r
+    }\r
+    | parameter_qualifier parameter_declarator {\r
+        $$ = $2;\r
+        if (parseContext.parameterSamplerErrorCheck($2.line, $1, *$2.param.type))\r
+            parseContext.recover();\r
+        if (parseContext.paramErrorCheck($2.line, EvqTemporary, $1, $$.param.type))\r
+            parseContext.recover();\r
+    }\r
+    //\r
+    // Only type \r
+    //\r
+    | type_qualifier parameter_qualifier parameter_type_specifier {\r
+        $$ = $3;\r
+        if (parseContext.paramErrorCheck($3.line, $1.qualifier, $2, $$.param.type))\r
+            parseContext.recover();\r
+    }\r
+    | parameter_qualifier parameter_type_specifier {\r
+        $$ = $2;\r
+        if (parseContext.parameterSamplerErrorCheck($2.line, $1, *$2.param.type))\r
+            parseContext.recover();\r
+        if (parseContext.paramErrorCheck($2.line, EvqTemporary, $1, $$.param.type))\r
+            parseContext.recover();\r
+    }\r
+    ;\r
+    \r
+parameter_qualifier\r
+    : /* empty */ {\r
+        $$ = EvqIn;\r
+    }\r
+    | IN_QUAL {\r
+        $$ = EvqIn;\r
+    }\r
+    | OUT_QUAL {\r
+        $$ = EvqOut;\r
+    }\r
+    | INOUT_QUAL {\r
+        $$ = EvqInOut;\r
+    }\r
+    ;\r
+\r
+parameter_type_specifier \r
+    : type_specifier {\r
+        TParameter param = { 0, new TType($1) };\r
+        $$.param = param;\r
+        \r
+    }\r
+    | type_specifier LEFT_BRACKET constant_expression RIGHT_BRACKET {\r
+        // Check that we can make an array out of this type \r
+        if ($1.array) {\r
+            parseContext.error($2.line, "cannot declare arrays of this type", TType($1).getCompleteString().c_str(), "");\r
+            parseContext.recover();\r
+        }\r
+        $1.array = true;\r
+        TType* type = new TType($1);       \r
+        if ($3->getAsConstantUnion())\r
+            type->setArraySize($3->getAsConstantUnion()->getUnionArrayPointer()->iConst);\r
+\r
+        TParameter param = { 0, type };\r
+        $$.line = $2.line;\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, $1.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
+        $$ = $1;\r
+        if (parseContext.structQualifierErrorCheck($3.line, $1.type))\r
+            parseContext.recover();\r
+            \r
+        if (parseContext.arrayErrorCheck($4.line, *$3.string, $$.type, 0))\r
+            parseContext.recover();\r
+    }\r
+    | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET {\r
+        $$ = $1;\r
+        if (parseContext.structQualifierErrorCheck($3.line, $1.type))\r
+            parseContext.recover();\r
+            \r
+        if (parseContext.arrayErrorCheck($4.line, *$3.string, $$.type, $5))\r
+            parseContext.recover();\r
+    }\r
+    | init_declarator_list COMMA IDENTIFIER EQUAL initializer {\r
+        $$ = $1;\r
+        if (parseContext.structQualifierErrorCheck($3.line, $1.type))\r
+            parseContext.recover();\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
+        $$.type = $1;\r
+        if (parseContext.structQualifierErrorCheck($2.line, $1))\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
+        $$.type = $1;\r
+        if (parseContext.structQualifierErrorCheck($2.line, $1))\r
+            parseContext.recover();\r
+        \r
+        if (parseContext.arrayErrorCheck($3.line, *$2.string, $$.type, 0))\r
+            parseContext.recover();\r
+    }\r
+    | fully_specified_type IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET {\r
+        $$.intermAggregate = 0;\r
+        $$.type = $1;\r
+        if (parseContext.structQualifierErrorCheck($2.line, $1))\r
+            parseContext.recover();\r
+        \r
+        if (parseContext.arrayErrorCheck($3.line, *$2.string, $$.type, $4))\r
+            parseContext.recover();\r
+    }\r
+    | fully_specified_type IDENTIFIER EQUAL initializer {\r
+        $$.type = $1;\r
+        if (parseContext.structQualifierErrorCheck($2.line, $1))\r
+            parseContext.recover();\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
+//\r
+// Place holder for the pack/unpack languages.\r
+//\r
+//    | buffer_specifier {\r
+//        $$.intermAggregate = 0;\r
+//    }\r
+    ;\r
+\r
+// Grammar Note:  No 'enum', or 'typedef'.\r
+\r
+//\r
+// Place holder for the pack/unpack languages.\r
+//\r
+//%type <interm> buffer_declaration\r
+//%type <interm.type> buffer_specifier input_or_output buffer_declaration_list \r
+//buffer_specifier\r
+//    : input_or_output LEFT_BRACE buffer_declaration_list RIGHT_BRACE {\r
+//    }\r
+//    ;\r
+//\r
+//input_or_output\r
+//    : INPUT {\r
+//        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "input"))\r
+//            parseContext.recover();\r
+//        UNPACK_ONLY("input", $1.line);\r
+//        $$.qualifier = EvqInput;        \r
+//    }\r
+//    | OUTPUT {\r
+//        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "output"))\r
+//            parseContext.recover();\r
+//        PACK_ONLY("output", $1.line);\r
+//        $$.qualifier = EvqOutput;\r
+//    }\r
+//    ;\r
+\r
+//\r
+// Place holder for the pack/unpack languages.\r
+//\r
+//buffer_declaration_list\r
+//    : buffer_declaration {\r
+//    }\r
+//    | buffer_declaration_list buffer_declaration {\r
+//    }\r
+//    ;\r
+\r
+//\r
+// Input/output semantics:\r
+//   float must be 16 or 32 bits\r
+//   float alignment restrictions?\r
+//   check for only one input and only one output\r
+//   sum of bitfields has to be multiple of 32\r
+//\r
+\r
+//\r
+// Place holder for the pack/unpack languages.\r
+//\r
+//buffer_declaration\r
+//    : type_specifier IDENTIFIER COLON constant_expression SEMICOLON {\r
+//        if (parseContext.reservedErrorCheck($2.line, *$2.string, parseContext))\r
+//            parseContext.recover();\r
+//        $$.variable = new TVariable($2.string, $1);\r
+//        if (! parseContext.symbolTable.insert(*$$.variable)) {\r
+//            parseContext.error($2.line, "redefinition", $$.variable->getName().c_str(), "");\r
+//            parseContext.recover();\r
+//            // don't have to delete $$.variable, the pool pop will take care of it\r
+//        }\r
+//    }\r
+//    ;\r
+\r
+fully_specified_type\r
+    : type_specifier {\r
+        $$ = $1;\r
+    }\r
+    | type_qualifier type_specifier  { \r
+        TPublicType t = { $2.type, $1.qualifier, $2.size, $2.matrix, false, $2.userDef, 0 };\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
+        $$ = t;\r
+    }\r
+    ;\r
+\r
+type_qualifier\r
+    : CONST_QUAL { \r
+        TPublicType t = { EbtVoid,  EvqConst,     1, false, false, 0 }; \r
+        $$ = t; \r
+    }\r
+    | ATTRIBUTE { \r
+        VERTEX_ONLY("attribute", $1.line);\r
+        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "attribute"))\r
+            parseContext.recover();\r
+        TPublicType t = { EbtVoid,  EvqAttribute, 1, false, false, 0 }; \r
+        $$ = t; \r
+    }\r
+    | VARYING {\r
+        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "varying"))\r
+            parseContext.recover();\r
+        TPublicType t = { EbtVoid,  EvqVaryingIn, 1, false, false, 0 };\r
+        if (parseContext.language == EShLangVertex)\r
+            t.qualifier = EvqVaryingOut;\r
+        $$ = t; \r
+    }\r
+    | UNIFORM {\r
+        if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "uniform"))\r
+            parseContext.recover();\r
+        TPublicType t = { EbtVoid,  EvqUniform,   1, false, false, 0 }; \r
+        $$ = t;\r
+    }\r
+    ;\r
+\r
+type_specifier\r
+    : VOID_TYPE {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtVoid, qual, 1, false, false, 0, $1.line }; \r
+        $$ = t; \r
+    }\r
+    | FLOAT_TYPE {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtFloat, qual, 1, false, false, 0, $1.line }; \r
+        $$ = t; \r
+    }\r
+    | INT_TYPE {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtInt, qual, 1, false, false, 0, $1.line }; \r
+        $$ = t; \r
+    }\r
+    | BOOL_TYPE {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtBool, qual, 1, false, false, 0, $1.line }; \r
+        $$ = t; \r
+    }\r
+//    | UNSIGNED INT_TYPE { \r
+//        PACK_UNPACK_ONLY("unsigned", $1.line); \r
+//        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+//        TPublicType t = { EbtInt, qual, 1, false, false, 0, $1.line }; \r
+//        $$ = t; \r
+//    }\r
+    | VEC2 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtFloat, qual, 2, false, false, 0, $1.line }; \r
+        $$ = t; \r
+    }\r
+    | VEC3 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtFloat, qual, 3, false, false, 0, $1.line }; \r
+        $$ = t; \r
+    }\r
+    | VEC4 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtFloat, qual, 4, false, false, 0, $1.line }; \r
+        $$ = t; \r
+    }\r
+    | BVEC2 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtBool, qual, 2, false, false, 0, $1.line }; \r
+        $$ = t; \r
+    }\r
+    | BVEC3 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtBool, qual, 3, false, false, 0, $1.line }; \r
+        $$ = t; \r
+    }\r
+    | BVEC4 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtBool, qual, 4, false, false, 0, $1.line }; \r
+        $$ = t; \r
+    }\r
+    | IVEC2 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtInt, qual, 2, false, false, 0, $1.line }; \r
+        $$ = t; \r
+    }\r
+    | IVEC3 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtInt, qual, 3, false, false, 0, $1.line }; \r
+        $$ = t; \r
+    }\r
+    | IVEC4 {\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtInt, qual, 4, false, false, 0, $1.line }; \r
+        $$ = t; \r
+    }\r
+    | MATRIX2 {\r
+        FRAG_VERT_ONLY("mat2", $1.line); \r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtFloat, qual, 2, true, false, 0, $1.line }; \r
+        $$ = t; \r
+    }\r
+    | MATRIX3 { \r
+        FRAG_VERT_ONLY("mat3", $1.line); \r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtFloat, qual, 3, true, false, 0, $1.line }; \r
+        $$ = t; \r
+    }\r
+    | MATRIX4 { \r
+        FRAG_VERT_ONLY("mat4", $1.line);\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtFloat, qual, 4, true, false, 0, $1.line }; \r
+        $$ = t; \r
+    } \r
+    | SAMPLER1D {\r
+        FRAG_VERT_ONLY("sampler1D", $1.line);\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtSampler1D, qual, 1, false, false, 0, $1.line }; \r
+        $$ = t;\r
+    } \r
+    | SAMPLER2D {\r
+        FRAG_VERT_ONLY("sampler2D", $1.line);\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtSampler2D, qual, 1, false, false, 0, $1.line }; \r
+        $$ = t;\r
+    } \r
+    | SAMPLER3D {\r
+        FRAG_VERT_ONLY("sampler3D", $1.line);\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtSampler3D, qual, 1, false, false, 0, $1.line }; \r
+        $$ = t;\r
+    } \r
+    | SAMPLERCUBE {\r
+        FRAG_VERT_ONLY("samplerCube", $1.line);\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtSamplerCube, qual, 1, false, false, 0, $1.line }; \r
+        $$ = t;\r
+    } \r
+    | SAMPLER1DSHADOW {\r
+        FRAG_VERT_ONLY("sampler1DShadow", $1.line);\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtSampler1DShadow, qual, 1, false, false, 0, $1.line }; \r
+        $$ = t;\r
+    } \r
+    | SAMPLER2DSHADOW {\r
+        FRAG_VERT_ONLY("sampler2DShadow", $1.line);\r
+        TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;\r
+        TPublicType t = { EbtSampler2DShadow, qual, 1, false, false, 0, $1.line }; \r
+        $$ = t;\r
+    }\r
+    | struct_specifier {\r
+        FRAG_VERT_ONLY("struct", $1.line);\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
+        TPublicType t = { EbtStruct, qual, 1, false, false, &structure, $1.line }; \r
+        $$ = t;\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
+        TPublicType t = { EbtStruct, EvqTemporary, 1, false, false, structure, $1.line };\r
+        $$ = t;\r
+    }\r
+    | STRUCT LEFT_BRACE struct_declaration_list RIGHT_BRACE {\r
+        TType* structure = new TType($3, TString(""));\r
+        TPublicType t = { EbtStruct, EvqTemporary, 1, false, false, structure, $1.line };\r
+        $$ = t;\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
+            if ($1.userDef)\r
+                (*$$)[i].type->setTypeName($1.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 constant_expression RIGHT_BRACKET {\r
+        $$.type = new TType(EbtVoid);\r
+        $$.line = $1.line;\r
+        $$.type->setFieldName(*$1.string);\r
+        \r
+        if ($3->getAsConstantUnion() == 0 || $3->getAsConstantUnion()->getBasicType() != EbtInt ||\r
+            $3->getAsConstantUnion()->getUnionArrayPointer()->iConst <= 0) {\r
+            parseContext.error($2.line, "structure field array size must be a positive integer", $1.string->c_str(), "");\r
+            parseContext.recover();\r
+        } else {           \r
+            $$.type->setArraySize($3->getAsConstantUnion()->getUnionArrayPointer()->iConst);\r
+        }\r
+    }\r
+    ;\r
+\r
+initializer\r
+    : assignment_expression { $$ = $1; }\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:  No labeled statements; 'goto' is not supported.\r
+\r
+simple_statement \r
+    : declaration_statement { $$ = $1; }\r
+    | expression_statement  { $$ = $1; } \r
+    | selection_statement   { $$ = $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
+// Grammar Note:  No 'switch'.  Switch statements not supported.\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
+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 <= 0) {\r
+            parseContext.error($1.line, "break statement only allowed in 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