--- /dev/null
+/*\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
--- /dev/null
+//\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