Add more allowances for relaxed error checking mode: Warn instead of error on use of a disabled extension, allow 'f' suffix on floating point literals, and allow #version after tokens.
git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@27113 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
parent
fd30542a0f
commit
7e991e7be1
5 changed files with 113 additions and 56 deletions
|
|
@ -155,79 +155,117 @@ void TInputScanner::consumeWhitespaceComment(bool& foundNonSpaceTab)
|
||||||
// or no #version was found; otherwise, returns false. There is no error case, it always
|
// 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.
|
// 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
|
// 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,
|
// is that scanning will start anew, following the rules for the chosen version/profile,
|
||||||
// and with a corresponding parsing context.
|
// 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,
|
// This function doesn't have to get all the semantics correct,
|
||||||
// just find the #version if there is a correct one present.
|
// just find the #version if there is a correct one present.
|
||||||
// The preprocessor will have the responsibility of getting all the semantics right.
|
// 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
|
version = 0; // means not found
|
||||||
profile = ENoProfile;
|
profile = ENoProfile;
|
||||||
|
|
||||||
bool foundNonSpaceTab = false;
|
bool foundNonSpaceTab = false;
|
||||||
consumeWhitespaceComment(foundNonSpaceTab);
|
bool lookingInMiddle = false;
|
||||||
|
|
||||||
// #
|
|
||||||
if (get() != '#')
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// whitespace
|
|
||||||
int c;
|
int c;
|
||||||
do {
|
do {
|
||||||
c = get();
|
if (lookingInMiddle) {
|
||||||
} while (c == ' ' || c == '\t');
|
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;
|
||||||
|
|
||||||
if ( c != 'v' ||
|
// Nominal start, skipping the desktop allowed comments and white space, but tracking if
|
||||||
get() != 'e' ||
|
// something else was found for ES:
|
||||||
get() != 'r' ||
|
consumeWhitespaceComment(foundNonSpaceTab);
|
||||||
get() != 's' ||
|
if (foundNonSpaceTab)
|
||||||
get() != 'i' ||
|
versionNotFirst = true;
|
||||||
get() != 'o' ||
|
|
||||||
get() != 'n')
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// whitespace
|
// "#"
|
||||||
do {
|
if (get() != '#') {
|
||||||
c = get();
|
versionNotFirst = true;
|
||||||
} while (c == ' ' || c == '\t');
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// version number
|
// whitespace
|
||||||
while (c >= '0' && c <= '9') {
|
do {
|
||||||
version = 10 * version + (c - '0');
|
c = get();
|
||||||
c = get();
|
} while (c == ' ' || c == '\t');
|
||||||
}
|
|
||||||
if (version == 0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// whitespace
|
|
||||||
while (c == ' ' || c == '\t')
|
|
||||||
c = get();
|
|
||||||
|
|
||||||
// profile
|
// "version"
|
||||||
const int maxProfileLength = 13; // not including any 0
|
if ( c != 'v' ||
|
||||||
char profileString[maxProfileLength];
|
get() != 'e' ||
|
||||||
int profileLength;
|
get() != 'r' ||
|
||||||
for (profileLength = 0; profileLength < maxProfileLength; ++profileLength) {
|
get() != 's' ||
|
||||||
if (c < 0 || c == ' ' || c == '\t' || c == '\n' || c == '\r')
|
get() != 'i' ||
|
||||||
break;
|
get() != 'o' ||
|
||||||
profileString[profileLength] = c;
|
get() != 'n') {
|
||||||
c = get();
|
versionNotFirst = true;
|
||||||
}
|
continue;
|
||||||
if (c > 0 && c != ' ' && c != '\t' && c != '\n' && c != '\r')
|
}
|
||||||
return true;
|
|
||||||
|
|
||||||
if (profileLength == 2 && strncmp(profileString, "es", profileLength) == 0)
|
// whitespace
|
||||||
profile = EEsProfile;
|
do {
|
||||||
else if (profileLength == 4 && strncmp(profileString, "core", profileLength) == 0)
|
c = get();
|
||||||
profile = ECoreProfile;
|
} while (c == ' ' || c == '\t');
|
||||||
else if (profileLength == 13 && strncmp(profileString, "compatibility", profileLength) == 0)
|
|
||||||
profile = ECompatibilityProfile;
|
|
||||||
|
|
||||||
return foundNonSpaceTab;
|
// version number
|
||||||
|
while (c >= '0' && c <= '9') {
|
||||||
|
version = 10 * version + (c - '0');
|
||||||
|
c = get();
|
||||||
|
}
|
||||||
|
if (version == 0) {
|
||||||
|
versionNotFirst = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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') {
|
||||||
|
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 versionNotFirst;
|
||||||
|
} while (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill this in when doing glslang-level scanning, to hand back to the parser.
|
// Fill this in when doing glslang-level scanning, to hand back to the parser.
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ public:
|
||||||
void consumeWhiteSpace(bool& foundNonSpaceTab);
|
void consumeWhiteSpace(bool& foundNonSpaceTab);
|
||||||
bool consumeComment();
|
bool consumeComment();
|
||||||
void consumeWhitespaceComment(bool& foundNonSpaceTab);
|
void consumeWhitespaceComment(bool& foundNonSpaceTab);
|
||||||
bool scanVersion(int& version, EProfile& profile);
|
bool scanVersion(int& version, EProfile& profile, bool& notFirstToken);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -461,11 +461,19 @@ bool CompileDeferred(
|
||||||
int version;
|
int version;
|
||||||
EProfile profile;
|
EProfile profile;
|
||||||
glslang::TInputScanner userInput(numStrings, &strings[1], &lengths[1]); // no preamble
|
glslang::TInputScanner userInput(numStrings, &strings[1], &lengths[1]); // no preamble
|
||||||
bool versionNotFirst = userInput.scanVersion(version, profile);
|
bool versionNotFirstToken;
|
||||||
|
bool versionNotFirst = userInput.scanVersion(version, profile, versionNotFirstToken);
|
||||||
bool versionNotFound = version == 0;
|
bool versionNotFound = version == 0;
|
||||||
bool goodVersion = DeduceVersionProfile(compiler->infoSink, compiler->getLanguage(), versionNotFirst, defaultVersion, version, profile);
|
bool goodVersion = DeduceVersionProfile(compiler->infoSink, compiler->getLanguage(), versionNotFirst, defaultVersion, version, profile);
|
||||||
bool versionWillBeError = (versionNotFound || (profile == EEsProfile && version >= 300 && versionNotFirst));
|
bool versionWillBeError = (versionNotFound || (profile == EEsProfile && version >= 300 && versionNotFirst));
|
||||||
|
bool warnVersionNotFirst = false;
|
||||||
|
if (! versionWillBeError && versionNotFirstToken) {
|
||||||
|
if (messages & EShMsgRelaxedErrors)
|
||||||
|
warnVersionNotFirst = true;
|
||||||
|
else
|
||||||
|
versionWillBeError = true;
|
||||||
|
}
|
||||||
|
|
||||||
intermediate.setVersion(version);
|
intermediate.setVersion(version);
|
||||||
intermediate.setProfile(profile);
|
intermediate.setProfile(profile);
|
||||||
SetupBuiltinSymbolTable(version, profile);
|
SetupBuiltinSymbolTable(version, profile);
|
||||||
|
|
@ -496,6 +504,12 @@ bool CompileDeferred(
|
||||||
parseContext.setLimits(*resources);
|
parseContext.setLimits(*resources);
|
||||||
if (! goodVersion)
|
if (! goodVersion)
|
||||||
parseContext.addError();
|
parseContext.addError();
|
||||||
|
if (warnVersionNotFirst) {
|
||||||
|
TSourceLoc loc;
|
||||||
|
loc.line = 1;
|
||||||
|
loc.string = 0;
|
||||||
|
parseContext.warn(loc, "Illegal to have non-comment, non-whitespace tokens before #version", "#version", "");
|
||||||
|
}
|
||||||
|
|
||||||
parseContext.initializeExtensionBehavior();
|
parseContext.initializeExtensionBehavior();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -367,6 +367,10 @@ void TParseContext::requireExtensions(TSourceLoc loc, int numExtensions, const c
|
||||||
bool warned = false;
|
bool warned = false;
|
||||||
for (int i = 0; i < numExtensions; ++i) {
|
for (int i = 0; i < numExtensions; ++i) {
|
||||||
TExtensionBehavior behavior = getExtensionBehavior(extensions[i]);
|
TExtensionBehavior behavior = getExtensionBehavior(extensions[i]);
|
||||||
|
if (behavior == EBhDisable && (messages & EShMsgRelaxedErrors)) {
|
||||||
|
infoSink.info.message(EPrefixWarning, "The following extension must be enabled to use this feature:", loc);
|
||||||
|
behavior = EBhWarn;
|
||||||
|
}
|
||||||
if (behavior == EBhWarn) {
|
if (behavior == EBhWarn) {
|
||||||
infoSink.info.message(EPrefixWarning, ("extension " + TString(extensions[i]) + " is being used for " + featureDesc).c_str(), loc);
|
infoSink.info.message(EPrefixWarning, ("extension " + TString(extensions[i]) + " is being used for " + featureDesc).c_str(), loc);
|
||||||
warned = true;
|
warned = true;
|
||||||
|
|
|
||||||
|
|
@ -205,7 +205,8 @@ int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
|
||||||
}
|
}
|
||||||
} else if (ch == 'f' || ch == 'F') {
|
} else if (ch == 'f' || ch == 'F') {
|
||||||
parseContext.profileRequires(ppToken->loc, EEsProfile, 300, 0, "floating-point suffix");
|
parseContext.profileRequires(ppToken->loc, EEsProfile, 300, 0, "floating-point suffix");
|
||||||
parseContext.profileRequires(ppToken->loc, ~EEsProfile, 120, 0, "floating-point suffix");
|
if ((parseContext.messages & EShMsgRelaxedErrors) == 0)
|
||||||
|
parseContext.profileRequires(ppToken->loc, ~EEsProfile, 120, 0, "floating-point suffix");
|
||||||
if (! HasDecimalOrExponent)
|
if (! HasDecimalOrExponent)
|
||||||
parseContext.error(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
|
parseContext.error(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
|
||||||
if (len < TPpToken::maxTokenLength)
|
if (len < TPpToken::maxTokenLength)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue