#include <string.h>
-#include "Scan.h"
-#include "Include/Types.h"
+#include "../Include/Types.h"
#include "SymbolTable.h"
-#include "glslang_tab.cpp.h"
#include "ParseHelper.h"
+#include "glslang_tab.cpp.h"
#include "ScanContext.h"
+#include "Scan.h"
// preprocessor includes
#include "preprocessor/PpContext.h"
namespace glslang {
// read past any white space
-void ConsumeWhiteSpace(TInputScanner& input, bool& foundNonSpaceTab)
+void TInputScanner::consumeWhiteSpace(bool& foundNonSpaceTab)
{
- char c = input.peek(); // don't accidentally consume anything other than whitespace
+ int c = peek(); // don't accidentally consume anything other than whitespace
while (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
if (c == '\r' || c == '\n')
foundNonSpaceTab = true;
- input.get();
- c = input.peek();
+ get();
+ c = peek();
}
}
// return true if a comment was actually consumed
-bool ConsumeComment(TInputScanner& input)
+bool TInputScanner::consumeComment()
{
- if (input.peek() != '/')
+ if (peek() != '/')
return false;
- input.get(); // consume the '/'
- char c = input.peek();
+ get(); // consume the '/'
+ int c = peek();
if (c == '/') {
// a '//' style comment
- input.get(); // consume the second '/'
- c = input.get();
+ get(); // consume the second '/'
+ c = get();
do {
while (c > 0 && c != '\\' && c != '\r' && c != '\n')
- c = input.get();
+ c = get();
if (c <= 0 || c == '\r' || c == '\n') {
while (c == '\r' || c == '\n')
- c = input.get();
+ c = get();
// we reached the end of the comment
break;
} else {
// it's a '\', so we need to keep going, after skipping what's escaped
-
+
// read the skipped character
- c = input.get();
+ c = get();
// if it's a two-character newline, skip both characters
- if (c == '\r' && input.peek() == '\n')
- input.get();
- c = input.get();
+ if (c == '\r' && peek() == '\n')
+ get();
+ c = get();
}
} while (true);
// put back the last non-comment character
if (c > 0)
- input.unget();
+ unget();
return true;
} else if (c == '*') {
// a '/*' style comment
- input.get(); // consume the '*'
- c = input.get();
+ get(); // consume the '*'
+ c = get();
do {
while (c > 0 && c != '*')
- c = input.get();
+ c = get();
if (c == '*') {
- c = input.get();
+ c = get();
if (c == '/')
break; // end of comment
// not end of comment
return true;
} else {
// it's not a comment, put the '/' back
- input.unget();
+ unget();
return false;
}
}
// skip whitespace, then skip a comment, rinse, repeat
-void ConsumeWhitespaceComment(TInputScanner& input, bool& foundNonSpaceTab)
+void TInputScanner::consumeWhitespaceComment(bool& foundNonSpaceTab)
{
do {
- ConsumeWhiteSpace(input, foundNonSpaceTab);
+ consumeWhiteSpace(foundNonSpaceTab);
// if not starting a comment now, then done
- char c = input.peek();
+ int c = peek();
if (c != '/' || c < 0)
return;
// skip potential comment
foundNonSpaceTab = true;
- if (! ConsumeComment(input))
+ if (! consumeComment())
return;
} while (true);
// or no #version was found; otherwise, returns false. There is no error case, it always
// succeeds, but will leave version == 0 if no #version was found.
//
+// Sets versionNotFirstToken based on whether tokens (beyond white space and comments)
+// appeared before the #version.
+//
// N.B. does not attempt to leave input in any particular known state. The assumption
// is that scanning will start anew, following the rules for the chosen version/profile,
// and with a corresponding parsing context.
//
-bool ScanVersion(TInputScanner& input, int& version, EProfile& profile)
+bool TInputScanner::scanVersion(int& version, EProfile& profile, bool& notFirstToken)
{
- // This function doesn't have to get all the semantics correct,
+ // This function doesn't have to get all the semantics correct,
// just find the #version if there is a correct one present.
// The preprocessor will have the responsibility of getting all the semantics right.
+ bool versionNotFirst = false; // means not first WRT comments and white space, nothing more
+ notFirstToken = false; // means not first WRT to real tokens
version = 0; // means not found
profile = ENoProfile;
bool foundNonSpaceTab = false;
- ConsumeWhitespaceComment(input, foundNonSpaceTab);
+ bool lookingInMiddle = false;
+ int c;
+ do {
+ if (lookingInMiddle) {
+ notFirstToken = true;
+ // make forward progress by finishing off the current line plus extra new lines
+ if (peek() == '\n' || peek() == '\r') {
+ while (peek() == '\n' || peek() == '\r')
+ get();
+ } else
+ do {
+ c = get();
+ } while (c > 0 && c != '\n' && c != '\r');
+ while (peek() == '\n' || peek() == '\r')
+ get();
+ if (peek() < 0)
+ return true;
+ }
+ lookingInMiddle = true;
+
+ // Nominal start, skipping the desktop allowed comments and white space, but tracking if
+ // something else was found for ES:
+ consumeWhitespaceComment(foundNonSpaceTab);
+ if (foundNonSpaceTab)
+ versionNotFirst = true;
+
+ // "#"
+ if (get() != '#') {
+ versionNotFirst = true;
+ continue;
+ }
- // #
- if (input.get() != '#')
- return true;
+ // whitespace
+ do {
+ c = get();
+ } while (c == ' ' || c == '\t');
+
+ // "version"
+ if ( c != 'v' ||
+ get() != 'e' ||
+ get() != 'r' ||
+ get() != 's' ||
+ get() != 'i' ||
+ get() != 'o' ||
+ get() != 'n') {
+ versionNotFirst = true;
+ continue;
+ }
- // whitespace
- char c;
- do {
- c = input.get();
- } while (c == ' ' || c == '\t');
-
- if ( c != 'v' ||
- input.get() != 'e' ||
- input.get() != 'r' ||
- input.get() != 's' ||
- input.get() != 'i' ||
- input.get() != 'o' ||
- input.get() != 'n')
- return true;
+ // whitespace
+ do {
+ c = get();
+ } while (c == ' ' || c == '\t');
- // whitespace
- do {
- c = input.get();
- } while (c == ' ' || c == '\t');
+ // version number
+ while (c >= '0' && c <= '9') {
+ version = 10 * version + (c - '0');
+ c = get();
+ }
+ if (version == 0) {
+ versionNotFirst = true;
+ continue;
+ }
- // version number
- while (c >= '0' && c <= '9') {
- version = 10 * version + (c - '0');
- c = input.get();
- }
- if (version == 0)
- return true;
-
- // whitespace
- while (c == ' ' || c == '\t')
- c = input.get();
-
- // profile
- const int maxProfileLength = 13; // not including any 0
- char profileString[maxProfileLength];
- int profileLength;
- for (profileLength = 0; profileLength < maxProfileLength; ++profileLength) {
- if (c < 0 || c == ' ' || c == '\t' || c == '\n' || c == '\r')
- break;
- profileString[profileLength] = c;
- c = input.get();
- }
- if (c > 0 && c != ' ' && c != '\t' && c != '\n' && c != '\r')
- return true;
+ // whitespace
+ while (c == ' ' || c == '\t')
+ c = get();
- if (profileLength == 2 && strncmp(profileString, "es", profileLength) == 0)
- profile = EEsProfile;
- else if (profileLength == 4 && strncmp(profileString, "core", profileLength) == 0)
- profile = ECoreProfile;
- else if (profileLength == 13 && strncmp(profileString, "compatibility", profileLength) == 0)
- profile = ECompatibilityProfile;
+ // profile
+ const int maxProfileLength = 13; // not including any 0
+ char profileString[maxProfileLength];
+ int profileLength;
+ for (profileLength = 0; profileLength < maxProfileLength; ++profileLength) {
+ if (c < 0 || c == ' ' || c == '\t' || c == '\n' || c == '\r')
+ break;
+ profileString[profileLength] = (char)c;
+ c = get();
+ }
+ if (c > 0 && c != ' ' && c != '\t' && c != '\n' && c != '\r') {
+ versionNotFirst = true;
+ continue;
+ }
+
+ if (profileLength == 2 && strncmp(profileString, "es", profileLength) == 0)
+ profile = EEsProfile;
+ else if (profileLength == 4 && strncmp(profileString, "core", profileLength) == 0)
+ profile = ECoreProfile;
+ else if (profileLength == 13 && strncmp(profileString, "compatibility", profileLength) == 0)
+ profile = ECompatibilityProfile;
- return foundNonSpaceTab;
+ return versionNotFirst;
+ } while (true);
}
// Fill this in when doing glslang-level scanning, to hand back to the parser.
explicit TParserToken(YYSTYPE& b) : sType(b) { }
YYSTYPE& sType;
+protected:
+ TParserToken(TParserToken&);
+ TParserToken& operator=(TParserToken&);
};
} // end namespace glslang
{
glslang::TParserToken token(*glslangTokenDesc);
- return parseContext.scanContext->tokenize(parseContext.ppContext, token);
+ return parseContext.getScanContext()->tokenize(parseContext.getPpContext(), token);
}
namespace {
(*KeywordMap)["sampler2DRect"] = SAMPLER2DRECT;
(*KeywordMap)["sampler2DRectShadow"] = SAMPLER2DRECTSHADOW;
(*KeywordMap)["sampler1DArray"] = SAMPLER1DARRAY;
+ (*KeywordMap)["samplerExternalOES"] = SAMPLEREXTERNALOES; // GL_OES_EGL_image_external
(*KeywordMap)["noperspective"] = NOPERSPECTIVE;
(*KeywordMap)["smooth"] = SMOOTH;
(*KeywordMap)["flat"] = FLAT;
ReservedSet->insert("using");
}
+void TScanContext::deleteKeywordMap()
+{
+ delete KeywordMap;
+ KeywordMap = 0;
+ delete ReservedSet;
+ ReservedSet = 0;
+}
+
int TScanContext::tokenize(TPpContext* pp, TParserToken& token)
{
- parserToken = &token;
- TPpToken ppToken;
- tokenText = pp->tokenize(&ppToken);
-
- loc = ppToken.loc;
- parserToken->sType.lex.loc = loc;
- switch (ppToken.ppToken) {
- case ';': afterType = false; return SEMICOLON;
- case ',': afterType = false; return COMMA;
- case ':': return COLON;
- case '=': afterType = false; return EQUAL;
- case '(': afterType = false; return LEFT_PAREN;
- case ')': afterType = false; return RIGHT_PAREN;
- case '.': field = true; return DOT;
- case '!': return BANG;
- case '-': return DASH;
- case '~': return TILDE;
- case '+': return PLUS;
- case '*': return STAR;
- case '/': return SLASH;
- case '%': return PERCENT;
- case '<': return LEFT_ANGLE;
- case '>': return RIGHT_ANGLE;
- case '|': return VERTICAL_BAR;
- case '^': return CARET;
- case '&': return AMPERSAND;
- case '?': return QUESTION;
- case '[': return LEFT_BRACKET;
- case ']': return RIGHT_BRACKET;
- case '{': return LEFT_BRACE;
- case '}': return RIGHT_BRACE;
-
- case CPP_AND_OP: return AND_OP;
- case CPP_SUB_ASSIGN: return SUB_ASSIGN;
- case CPP_MOD_ASSIGN: return MOD_ASSIGN;
- case CPP_ADD_ASSIGN: return ADD_ASSIGN;
- case CPP_DIV_ASSIGN: return DIV_ASSIGN;
- case CPP_MUL_ASSIGN: return MUL_ASSIGN;
- case CPP_EQ_OP: return EQ_OP;
- case CPP_XOR_OP: return XOR_OP;
- case CPP_GE_OP: return GE_OP;
- case CPP_RIGHT_OP: return RIGHT_OP;
- case CPP_LE_OP: return LE_OP;
- case CPP_LEFT_OP: return LEFT_OP;
- case CPP_DEC_OP: return DEC_OP;
- case CPP_NE_OP: return NE_OP;
- case CPP_OR_OP: return OR_OP;
- case CPP_INC_OP: return INC_OP;
- case CPP_RIGHT_ASSIGN: return RIGHT_ASSIGN;
- case CPP_LEFT_ASSIGN: return LEFT_ASSIGN;
- case CPP_AND_ASSIGN: return AND_ASSIGN;
- case CPP_OR_ASSIGN: return OR_ASSIGN;
- case CPP_XOR_ASSIGN: return XOR_ASSIGN;
+ do {
+ parserToken = &token;
+ TPpToken ppToken;
+ tokenText = pp->tokenize(&ppToken);
+ if (tokenText == 0)
+ return 0;
+
+ loc = ppToken.loc;
+ parserToken->sType.lex.loc = loc;
+ switch (ppToken.token) {
+ case ';': afterType = false; return SEMICOLON;
+ case ',': afterType = false; return COMMA;
+ case ':': return COLON;
+ case '=': afterType = false; return EQUAL;
+ case '(': afterType = false; return LEFT_PAREN;
+ case ')': afterType = false; return RIGHT_PAREN;
+ case '.': field = true; return DOT;
+ case '!': return BANG;
+ case '-': return DASH;
+ case '~': return TILDE;
+ case '+': return PLUS;
+ case '*': return STAR;
+ case '/': return SLASH;
+ case '%': return PERCENT;
+ case '<': return LEFT_ANGLE;
+ case '>': return RIGHT_ANGLE;
+ case '|': return VERTICAL_BAR;
+ case '^': return CARET;
+ case '&': return AMPERSAND;
+ case '?': return QUESTION;
+ case '[': return LEFT_BRACKET;
+ case ']': return RIGHT_BRACKET;
+ case '{': return LEFT_BRACE;
+ case '}': return RIGHT_BRACE;
+ case '\\':
+ parseContext.error(loc, "illegal use of escape character", "\\", "");
+ break;
+
+ case CPP_AND_OP: return AND_OP;
+ case CPP_SUB_ASSIGN: return SUB_ASSIGN;
+ case CPP_MOD_ASSIGN: return MOD_ASSIGN;
+ case CPP_ADD_ASSIGN: return ADD_ASSIGN;
+ case CPP_DIV_ASSIGN: return DIV_ASSIGN;
+ case CPP_MUL_ASSIGN: return MUL_ASSIGN;
+ case CPP_EQ_OP: return EQ_OP;
+ case CPP_XOR_OP: return XOR_OP;
+ case CPP_GE_OP: return GE_OP;
+ case CPP_RIGHT_OP: return RIGHT_OP;
+ case CPP_LE_OP: return LE_OP;
+ case CPP_LEFT_OP: return LEFT_OP;
+ case CPP_DEC_OP: return DEC_OP;
+ case CPP_NE_OP: return NE_OP;
+ case CPP_OR_OP: return OR_OP;
+ case CPP_INC_OP: return INC_OP;
+ case CPP_RIGHT_ASSIGN: return RIGHT_ASSIGN;
+ case CPP_LEFT_ASSIGN: return LEFT_ASSIGN;
+ case CPP_AND_ASSIGN: return AND_ASSIGN;
+ case CPP_OR_ASSIGN: return OR_ASSIGN;
+ case CPP_XOR_ASSIGN: return XOR_ASSIGN;
- case CPP_INTCONSTANT: parserToken->sType.lex.i = ppToken.ival; return INTCONSTANT;
- case CPP_UINTCONSTANT: parserToken->sType.lex.i = ppToken.ival; return UINTCONSTANT;
- case CPP_FLOATCONSTANT: parserToken->sType.lex.d = ppToken.dval; return FLOATCONSTANT;
- case CPP_DOUBLECONSTANT: parserToken->sType.lex.d = ppToken.dval; return DOUBLECONSTANT;
- case CPP_IDENTIFIER: return tokenizeIdentifier();
+ case CPP_INTCONSTANT: parserToken->sType.lex.i = ppToken.ival; return INTCONSTANT;
+ case CPP_UINTCONSTANT: parserToken->sType.lex.i = ppToken.ival; return UINTCONSTANT;
+ case CPP_FLOATCONSTANT: parserToken->sType.lex.d = ppToken.dval; return FLOATCONSTANT;
+ case CPP_DOUBLECONSTANT: parserToken->sType.lex.d = ppToken.dval; return DOUBLECONSTANT;
+ case CPP_IDENTIFIER: return tokenizeIdentifier();
- case EOF: return 0;
+ case EOF: return 0;
- default:
- parseContext.infoSink.info.message(EPrefixInternalError, "Unknown PP token", loc);
- return 0;
- }
+ default:
+ char buf[2];
+ buf[0] = (char)ppToken.token;
+ buf[1] = 0;
+ parseContext.error(loc, "unexpected token", buf, "");
+ break;
+ }
+ } while (true);
}
int TScanContext::tokenizeIdentifier()
if (ReservedSet->find(tokenText) != ReservedSet->end())
return reservedWord();
- keyword = (*KeywordMap)[tokenText];
- if (keyword == 0) {
+ std::map<std::string, int>::const_iterator it = KeywordMap->find(tokenText);
+ if (it == KeywordMap->end()) {
// Should have an identifier of some sort
return identifierOrType();
}
+ keyword = it->second;
field = false;
switch (keyword) {
case SWITCH:
case DEFAULT:
- if (parseContext.profile == EEsProfile && parseContext.version < 300 ||
- parseContext.profile != EEsProfile && parseContext.version < 130)
+ if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
+ (parseContext.profile != EEsProfile && parseContext.version < 130))
reservedWord();
return keyword;
return keyword;
case BUFFER:
- if (parseContext.version < 430)
+ if ((parseContext.profile == EEsProfile && parseContext.version < 310) ||
+ (parseContext.profile != EEsProfile && parseContext.version < 430))
return identifierOrType();
return keyword;
+ case ATOMIC_UINT:
+ if (parseContext.profile == EEsProfile && parseContext.version >= 310 ||
+ parseContext.extensionsTurnedOn(1, &GL_ARB_shader_atomic_counters))
+ return keyword;
+ return es30ReservedFromGLSL(420);
+
case COHERENT:
case RESTRICT:
case READONLY:
case WRITEONLY:
- case ATOMIC_UINT:
- return es30ReservedFromGLSL(420);
+ if (parseContext.profile == EEsProfile && parseContext.version >= 310)
+ return keyword;
+ return es30ReservedFromGLSL(parseContext.extensionsTurnedOn(1, &GL_ARB_shader_image_load_store) ? 130 : 420);
case VOLATILE:
- if (parseContext.profile == EEsProfile || parseContext.version < 420)
+ if (parseContext.profile == EEsProfile && parseContext.version >= 310)
+ return keyword;
+ if (! parseContext.symbolTable.atBuiltInLevel() && (parseContext.profile == EEsProfile || (parseContext.version < 420 && ! parseContext.extensionsTurnedOn(1, &GL_ARB_shader_image_load_store))))
reservedWord();
return keyword;
case LAYOUT:
+ {
+ const int numLayoutExts = 2;
+ const char* layoutExts[numLayoutExts] = { GL_ARB_shading_language_420pack,
+ GL_ARB_explicit_attrib_location };
+ if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
+ (parseContext.profile != EEsProfile && parseContext.version < 140 &&
+ ! parseContext.extensionsTurnedOn(numLayoutExts, layoutExts)))
+ return identifierOrType();
+ return keyword;
+ }
case SHARED:
- if (parseContext.profile == EEsProfile && parseContext.version < 300 ||
- parseContext.profile != EEsProfile && parseContext.version < 140)
+ if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
+ (parseContext.profile != EEsProfile && parseContext.version < 140))
return identifierOrType();
return keyword;
case PATCH:
+ if (parseContext.symbolTable.atBuiltInLevel() || parseContext.extensionsTurnedOn(1, &GL_ARB_tessellation_shader))
+ return es30ReservedFromGLSL(150);
+ else
+ return es30ReservedFromGLSL(400);
+
case SAMPLE:
case SUBROUTINE:
return es30ReservedFromGLSL(400);
case IMAGE1D:
case IIMAGE1D:
case UIMAGE1D:
+ case IMAGE1DARRAY:
+ case IIMAGE1DARRAY:
+ case UIMAGE1DARRAY:
+ case IMAGE2DRECT:
+ case IIMAGE2DRECT:
+ case UIMAGE2DRECT:
+ case IMAGEBUFFER:
+ case IIMAGEBUFFER:
+ case UIMAGEBUFFER:
+ return firstGenerationImage(false);
+
case IMAGE2D:
case IIMAGE2D:
case UIMAGE2D:
case IMAGE3D:
case IIMAGE3D:
case UIMAGE3D:
- case IMAGE2DRECT:
- case IIMAGE2DRECT:
- case UIMAGE2DRECT:
case IMAGECUBE:
case IIMAGECUBE:
case UIMAGECUBE:
- case IMAGEBUFFER:
- case IIMAGEBUFFER:
- case UIMAGEBUFFER:
- case IMAGE1DARRAY:
- case IIMAGE1DARRAY:
- case UIMAGE1DARRAY:
case IMAGE2DARRAY:
case IIMAGE2DARRAY:
case UIMAGE2DARRAY:
- return firstGenerationImage();
+ return firstGenerationImage(true);
case IMAGECUBEARRAY:
case IIMAGECUBEARRAY:
- case UIMAGECUBEARRAY:
+ case UIMAGECUBEARRAY:
case IMAGE2DMS:
case IIMAGE2DMS:
case UIMAGE2DMS:
case DVEC2:
case DVEC3:
case DVEC4:
+ afterType = true;
+ if (parseContext.profile == EEsProfile || parseContext.version < 400)
+ reservedWord();
+ return keyword;
+
case SAMPLERCUBEARRAY:
case SAMPLERCUBEARRAYSHADOW:
case ISAMPLERCUBEARRAY:
case USAMPLERCUBEARRAY:
afterType = true;
- if (parseContext.profile == EEsProfile || parseContext.version < 400)
+ if (parseContext.profile == EEsProfile || (parseContext.version < 400 && ! parseContext.extensionsTurnedOn(1, &GL_ARB_texture_cube_map_array)))
reservedWord();
return keyword;
case SAMPLER2DMS:
case ISAMPLER2DMS:
case USAMPLER2DMS:
+ afterType = true;
+ if (parseContext.profile == EEsProfile && parseContext.version >= 310)
+ return keyword;
+ return es30ReservedFromGLSL(150);
+
case SAMPLER2DMSARRAY:
case ISAMPLER2DMSARRAY:
case USAMPLER2DMSARRAY:
return keyword;
case SAMPLER3D:
+ afterType = true;
+ if (parseContext.profile == EEsProfile && parseContext.version < 300) {
+ if (! parseContext.extensionsTurnedOn(1, &GL_OES_texture_3D))
+ reservedWord();
+ }
+ return keyword;
+
case SAMPLER2DSHADOW:
afterType = true;
if (parseContext.profile == EEsProfile && parseContext.version < 300)
case SAMPLER2DRECT:
case SAMPLER2DRECTSHADOW:
afterType = true;
- if (parseContext.profile == EEsProfile ||
- parseContext.profile != EEsProfile && parseContext.version < 140)
+ if (parseContext.profile == EEsProfile)
reservedWord();
+ else if (parseContext.version < 140 && ! parseContext.symbolTable.atBuiltInLevel() && ! parseContext.extensionsTurnedOn(1, &GL_ARB_texture_rectangle)) {
+ if (parseContext.messages & EShMsgRelaxedErrors)
+ parseContext.requireExtensions(loc, 1, &GL_ARB_texture_rectangle, "texture-rectangle sampler keyword");
+ else
+ reservedWord();
+ }
return keyword;
case SAMPLER1DARRAY:
afterType = true;
if (parseContext.profile == EEsProfile && parseContext.version == 300)
reservedWord();
- else if (parseContext.profile == EEsProfile && parseContext.version < 300 ||
- parseContext.profile != EEsProfile && parseContext.version < 130)
+ else if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
+ (parseContext.profile != EEsProfile && parseContext.version < 130))
return identifierOrType();
return keyword;
+ case SAMPLEREXTERNALOES:
+ afterType = true;
+ if (parseContext.symbolTable.atBuiltInLevel() || parseContext.extensionsTurnedOn(1, &GL_OES_EGL_image_external))
+ return keyword;
+ return identifierOrType();
+
case NOPERSPECTIVE:
return es30ReservedFromGLSL(130);
case SMOOTH:
- if (parseContext.profile == EEsProfile && parseContext.version < 300 ||
- parseContext.profile != EEsProfile && parseContext.version < 130)
+ if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
+ (parseContext.profile != EEsProfile && parseContext.version < 130))
return identifierOrType();
return keyword;
return keyword;
case PRECISE:
- if (parseContext.profile == EEsProfile ||
- parseContext.profile != EEsProfile && parseContext.version < 400)
+ if (parseContext.profile == EEsProfile && parseContext.version >= 310)
+ reservedWord();
+ else if (parseContext.profile == EEsProfile ||
+ (parseContext.profile != EEsProfile && parseContext.version < 400))
return identifierOrType();
return keyword;
return keyword;
case PACKED:
- if (parseContext.profile == EEsProfile && parseContext.version < 300 ||
- parseContext.profile != EEsProfile && parseContext.version < 330)
+ if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
+ (parseContext.profile != EEsProfile && parseContext.version < 330))
return reservedWord();
return identifierOrType();
case RESOURCE:
{
- bool reserved = parseContext.profile == EEsProfile && parseContext.version >= 300 ||
- parseContext.profile != EEsProfile && parseContext.version >= 420;
+ bool reserved = (parseContext.profile == EEsProfile && parseContext.version >= 300) ||
+ (parseContext.profile != EEsProfile && parseContext.version >= 420);
return identifierOrReserved(reserved);
}
case SUPERP:
return identifierOrReserved(reserved);
}
- default:
+ default:
parseContext.infoSink.info.message(EPrefixInternalError, "Unknown glslang keyword", loc);
return 0;
}
parserToken->sType.lex.symbol = parseContext.symbolTable.find(*parserToken->sType.lex.string);
if (afterType == false && parserToken->sType.lex.symbol) {
- if (TVariable* variable = parserToken->sType.lex.symbol->getAsVariable()) {
+ if (const TVariable* variable = parserToken->sType.lex.symbol->getAsVariable()) {
if (variable->isUserType()) {
afterType = true;
return IDENTIFIER;
}
+// Give an error for use of a reserved symbol.
+// However, allow built-in declarations to use reserved words, to allow
+// extension support before the extension is enabled.
int TScanContext::reservedWord()
{
- parseContext.error(loc, "Reserved word.", tokenText, "", "");
+ if (! parseContext.symbolTable.atBuiltInLevel())
+ parseContext.error(loc, "Reserved word.", tokenText, "", "");
return 0;
}
// but then got reserved by ES 3.0.
int TScanContext::es30ReservedFromGLSL(int version)
{
- if (parseContext.profile == EEsProfile && parseContext.version < 300 ||
- parseContext.profile != EEsProfile && parseContext.version < version) {
+ if (parseContext.symbolTable.atBuiltInLevel())
+ return keyword;
+
+ if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
+ (parseContext.profile != EEsProfile && parseContext.version < version)) {
if (parseContext.forwardCompatible)
parseContext.warn(loc, "future reserved word in ES 300 and keyword in GLSL", tokenText, "");
// showed up, both in an es version and a non-ES version.
int TScanContext::nonreservedKeyword(int esVersion, int nonEsVersion)
{
- if (parseContext.profile == EEsProfile && parseContext.version < esVersion ||
- parseContext.profile != EEsProfile && parseContext.version < nonEsVersion) {
+ if ((parseContext.profile == EEsProfile && parseContext.version < esVersion) ||
+ (parseContext.profile != EEsProfile && parseContext.version < nonEsVersion)) {
if (parseContext.forwardCompatible)
parseContext.warn(loc, "using future keyword", tokenText, "");
return identifierOrType();
}
-int TScanContext::firstGenerationImage()
+int TScanContext::firstGenerationImage(bool inEs310)
{
afterType = true;
- if (parseContext.profile != EEsProfile && parseContext.version >= 420)
+ if (parseContext.symbolTable.atBuiltInLevel() ||
+ (parseContext.profile != EEsProfile && (parseContext.version >= 420 || parseContext.extensionsTurnedOn(1, &GL_ARB_shader_image_load_store))) ||
+ (inEs310 && parseContext.profile == EEsProfile && parseContext.version >= 310))
return keyword;
- if (parseContext.profile == EEsProfile && parseContext.version >= 300 ||
- parseContext.profile != EEsProfile && parseContext.version >= 130) {
+ if ((parseContext.profile == EEsProfile && parseContext.version >= 300) ||
+ (parseContext.profile != EEsProfile && parseContext.version >= 130)) {
reservedWord();
return keyword;
{
afterType = true;
- if (parseContext.profile != EEsProfile && parseContext.version >= 420)
+ if (parseContext.profile == EEsProfile && parseContext.version >= 310) {
+ reservedWord();
+ return keyword;
+ }
+
+ if (parseContext.symbolTable.atBuiltInLevel() || parseContext.profile != EEsProfile && (parseContext.version >= 420 || parseContext.extensionsTurnedOn(1, &GL_ARB_shader_image_load_store)))
return keyword;
if (parseContext.forwardCompatible)