#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"
// read past any white space
void TInputScanner::consumeWhiteSpace(bool& foundNonSpaceTab)
{
- char c = 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;
return false;
get(); // consume the '/'
- char c = peek();
+ int c = peek();
if (c == '/') {
// a '//' style comment
consumeWhiteSpace(foundNonSpaceTab);
// if not starting a comment now, then done
- char c = peek();
+ int c = peek();
if (c != '/' || c < 0)
return;
// 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 TInputScanner::scanVersion(int& version, EProfile& profile)
+bool TInputScanner::scanVersion(int& version, EProfile& profile, bool& notFirstToken)
{
// 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(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 (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 = get();
- } while (c == ' ' || c == '\t');
-
- if ( c != 'v' ||
- get() != 'e' ||
- get() != 'r' ||
- get() != 's' ||
- get() != 'i' ||
- get() != 'o' ||
- get() != 'n')
- return true;
+ // whitespace
+ do {
+ c = get();
+ } while (c == ' ' || c == '\t');
- // whitespace
- do {
- c = 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 = get();
- }
- if (version == 0)
- return true;
-
- // whitespace
- while (c == ' ' || c == '\t')
- c = get();
+ // whitespace
+ while (c == ' ' || c == '\t')
+ c = 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 = get();
- }
- if (c > 0 && c != ' ' && c != '\t' && c != '\n' && c != '\r')
- return true;
+ // 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;
+ 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
ReservedSet->insert("using");
}
+void TScanContext::deleteKeywordMap()
+{
+ delete KeywordMap;
+ KeywordMap = 0;
+ delete ReservedSet;
+ ReservedSet = 0;
+}
+
int TScanContext::tokenize(TPpContext* pp, TParserToken& token)
{
do {
default:
char buf[2];
- buf[0] = ppToken.token;
+ buf[0] = (char)ppToken.token;
buf[1] = 0;
parseContext.error(loc, "unexpected token", buf, "");
break;
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))
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:
afterType = true;
if (parseContext.profile == EEsProfile)
reservedWord();
- else if (parseContext.version < 140 && ! parseContext.symbolTable.atBuiltInLevel() && ! parseContext.extensionsTurnedOn(1, &GL_ARB_texture_rectangle))
- 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:
return keyword;
case PRECISE:
- if (parseContext.profile == EEsProfile ||
+ if (parseContext.profile == EEsProfile && parseContext.version >= 310)
+ reservedWord();
+ else if (parseContext.profile == EEsProfile ||
(parseContext.profile != EEsProfile && parseContext.version < 400))
return identifierOrType();
return keyword;
// but then got reserved by ES 3.0.
int TScanContext::es30ReservedFromGLSL(int version)
{
+ if (parseContext.symbolTable.atBuiltInLevel())
+ return keyword;
+
if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
(parseContext.profile != EEsProfile && parseContext.version < version)) {
if (parseContext.forwardCompatible)
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) ||
{
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)